Repository navigation
test(harness): a Pydantic AI reference agent for the hosted path (TH-8808) - #304
khushalsonawat wants to merge 4 commits into
Conversation
…8808) A small support agent on Pydantic AI 2.61.0, the same desk as the OpenAI Agents SDK reference: three plain function tools, a module-level agent_callback for the kit's callback bridge, the persona given as instructions (a system prompt is dropped once there is history), and the model built per call as an OpenAIChatModel on a client that is closed with the call. A plain openai: model string would use the Responses API. Offline tests pin what the hosted path does with it, with a stand-in for the library: it is detected as pydantic_ai; the build runs it through the callback bridge with the tool tracer bound to its three tools; the tracer records each tool as 2.61.0 calls it (anyio worker threads); and the callback sends each turn once, as prompt plus history, and replies with content only. Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
| trace = tmp_path / "calls.jsonl" | ||
| bindings = [{"name": name, "module": "agent", "callable": name} for name in TOOLS] | ||
|
|
||
| completed = subprocess.run( |
There was a problem hiding this comment.
P3. No timeout on this subprocess.run, so a hang in the driver hangs the whole suite. #305's equivalent uses timeout=180; add the same here.
| assert agent.environment["PORT"] == "{{PORT_agent}}" | ||
| assert "requirements.txt" in json.dumps(agent.build_commands) | ||
| assert agent.environment["HARNESS_TOOL_TRACE"] == "{{WORLD_DIR}}/agent-tool-calls.jsonl" | ||
| bindings = json.loads(agent.environment["ALK_TOOL_TRACE_BINDINGS"]) |
There was a problem hiding this comment.
P3. The bindings this asserts are the ones the test writes into the contract itself, and _source_tool_trace_environment copies them through unchanged, so the assert compares the test's input with itself. Renaming return_policy in the example leaves this test green (three other tests catch it).
Fix: assert the bindings against the example's real functions, or drop the bindings claim from the test's name.
| } | ||
|
|
||
|
|
||
| def _copy_example(destination: Path) -> Path: |
There was a problem hiding this comment.
P3. Same copied setup as the other reference-agent PRs (_copy_example, the stand-in writer, the fresh-import fixture, the detection tests, the build test skeleton, the tracer driver, the pin tests). See the shared-helper comment on #301: this file would import from that one module instead.
…-ai-reference Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
…elpers, and refuse a key with no base URL (TH-8808) The test file uses tests/harness/reference_agents.py from #301; the tracer subprocess has a timeout, and the build test checks each tracer binding against the example's real functions. The example refuses, before building a client, a key given without OPENAI_BASE_URL, and the README says why agent-simulate is pinned. Signed-off-by: khushalsonawat <khushalsonawat@gmail.com>
| # T2: the build ------------------------------------------------------------------------------ | ||
|
|
||
|
|
||
| def _example_module_for_bindings(tmp_path: Path): |
There was a problem hiding this comment.
P3. This helper re-implements the shared fresh_import with its own sys.path and sys.modules handling. The example_module fixture above already gives a fresh import on the same stand-ins, and #305's build test uses its fixture this way. Taking example_module as a parameter of the build test and calling module = example_module() keeps all 16 tests green, still fails when a tool is renamed, and drops this helper and the importlib.util import.
The loop at lines 226-233 that checks each binding against the real function is also the same as #305's, and #301's build test still compares the bindings with its own input (test_openai_agents_reference.py:180). One assert_bindings_match(bindings, module, module_name) in reference_agents.py would serve all three.
Summary
TH-8808 is part of T43: qualify the hosted harness across frameworks. This is Pydantic AI's offline half, on the same pattern as the OpenAI Agents SDK reference (#301). A local end-to-end run with a real reading and a real model is summarised under Verification.
examples/harness/pydantic_ai_support/is a small support agent on Pydantic AI 2.61.0, with the same three tools as test(harness): an OpenAI Agents SDK reference agent for the hosted path (TH-8800) #301 so the frameworks can be compared:agent_callbackfor the kit's callback bridge.instructions=. Asystem_prompt=is added only while the history is empty, so it would vanish from the second turn on.OpenAIChatModelon a client closed with the call. A plainopenai:model string maps to the Responses API, which the model gateway serves only for OpenAI-format routes.OPENAI_API_KEYis set andOPENAI_BASE_URLisn't, the callback raises before building a client, naming the missing setting.tests/harness/test_pydantic_ai_reference.pypins what the hosted path does with it, using a stand-in for the library (it isn't a kit dependency):pydantic_ai(run folder, subfolder, in place), and a shadowingpydantic_ai.pychanges the result.No kit code changes. The tests use the shared helpers in
tests/harness/reference_agents.py.Stacked on #301 (
feat/th-8800-openai-agents-reference): it uses #301's shared test helpers, so #301 merges first, with a merge commit.Verification
ruff checkon the new filestest_framework_detection.py,test_python_tool_trace_bootstrap.pyandtest_callback_http_adapter.py. 293 passed.uv run pytest -q: not run, because no shared runtime is touched.sdk-smokeruns a fixed list of test files, which didn't include this one. It now does (tests/harness/test_pydantic_ai_reference.py).vertex_ai/gemini-3.7-flashthrough the model gateway): it passes end to end. 3 right replies, and the trace file has the 3 calls with their arguments and results.openai:model string;pydantic_ai.py;system_prompt=instead ofinstructions=.Review round 1 (Dileep)
agent-simulateis pinned.Known limits
openai:<model>and run on the gateway with a non-OpenAI model gets the gateway's 501, because it uses the Responses API. A guidance line to writeopenai-chat:<target_model>, next to fix(harness): let an OpenAI Agents SDK agent run on the model gateway (TH-8800) #303's, follows as a separate PR once fix(harness): let an OpenAI Agents SDK agent run on the model gateway (TH-8800) #303 merges (a register row).Checklist
agent_learning.*,agent-learn, or@future-agi/agent-learning-kit