generate an internal json schema for RolloutLine (#14434)

### Why
i'm working on something that parses and analyzes codex rollout logs,
and i'd like to have a schema for generating a parser/validator.

`codex app-server generate-internal-json-schema` writes an
`RolloutLine.json` file

while doing this, i noticed we have a writer <> reader mismatch issue on
`FunctionCallOutputPayload` and reasoning item ID -- added some schemars
annotations to fix those

### Test

```
$ just codex app-server generate-internal-json-schema --out ./foo
```

generates an `RolloutLine.json` file, which i validated against jsonl
files on disk

`just codex app-server --help` doesn't expose the
`generate-internal-json-schema` option by default, but you can do `just
codex app-server generate-internal-json-schema --help` if you know the
command

everything else still works

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Keyan Zhang
2026-03-17 11:19:42 -07:00
committed by GitHub
parent 0d531c05f2
commit 904dbd414f
12 changed files with 44 additions and 140 deletions

View File

@@ -871,24 +871,6 @@
}
]
},
"FunctionCallOutputPayload": {
"description": "The payload we send back to OpenAI when reporting a tool call result.\n\n`body` serializes directly as the wire value for `function_call_output.output`. `success` remains internal metadata for downstream handling.",
"properties": {
"body": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"success": {
"type": [
"boolean",
"null"
]
}
},
"required": [
"body"
],
"type": "object"
},
"FuzzyFileSearchParams": {
"properties": {
"cancellationToken": {
@@ -1583,10 +1565,6 @@
"null"
]
},
"id": {
"type": "string",
"writeOnly": true
},
"summary": {
"items": {
"$ref": "#/definitions/ReasoningItemReasoningSummary"
@@ -1602,7 +1580,6 @@
}
},
"required": [
"id",
"summary",
"type"
],
@@ -1736,7 +1713,7 @@
"type": "string"
},
"output": {
"$ref": "#/definitions/FunctionCallOutputPayload"
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
@@ -1801,7 +1778,7 @@
"type": "string"
},
"output": {
"$ref": "#/definitions/FunctionCallOutputPayload"
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [

View File

@@ -7731,24 +7731,6 @@
}
]
},
"FunctionCallOutputPayload": {
"description": "The payload we send back to OpenAI when reporting a tool call result.\n\n`body` serializes directly as the wire value for `function_call_output.output`. `success` remains internal metadata for downstream handling.",
"properties": {
"body": {
"$ref": "#/definitions/v2/FunctionCallOutputBody"
},
"success": {
"type": [
"boolean",
"null"
]
}
},
"required": [
"body"
],
"type": "object"
},
"GetAccountParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
@@ -10195,10 +10177,6 @@
"null"
]
},
"id": {
"type": "string",
"writeOnly": true
},
"summary": {
"items": {
"$ref": "#/definitions/v2/ReasoningItemReasoningSummary"
@@ -10214,7 +10192,6 @@
}
},
"required": [
"id",
"summary",
"type"
],
@@ -10348,7 +10325,7 @@
"type": "string"
},
"output": {
"$ref": "#/definitions/v2/FunctionCallOutputPayload"
"$ref": "#/definitions/v2/FunctionCallOutputBody"
},
"type": {
"enum": [
@@ -10413,7 +10390,7 @@
"type": "string"
},
"output": {
"$ref": "#/definitions/v2/FunctionCallOutputPayload"
"$ref": "#/definitions/v2/FunctionCallOutputBody"
},
"type": {
"enum": [

View File

@@ -4375,24 +4375,6 @@
}
]
},
"FunctionCallOutputPayload": {
"description": "The payload we send back to OpenAI when reporting a tool call result.\n\n`body` serializes directly as the wire value for `function_call_output.output`. `success` remains internal metadata for downstream handling.",
"properties": {
"body": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"success": {
"type": [
"boolean",
"null"
]
}
},
"required": [
"body"
],
"type": "object"
},
"FuzzyFileSearchParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
@@ -6983,10 +6965,6 @@
"null"
]
},
"id": {
"type": "string",
"writeOnly": true
},
"summary": {
"items": {
"$ref": "#/definitions/ReasoningItemReasoningSummary"
@@ -7002,7 +6980,6 @@
}
},
"required": [
"id",
"summary",
"type"
],
@@ -7136,7 +7113,7 @@
"type": "string"
},
"output": {
"$ref": "#/definitions/FunctionCallOutputPayload"
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
@@ -7201,7 +7178,7 @@
"type": "string"
},
"output": {
"$ref": "#/definitions/FunctionCallOutputPayload"
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [

View File

@@ -133,24 +133,6 @@
}
]
},
"FunctionCallOutputPayload": {
"description": "The payload we send back to OpenAI when reporting a tool call result.\n\n`body` serializes directly as the wire value for `function_call_output.output`. `success` remains internal metadata for downstream handling.",
"properties": {
"body": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"success": {
"type": [
"boolean",
"null"
]
}
},
"required": [
"body"
],
"type": "object"
},
"GhostCommit": {
"description": "Details of a ghost commit created from a repository state.",
"properties": {
@@ -413,10 +395,6 @@
"null"
]
},
"id": {
"type": "string",
"writeOnly": true
},
"summary": {
"items": {
"$ref": "#/definitions/ReasoningItemReasoningSummary"
@@ -432,7 +410,6 @@
}
},
"required": [
"id",
"summary",
"type"
],
@@ -566,7 +543,7 @@
"type": "string"
},
"output": {
"$ref": "#/definitions/FunctionCallOutputPayload"
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
@@ -631,7 +608,7 @@
"type": "string"
},
"output": {
"$ref": "#/definitions/FunctionCallOutputPayload"
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [

View File

@@ -191,24 +191,6 @@
}
]
},
"FunctionCallOutputPayload": {
"description": "The payload we send back to OpenAI when reporting a tool call result.\n\n`body` serializes directly as the wire value for `function_call_output.output`. `success` remains internal metadata for downstream handling.",
"properties": {
"body": {
"$ref": "#/definitions/FunctionCallOutputBody"
},
"success": {
"type": [
"boolean",
"null"
]
}
},
"required": [
"body"
],
"type": "object"
},
"GhostCommit": {
"description": "Details of a ghost commit created from a repository state.",
"properties": {
@@ -479,10 +461,6 @@
"null"
]
},
"id": {
"type": "string",
"writeOnly": true
},
"summary": {
"items": {
"$ref": "#/definitions/ReasoningItemReasoningSummary"
@@ -498,7 +476,6 @@
}
},
"required": [
"id",
"summary",
"type"
],
@@ -632,7 +609,7 @@
"type": "string"
},
"output": {
"$ref": "#/definitions/FunctionCallOutputPayload"
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [
@@ -697,7 +674,7 @@
"type": "string"
},
"output": {
"$ref": "#/definitions/FunctionCallOutputPayload"
"$ref": "#/definitions/FunctionCallOutputBody"
},
"type": {
"enum": [

View File

@@ -1,12 +0,0 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { FunctionCallOutputBody } from "./FunctionCallOutputBody";
/**
* The payload we send back to OpenAI when reporting a tool call result.
*
* `body` serializes directly as the wire value for `function_call_output.output`.
* `success` remains internal metadata for downstream handling.
*/
export type FunctionCallOutputPayload = { body: FunctionCallOutputBody, success: boolean | null, };

View File

@@ -2,7 +2,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ContentItem } from "./ContentItem";
import type { FunctionCallOutputPayload } from "./FunctionCallOutputPayload";
import type { FunctionCallOutputBody } from "./FunctionCallOutputBody";
import type { GhostCommit } from "./GhostCommit";
import type { LocalShellAction } from "./LocalShellAction";
import type { LocalShellStatus } from "./LocalShellStatus";
@@ -15,4 +15,4 @@ export type ResponseItem = { "type": "message", role: string, content: Array<Con
/**
* Set when using the Responses API.
*/
call_id: string | null, status: LocalShellStatus, action: LocalShellAction, } | { "type": "function_call", name: string, namespace?: string, arguments: string, call_id: string, } | { "type": "tool_search_call", call_id: string | null, status?: string, execution: string, arguments: unknown, } | { "type": "function_call_output", call_id: string, output: FunctionCallOutputPayload, } | { "type": "custom_tool_call", status?: string, call_id: string, name: string, input: string, } | { "type": "custom_tool_call_output", call_id: string, output: FunctionCallOutputPayload, } | { "type": "tool_search_output", call_id: string | null, status: string, execution: string, tools: unknown[], } | { "type": "web_search_call", status?: string, action?: WebSearchAction, } | { "type": "image_generation_call", id: string, status: string, revised_prompt?: string, result: string, } | { "type": "ghost_snapshot", ghost_commit: GhostCommit, } | { "type": "compaction", encrypted_content: string, } | { "type": "other" };
call_id: string | null, status: LocalShellStatus, action: LocalShellAction, } | { "type": "function_call", name: string, namespace?: string, arguments: string, call_id: string, } | { "type": "tool_search_call", call_id: string | null, status?: string, execution: string, arguments: unknown, } | { "type": "function_call_output", call_id: string, output: FunctionCallOutputBody, } | { "type": "custom_tool_call", status?: string, call_id: string, name: string, input: string, } | { "type": "custom_tool_call_output", call_id: string, output: FunctionCallOutputBody, } | { "type": "tool_search_output", call_id: string | null, status: string, execution: string, tools: unknown[], } | { "type": "web_search_call", status?: string, action?: WebSearchAction, } | { "type": "image_generation_call", id: string, status: string, revised_prompt?: string, result: string, } | { "type": "ghost_snapshot", ghost_commit: GhostCommit, } | { "type": "compaction", encrypted_content: string, } | { "type": "other" };

View File

@@ -18,7 +18,6 @@ export type { FileChange } from "./FileChange";
export type { ForcedLoginMethod } from "./ForcedLoginMethod";
export type { FunctionCallOutputBody } from "./FunctionCallOutputBody";
export type { FunctionCallOutputContentItem } from "./FunctionCallOutputContentItem";
export type { FunctionCallOutputPayload } from "./FunctionCallOutputPayload";
export type { FuzzyFileSearchParams } from "./FuzzyFileSearchParams";
export type { FuzzyFileSearchResponse } from "./FuzzyFileSearchResponse";
export type { FuzzyFileSearchResult } from "./FuzzyFileSearchResult";

View File

@@ -17,6 +17,7 @@ use crate::protocol::common::EXPERIMENTAL_CLIENT_METHODS;
use anyhow::Context;
use anyhow::Result;
use anyhow::anyhow;
use codex_protocol::protocol::RolloutLine;
use schemars::JsonSchema;
use schemars::schema_for;
use serde::Serialize;
@@ -185,6 +186,12 @@ pub fn generate_json(out_dir: &Path) -> Result<()> {
generate_json_with_experimental(out_dir, /*experimental_api*/ false)
}
pub fn generate_internal_json_schema(out_dir: &Path) -> Result<()> {
ensure_dir(out_dir)?;
write_json_schema::<RolloutLine>(out_dir, "RolloutLine")?;
Ok(())
}
pub fn generate_json_with_experimental(out_dir: &Path, experimental_api: bool) -> Result<()> {
ensure_dir(out_dir)?;
let envelope_emitters: Vec<JsonSchemaEmitter> = vec![

View File

@@ -6,6 +6,7 @@ mod schema_fixtures;
pub use experimental_api::*;
pub use export::GenerateTsOptions;
pub use export::generate_internal_json_schema;
pub use export::generate_json;
pub use export::generate_json_with_experimental;
pub use export::generate_ts;

View File

@@ -351,12 +351,17 @@ struct AppServerCommand {
}
#[derive(Debug, clap::Subcommand)]
#[allow(clippy::enum_variant_names)]
enum AppServerSubcommand {
/// [experimental] Generate TypeScript bindings for the app server protocol.
GenerateTs(GenerateTsCommand),
/// [experimental] Generate JSON Schema for the app server protocol.
GenerateJsonSchema(GenerateJsonSchemaCommand),
/// [internal] Generate internal JSON Schema artifacts for Codex tooling.
#[clap(hide = true)]
GenerateInternalJsonSchema(GenerateInternalJsonSchemaCommand),
}
#[derive(Debug, Args)]
@@ -385,6 +390,13 @@ struct GenerateJsonSchemaCommand {
experimental: bool,
}
#[derive(Debug, Args)]
struct GenerateInternalJsonSchemaCommand {
/// Output directory where internal JSON Schema artifacts will be written
#[arg(short = 'o', long = "out", value_name = "DIR")]
out_dir: PathBuf,
}
#[derive(Debug, Parser)]
struct StdioToUdsCommand {
/// Path to the Unix domain socket to connect to.
@@ -665,6 +677,9 @@ async fn cli_main(arg0_paths: Arg0DispatchPaths) -> anyhow::Result<()> {
gen_cli.experimental,
)?;
}
Some(AppServerSubcommand::GenerateInternalJsonSchema(gen_cli)) => {
codex_app_server_protocol::generate_internal_json_schema(&gen_cli.out_dir)?;
}
},
#[cfg(target_os = "macos")]
Some(Subcommand::App(app_cli)) => {

View File

@@ -231,6 +231,8 @@ pub enum ResponseInputItem {
},
FunctionCallOutput {
call_id: String,
#[ts(as = "FunctionCallOutputBody")]
#[schemars(with = "FunctionCallOutputBody")]
output: FunctionCallOutputPayload,
},
McpToolCallOutput {
@@ -239,6 +241,8 @@ pub enum ResponseInputItem {
},
CustomToolCallOutput {
call_id: String,
#[ts(as = "FunctionCallOutputBody")]
#[schemars(with = "FunctionCallOutputBody")]
output: FunctionCallOutputPayload,
},
ToolSearchOutput {
@@ -306,6 +310,7 @@ pub enum ResponseItem {
Reasoning {
#[serde(default, skip_serializing)]
#[ts(skip)]
#[schemars(skip)]
id: String,
summary: Vec<ReasoningItemReasoningSummary>,
#[serde(default, skip_serializing_if = "should_serialize_reasoning_content")]
@@ -356,6 +361,8 @@ pub enum ResponseItem {
// We keep this behavior centralized in `FunctionCallOutputPayload`.
FunctionCallOutput {
call_id: String,
#[ts(as = "FunctionCallOutputBody")]
#[schemars(with = "FunctionCallOutputBody")]
output: FunctionCallOutputPayload,
},
CustomToolCall {
@@ -375,6 +382,8 @@ pub enum ResponseItem {
// text or structured content items.
CustomToolCallOutput {
call_id: String,
#[ts(as = "FunctionCallOutputBody")]
#[schemars(with = "FunctionCallOutputBody")]
output: FunctionCallOutputPayload,
},
ToolSearchOutput {