OpenProgram · Provider / Runtime 设计文档 · implemented and reviewed · 2026-08-12

JSON Schema Structured Output

设计基线:main@708bfbab。实现证据:Tasks 1–6,最终审查提交 2fb471b3。第 2–15 节保留获批设计与实施清单;第 16 节区分已实现合同、验证证据与未满足的完整门禁。

设计结论:继续使用现有 Runtime.exec(..., response_format=...) 作为唯一公共入口;在 provider 公共类型中加入规范化后的 schema 配置,由 capability negotiation 选择 provider 原生 JSON Schema 或受约束的隐藏 tool fallback。无论 provider 是否宣称 strict,最终结果都必须经过严格 JSON 解析和调用方原始 JSON Schema 的本地校验。失败最多执行一次语义修复请求,最终只返回已校验的 Python JSON 值。

当前实现已经沿既有 Agent loop 完成 schema 规范化、能力协商、严格本地校验、一次可选修复、CLI/Web typed 入口、record/replay v2 和 session title consumer。未验证的 provider 组合保持 fail closed;普通文本调用保持原返回语义。

1. 范围、目标与边界

统一语义

Python Runtime、Agent、CLI、WebSocket/API 使用同一份 schema、相同协商结果、相同验证器和错误分类。

流式兼容

保留 provider 的增量文本和 tool 事件,同时明确候选尝试、丢弃、重试与最终结构化结果事件。

可复现

record/replay 记录规范化请求和每次 provider 调用;离线 replay 重新执行同一解析、校验与有限重试。

不在本次实现范围:任意 schema 到 provider 子集的有损改写、自动生成 Pydantic 类型、跨语言代码生成、逐 token 的增量 JSON AST、Web UI schema 编辑器、改变普通文本调用的返回值或流事件。

2. 设计基线审计(main@708bfbab)

本节记录立项时的事实与缺口,作为后续设计决定的来源,不描述 2fb471b3 的当前状态。

当前事实缺口
公共 Runtimeagentic_programming/runtime.py 已暴露 response_format: dict,并在 callable-model 路径透传。_call_via_providers() 没有使用它;默认 provider 调用静默退化为普通文本。
Provider 类型StreamOptions 有采样、tool、transport、header 等字段;Model 有 reasoning/thinking/compat;AssistantMessage 只保存文本/tool/错误。没有 output schema、模型能力或已解析 JSON 字段。
模型目录models_dev.py 已把 models.dev 的 structured_output 规范化并缓存。Model 没有对应字段,Pydantic 构造时丢弃;模型列表也没有展示该能力。
Agent loopAgentLoopConfig 继承公共 stream options;每轮可执行 tool,直到得到不含 tool call 的 assistant message。重建 SimpleStreamOptions 时无 schema 可转发;没有最终候选校验与修复状态。
流事件provider 事件覆盖 text/thinking/tool/done/error;dispatcher 再转换为 Web/CLI 的 stream_event无法表示“第 1 个候选无效,清空后进入第 2 次尝试”及“最终结构化值已校验”。
CLI / Web / API--print 最终打印字符串;WS chat_response.result.content 是字符串;POST /api/function/{name} 返回异步 ack。请求不能携带 schema,成功结果没有 typed JSON,错误没有稳定 machine-readable code。
Session title设计文档写明 {title:string} schema。agent/dispatcher/titles.py 实际提示“ONLY title text”,再按行、引号、前缀与长度清理。
Record/replayformat v1 记录 model、context、options 及原始 provider 事件;replay 严格比较字段。加入默认字段会让旧录制与新请求产生形状差异;结构化校验重试需保持 call index 顺序。

调用与返回链

Runtime.exec
_call_via_providers
AgentSession
Agent loop
API provider stream
event parsing
CLI / WS / API

schema 必须沿这条现有链路传递;不新增绕过 Agent loop 的“structured provider client”,否则 tool calling、deadline、record/replay、DAG 与 session persistence 会形成第二套语义。

3. 公共 API 与规范化类型

保留参数名 response_format,因为它已经公开并出现在现有设计文档。支持两种输入形状:裸 JSON Schema,以及带 OpenProgram 控制项的 envelope。规范化只发生一次。

