JSON Schema Structured Output Implementation Plan#
For implementation: Execute each task with a failing test first. Keep the existing
Runtime.exec -> AgentSession -> agent_loop -> stream_simplepath; do not add a second provider client.
Goal: Make Runtime.exec(..., response_format=...) carry a normalized JSON Schema to
the provider path and return a strictly parsed, locally validated Python JSON value.
Architecture: Normalize and validate the caller schema at the Runtime trust boundary, carry the immutable option through existing agent/provider option types, map it only in adapters with a verified native contract, and validate the final assistant text locally. The first implementation batch covers the shared path and OpenAI-compatible native payloads. Other adapters remain explicitly unsupported until their contract tests exist.
Dependencies: Existing Pydantic models and the already locked jsonschema package.
Task 1: Structured-output value object and strict validator#
Files:
- Create:
openprogram/providers/structured_output.py - Modify:
openprogram/providers/types.py - Test:
tests/providers/test_structured_output.py
- Add failing tests for bare-schema/envelope normalization, invalid schema rejection, rejection of fenced/trailing/non-finite JSON, deterministic bounded issues, and valid typed values.
- Run
pytest -q tests/providers/test_structured_output.pyand confirm failure. - Add
JsonSchemaOutput, structured error classes,normalize_response_format, andparse_and_validate_jsonusingjsonschema.validators.validator_for. - Add
response_formattoStreamOptionsand structured result metadata toAssistantMessage. - Re-run the focused test and commit.
Task 2: Preserve response_format through Runtime and AgentSession#
Files:
- Modify:
openprogram/agent/agent.py - Modify:
openprogram/agent/session.py - Modify:
openprogram/agent/agent_loop.py - Modify:
openprogram/providers/callable_model.py - Modify:
openprogram/agentic_programming/runtime.py - Test:
tests/agent/test_loop_options.py - Test:
tests/agentic_programming/test_runtime_structured_output.py
- Add failing tests proving the stream function receives the normalized option and a callable-backed Runtime returns a Python value after strict local validation.
- Thread
response_formatthroughAgentOptions,AgentSession,AgentLoopConfig, and_stream_assistant_response'sSimpleStreamOptionsrebuild. - Make the callable adapter read the per-call option rather than capture a stale value.
- Normalize before the network boundary, validate the final assistant text, retain its canonical JSON text for history, and return the parsed value from Runtime.
- Re-run focused Runtime/Agent tests and commit.
Task 3: OpenAI native payload mapping#
Files:
- Modify:
openprogram/providers/openai_completions/openai_completions.py - Modify:
openprogram/providers/openai_responses/openai_responses.py - Test: existing request-builder tests under
tests/providers/
- Locate the existing request-builder tests and add failures for Chat Completions
response_format.json_schemaand Responsestext.formatpayloads. - Map the normalized option without mutating the caller schema.
- Reject provider-private input shapes at normalization rather than passing them through.
- Re-run provider tests and commit.
Task 4: Bounded semantic repair#
Files:
- Modify:
openprogram/agent/agent_loop.py - Modify:
openprogram/providers/structured_output.py - Test:
tests/agent/test_structured_output_loop.py
- Add a two-response stream fake: the first candidate fails validation and the second succeeds; assert exactly two provider calls and only the valid final message persists.
- At the no-tool terminal boundary, validate; on a validation failure and remaining budget, remove the invalid candidate and append a bounded repair user message to the temporary loop context.
- Do not retry refusal, incomplete, cancellation, or transport failures as validation failures.
- Re-run loop tests and commit.
Task 5: Verification#
- Run focused provider, agent, and runtime suites.
- Run
ruff checkon changed Python files andgit diff --check. - Run
pytest -q tests/unit tests/agent tests/providers tests/agentic_programming. - Record explicitly which provider adapters remain unsupported; do not advertise them as implemented.