From 1e30567cbd3d83274b5fb19d514dca45669d1dfd Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 09:40:10 +0000 Subject: [PATCH 1/4] feat(spec): offer agent.structuredOutput on the agent form; drop its stale omit row The reconciliation ledger excused `agent.structuredOutput` as declared but not enforced. The key is enforced now (liveness `live`), and the ledger's own rule hands the offer decision to the enforcement. Studio's composite control carries every child of the block, the free-form JSON Schema record included (raw JSON editor), so the key is offered as a composite beside the other agent blocks and the row goes. Claude-Session: https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM Co-authored-by: Claude --- packages/spec/src/ai/agent.form.ts | 1 + .../src/system/metadata-form-zod-reconciliation.test.ts | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/spec/src/ai/agent.form.ts b/packages/spec/src/ai/agent.form.ts index 389959df2b8..f37667ab25a 100644 --- a/packages/spec/src/ai/agent.form.ts +++ b/packages/spec/src/ai/agent.form.ts @@ -42,6 +42,7 @@ export const agentForm = defineForm({ { field: 'planning', type: 'composite', helpText: 'Autonomous reasoning configuration (strategy, max iterations, replan)' }, { field: 'memory', type: 'composite', helpText: 'Memory management (short-term, long-term, reflection)' }, { field: 'lifecycle', type: 'composite', helpText: 'State machine defining conversation flow' }, + { field: 'structuredOutput', type: 'composite', helpText: "Output contract for the agent's final answer: JSON format, the JSON Schema it is checked against, retries, fallback format and transform steps. Enforced by the cloud AI runtime." }, ], }, { diff --git a/packages/spec/src/system/metadata-form-zod-reconciliation.test.ts b/packages/spec/src/system/metadata-form-zod-reconciliation.test.ts index 065d8282808..2350eaed10b 100644 --- a/packages/spec/src/system/metadata-form-zod-reconciliation.test.ts +++ b/packages/spec/src/system/metadata-form-zod-reconciliation.test.ts @@ -405,13 +405,6 @@ const LEDGER: ReadonlyArray = [ key: 'requires', why: 'declared, not enforced yet — liveness verdict `planned` (ADR-0080: inferred at compile time; save/load enforcement of plugin presence is deferred). No offer until it is enforced; whether to offer it then is a ruling for the enforcement, not for this gate', }, - { - kind: 'omit', - type: 'agent', - path: ROOT_PATH, - key: 'structuredOutput', - why: 'declared, not enforced yet — `[EXPERIMENTAL — not enforced]` in its own describe and `experimental` in the liveness ledger: parsed, no runtime consumer. No offer until it is enforced; whether to offer it then is a ruling for the enforcement, not for this gate', - }, { kind: 'omit', type: 'action', From b2c9cb9ea47a06c9a1b6ad978b186938d001713b Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 09:57:44 +0000 Subject: [PATCH 2/4] chore(platform-objects): regenerate the metadata-form catalogs for the structuredOutput row `pnpm i18n:extract` adds the agent form's new `structuredOutput` row (label and help text) to the four metadata-form bundles. The zh-CN, ja-JP and es-ES leaves are authored, not left as copies of the English source, and the re-run extract drops their source-hash entries by itself. Changeset: spec minor (a new form offer), platform-objects patch. Claude-Session: https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM Co-authored-by: Claude --- .../21374-agent-structured-output-form-offer.md | 13 +++++++++++++ .../translations/en.metadata-forms.generated.ts | 4 ++++ .../translations/es-ES.metadata-forms.generated.ts | 4 ++++ .../translations/ja-JP.metadata-forms.generated.ts | 4 ++++ .../translations/zh-CN.metadata-forms.generated.ts | 4 ++++ 5 files changed, 29 insertions(+) create mode 100644 .changeset/21374-agent-structured-output-form-offer.md diff --git a/.changeset/21374-agent-structured-output-form-offer.md b/.changeset/21374-agent-structured-output-form-offer.md new file mode 100644 index 00000000000..bf7ac6115f0 --- /dev/null +++ b/.changeset/21374-agent-structured-output-form-offer.md @@ -0,0 +1,13 @@ +--- +"@objectstack/spec": minor +"@objectstack/platform-objects": patch +--- + +The agent metadata form now offers `structuredOutput`, the output contract the cloud AI runtime enforces on every final answer. It is a `composite` row in the AI Configuration section, spelled like the `memory` and `guardrails` rows: Studio derives its seven sub-rows from the served JSON Schema. + +Clause-②: no + +- Before this, the block had no row on the agent form, so the only way to author it in Studio was the Source tab. The form's reconciliation test excused that with a ledger row saying the key was declared but not enforced. The key has been enforced since the structured-output enforcement landed (liveness `live`), and that row is gone. +- What Studio renders, read at the console pin `31971ff1e28f`: `format` and `fallbackFormat` are selects over `json_object` / `json_schema`. `strict` and `retryOnValidationFailure` are switches, and `maxRetries` is a number. `transformPipeline` is a multi-select over `trim` / `parse_json` / `validate`. `schema`, the free-form JSON Schema record, is a JSON text editor: the stored value is shown as JSON and saved back as parsed. That is the same editor the action form already gives `ai.outputSchema`, which is the other slot this JSON Schema rule governs. +- Two editing limits of those controls. A multi-select toggle stores the steps in the order the enum declares them (`trim`, `parse_json`, `validate`). And the schema editor keeps the last valid JSON while the text does not parse. A value nobody edits is saved back unchanged. +- No schema, parse or export change. The accept set of `AgentSchema` is unchanged, and so is the refusal of an untyped JSON subschema at `structuredOutput.schema`. What moves is the form payload `getMetaTypes()` serves, and the two new leaves of the `platform-objects` metadata-form catalogs (the row's label and help text). Those are authored in `zh-CN`, `ja-JP` and `es-ES`, not left as copies of the English source. diff --git a/packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts b/packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts index 5af59de123e..d41e928ca79 100644 --- a/packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts +++ b/packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts @@ -2404,6 +2404,10 @@ export const enMetadataForms: NonNullable = { label: "Lifecycle", helpText: "State machine defining conversation flow" }, + structuredOutput: { + label: "Structured Output", + helpText: "Output contract for the agent's final answer: JSON format, the JSON Schema it is checked against, retries, fallback format and transform steps. Enforced by the cloud AI runtime." + }, skills: { label: "Skills", helpText: "Skill names (Agent→Skill→Tool architecture)" diff --git a/packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts b/packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts index ea21afd67fc..09004e7bc6a 100644 --- a/packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts +++ b/packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts @@ -2404,6 +2404,10 @@ export const esESMetadataForms: NonNullable = label: "Ciclo de vida", helpText: "Máquina de estado que define el flujo de conversación" }, + structuredOutput: { + label: "Salida estructurada", + helpText: "Contrato de salida para la respuesta final del agente: formato JSON, el JSON Schema con el que se valida, reintentos, formato de respaldo y pasos de transformación. Lo aplica el runtime de IA en la nube." + }, skills: { label: "Habilidades", helpText: "Nombres de skill (arquitectura Agent→Skill→Tool)" diff --git a/packages/platform-objects/src/apps/translations/ja-JP.metadata-forms.generated.ts b/packages/platform-objects/src/apps/translations/ja-JP.metadata-forms.generated.ts index 3fc626b2373..88fb39707e6 100644 --- a/packages/platform-objects/src/apps/translations/ja-JP.metadata-forms.generated.ts +++ b/packages/platform-objects/src/apps/translations/ja-JP.metadata-forms.generated.ts @@ -2404,6 +2404,10 @@ export const jaJPMetadataForms: NonNullable = label: "ライフサイクル", helpText: "会話フローを定義するステートマシン" }, + structuredOutput: { + label: "構造化出力", + helpText: "エージェントの最終回答に対する出力契約: JSON 形式、回答の検証に使う JSON Schema、リトライ、フォールバック形式、変換ステップ。クラウド AI ランタイムが適用します。" + }, skills: { label: "スキル", helpText: "スキル名(Agent→Skill→Tool アーキテクチャ)" diff --git a/packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts b/packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts index a2ebf07fc73..82223c0f1d5 100644 --- a/packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts +++ b/packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts @@ -2404,6 +2404,10 @@ export const zhCNMetadataForms: NonNullable = label: "生命周期", helpText: "定义会话流程的状态机" }, + structuredOutput: { + label: "结构化输出", + helpText: "代理最终回答的输出契约:JSON 格式、用于校验回答的 JSON Schema、重试、回退格式与转换步骤。由云端 AI 运行时强制执行。" + }, skills: { label: "技能", helpText: "技能名称(Agent→Skill→Tool 架构)" From 77dedb2c867dba4c3340c2572beb31e15cd6d273 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 09:59:50 +0000 Subject: [PATCH 3/4] test(platform-objects): the translated-label control reads 660 with the structuredOutput row The per-locale positive control counts the metadata-form labels authored in each of zh-CN, ja-JP and es-ES. The agent form's new row adds one, so the measured count is 660 (was 659) in every locale. Claude-Session: https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM Co-authored-by: Claude --- .../object-lifecycle-panel-echo-decisions.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/platform-objects/src/apps/translations/object-lifecycle-panel-echo-decisions.test.ts b/packages/platform-objects/src/apps/translations/object-lifecycle-panel-echo-decisions.test.ts index 6824bdde966..8bec79f9bff 100644 --- a/packages/platform-objects/src/apps/translations/object-lifecycle-panel-echo-decisions.test.ts +++ b/packages/platform-objects/src/apps/translations/object-lifecycle-panel-echo-decisions.test.ts @@ -1150,7 +1150,9 @@ describe('#19403 round 10 — the verdicts, on the live bundles', () => { // three locales. // 659 since the field form offers `useGrouping` on `number` fields: one // new row label, authored in all three locales. - expect(translated.length, `${locale} positive control`).toBe(659); + // 660 since the agent form offers `structuredOutput`: one new row label, + // authored in all three locales. + expect(translated.length, `${locale} positive control`).toBe(660); } // ⭐ DARK — the blindness, executable. On a synthetic two-locale catalog the // all-three predicate returns 0 while the per-locale one returns 1, so the From 417fb601f873ab86bde6bc10eb83454b1d38a088 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 10:42:09 +0000 Subject: [PATCH 4/4] docs(changeset): describe the renderer reading without a pin sha The console pin moved on main after the reading; the renderer files the reading cites are unchanged across the move, so the changeset names the renderer rather than one sha. Claude-Session: https://claude.ai/code/session_01YDt3PzwfrkuFzUBF89WPmM Co-authored-by: Claude --- .changeset/21374-agent-structured-output-form-offer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/21374-agent-structured-output-form-offer.md b/.changeset/21374-agent-structured-output-form-offer.md index bf7ac6115f0..e6c00873b31 100644 --- a/.changeset/21374-agent-structured-output-form-offer.md +++ b/.changeset/21374-agent-structured-output-form-offer.md @@ -8,6 +8,6 @@ The agent metadata form now offers `structuredOutput`, the output contract the c Clause-②: no - Before this, the block had no row on the agent form, so the only way to author it in Studio was the Source tab. The form's reconciliation test excused that with a ledger row saying the key was declared but not enforced. The key has been enforced since the structured-output enforcement landed (liveness `live`), and that row is gone. -- What Studio renders, read at the console pin `31971ff1e28f`: `format` and `fallbackFormat` are selects over `json_object` / `json_schema`. `strict` and `retryOnValidationFailure` are switches, and `maxRetries` is a number. `transformPipeline` is a multi-select over `trim` / `parse_json` / `validate`. `schema`, the free-form JSON Schema record, is a JSON text editor: the stored value is shown as JSON and saved back as parsed. That is the same editor the action form already gives `ai.outputSchema`, which is the other slot this JSON Schema rule governs. +- What Studio renders, read in the console's metadata form renderer: `format` and `fallbackFormat` are selects over `json_object` / `json_schema`. `strict` and `retryOnValidationFailure` are switches, and `maxRetries` is a number. `transformPipeline` is a multi-select over `trim` / `parse_json` / `validate`. `schema`, the free-form JSON Schema record, is a JSON text editor: the stored value is shown as JSON and saved back as parsed. That is the same editor the action form already gives `ai.outputSchema`, which is the other slot this JSON Schema rule governs. - Two editing limits of those controls. A multi-select toggle stores the steps in the order the enum declares them (`trim`, `parse_json`, `validate`). And the schema editor keeps the last valid JSON while the text does not parse. A value nobody edits is saved back unchanged. - No schema, parse or export change. The accept set of `AgentSchema` is unchanged, and so is the refusal of an untyped JSON subschema at `structuredOutput.schema`. What moves is the form payload `getMetaTypes()` serves, and the two new leaves of the `platform-objects` metadata-form catalogs (the row's label and help text). Those are authored in `zh-CN`, `ja-JP` and `es-ES`, not left as copies of the English source.