Skip to content

Conversation

@apanasenko-oai
Copy link
Collaborator

What changed

  • Added outputSchema support to the app-server APIs, mirroring codex exec --output-schema behavior.
    • V1 sendUserTurn now accepts outputSchema and constrains the final assistant message for that turn.
    • V2 turn/start now accepts outputSchema and constrains the final assistant message for that turn (explicitly per-turn only).

Core behavior

  • Op::UserTurn already supported final_output_json_schema; now V1 sendUserTurn forwards outputSchema into that field.
  • Op::UserInput now carries final_output_json_schema for per-turn settings updates; core maps it into SessionSettingsUpdate.final_output_json_schema so it applies to the created turn context.
  • V2 turn/start does NOT persist the schema via OverrideTurnContext (it’s applied only for the current turn). Other overrides (cwd/model/etc) keep their existing persistent behavior.

API / docs

  • codex-rs/app-server-protocol/src/protocol/v1.rs: add output_schema: Option<serde_json::Value> to SendUserTurnParams (serialized as outputSchema).
  • codex-rs/app-server-protocol/src/protocol/v2.rs: add output_schema: Option<JsonValue> to TurnStartParams (serialized as outputSchema).
  • codex-rs/app-server/README.md: document outputSchema for turn/start and clarify it applies only to the current turn.
  • codex-rs/docs/codex_mcp_interface.md: document outputSchema for v1 sendUserTurn and v2 turn/start.

Tests added/updated

  • New app-server integration tests asserting outputSchema is forwarded into outbound /responses requests as text.format:
    • codex-rs/app-server/tests/suite/output_schema.rs
    • codex-rs/app-server/tests/suite/v2/output_schema.rs
  • Added per-turn semantics tests (schema does not leak to the next turn):
    • send_user_turn_output_schema_is_per_turn_v1
    • turn_start_output_schema_is_per_turn_v2
  • Added protocol wire-compat tests for the merged op:
    • serialize omits final_output_json_schema when None
    • deserialize works when field is missing
    • serialize includes final_output_json_schema when Some(schema)

Call site updates (high level)

  • Updated all Op::UserInput { .. } constructions to include final_output_json_schema:
    • codex-rs/app-server/src/codex_message_processor.rs
    • codex-rs/core/src/codex_delegate.rs
    • codex-rs/mcp-server/src/codex_tool_runner.rs
    • codex-rs/tui/src/chatwidget.rs
    • codex-rs/tui2/src/chatwidget.rs
    • plus impacted core tests.

Validation

  • just fmt
  • cargo test -p codex-core
  • cargo test -p codex-app-server
  • cargo test -p codex-mcp-server
  • cargo test -p codex-tui
  • cargo test -p codex-tui2
  • cargo test -p codex-protocol
  • cargo clippy --all-features --tests --profile dev --fix -- -D warnings

items: vec![UserInput::Text {
text: "hello 1".into(),
}],
final_output_json_schema: None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we have this value on the UserTurn, should we use that instead? I'd like to remove UserInput all together. They call the same codepath eventually anyway.

Copy link
Collaborator

@pakrym-oai pakrym-oai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding final_output_json_schema to UserInput isn't great but we should've unified it with UserTurn a long time ago.

@apanasenko-oai apanasenko-oai merged commit 807f8a4 into main Jan 5, 2026
26 checks passed
@apanasenko-oai apanasenko-oai deleted the anton_panasenko_structured_output branch January 5, 2026 18:27
@github-actions github-actions bot locked and limited conversation to collaborators Jan 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants