Skip to content

Python: fix tools from context providers - #9403

Open
sophia-ramsey wants to merge 2 commits into
mainfrom
sramsey/python-tool-definitions
Open

sophia-ramsey wants to merge 2 commits into
mainfrom
sramsey/python-tool-definitions

Conversation

@sophia-ramsey

Copy link
Copy Markdown
Member

Motivation & Context

The agent evaluation previously omitted tools injected by context providers, causing Foundry tool-selection and tool-input-accuracy evaluators to return null scores because tool definitions were missing. This change captures the tool definitions available during execution and preserves schema-only snapshots across response serialization, so they remain available for evaluation. It supports evaluating agents with dynamically provided tools, both immediately after execution and from saved responses.

Description & Review Guide

  • What are the major changes? Capturing run-specific tool definitions, including provider-injected and dynamically exposed tools, and preserving schema-only snapshots across JSON/pickle serialization and agent-loop aggregation. Evaluation automatically uses these definitions, with an optional tools= override.
  • What is the impact of these changes? Evaluation receiving the definitions needed to score tool calls without persisting executable callbacks or connections. Serialized responses gain tool-schema metadata, and schema capture introduces earlier JSON-compatibility validation that can reject non-serializable custom schemas.
  • What do you want reviewers to focus on? Potential changes in serialization, specifically whether the metadata and schema validation introduces compatibility changes. The addition of tools= was not explicitly required to resolve this issue, but it seemed like it would improve the developer experience.

Related Issue

Fixes #9160

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: Used copilot with GPT-6.1 Sol for solution planning, design evaluation, implementation, and testing.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Copilot AI balanced review requested due to automatic review settings October 14, 2026 23:47
@sophia-ramsey
sophia-ramsey deployed to github-app-auth October 14, 2026 23:47 — with GitHub Actions Active
@sophia-ramsey
sophia-ramsey deployed to github-app-auth October 14, 2026 23:47 — with GitHub Actions Active
@agent-framework-automation agent-framework-automation Bot added documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python labels Oct 14, 2026
@github-code-quality

Copy link
Copy Markdown
Contributor

Code coverage overview

Languages: Python

Python / code-coverage/python

main 95511ff sramsey/python-tool-... 36a84a8 +/-
92% 92% 0%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Serialization and supported streaming/client paths can still lose or misrepresent tool definitions.

4 open findings
What changed in this PR

Addresses #9160 by capturing run-specific tool definitions for evaluation, including tools supplied by context providers.

Changes:

  • Captures schema-only tool snapshots and preserves them through serialization.
  • Adds an explicit tools= evaluation override and loop aggregation support.
  • Adds regression tests and documents snapshot behavior.
File Description
python/​packages/​core/​tests/​core/​test_evaluation.py Tests tool discovery, overrides, and serialization.
python/​packages/​core/​AGENTS.md Documents evaluation snapshots.
python/​packages/​core/​agent_framework/​_types.py Stores and restores tool schemas.
python/​packages/​core/​agent_framework/​_harness/​_loop.py Aggregates definitions across loop iterations.
python/​packages/​core/​agent_framework/​_evaluation.py Uses captured definitions and explicit overrides.
python/​packages/​core/​agent_framework/​_agents.py Captures tools during execution.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

session_context = context["session_context"]
if context["suppress_response_id"]:
response.response_id = None
response._set_evaluation_tools(context["evaluation_tools"]) # pyright: ignore[reportPrivateUsage]
for tool in _normalize_tools(co.get("tools"))
if isinstance(tool, FunctionTool)
]
if isinstance(self.client, ChatMiddlewareLayer):
Comment on lines +57 to +58
schema = deepcopy(tool.parameters())
json.dumps(schema, allow_nan=False)
Comment on lines +3362 to +3365
if definitions:
self.additional_properties[_EVALUATION_TOOLS_METADATA_KEY] = {"version": 1, "tools": definitions}
else:
self.additional_properties.pop(_EVALUATION_TOOLS_METADATA_KEY, None)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAF Automated Review — Iteration 1

Result: Findings reported
Scope: full PR (2 commit(s)): 813d7c0994f1, 36a84a8608a6
Model: gpt-5.6-sol

Overview

The change captures run-specific tool declarations with deep-copied, JSON-validated schemas, restores them as non-executable tools, and carries them through normal response serialization and loop aggregation. Per-run capture, malformed-metadata validation, explicit overrides, and broad streaming/non-streaming tests are strong guardrails. Three serialization and lifecycle gaps remain: empty snapshots are erased, same-name progressive replacements retain stale schemas, and update-only streaming round trips omit the snapshots.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
3 verified findings remained after source verification (3 medium) across 2 files. Details are attached to the affected lines below.

Affected areas: python/packages/core/agent_framework/_agents.py, python/packages/core/agent_framework/_types.py

if definitions:
self.additional_properties[_EVALUATION_TOOLS_METADATA_KEY] = {"version": 1, "tools": definitions}
else:
self.additional_properties.pop(_EVALUATION_TOOLS_METADATA_KEY, None)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An empty capture is still a meaningful snapshot, but this branch deletes its serialized marker. After a JSON/dict/pickle round trip, _get_evaluation_tools() returns None, so evaluation with an agent falls back to the agent's current tools and evaluates a no-tool run against unrelated definitions. Please persist {"version": 1, "tools": []} so serialized responses distinguish "captured empty" from legacy responses with no snapshot.

from ._tools import FunctionTool

for tool in _normalize_tools((context.options or {}).get("tools")):
if isinstance(tool, FunctionTool) and tool.name not in self._seen:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove_tools() followed by add_tools() can validly replace a tool with the same name on the next function-loop iteration, but this name-only gate keeps the original declaration. The model can then invoke the replacement schema while evaluation sees the obsolete one. Please update the captured declaration when a same-name description or schema changes, or reject that replacement explicitly instead of silently retaining stale metadata.

session_context = context["session_context"]
if context["suppress_response_id"]:
response.response_id = None
response._set_evaluation_tools(context["evaluation_tools"]) # pyright: ignore[reportPrivateUsage]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attaching the snapshot only in the result hook means none of the already-emitted AgentResponseUpdates carries it. Consumers that persist streaming updates and rebuild with the public AgentResponse.from_updates() API therefore lose the definitions and cannot perform the post-hoc evaluation this change enables. Please carry the versioned schema metadata on the terminal update, or otherwise make update-only streaming round trips preserve it.

This branch was successfully deployed

1 active deployment
github-app-auth — 36a84a86 Deployed Oct 14, 2026 by sophia-ramsey via team_check #6837
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: evaluate_agent() omits ContextProvider/SkillsProvider tools from tool_definitions, breaking tool_selection/tool_input_accuracy

2 participants