JsonValue = None | bool | int | float | str | list["JsonValue"] | dict[str, "JsonValue"]

class JsonSchemaOutput(BaseModel):
    type: Literal["json_schema"] = "json_schema"
    schema: dict[str, Any]                  # 调用方原始 schema,禁止原地改写
    name: str = "response"                 # ^[A-Za-z_][A-Za-z0-9_-]{0,63}$
    description: str | None = None
    strict: bool = True
    fallback: Literal["auto", "none", "prompt"] = "auto"
    max_validation_retries: Literal[0, 1] = 1

# 兼容现有调用:裸 dict 视为 schema 本身,而不是 provider payload。
Runtime.exec(content=..., response_format={"type":"object", ...}) -> JsonValue
Runtime.exec(content=..., response_format=JsonSchemaOutput(...)) -> JsonValue
Runtime.exec(content=..., response_format=None) -> str

Provider 公共字段

class Model(BaseModel):
    structured_output: bool | None = None   # models.dev: true / false / unknown

class StreamOptions(BaseModel):
    ...
    response_format: JsonSchemaOutput | None = None

class AssistantMessage(BaseModel):
    ...
    structured_output: JsonValue | None = None
    structured_output_mode: Literal["native", "tool", "prompt"] | None = None
    structured_output_attempt: int | None = None

None 是未知能力,不等于 False。原始 JSON 文本继续保存在 assistant text content 中,便于历史、DAG、审计和 replay;程序调用返回 structured_output

4. Capability negotiation

模型目录只回答“该模型是否宣称支持 structured output”;API adapter 还必须回答 payload 方言、streaming、与 tools 的组合约束。协商同时检查两者。

class StructuredOutputCapabilities(BaseModel):
    native: Literal["supported", "unsupported", "unknown"]
    dialect: Literal["openai_chat", "openai_responses", "anthropic",
                     "google", "bedrock"] | None
    streaming: bool
    with_tools: bool
    schema_profile: str                 # provider 子集检查器名称

negotiate(model, api_provider, options, tools) -> StructuredOutputPlan
# plan.mode: native | tool | prompt
# plan.provider_schema: 经等价投影后的副本
# plan.original_schema: 本地最终验证使用
  1. schema 自身非法:立即失败。
  2. adapter 为该 API 明确支持、模型字段不是 False、schema 可无损投影、当前 tools 组合受支持:选择 native
  3. fallback="auto" 且 provider 支持 strict tool schema、schema 可无损投影、tool_choice 未禁止/强制其他 tool:选择隐藏 tool。
  4. fallback="prompt":显式选择 prompt fallback;它只保证本地校验,不宣称 provider-level strict。
  5. 否则抛 StructuredOutputUnsupportedError,请求发出前给出 provider、model、冲突能力和 fallback 原因。
未知不作乐观推断。 openai-codexgemini-subscription 可能借用官方模型条目,但它们使用不同后端。除非该 API adapter 有契约测试,不能因为 Model.structured_output=True 就发送原生字段。

Provider 映射与首版边界

API原生 payload首版策略组合限制
openai-completionsresponse_format={type:"json_schema", json_schema:{name,description,strict,schema}}native按兼容 profile 检查 tools/parallel;不为 community endpoint 假定完整 OpenAI 支持。
openai-responsestext.format={type:"json_schema", name,description,strict,schema}native保留 refusal/incomplete 终止语义;能力不满足时转 hidden tool。
azure-openai-responsesResponses text.formatnative部署模型和 API version 必须通过 adapter 探针/契约测试,不能只看模型名。
anthropic-messagesoutput_config.format={type:"json_schema", schema}native与现有 output_config.effort 合并,禁止覆盖;refusal/max_tokens 仍需本地失败分类。
google-generative-airesponse_mime_type="application/json" + response_json_schemanative只接受官方支持子集;工具组合在契约测试通过前标为 with_tools=False
bedrock-converse-streamoutputConfig.textFormat.structure.jsonSchema,其中 schema 是 JSON 字符串native模型支持名单与 citations 冲突由 adapter 判定;本地仍按原 schema 校验。
openai-codex无已验证的 ChatGPT backend 契约tool fallback原生为 unknown;不发送 OpenAI Responses 私有字段。
gemini-subscriptionCloud Code Assist request 内部有 generationConfig,但兼容性未验证tool fallback独立契约测试通过后才能打开原生能力。

