[app-server] feat: add command to generate json schema (#6406)
Add a `codex generate-json-schema` command for generating a JSON schema bundle of app-server types, analogous to the existing `codex generate-ts` command for Typescript.
This commit is contained in:
@@ -666,6 +666,8 @@ fn ts_files_in_recursive(dir: &Path) -> Result<Vec<PathBuf>> {
|
|||||||
Ok(files)
|
Ok(files)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate an index.ts file that re-exports all generated types.
|
||||||
|
/// This allows consumers to import all types from a single file.
|
||||||
fn generate_index_ts(out_dir: &Path) -> Result<PathBuf> {
|
fn generate_index_ts(out_dir: &Path) -> Result<PathBuf> {
|
||||||
let mut entries: Vec<String> = Vec::new();
|
let mut entries: Vec<String> = Vec::new();
|
||||||
let mut stems: Vec<String> = ts_files_in(out_dir)?
|
let mut stems: Vec<String> = ts_files_in(out_dir)?
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ Similar to [MCP](https://modelcontextprotocol.io/), `codex app-server` supports
|
|||||||
|
|
||||||
## Message Schema
|
## Message Schema
|
||||||
|
|
||||||
Currently, you can dump a TypeScript version of the schema using `codex generate-ts`. It is specific to the version of Codex you used to run `generate-ts`, so the two are guaranteed to be compatible.
|
Currently, you can dump a TypeScript version of the schema using `codex app-server generate-ts`, or a JSON Schema bundle via `codex app-server generate-json-schema`. Each output is specific to the version of Codex you used to run the command, so the generated artifacts are guaranteed to match that version.
|
||||||
|
|
||||||
```
|
```
|
||||||
codex generate-ts --out DIR
|
codex app-server generate-ts --out DIR
|
||||||
|
codex app-server generate-json-schema --out DIR
|
||||||
```
|
```
|
||||||
|
|
||||||
## Initialization
|
## Initialization
|
||||||
@@ -49,15 +50,16 @@ The JSON-RPC API exposes dedicated methods for managing Codex conversations. Thr
|
|||||||
|
|
||||||
### 1) Start or resume a thread
|
### 1) Start or resume a thread
|
||||||
|
|
||||||
Start a fresh thread when you need a new Codex conversation. Optional fields mirror CLI defaults: set `model`, `modelProvider`, `cwd`, `approvalPolicy`, `sandbox`, or custom `config` values. Instructions can be set via `baseInstructions` and `developerInstructions`:
|
Start a fresh thread when you need a new Codex conversation.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{ "method": "thread/start", "id": 10, "params": {
|
{ "method": "thread/start", "id": 10, "params": {
|
||||||
|
// Optionally set config settings. If not specified, will use the user's
|
||||||
|
// current config settings.
|
||||||
"model": "gpt-5-codex",
|
"model": "gpt-5-codex",
|
||||||
"cwd": "/Users/me/project",
|
"cwd": "/Users/me/project",
|
||||||
"approvalPolicy": "never",
|
"approvalPolicy": "never",
|
||||||
"sandbox": "workspace-write",
|
"sandbox": "workspaceWrite",
|
||||||
"baseInstructions": "You're helping with refactors."
|
|
||||||
} }
|
} }
|
||||||
{ "id": 10, "result": {
|
{ "id": 10, "result": {
|
||||||
"thread": {
|
"thread": {
|
||||||
@@ -90,7 +92,6 @@ Example:
|
|||||||
{ "method": "thread/list", "id": 20, "params": {
|
{ "method": "thread/list", "id": 20, "params": {
|
||||||
"cursor": null,
|
"cursor": null,
|
||||||
"limit": 25,
|
"limit": 25,
|
||||||
"modelProviders": ["openai"]
|
|
||||||
} }
|
} }
|
||||||
{ "id": 20, "result": {
|
{ "id": 20, "result": {
|
||||||
"data": [
|
"data": [
|
||||||
@@ -122,18 +123,23 @@ Turns attach user input (text or images) to a thread and trigger Codex generatio
|
|||||||
- `{"type":"image","url":"https://…png"}`
|
- `{"type":"image","url":"https://…png"}`
|
||||||
- `{"type":"localImage","path":"/tmp/screenshot.png"}`
|
- `{"type":"localImage","path":"/tmp/screenshot.png"}`
|
||||||
|
|
||||||
Override knobs apply to the new turn and become the defaults for subsequent turns on the same thread:
|
You can optionally specify config overrides on the new turn. If specified, these settings become the default for subsequent turns on the same thread.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{ "method": "turn/start", "id": 30, "params": {
|
{ "method": "turn/start", "id": 30, "params": {
|
||||||
"threadId": "thr_123",
|
"threadId": "thr_123",
|
||||||
"input": [ { "type": "text", "text": "Run tests" } ],
|
"input": [ { "type": "text", "text": "Run tests" } ],
|
||||||
|
// Below are optional config overrides
|
||||||
"cwd": "/Users/me/project",
|
"cwd": "/Users/me/project",
|
||||||
"approvalPolicy": "untrusted",
|
"approvalPolicy": "unlessTrusted",
|
||||||
"sandboxPolicy": "workspace-write",
|
"sandboxPolicy": {
|
||||||
|
"mode": "workspaceWrite",
|
||||||
|
"writableRoots": ["/Users/me/project"],
|
||||||
|
"networkAccess": true
|
||||||
|
},
|
||||||
"model": "gpt-5-codex",
|
"model": "gpt-5-codex",
|
||||||
"effort": "medium",
|
"effort": "medium",
|
||||||
"summary": "focus-on-test-failures"
|
"summary": "concise"
|
||||||
} }
|
} }
|
||||||
{ "id": 30, "result": { "turn": {
|
{ "id": 30, "result": { "turn": {
|
||||||
"id": "turn_456",
|
"id": "turn_456",
|
||||||
@@ -159,7 +165,7 @@ The server requests cancellations for running subprocesses, then emits a `turn/c
|
|||||||
|
|
||||||
## Auth endpoints
|
## Auth endpoints
|
||||||
|
|
||||||
The v2 JSON-RPC auth/account surface exposes request/response methods plus server-initiated notifications (no `id`). Use these to determine auth state, start or cancel logins, logout, and inspect ChatGPT rate limits.
|
The JSON-RPC auth/account surface exposes request/response methods plus server-initiated notifications (no `id`). Use these to determine auth state, start or cancel logins, logout, and inspect ChatGPT rate limits.
|
||||||
|
|
||||||
### Quick reference
|
### Quick reference
|
||||||
- `account/read` — fetch current account info; optionally refresh tokens.
|
- `account/read` — fetch current account info; optionally refresh tokens.
|
||||||
@@ -249,5 +255,6 @@ Field notes:
|
|||||||
|
|
||||||
### Dev notes
|
### Dev notes
|
||||||
|
|
||||||
- `codex generate-ts --out <dir>` emits v2 types under `v2/`.
|
- `codex app-server generate-ts --out <dir>` emits v2 types under `v2/`.
|
||||||
|
- `codex app-server generate-json-schema --out <dir>` outputs `codex_app_server_protocol.schemas.json`.
|
||||||
- See [“Authentication and authorization” in the config docs](../../docs/config.md#authentication-and-authorization) for configuration knobs.
|
- See [“Authentication and authorization” in the config docs](../../docs/config.md#authentication-and-authorization) for configuration knobs.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use clap::Args;
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use clap_complete::Shell;
|
use clap_complete::Shell;
|
||||||
@@ -82,8 +83,8 @@ enum Subcommand {
|
|||||||
/// [experimental] Run the Codex MCP server (stdio transport).
|
/// [experimental] Run the Codex MCP server (stdio transport).
|
||||||
McpServer,
|
McpServer,
|
||||||
|
|
||||||
/// [experimental] Run the app server.
|
/// [experimental] Run the app server or related tooling.
|
||||||
AppServer,
|
AppServer(AppServerCommand),
|
||||||
|
|
||||||
/// Generate shell completion scripts.
|
/// Generate shell completion scripts.
|
||||||
Completion(CompletionCommand),
|
Completion(CompletionCommand),
|
||||||
@@ -99,9 +100,6 @@ enum Subcommand {
|
|||||||
/// Resume a previous interactive session (picker by default; use --last to continue the most recent).
|
/// Resume a previous interactive session (picker by default; use --last to continue the most recent).
|
||||||
Resume(ResumeCommand),
|
Resume(ResumeCommand),
|
||||||
|
|
||||||
/// [experimental] Generate TypeScript bindings for the app server protocol.
|
|
||||||
GenerateTs(GenerateTsCommand),
|
|
||||||
|
|
||||||
/// [EXPERIMENTAL] Browse tasks from Codex Cloud and apply changes locally.
|
/// [EXPERIMENTAL] Browse tasks from Codex Cloud and apply changes locally.
|
||||||
#[clap(name = "cloud", alias = "cloud-tasks")]
|
#[clap(name = "cloud", alias = "cloud-tasks")]
|
||||||
Cloud(CloudTasksCli),
|
Cloud(CloudTasksCli),
|
||||||
@@ -208,6 +206,22 @@ struct LogoutCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
|
struct AppServerCommand {
|
||||||
|
/// Omit to run the app server; specify a subcommand for tooling.
|
||||||
|
#[command(subcommand)]
|
||||||
|
subcommand: Option<AppServerSubcommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, clap::Subcommand)]
|
||||||
|
enum AppServerSubcommand {
|
||||||
|
/// [experimental] Generate TypeScript bindings for the app server protocol.
|
||||||
|
GenerateTs(GenerateTsCommand),
|
||||||
|
|
||||||
|
/// [experimental] Generate JSON Schema for the app server protocol.
|
||||||
|
GenerateJsonSchema(GenerateJsonSchemaCommand),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Args)]
|
||||||
struct GenerateTsCommand {
|
struct GenerateTsCommand {
|
||||||
/// Output directory where .ts files will be written
|
/// Output directory where .ts files will be written
|
||||||
#[arg(short = 'o', long = "out", value_name = "DIR")]
|
#[arg(short = 'o', long = "out", value_name = "DIR")]
|
||||||
@@ -218,6 +232,13 @@ struct GenerateTsCommand {
|
|||||||
prettier: Option<PathBuf>,
|
prettier: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Args)]
|
||||||
|
struct GenerateJsonSchemaCommand {
|
||||||
|
/// Output directory where the schema bundle will be written
|
||||||
|
#[arg(short = 'o', long = "out", value_name = "DIR")]
|
||||||
|
out_dir: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
struct StdioToUdsCommand {
|
struct StdioToUdsCommand {
|
||||||
/// Path to the Unix domain socket to connect to.
|
/// Path to the Unix domain socket to connect to.
|
||||||
@@ -410,9 +431,20 @@ async fn cli_main(codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()
|
|||||||
prepend_config_flags(&mut mcp_cli.config_overrides, root_config_overrides.clone());
|
prepend_config_flags(&mut mcp_cli.config_overrides, root_config_overrides.clone());
|
||||||
mcp_cli.run().await?;
|
mcp_cli.run().await?;
|
||||||
}
|
}
|
||||||
Some(Subcommand::AppServer) => {
|
Some(Subcommand::AppServer(app_server_cli)) => match app_server_cli.subcommand {
|
||||||
codex_app_server::run_main(codex_linux_sandbox_exe, root_config_overrides).await?;
|
None => {
|
||||||
}
|
codex_app_server::run_main(codex_linux_sandbox_exe, root_config_overrides).await?;
|
||||||
|
}
|
||||||
|
Some(AppServerSubcommand::GenerateTs(gen_cli)) => {
|
||||||
|
codex_app_server_protocol::generate_ts(
|
||||||
|
&gen_cli.out_dir,
|
||||||
|
gen_cli.prettier.as_deref(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Some(AppServerSubcommand::GenerateJsonSchema(gen_cli)) => {
|
||||||
|
codex_app_server_protocol::generate_json(&gen_cli.out_dir)?;
|
||||||
|
}
|
||||||
|
},
|
||||||
Some(Subcommand::Resume(ResumeCommand {
|
Some(Subcommand::Resume(ResumeCommand {
|
||||||
session_id,
|
session_id,
|
||||||
last,
|
last,
|
||||||
@@ -527,9 +559,6 @@ async fn cli_main(codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()
|
|||||||
tokio::task::spawn_blocking(move || codex_stdio_to_uds::run(socket_path.as_path()))
|
tokio::task::spawn_blocking(move || codex_stdio_to_uds::run(socket_path.as_path()))
|
||||||
.await??;
|
.await??;
|
||||||
}
|
}
|
||||||
Some(Subcommand::GenerateTs(gen_cli)) => {
|
|
||||||
codex_app_server_protocol::generate_ts(&gen_cli.out_dir, gen_cli.prettier.as_deref())?;
|
|
||||||
}
|
|
||||||
Some(Subcommand::Features(FeaturesCli { sub })) => match sub {
|
Some(Subcommand::Features(FeaturesCli { sub })) => match sub {
|
||||||
FeaturesSubcommand::List => {
|
FeaturesSubcommand::List => {
|
||||||
// Respect root-level `-c` overrides plus top-level flags like `--profile`.
|
// Respect root-level `-c` overrides plus top-level flags like `--profile`.
|
||||||
|
|||||||
Reference in New Issue
Block a user