Structured Output Extraction Contract¶
This document defines the canonical contract for how agent structured outputs are extracted, validated, and consumed in the mozaiks runtime.
Overview¶
The structured output extraction pattern enables: 1. Agents to produce typed JSON outputs 2. Runtime to validate outputs against Pydantic models 3. Auto-invoked tools to consume validated outputs 4. UI artifacts to be generated from agent outputs
Architecture¶
Agent (structured_outputs_required: true)
│
▼ emits JSON matching registered model
│
structured_outputs.yaml (registry: Agent → Model)
│
▼ runtime validates against Pydantic model
│
AutoToolEventHandler
│
▼ finds tool with auto_tool_call: true for this agent
│
tools.yaml (agent + auto_tool_call: true)
│
▼ invokes tool function with validated payload
│
tools/{function}.py
│
▼ persists, emits UI events, updates context
│
UI (receives tool_call/tool_response events)
Key Files¶
| File | Purpose |
|---|---|
structured_outputs.yaml | Model definitions + agent→model registry |
agents.yaml | Agent config with structured_outputs_required: true |
tools.yaml | Tool bindings with auto_tool_call: true |
tools/*.py | Python tool implementations |
extended_orchestration/mfj_extension.json | MFJ (fan-out/fan-in) config |
Contract Details¶
1. structured_outputs.yaml¶
Defines Pydantic models and maps agents to their output models.
# Registry: agent name → model name
registry:
ExampleDecomposerAgent: ExampleDecomposition
ExamplePresenterAgent: ExamplePresentation
# Model definitions
models:
ExampleChildSpec:
type: model
fields:
name:
type: literal
values: [ExampleWorker]
description: Fixed child workflow name
description:
type: str
description: The angle label in 3-5 words
initial_message:
type: str
description: Full prompt for the child workflow
ExampleDecomposition:
type: model
fields:
agent_message:
type: str
description: Status message shown to user
workflows:
type: list
items: ExampleChildSpec
description: Child workflows to spawn
Supported field types: - str, int, float, bool - optional_str (Optional[str]) - list (requires items) - optional_list (Optional[List]) - dict (Dict[str, Any]) - literal (requires values list → becomes Enum) - union (requires variants list) - Model references (use model name as type)
2. agents.yaml¶
Agents that produce structured outputs must set structured_outputs_required: true.
agents:
- name: ExampleDecomposerAgent
prompt_sections:
- id: role
heading: '[ROLE]'
content: You are JokeDecomposer...
- id: output_format
heading: '[OUTPUT FORMAT]'
content: |
Respond with ONLY valid JSON matching ExampleDecomposition.
No extra text. No markdown fences.
structured_outputs_required: true # REQUIRED
max_consecutive_auto_reply: 3
Agent prompt contract: - Include [OUTPUT FORMAT] section specifying exact JSON shape - Instruct agent to output ONLY JSON, no extra text - Reference the model name from structured_outputs.yaml
3. tools.yaml¶
Tools with auto_tool_call: true are called automatically when their agent produces output.
tools:
# Auto-invoked tool for structured output consumption
- agent: ExampleDecomposerAgent
file: spawn_example_workers.py
function: spawn_example_workers
tool_type: Agent_Tool
auto_tool_call: true # Called automatically after agent output
# One-way UI surface for artifact display
- agent: ExamplePresenterAgent
file: display_presentation.py
function: display_presentation
tool_type: UI_Surface
auto_tool_call: true
ui:
component: ExampleGallery
mode: artifact
auto_tool_call behavior: - When agent emits output → runtime validates against model - If valid → finds tool with auto_tool_call: true for this agent - Invokes tool function with validated payload as kwargs - Tool receives structured output fields directly as parameters
4. Tool Implementation¶
Tools receive the validated structured output fields as keyword arguments.
# tools/spawn_example_workers.py
async def spawn_example_workers(
agent_message: str,
workflows: list,
context_variables=None, # Optional: runtime context
**kwargs
) -> dict:
"""
Receives validated ExampleDecomposition fields directly.
Args:
agent_message: From ExampleDecomposition.agent_message
workflows: From ExampleDecomposition.workflows (list of ExampleChildSpec)
context_variables: Runtime context container
"""
# Tool logic - persist, spawn children, emit events
for workflow_spec in workflows:
# workflow_spec is already validated against JokeAngleSpec
child_name = workflow_spec["name"]
child_message = workflow_spec["initial_message"]
# ... spawn logic
return {
"success": True,
"spawned": len(workflows),
"context_updates": {
"decomposition_complete": True,
}
}
Tool parameter binding: - Model field names are matched to function parameters - Case-insensitive matching (agent_message matches agentMessage) - context_variables is injected if function accepts it - Metadata (chat_id, app_id, workflow_name, turn_idempotency_key) injected if accepted
Runtime Flow¶
AutoToolEventHandler¶
Located at: mozaiksai/core/events/auto_tool_handler.py
The handler: 1. Listens for chat.agent_output_validated events 2. Checks if auto_tool_call: true 3. Resolves tool binding from workflow's tools.yaml 4. Validates structured_data against the model 5. Builds kwargs from validated payload + context 6. Invokes the tool function 7. Persists context variable updates 8. Emits tool_call and tool_response events to UI
Event Flow¶
Agent output → TextEvent
│
▼
Stream processor detects structured output
│
▼
Emits chat.agent_output_validated event:
{
"kind": "runtime.agent_output_validated",
"agent_name": "ExampleDecomposerAgent",
"model_name": "ExampleDecomposition",
"structured_data": { ... validated JSON ... },
"auto_tool_call": true,
"context": { "chat_id", "app_id", "workflow_name" }
}
│
▼
AutoToolEventHandler.handle_tool_dispatch()
│
▼
Tool function invoked with validated kwargs
│
▼
Emits chat.tool_call + chat.tool_response to UI
MFJ (Mid-Flight Journeys)¶
For workflows that fan-out to child workflows, use extended_orchestration/mfj_extension.json.
{
"version": 3,
"mid_flight_journeys": [
{
"id": "parallel-example-generation",
"description": "Spawn 3 parallel ExampleWorker children",
"decomposition_agent": "ExampleDecomposerAgent",
"fan_out": {
"spawn_mode": "workflow",
"max_children": 3
},
"fan_in": {
"resume_agent": "ExamplePresenterAgent",
"resume_entry_agent": "ResumeRouterAgent",
"inject_as": "mfj_example_results"
}
}
]
}
MFJ structured output contract: - decomposition_agent must have structured_outputs_required: true - Model must include workflows field (list of child specs) - Each child spec must include name (workflow name) and initial_message - Fan-in results injected into context as inject_as key
What Does NOT Exist¶
The following do NOT exist in the mozaiks runtime:
| Aspirational Concept | Reality |
|---|---|
| Standalone extractor classes | Does not exist. Tools consume structured outputs directly |
| Separate "extraction" phase | Does not exist. Auto-invoke tools handle consumption inline |
Complete Example¶
Below is a schematic workflow bundle showing the complete contract shape. Use live production workflows under factory_app/workflows/* or an active app root's app/workflows/* for implementation references:
ExampleWorkflow/
├── orchestrator.yaml # workflow_startup_mode, initial_agent
├── agents.yaml # Agents with structured_outputs_required
├── structured_outputs.yaml # ExampleDecomposition, ExamplePresentation models
├── handoffs.yaml # Agent-to-agent routing
├── tools.yaml # auto_tool_call tools
├── context_variables.yaml # State definitions
├── hooks.yaml # Optional hooks
├── ui_config.yaml # visual_agents
├── extended_orchestration/
│ └── mfj_extension.json # MFJ fan-out/fan-in config (optional)
└── tools/
├── save_jokes.py
├── rate_joke.py
└── display_ratings.py
Validation¶
The runtime validates all YAML files using Pydantic models with extra="forbid".
Contract enforcement is in: mozaiksai/core/workflow/declarative/contracts.py
Key validation models: - StructuredOutputsConfig - validates structured_outputs.yaml - ToolsConfig - validates tools.yaml - AgentsConfig - validates agents.yaml
Cross References¶
- workflow-authoring-contracts.md
mozaiksai/core/events/auto_tool_handler.pymozaiksai/core/workflow/outputs/structured.py