外部契约依据:OpenAI Structured OutputsAnthropic structured outputsGoogle GenerateContent APIAmazon Bedrock structured outputsAzure OpenAI structured outputs。这些接口会变化,adapter 契约测试是启用能力的必要条件。

5. 原生模式与 fallback

原生 schema

adapter 只负责把规范化配置映射到 provider payload。现有 providers/_schema 可复用遍历与方言识别,但只能执行语义等价变换,例如 key 命名或 JSON 字符串序列化。任何删除 constraint、放宽 additionalProperties、改写 union 等有损处理都返回具体路径并使原生方案不可用。最终验证永远使用调用方原始 schema。

隐藏 tool fallback

{
  "name": "__openprogram_submit_json",
  "description": "Submit the final response matching the required schema.",
  "parameters": <provider_schema>,
  "strict": true
}

Prompt fallback

只在调用方明确设置 fallback="prompt" 时启用:把紧凑 schema 和“仅返回 JSON”要求加入系统层,并对最终文本执行相同解析/校验。它不标记为 strict,不在 auto 中静默使用。这样可以区分 provider-level 约束与纯本地检测。

6. 流式事件和增量文本

structured output 不做增量 schema 校验。每次尝试仍转发原始文本 delta,消费者可显示正在生成的 JSON;最终 text_end 后才解析。为避免无效尝试被提交为最终消息,增加两个框架事件,并给 text 事件增加可选 attempt 元数据。

EventTextStart/TextDelta/TextEnd.output_attempt: int | None = None

EventStructuredOutputRetry {
  type: "structured_output_retry",
  attempt: 1,
  next_attempt: 2,
  issues: [{code, path, schema_path, message}],
}

EventStructuredOutputEnd {
  type: "structured_output_end",
  attempt: 1 | 2,
  mode: "native" | "tool" | "prompt",
  value: JsonValue,
}
1
转发 attempt=1 的 text/tool 增量,客户端写入“候选缓冲区”,不提交持久消息。
2
收到 provider 的 raw done 后严格解析并校验。成功则发 structured_output_end,随后发唯一一次 done;stream 直接 EOF 而没有 raw done/error 时按 incomplete 失败,不能用 partial message 合成成功。
3
失败且可修复时发 structured_output_retry。CLI/Web 清空候选缓冲区;Agent loop 发起下一次 provider stream。
4
第 2 次成功则提交;再次失败则发 error,不发 done,不持久化无效 assistant final。

provider 自己的 raw done 由 Agent loop 消费;对外只暴露结构化事务的最终 done。普通文本模式保持原事件序列。CLI/TUI/Web 对未知新事件必须继续安全忽略,保证版本滚动升级。

7. 严格解析、校验和有限重试

解析规则

重试状态

失败是否消耗 validation retry处理
schema definition 非法请求前 StructuredOutputSchemaError
provider/模型不支持或配置冲突请求前 StructuredOutputUnsupportedError
JSON syntax、schema violation、missing hidden submission是,最多 1 次把无效 assistant 候选和确定性的 issue 列表追加到临时修复上下文,再请求一次。
refusal、content filter、安全阻止StructuredOutputGenerationError(code="refusal")
max_tokens/incomplete、context length保留 provider reason;调用方调整预算。框架不自行放大 token 上限。
transport/rate limit/provider internal继续由现有 stream/exec retry 处理;不计入 validation retry,但每次 Runtime provider 调用都消耗共享的 max_retries 预算。
取消或 deadline立即传播,不进入修复。

共享调用预算

