AgentGenerator Output Assembly Contract¶
Status: CANONICAL — describes what actually exists Last verified: 2026-09-29 Source files: - factory_app/workflows/AgentGenerator/tools/generate_and_download.py - factory_app/workflows/AgentGenerator/tools/workflow_converter.py - factory_app/workflows/AgentGenerator/structured_outputs.yaml - factory_app/workflows/AgentGenerator/agents.yaml - factory_app/workflows/AgentGenerator/extended_orchestration/task_batches.yaml
Related:
structured-output-extraction-contract.md— the general runtime contract for structured outputs and auto-tool-call. This document covers the AgentGenerator-specific pattern where a task batch worker agent produces all workflow bundle files in a single structured output.
How This Works¶
AgentGenerator first validates and reviews the workflow partition:
PatternAgentemitsPatternSelection. Its tool validates the typed selection against the canonical DesignDocs workflow surface map before writingworkflows_spec. Module pricing selections are validated by the subscription designer and AppGenerator with their data contract; AgentGenerator does not revalidate them.- Invalid selections return validation feedback to
PatternAgent. Three total selection attempts are permitted per run; exhausted attempts fail rather than dispatching an invalid plan. ProjectOverviewAgentpresentsWorkflowPlanReview, except for a validated empty partition in explicit autonomous mode. Approval, request-changes, and cancellation are structured UI responses correlated byreview_idand the exact selection hash. Chat keywords cannot approve a plan.- For an approved non-empty partition,
PackBuildCoordinatorstartsworkflow_generation_tasks: oneWorkflowBundleBuilderAgentper workflow. - Each worker emits
WorkflowBundleBuilderOutputcontainingCodeFileentries. The runtime collects results inworkflow_bundle_results, keyed by task ID. generate_and_downloadvalidates the resulting workflow contracts before writing accepted bundles, creating the ZIP, or presenting the download UI.
Workflow features are excluded from generated pricing until workflow launch enforces plan grants (#770). AgentGenerator rejects a saved contract that still selects a workflow pricing feature and asks for SubscriptionContractDesigner to rerun. Unpriced workflows continue using the workflow name capability convention for event routing.
Apps Without AI Workflows¶
An explicit workflows: [], is_multi_workflow: false, and non-empty pack_partition_reason is valid when the approved design requires only modules and pages. A missing or malformed selection is not equivalent to this decision. Unknown surface kinds and contradictions with DesignDocs fail validation.
When coding_participation is exactly autonomous, the validated empty partition records workflow_plan_review.status: not_required with its selection hash and rationale, without requesting or claiming human approval. Other modes retain the review. After that decision or human approval, the existing artifact recorder saves a workflow_bundle build record with workflows: [], the review disposition, and no workflow ZIP, primary workflow, API endpoint, or websocket endpoint. The stage completes only after this required save succeeds. It does not run the task batch or fabricate a workflow. Downstream AppGenerator consumes the same explicit empty integration metadata; prior workflow hints are cleared.
Review changes return to PatternAgent; at most three review attempts are allowed, with retries only after changes_requested. These limits are runtime execution guards, not freemium or subscription entitlements. Cancellation, stale approval, failed recording, and exhausted attempts fail the stage.
There are no sequential planning agents scraping MongoDB. Each WorkflowBundleBuilderAgent instance owns its full bundle output end-to-end.
Generated workflow bundles are staged at:
They do not become active runtime-loaded workflows until an explicit promotion step copies them into an active app root's workflows/ directory.
Agent Roster¶
| Agent | Role |
|---|---|
InterviewAgent | Clarifies missing AI requirements without inventing automation |
PatternAgent | Selects zero, one, or multiple workflows inside the approved design boundary |
ProjectOverviewAgent | Presents the draft-correlated workflow plan review |
PackBuildCoordinator | Starts the task batch for an approved non-empty partition |
WorkflowBundleBuilderAgent | Task batch worker — generates all YAML and code files for one workflow bundle |
PackMetadataAgent | Produces pack-level extension_registry.json metadata after workflow bundles complete |
DownloadAgent | Triggers generate_and_download after pack metadata is ready |
Task Batch: workflow_generation_tasks¶
Declared in extended_orchestration/task_batches.yaml.
source:
kind: context_variable
path: workflows_spec
task_model: WorkflowInPack
worker:
mode: ag2_agent
agent_field: initial_agent # WorkflowBundleBuilderAgent
prompt_field: initial_message
result:
context_key: workflow_bundle_results
status_key: workflow_bundle_status
Each task receives one WorkflowInPack entry from workflows_spec. Its optional design_surface_id references the approved DesignDocs workflow surface. The runtime injects it as context_variables["structured_output"] for the worker.
WorkflowBundleBuilderOutput¶
The serialized YAML inside each orchestrator.yaml file must declare top-level schema_version: mozaiks.orchestrator.v1; each structured_outputs.yaml file must declare schema_version: mozaiks.structured_outputs.v1. The assembler validates these document versions; the outer bundle is not their authority.
The worker emits a single WorkflowBundleBuilderOutput structured output:
workflow_name: str
outcome_plans: []
files:
- filename: orchestrator.yaml
content: "..."
- filename: agents.yaml
content: "..."
- filename: transition_graph.yaml
content: "..."
- filename: context_variables.yaml
content: "..."
- filename: structured_outputs.yaml
content: "..."
- filename: tools.yaml
content: "..."
- filename: middleware.yaml
content: "..."
- filename: ui_config.yaml
content: "..."
- filename: tools/some_tool.py
content: "..."
- filename: ui/index.js
content: "..."
Each CodeFile has: - filename — workflow-local relative path (e.g., tools/save_result.py, ui/index.js) - content — full file content as a string
The outer structured response does not validate the YAML or Python inside content. The quality gate parses all eight required workflow documents, plus optional a2a.yaml, through the same schema parsers used by the runtime. It also checks context references, transition compilation, and task-batch contracts. Duplicate filenames, retired declarative JSON/YML variants, and unrendered .j2 files block export.
Declared tools must have an included Python file and matching top-level function. Python syntax errors and unfinished tool implementations block export. Workers must implement the tool behavior; there is no later tool-implementation stage. These static checks do not prove arbitrary business logic or external integrations work. Functional execution tests remain necessary for those behaviors.
outcome_plans is a typed list of operation plans. Each plan names agent, function, context_key, attempts_key, result_field, error_value, max_attempts, retry_on, and routes: [{value, target_agent}]. Use an empty list only when no operation needs outcome-dependent routing. Business-specific outcomes are allowed; every outcome must have one known destination.
outcome_materialization.py deterministically generates the matching tool outcome binding, protected context definitions, and ordinary graph transitions. Workers omit these owned context definitions and source-agent transitions from their raw files. They still generate the operation's implementation, tool binding, agent definition, and structured input model. Quality gates validate the materialized files; downloads contain those files, not a runtime dependency on Factory or its build-time plans. Hand-authored workflows use the same runtime tools[].outcome contract documented in Workflow Authoring Contracts.
workflow_bundle_results Structure¶
After the task batch completes, context_variables["workflow_bundle_results"] is a dict:
{
"task_id_1": {
"workflow_name": "StoryCreator",
"files": [
{"filename": "orchestrator.yaml", "content": "..."},
{"filename": "agents.yaml", "content": "..."},
...
]
},
"task_id_2": {
"workflow_name": "ReviewWorkflow",
"files": [ ... ]
}
}
Keys starting with _ are internal meta entries and are skipped during assembly.
Assembly: generate_and_download¶
Reads workflow_bundle_results directly from context. For each bundle entry:
- Materialize operation plans and validate the resulting workflow contracts.
- On failure, schedule bounded workflow repair or return to user attention.
_write_bundle_to_disk(wf_name, files, base_dir)writes accepted files underbase_dir/{wf_name}/._build_pack_zip(bundle_dirs, output_path)zips the workflow directories.use_ui_tool("DownloadCenter", ...)presents the download UI.
Assembly reads task-batch structured outputs directly from runtime context.
Workflow Integration Metadata¶
During bundle assembly, generate_and_download derives workflow_integration_metadata from each generated workflow's orchestrator.yaml:
workflow_name- derived stable
capability_id workflow_startup_mode- event triggers from the
triggers[]block
The normalized metadata is written back to context as:
workflow_integration_metadatagenerated_workflow_integrationsgenerated_workflow_namegenerated_workflow_capability_idgenerated_workflow_startup_modegenerated_workflow_trigger_events
AgentGenerator persists the same metadata on the workflow_bundle artifact. AppGenerator hydrates it from the latest current workflow_bundle artifact before agents run, then its deterministic acceptance gate blocks export unless the generated app wires the workflow through module capabilities, emitted events, and contracts/reactions.yaml.
Smoke coverage:
python scripts/smoke_factory_artifact_lineage.py
python scripts/smoke_factory_artifact_lineage.py --real-store
python scripts/smoke_factory_artifact_lineage.py --real-store --live-agentgenerator --timeout-seconds 600
The first command runs the deterministic in-memory chain. The second uses the Mongo-backed ArtifactStore. The third runs live AgentGenerator AG2 calls, persists the live workflow metadata through the real artifact store, hydrates AppGenerator from that workflow_bundle, and verifies app acceptance/export and runtime loader reaction wiring.
generate_and_download runs the workflow bundle quality gate before download, artifact registration, zip creation, or promotion. The gate writes workflow_bundle_validation_status, workflow_bundle_validation_errors, and workflow_bundle_semantic_drift to context. Blocking failures return status: blocked; the generated bundle is not packaged.
When blocking failures map to specific workflows, generate_and_download schedules a bounded repair pass instead of broad regeneration. It writes workflow_bundle_repair_status: needs_revision, increments workflow_bundle_repair_count, preserves the full pre-repair workflow_bundle_results, narrows workflows_spec to the failed workflow specs, and routes back to PackBuildCoordinator. Each repaired worker receives the exact quality-gate failures in its scoped initial_message. After the repair task batch completes, WorkflowBundleMergeAgent invokes the deterministic merge_workflow_bundle_repair_results auto tool. It commits repaired workflow outputs together with the preserved successful outputs and restores the complete workflows_spec before PackMetadataAgent generates metadata and packaging runs again. The merge is not a prompt hook: workflow_bundle_results requires an authorized writer. Only a committed merged status advances to metadata; a refused write cannot report success. After the configured attempt limit, the status becomes blocked and the workflow returns to the user.
The live AgentGenerator pack smoke also emits the same semantic_drift report. That report is intentionally prompt-oriented: it flags generated workflow YAML that loads but no longer preserves the requested workflow meaning, such as event triggers with missing capability_id, generic trigger descriptions, or conveyor workflows that collapse downstream parallel work into one execution agent. Conveyor workflows that represent heavy downstream work must declare at least two distinct execution agents in extended_orchestration/task_batches.yaml; repeating the same worker name is semantic drift. Fix those failures in AgentGenerator prompt or structured-output contracts first, then rerun the live smoke.
Files Written¶
$MOZAIKS_GENERATED_ARTIFACTS_PATH/workflows/{app_id}/{build_id}/
├── {WorkflowName}/
│ ├── orchestrator.yaml
│ ├── agents.yaml
│ ├── transition_graph.yaml
│ ├── context_variables.yaml
│ ├── structured_outputs.yaml
│ ├── tools.yaml
│ ├── middleware.yaml
│ ├── ui_config.yaml
│ ├── extended_orchestration/
│ │ └── task_batches.yaml ← if workflow uses task batches
│ ├── tools/
│ │ └── *.py ← tool implementations
│ └── ui/
│ ├── index.js ← component barrel
│ └── *.jsx ← workflow-local React components
└── {PackName}.zip ← all workflows bundled together
Generated workflow tools are workflow-local. Generated bundles must not reference workflows/_shared, sibling workflow tool folders, or root-level shared paths. Reusable framework-owned support code belongs under mozaiksai.core.*.
Workflow Name and Pack Name¶
bundle_nameis derived fromcontext_variables["pack_name"]if set, otherwise from the first workflow'sworkflow_name- All names are converted to PascalCase for the output folder and zip file name
Normalization Utilities in workflow_converter.py¶
workflow_converter.py is a contract normalization helper — it does NOT do assembly. Functions exported:
| Function | Purpose |
|---|---|
promote_generated_workflow(source_dir, target_root) | Copy a generated workflow into the active workflows root |
_normalize_transition_rules(raw_rules) | Normalize transition rule list; rejects LLM-evaluated conditions |
_normalize_tools_manifest(output, wf_logger) | Normalize tools + lifecycle_tools with UI realization stamps |
_normalize_visual_agents(value, workflow_startup_mode) | Normalize visual_agents list per workflow_startup_mode |
_collect_ui_code_files(output, tools_config, wf_logger) | Collect UIFileGenerator output, skip shipped primitives, synthesize barrel |
_normalize_runtime_extensions(extensions, workflow_name, wf_logger) | Keep extensions workflow-local |
_normalize_orchestrator_triggers(triggers, wf_logger) | Validate trigger types against declared schema |
These are used by tests and by WorkflowBundleBuilderAgent implementations as reference for what a well-formed bundle looks like.
Current Boundaries¶
AgentGenerator's runtime path is a compact task-batch workflow:
PatternAgentselects the workflow topology and AG2 network pattern.ProjectOverviewAgentpresents the generated-workflow plan for review.PackBuildCoordinatortriggersworkflow_generation_tasks.WorkflowBundleBuilderAgentworkers generate complete workflow bundles in parallel.WorkflowBundleMergeAgentrestores the full workflow set after a repair batch.PackMetadataAgentgenerates pack-level routing metadata.DownloadAgentpackages the generated artifacts.
Bundle assembly is context-first: generated workflow files come from workflow_bundle_results, and pack metadata comes from the current structured outputs. Runtime loading still requires explicit promotion into an active workspace workflow root.
Cross References¶
- structured-output-extraction-contract.md — general auto-tool-call pattern
- workflow-authoring-contracts.md —
extended_orchestration/task_batches.yamlformat factory_app/workflows/AgentGenerator/tools/generate_and_download.py— assembly and downloadfactory_app/workflows/AgentGenerator/tools/workflow_converter.py— normalization utilitiesfactory_app/workflows/AgentGenerator/extended_orchestration/task_batches.yaml— task batch configfactory_app/workflows/AgentGenerator/structured_outputs.yaml—WorkflowBundleBuilderOutputmodel