max_validation_retriesmax_retries 是两个限制,不是两个可相乘的循环。前者限制首次候选失败后最多进行多少次语义修复;后者限制一次同步或异步 exec 在 Runtime 边界发起的 provider 调用总数,包含初次调用、语义修复调用和 transport failure 后的调用。只有 validation retry 尚未耗尽且共享调用预算仍有余额时,Runtime 才发起修复调用。

因此 Runtime 边界的 provider 调用数始终不超过 max_retries。例如 max_retries=1 时,无效首个候选直接返回 StructuredOutputValidationErrormax_retries=2 且默认允许一次 validation retry 时,最多是初次调用加一次修复。修复调用发生 transport failure 时,该失败已经消费预算,外层不能重新获得完整预算。provider adapter 或 SDK 自己的 transport retry 仍受现有 deadline 和 transport 层配置约束,不由 validation retry 计数。

structured_output_retry.attemptnext_attempt 继续表示结构化候选序号,不复用为 transport attempt。事件只在 Runtime 确认还有共享调用预算、即将进行修复时发送;预算耗尽时不发送虚假的 retry 事件。

修复 prompt 只包含失败类型和有界 issue 列表,不重新解释 schema,也不调用另一个 LLM。修复上下文只存在于该次 exec;session history 和最终 DAG 只保留最终有效 assistant message,但 model-call 记录保留两次 provider call 供审计。

8. Tool calling 共存

情形行为
原生 schema,无用户 tools直接应用原生 output format。
原生 schema + 用户 tools,adapter with_tools=True每个 agent round 都携带 schema;用户 tool 正常执行,最终无 tool round 的文本被校验。
原生 schema + tools,但组合未验证若 auto 可使用 hidden tool,则改用 tool fallback;否则 preflight 失败。
tool fallback + 用户 tools隐藏 submit tool 与用户 tools 合并;普通 tools 可多轮执行,submit tool 结束事务。
一次响应同时含普通 tool 与 submit tool拒绝该候选并进入有限修复;不执行普通 tool,避免在“final”之后产生副作用。
调用方强制特定 tool / 禁用 tools不覆写调用方意图;native 可用则 native,否则 unsupported。

结构化配置必须在 agent_loop._stream_assistant_response() 重建 SimpleStreamOptions 时明确复制。最终验证位于 Agent loop 的 no-tool terminal 边界,而不是各 provider parser 中重复实现。

9. CLI、WebSocket/API 与错误语义

Python API

value = runtime.exec(content=..., response_format=schema)  # Python JsonValue

except StructuredOutputError as e:
    e.code       # invalid_schema | unsupported | invalid_json | validation_failed |
                 # missing_submission | refusal | incomplete
    e.provider
    e.model
    e.attempts
    e.issues     # bounded machine-readable list

StructuredOutputError 归入现有 LLM error 边界,但不伪装成 transport error。retryable 表示“新 exec/new budget 是否可能成功”;validation retry 是否已用尽由 attempts 表示。

CLI

在现有 one-shot openprogram --print 增加 --json-schema PATH;首版不改变交互 REPL/TUI 输入方式。成功时 stdout 只写规范 JSON(UTF-8,非 pretty,末尾换行),退出码 0。错误写 stderr:用法/非法 schema 为 2,unsupported 为 3,生成或最终校验失败为 4,现有 provider/auth/cancel 语义不变。结构化结果以紧凑 JSON 字符串持久化到 session assistant content,同时附带 message metadata 中的 parsed value/mode。

WebSocket 与 HTTP 异步 API

// request: existing chat action and POST /api/function/{name} body
response_format?: JsonSchemaOutput | JSONSchema

// stream
{type:"chat_response", data:{type:"stream_event", event:{
  type:"structured_output_retry", attempt:1, next_attempt:2, issues:[...]}}}

// success
{type:"chat_response", data:{type:"result", content:"{...}",
  structured_output:<JsonValue>, structured_output_mode:"native", attempt:1}}

// terminal error
{type:"chat_response", data:{type:"error", code:"validation_failed",
  content:"Structured output failed validation", attempts:2, issues:[...]}}

10. Record/replay 与持久化

11. Session title 迁移

基础能力完成后,把 agent/dispatcher/titles.py 改为首个内部 consumer:

TITLE_SCHEMA = {
  "type": "object",
  "properties": {"title": {"type": "string", "minLength": 1, "maxLength": 80}},
  "required": ["title"],
  "additionalProperties": false,
}

result = runtime.exec(content=prompt, toolset="none", max_iterations=2,
  response_format=JsonSchemaOutput(
    schema=TITLE_SCHEMA, name="session_title", max_validation_retries=1,
))
title = result["title"]

保留 Unicode trim 和最终数据库长度防御;删除“ONLY title text”以及去引号、去 Title:、取首行等格式修复逻辑。title 生成仍是 best-effort,structured error 时保留 phase-1 placeholder,不影响主 turn。同步修正 session/name.md 与 feature matrix,使文档区分“已实现”和“设计”。

12. References 对比:采用、修改、拒绝

仓库 references/pi-ai 已有统一 stream option、provider-local payload builder、tool schema 和 supportsStrictMode,但 strict 仅针对 tool definition;没有通用 response schema、最终 JSON validator 或 structured retry。

决定来源/现状本设计处理
采用共享 option/type 经所有 provider adapter 透传。JsonSchemaOutput 放在公共类型;payload 映射留在各 provider。
采用tool strict 是 provider/model compatibility,而不是调用方单方面承诺。hidden tool fallback 受 capability negotiation 和 schema profile 约束。
修改pi-ai 把 strict 能力放在 compat 字段,models.dev 已有 structured_output 数据。模型用 tri-state 字段,API adapter 用独立 capability;两者联合决定。
修改现有 _schema 可以为 provider 降级 tool schema。structured output 只允许无损投影;本地始终按原始 schema 验证。
拒绝只依赖 provider strict,直接返回文本。拒绝。refusal、截断、兼容 endpoint 和 provider bug 都要求本地 parse + validate。
拒绝用 forgiving/partial JSON parser 修正最终输出。拒绝。只接受单一完整 JSON document,失败进入有界语义修复。
拒绝把每个 JSON delta 解析为增量对象并对外发布。拒绝。schema 校验只在完整候选上定义;流式阶段只传候选文本和 attempt。
拒绝另建独立 structured-output provider 调用路径。拒绝。必须复用 Agent loop、tools、deadline、DAG 和 record/replay。

13. 精确修改文件

文件修改
openprogram/providers/types.py新增 JsonSchemaOutput、JsonValue、Model tri-state、StreamOptions 字段、AssistantMessage parsed 字段与 structured retry/end 事件。
openprogram/providers/api_registry.py
openprogram/providers/register.py
为 API adapter 注册 structured capability;提供 unknown-safe 查询,不按模型名猜测。
openprogram/providers/structured_output.py new输入规范化、schema preflight、协商、严格解析、本地校验、issue 限界、schema hash 和错误类型。
openprogram/providers/_schema/*增加“无损/有损”报告接口和 provider schema profile;保留原 schema。
openprogram/providers/sources/models_dev.py
openprogram/providers/enabled_models.py
openprogram/webui/_model_listing/listing.py
保留、构造并展示 structured_output tri-state。
openprogram/providers/openai_completions/openai_completions.py
openprogram/providers/openai_responses/openai_responses.py
openprogram/providers/azure_openai_responses/azure_openai_responses.py
映射 Chat/Responses/Azure 原生 payload,并处理 response refusal/incomplete。
openprogram/providers/anthropic/anthropic.py把 format 合并进现有 output_config,保留 adaptive-thinking effort。
openprogram/providers/google/google.py
openprogram/providers/google_gemini_cli/google_gemini_cli.py
Google 官方 adapter 映射原生字段;subscription adapter 首版显式 unknown/tool fallback。
openprogram/providers/amazon_bedrock/amazon_bedrock.py
openprogram/providers/openai_codex/openai_codex.py
Bedrock 映射 outputConfig;Codex adapter 首版显式 unknown/tool fallback。
openprogram/agent/types.py
openprogram/agent/agent_loop.py
openprogram/agent/internals/_event_parsing.py
透传 schema;实现 no-tool terminal 校验、hidden tool、一次修复、派生事件和最终 parsed message。
openprogram/agentic_programming/runtime.py
openprogram/providers/callable_model.py
修复 provider 路径静默忽略;增加 overload/parsed return;对 callable model 应用同一最终校验。
openprogram/providers/recording.py
openprogram/providers/replay.py
format v2、规范化 option 比较、validation retry 多 call 测试;provider raw event 集合保持不变。
openprogram/_cli_cmds/chat.py
openprogram/cli.py
openprogram/cli_chat.py
openprogram/_cli_chat/turn.py
one-shot schema 参数、typed result、stdout/stderr/exit code、session persistence。
openprogram/webui/ws_actions/chat.py
openprogram/webui/routes/chat.py
openprogram/webui/_execute/chat.py
openprogram/webui/server.py
请求校验、schema 透传、structured stream/result/error envelope。
cli/src/ws/client.ts
cli/src/screens/repl/wsHandlers/handleChatResponse.ts
cli/src/screens/repl/wsHandlers/streamingHelpers.ts
TS 请求/事件类型、retry 清空候选、typed result 接收;不增加 schema 编辑 UI。
openprogram/agent/dispatcher/titles.py迁移 title consumer,删除文本格式清理,保留长度与 best-effort 边界。
pyproject.toml
uv.lock
直接依赖 jsonschema 并更新 lock。
docs/reference/design/runtime/session/name.md
docs/reference/design/feature-matrix.html
实现落地后修正文档状态和实际契约。

14. 测试矩阵与验收条件

必须覆盖建议文件
规范化/validator裸 schema、envelope、非法 meta-schema、object/array/scalar/null、非有限数、fence/尾随文本、稳定 issue path;remote ref 零网络、本地直接引用环、1 MiB/4096 nodes/8192 edges/100 depth 全局预算。tests/providers/test_structured_output.py(new)
协商true/false/unknown × adapter support;有损 schema;fallback none/auto/prompt;tool_choice/parallel 冲突。同上 + test_provider_meta.py
Provider payload逐 adapter 快照测试;Anthropic effort+format 合并;Bedrock schema JSON 字符串;unknown adapter 不发送私有字段。现有 tests/providers/test_openai.pytest_anthropic.pytest_gemini.py + 新 Bedrock cases
Streaming单次成功;invalid attempt 的 delta→retry→清空→成功;第 2 次失败无 done;取消/deadline 不重试;provider EOF 无 raw terminal 时不合成成功。tests/providers/test_structured_output_streaming.py(new)
Tools原生+tools;hidden tool 单独提交;普通 tool 多轮后提交;普通+submit 同轮拒绝;forced/none/parallel 冲突。tests/unit/test_tools_runtime.py + new Agent loop cases
Runtime无 schema 返回 str;有 schema 返回 JsonValue;默认 provider 路径确实透传;callable model 同样本地校验;同步/异步均证明初次调用、修复调用和 transport retry 共用 max_retries 预算。tests/agentic_programming/test_runtime_structured_output.py(new)
Record/replayv2 单 call、validation retry 两 calls、schema mismatch path、v1 拒绝、离线派生事件一致。tests/providers/test_record_replay.py
CLI成功 stdout 仅 JSON;exit 2/3/4;stderr 无候选全文;普通 --print 不变。tests/providers/test_cli.py + CLI integration
WS/APIrequest schema、retry event、typed result、machine error、foreign session routing、旧客户端忽略新字段。tests/unit/test_webui_chat_dispatcher.py + TS tests
Session title合法 title、structured failure 回退 placeholder、Unicode/80 字边界、无旧正则依赖。tests/unit/test_dispatcher_compaction_title.py
回归全部 provider stream、tool loop、普通聊天、DAG、session persistence、typecheck、docs HTML。现有 suites + npm test/npm run typecheck
验收门槛:每个标为 native 的 adapter 必须有 payload 契约测试和至少一个受控集成测试;结构化成功值必须通过本地原始 schema;Runtime provider 调用总数不超过 max_retries,且语义修复调用数不超过 max_validation_retries;普通文本模式的录制、事件和返回类型保持不变。

15. 实施顺序与完成判定

  1. 公共类型、直接依赖、schema preflight/validator/错误类;先建立纯单元测试。
  2. capability registry、models.dev tri-state 保留、provider schema profiles。
  3. 各 provider payload 映射与 adapter 契约测试;未验证 adapter 保持 unknown。
  4. Agent loop 的终态校验、hidden tool、事件、一次修复;Runtime parsed return。
  5. record/replay v2、CLI、WS/API consumer;验证旧文本调用不变。
  6. 迁移 session title,修正 feature matrix 与 session naming 文档。

provider 能力标记、契约测试与 session title consumer 已落地。feature matrix 保持用户批准的 78.5 分和既有状态单元;完整回归门禁与具体 trust-boundary 证据仍在本页独立记录。单纯增加 provider payload 字段不构成功能完成。

16. 实现与验证证据

范围已审查实现边界
公共合同与 providerJsonSchemaOutput 规范化和 preflight;registry snapshot 下的 native / hidden tool / explicit prompt 协商;OpenAI、Anthropic、Google 与 Bedrock 已验证映射;最终值按调用方原 schema 本地校验。未验证 adapter、模型未显式 opt-in、schema 无法无损投影或工具控制冲突时不发送未经验证的 native payload;fallback="prompt" 必须显式请求。
Agent / RuntimeAgent loop 统一拥有协商、typed retry/end 事件、最多一次 validation repair 与 parsed terminal;Runtime.exec/async_exec 返回已校验 Python JSON 值,普通调用仍返回文本。无效候选不写入最终 assistant message;取消、deadline、refusal 与 incomplete 不转成 repair。
入口与复现CLI --json-schema PATH|-、Web typed lifecycle、recording v2 与严格离线 replay 共用规范化合同;CLI structured one-shot stdout 只有一个 JSON document。没有 Web schema editor、跨语言代码生成或增量 JSON AST;v1 structured recording 明确拒绝,v1 ordinary recording 保持兼容。
Session title默认 agent provider/model、toolset="none"、两次最大模型迭代和一次 schema repair;只接受 {title:string},consumer 仅做 Unicode trim 与 80 code-point 存储防御。setup、exec、close 失败均为 best-effort,并只记录固定生命周期标签;provider 异常正文和 traceback 不进入日志。

提交证据:Task 1 00945c85..27a5aa8a;Task 2 da4ececd..8ca7b04c;Task 3 6f8c80b7..546c2bc7;Task 4 27e4764f..510f60ee;Task 5 9743f3e1..86ca66d5;Task 6 5bba3e64..2fb471b3。Tasks 1–6 的最终 SPEC 与 QUALITY scoped review 均为 PASS、remaining 0。

验证状态:Task 6 affected selection 为 219 passed, 1 skipped;Task 7 focused selection 为 226 passed, 1 skipped;文档构建为 453 pages、链接检查为 0 broken。Task 7 最终树上的完整 Python selection 得到 3290 passed, 5 skipped, 1 xfailed, 2 failed;两个失败分别是既有 tool cancellation 的 ExecInterrupt 断言与 memory writer turn-order 断言,并已在实现前基线 86ca66d5 独立复现。它们不归因于 structured-output diff,也不满足“完整门禁通过”的发布条件。

后续质量修复:全局 schema preflight 已增加 1 MiB/4096 nodes/8192 edges/100 depth 预算,拒绝外部 resource 和直接引用环;local validator 使用禁止检索的 registry;structured stream 只有收到 provider raw terminal 才能提交。该修复的 scoped SPEC/QUALITY 结论在 review 完成后记录。

仓库证据:openprogram/providers/types.pysources/models_dev.py、七类 provider adapter、agent/agent_loop.pyagentic_programming/runtime.pyagent/internals/_event_parsing.py、CLI/WebSocket 链、recording.py/replay.pyagent/dispatcher/titles.pyreferences/pi-ai。本文行号不绑定源码快照;实现时以符号和测试为定位依据。

外部 provider 文档仅用于确认当前 payload 与约束;能力启用仍以 OpenProgram adapter 契约测试为准。