Compare commits

...

26 Commits

Author SHA1 Message Date
Charles Cunningham
5bb8c89b99 tui: remove draft-only collaboration mode override state 2026-02-03 21:12:01 -08:00
Charles Cunningham
8d1d67730d tui: remove redundant clone in restore override test 2026-02-03 19:55:00 -08:00
Charles Cunningham
926b527830 tui: avoid code_mask dependency in restore override test 2026-02-03 19:00:35 -08:00
Charles Cunningham
3a077c3df3 tui: document queued override conflict handling 2026-02-03 18:55:55 -08:00
Charles Cunningham
bc7635a22b tui: preserve mode override when restoring queued drafts 2026-02-03 18:48:42 -08:00
Charles Cunningham
804dd148b9 tui: make mode-switch tests resilient to default mode naming 2026-02-03 13:18:37 -08:00
Charles Cunningham
8466456b3c tui: only reject mode-switch overrides during running turns 2026-02-03 11:29:37 -08:00
Charles Cunningham
b530c9285c tui: reject mode-switched submits while turn is running 2026-02-03 00:19:47 -08:00
Charles Cunningham
953cd450a2 tui: defer mode switch for queued plan nudges 2026-02-02 21:02:21 -08:00
Charles Cunningham
ebe80ee7d9 tui: queue steer/nudged messages while plan generation is active 2026-02-02 21:01:22 -08:00
pakrym-oai
bf87468c2b Restore status after preamble (#10465) 2026-02-02 20:35:50 -08:00
Eric Traut
8b280367b1 Updated bug and feature templates (#10453)
The current bug template uses CLI-specific instructions for getting the
version.

The current feature template doesn't ask the user to provide the Codex
variant (surface) they are using.

This PR addresses these problems.
2026-02-02 20:08:08 -08:00
pakrym-oai
cbfd2a37cc Trim compaction input (#10374)
Two fixes:

1. Include trailing tool output in the total context size calculation.
Otherwise when checking whether compaction should run we ignore newly
added outputs.
2. Trim trailing tool output/tool calls until we can fit the request
into the model context size. Otherwise the compaction endpoint will fail
to compact. We only trim items that can be reproduced again by the model
(tool calls, tool call outputs).
2026-02-02 19:03:11 -08:00
Colin Young
7e07ec8f73 [Codex][CLI] Gate image inputs by model modalities (#10271)
###### Summary

- Add input_modalities to model metadata so clients can determine
supported input types.
- Gate image paste/attach in TUI when the selected model does not
support images.
- Block submits that include images for unsupported models and show a
clear warning.
- Propagate modality metadata through app-server protocol/model-list
responses.
  - Update related tests/fixtures.

  ###### Rationale

  - Models support different input modalities.
- Clients need an explicit capability signal to prevent unsupported
requests.
- Backward-compatible defaults preserve existing behavior when modality
metadata is absent.

  ###### Scope

  - codex-rs/protocol, codex-rs/core, codex-rs/tui
  - codex-rs/app-server-protocol, codex-rs/app-server
  - Generated app-server types / schema fixtures

  ###### Trade-offs

- Default behavior assumes text + image when field is absent for
compatibility.
  - Server-side validation remains the source of truth.

  ###### Follow-up

- Non-TUI clients should consume input_modalities to disable unsupported
attachments.
- Model catalogs should explicitly set input_modalities for text-only
models.

  ###### Testing

  - cargo fmt --all
  - cargo test -p codex-tui
  - env -u GITHUB_APP_KEY cargo test -p codex-core --lib
  - just write-app-server-schema
- cargo run -p codex-cli --bin codex -- app-server generate-ts --out
app-server-types
  - test against local backend
  
<img width="695" height="199" alt="image"
src="https://github.com/user-attachments/assets/d22dd04f-5eba-4db9-a7c5-a2506f60ec44"
/>

---------

Co-authored-by: Josh McKinney <joshka@openai.com>
2026-02-02 18:56:39 -08:00
Ahmed Ibrahim
b8addcddb9 Require models refresh on cli version mismatch (#10414) 2026-02-02 18:55:25 -08:00
sayan-oai
fc05374344 chore: add phase to message responseitem (#10455)
### What

add wiring for `phase` field on `ResponseItem::Message` to lay
groundwork for differentiating model preambles and final messages.
currently optional.

follows pattern in #9698.

updated schemas with `just write-app-server-schema` so we can see type
changes.

### Tests
Updated existing tests for SSE parsing and hydrating from history
2026-02-03 02:52:26 +00:00
Ahmed Ibrahim
0999fd82b9 app tool tip (#10454)
# External (non-OpenAI) Pull Request Requirements

Before opening this Pull Request, please read the dedicated
"Contributing" markdown file or your PR may be closed:
https://github.com/openai/codex/blob/main/docs/contributing.md

If your PR conforms to our contribution guidelines, replace this text
with a detailed and high quality description of your changes.

Include a link to a bug report or enhancement request.
2026-02-03 02:37:01 +00:00
Michael Bolin
891ed87409 chore: remove deprecated mcp-types crate (#10357)
https://github.com/openai/codex/pull/10349 migrated us off of
`mcp-types`, so this PR deletes the code.

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/10357).
* __->__ #10357
* #10349
* #10356
2026-02-03 02:33:16 +00:00
Ahmed Ibrahim
97ff090104 Hide short worked-for label in final separator (#10452)
- Hide the "Worked for" label in the final message separator unless
elapsed time is over one minute.\n- Update/add tests to cover both
hidden (<60s) and shown (>=61s) behavior.
2026-02-03 02:29:20 +00:00
Eric Traut
8dd41e229b Fixed sandbox mode inconsistency if untrusted is selected (#10415)
This PR addresses #10395

When a user is asked to pick the trust level of a project, the code
currently reloads the config if they select "trusted". It doesn't reload
the config in the "untrusted" case but should. This causes the sandbox
mode to be reported incorrectly in `/status` during the first run (it's
displayed as `read-only` even though it acts as though it's
`workspace-write`).
2026-02-03 02:00:35 +00:00
Michael Bolin
66447d5d2c feat: replace custom mcp-types crate with equivalents from rmcp (#10349)
We started working with MCP in Codex before
https://crates.io/crates/rmcp was mature, so we had our own crate for
MCP types that was generated from the MCP schema:


8b95d3e082/codex-rs/mcp-types/README.md

Now that `rmcp` is more mature, it makes more sense to use their MCP
types in Rust, as they handle details (like the `_meta` field) that our
custom version ignored. Though one advantage that our custom types had
is that our generated types implemented `JsonSchema` and `ts_rs::TS`,
whereas the types in `rmcp` do not. As such, part of the work of this PR
is leveraging the adapters between `rmcp` types and the serializable
types that are API for us (app server and MCP) introduced in #10356.

Note this PR results in a number of changes to
`codex-rs/app-server-protocol/schema`, which merit special attention
during review. We must ensure that these changes are still
backwards-compatible, which is possible because we have:

```diff
- export type CallToolResult = { content: Array<ContentBlock>, isError?: boolean, structuredContent?: JsonValue, };
+ export type CallToolResult = { content: Array<JsonValue>, structuredContent?: JsonValue, isError?: boolean, _meta?: JsonValue, };
```

so `ContentBlock` has been replaced with the more general `JsonValue`.
Note that `ContentBlock` was defined as:

```typescript
export type ContentBlock = TextContent | ImageContent | AudioContent | ResourceLink | EmbeddedResource;
```

so the deletion of those individual variants should not be a cause of
great concern.

Similarly, we have the following change in
`codex-rs/app-server-protocol/schema/typescript/Tool.ts`:

```
- export type Tool = { annotations?: ToolAnnotations, description?: string, inputSchema: ToolInputSchema, name: string, outputSchema?: ToolOutputSchema, title?: string, };
+ export type Tool = { name: string, title?: string, description?: string, inputSchema: JsonValue, outputSchema?: JsonValue, annotations?: JsonValue, icons?: Array<JsonValue>, _meta?: JsonValue, };
```

so:

- `annotations?: ToolAnnotations` ➡️ `JsonValue`
- `inputSchema: ToolInputSchema` ➡️ `JsonValue`
- `outputSchema?: ToolOutputSchema` ➡️ `JsonValue`

and two new fields: `icons?: Array<JsonValue>, _meta?: JsonValue`

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/10349).
* #10357
* __->__ #10349
* #10356
2026-02-02 17:41:55 -08:00
Charley Cunningham
8f5edddf71 TUI: Render request_user_input results in history and simplify interrupt handling (#10064)
## Summary
This PR improves the TUI experience for `request_user_input` by
rendering submitted question/answer sets directly in conversation
history with clear, structured formatting.

It also intentionally simplifies interrupt behavior for now: on `Esc` /
`Ctrl+C`, the questions overlay interrupts the turn without attempting
to submit partial answers.

<img width="1344" height="573" alt="Screenshot 2026-02-02 at 4 51 40 PM"
src="https://github.com/user-attachments/assets/ff752131-7060-44c1-9ded-af061969a533"
/>

## Scope
- TUI-only changes.
- No core/protocol/app-server behavior changes in this PR.
- Resume reconstruction of interrupted question sets is out of scope for
this PR.

## What Changed
- Added a new history cell: `RequestUserInputResultCell` in
`codex-rs/tui/src/history_cell.rs`.
- On normal `request_user_input` submission, TUI now inserts that
history cell immediately after sending `Op::UserInputAnswer`.
- Rendering includes a `Questions` header with `answered/total` count.
- Rendering shows each question as a bullet item.
- Rendering styles submitted answer lines in cyan.
- Rendering styles notes (for option questions) as `note:` lines in
cyan.
- Rendering styles freeform text (for no-option questions) as `answer:`
lines in cyan.
- Rendering dims only the `(unanswered)` suffix.
- Rendering can include an interrupted suffix and summary text when the
cell is marked interrupted.
- Rendering redacts secret questions as `••••••` instead of showing raw
values.
- Added `wrap_with_prefix(...)` in `history_cell.rs` for wrapped
prefixed lines.
- Added `split_request_user_input_answer(...)` in `history_cell.rs` for
decoding `"user_note: ..."` entries.

## Interrupt Behavior (Intentional for this PR)
- `Esc` / `Ctrl+C` in the questions overlay now performs `Op::Interrupt`
and exits the overlay.
- It does **not** submit partial/committed answers on interrupt.
- Added TODO comments in `request_user_input` overlay interrupt paths
indicating where interrupted partial result emission should be
reintroduced once core support is finalized.
- Queued `request_user_input` overlays are discarded on interrupt in the
current behavior.

## Tests Updated
- Updated/added overlay tests in
`codex-rs/tui/src/bottom_pane/request_user_input/mod.rs` to reflect
interrupt-only behavior.
- Added helper assertion for interrupt-only event expectation.
- Existing submission-path tests now validate history insertion behavior
and expected answer maps.

## Behavior Notes
- Completed question flows now produce a readable `Questions` block in
transcript history.
- Interrupted flows currently do not persist partial answers to
model-visible tool output.

## Follow-ups
- Reintroduce partial-answer-on-interrupt semantics once core can
persist/sequence interrupted `request_user_input` outputs safely.
- Optionally add replay/resume rendering for interrupted question sets
as a separate PR.

## Codex author
`codex fork 019bfb8d-2a65-7313-9be2-ea7100d19a61`
2026-02-02 17:41:30 -08:00
Charley Cunningham
1096d6453c Fix plan implementation prompt reappearing after /agent thread switch (#10447)
## Summary

This fixes a UX bug (https://github.com/openai/codex/issues/10442) where
the **"Implement this plan?"** prompt could reappear after switching
agents with `/agent` and then switching back to the original agent
during plan execution.

## Root Cause

On thread switch, the TUI rebuilds `ChatWidget`, replays buffered thread
events, then drains any queued live events.

In this flow, a `TurnComplete` can be handled twice for the same logical
turn:
1. replayed (`from_replay = true`)
2. then live (`from_replay = false`)

`ChatWidget` used `saw_plan_item_this_turn` to decide whether to show
the plan implementation prompt, but that flag was only reset on
`TurnStarted`.
If duplicate completion events occurred, stale `saw_plan_item_this_turn
= true` could cause the prompt to re-trigger unexpectedly.

## Fix

- Clear `saw_plan_item_this_turn` at the end of `on_task_complete`,
after prompt gating runs.
- This keeps the flag truly turn-scoped and prevents duplicate
`TurnComplete` handling from reopening the prompt.
2026-02-02 17:40:05 -08:00
Ahmed Ibrahim
d02db8b43d Add codex app macOS launcher (#10418)
- Add `codex app <path>` to launch the Codex Desktop app.
- On macOS, auto-downloads the DMG if missing; non-macOS prints a link
to chatgpt.com/codex.
2026-02-02 17:37:04 -08:00
pash-openai
019d89ff86 make codex better at git (#10145)
adds basic git context to the session prefix so the model can anchor git
actions and be a bit more version-aware. structured it in a
multiroot-friendly shape even though we only have one root today
2026-02-02 16:57:29 -08:00
Gav Verma
e24058b7a8 feat: Read personal skills from .agents/skills (#10437)
- Issue: https://github.com/agentskills/agentskills/issues/15
- Follow-up to https://github.com/openai/codex/pull/10317 (for team/repo
skills)
- This change now also loads personal/user skills from
`$HOME/.agents/skills` (or `~/.agents/skills`) in addition to loading
from `.agents/skills` inside of git repos.
- The location of `.system` skills remains unchanged.
- Keeping backwards compatibility with `~/.codex/skills` for now until
we fully deprecate.

With skills in both personal folders:
<img width="831" height="421" alt="image"
src="https://github.com/user-attachments/assets/ad8ac918-bfe6-4a2d-8a8e-d608c9d3d701"
/>

We load from both places:
<img width="607" height="236" alt="image"
src="https://github.com/user-attachments/assets/480f4db0-ae64-4dc1-bdf5-c5de98c16f5c"
/>
2026-02-02 16:49:23 -08:00
181 changed files with 4408 additions and 15745 deletions

View File

@@ -19,7 +19,7 @@ body:
id: version
attributes:
label: What version of Codex is running?
description: Copy the output of `codex --version`
description: (App) look in "About Codex" dialog; (CLI) use `codex --version`; (IDE Extension) look in extensions panel.
validations:
required: true
- type: input

View File

@@ -12,6 +12,13 @@ body:
1. Search existing issues for similar features. If you find one, 👍 it rather than opening a new one.
2. The Codex team will try to balance the varying needs of the community when prioritizing or rejecting new features. Not all features will be accepted. See [Contributing](https://github.com/openai/codex#contributing) for more details.
- type: input
id: variant
attributes:
label: What variant of Codex are you using?
description: (e.g., CLI, App, IDE Extension, Web)
validations:
required: true
- type: textarea
id: feature
attributes:

View File

@@ -64,8 +64,6 @@ jobs:
components: rustfmt
- name: cargo fmt
run: cargo fmt -- --config imports_granularity=Item --check
- name: Verify codegen for mcp-types
run: ./mcp-types/check_lib_rs.py
cargo_shear:
name: cargo shear

25
codex-rs/Cargo.lock generated
View File

@@ -1108,7 +1108,6 @@ dependencies = [
"codex-utils-absolute-path",
"codex-utils-json-to-toml",
"core_test_support",
"mcp-types",
"os_info",
"pretty_assertions",
"rmcp",
@@ -1137,7 +1136,6 @@ dependencies = [
"codex-utils-absolute-path",
"codex-utils-cargo-bin",
"inventory",
"mcp-types",
"pretty_assertions",
"schemars 0.8.22",
"serde",
@@ -1422,6 +1420,7 @@ dependencies = [
"core-foundation 0.9.4",
"core_test_support",
"ctor 0.6.3",
"dirs",
"dunce",
"encoding_rs",
"env-flags",
@@ -1436,7 +1435,6 @@ dependencies = [
"landlock",
"libc",
"maplit",
"mcp-types",
"multimap",
"once_cell",
"openssl-sys",
@@ -1448,6 +1446,7 @@ dependencies = [
"regex",
"regex-lite",
"reqwest",
"rmcp",
"schemars 0.8.22",
"seccompiler",
"serde",
@@ -1511,10 +1510,10 @@ dependencies = [
"codex-utils-cargo-bin",
"core_test_support",
"libc",
"mcp-types",
"owo-colors",
"predicates",
"pretty_assertions",
"rmcp",
"serde",
"serde_json",
"shlex",
@@ -1716,10 +1715,10 @@ dependencies = [
"codex-protocol",
"codex-utils-json-to-toml",
"core_test_support",
"mcp-types",
"mcp_test_support",
"os_info",
"pretty_assertions",
"rmcp",
"schemars 0.8.22",
"serde",
"serde_json",
@@ -1828,7 +1827,6 @@ dependencies = [
"icu_decimal",
"icu_locale_core",
"icu_provider",
"mcp-types",
"mime_guess",
"pretty_assertions",
"schemars 0.8.22",
@@ -1872,7 +1870,6 @@ dependencies = [
"codex-utils-home-dir",
"futures",
"keyring",
"mcp-types",
"oauth2",
"pretty_assertions",
"reqwest",
@@ -1965,7 +1962,6 @@ dependencies = [
"itertools 0.14.0",
"lazy_static",
"libc",
"mcp-types",
"pathdiff",
"pretty_assertions",
"pulldown-cmark",
@@ -1974,6 +1970,7 @@ dependencies = [
"ratatui-macros",
"regex-lite",
"reqwest",
"rmcp",
"serde",
"serde_json",
"serial_test",
@@ -4652,16 +4649,6 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3eede3bdf92f3b4f9dc04072a9ce5ab557d5ec9038773bf9ffcd5588b3cc05b"
[[package]]
name = "mcp-types"
version = "0.0.0"
dependencies = [
"schemars 0.8.22",
"serde",
"serde_json",
"ts-rs",
]
[[package]]
name = "mcp_test_support"
version = "0.0.0"
@@ -4671,9 +4658,9 @@ dependencies = [
"codex-mcp-server",
"codex-utils-cargo-bin",
"core_test_support",
"mcp-types",
"os_info",
"pretty_assertions",
"rmcp",
"serde",
"serde_json",
"shlex",

View File

@@ -27,7 +27,6 @@ members = [
"lmstudio",
"login",
"mcp-server",
"mcp-types",
"network-proxy",
"ollama",
"process-hardening",
@@ -112,7 +111,6 @@ codex-utils-string = { path = "utils/string" }
codex-windows-sandbox = { path = "windows-sandbox-rs" }
core_test_support = { path = "core/tests/common" }
exec_server_test_support = { path = "exec-server/tests/common" }
mcp-types = { path = "mcp-types" }
mcp_test_support = { path = "mcp-server/tests/common" }
# External

View File

@@ -17,7 +17,6 @@ clap = { workspace = true, features = ["derive"] }
codex-protocol = { workspace = true }
codex-experimental-api-macros = { workspace = true }
codex-utils-absolute-path = { workspace = true }
mcp-types = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }

View File

@@ -1038,6 +1038,13 @@
],
"type": "string"
},
"MessagePhase": {
"enum": [
"commentary",
"final_answer"
],
"type": "string"
},
"ModeKind": {
"description": "Initial collaboration mode to use when the TUI starts.",
"enum": [
@@ -1317,6 +1324,16 @@
],
"writeOnly": true
},
"phase": {
"anyOf": [
{
"$ref": "#/definitions/MessagePhase"
},
{
"type": "null"
}
]
},
"role": {
"type": "string"
},

View File

@@ -93,34 +93,6 @@
}
]
},
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AskForApproval": {
"description": "Determines the conditions under which the user is consulted to approve running the command proposed by Codex.",
"oneOf": [
@@ -154,57 +126,6 @@
}
]
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -229,10 +150,9 @@
"CallToolResult": {
"description": "The server's response to a tool call.",
"properties": {
"_meta": true,
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"isError": {
@@ -390,25 +310,6 @@
}
]
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"ContentItem": {
"oneOf": [
{
@@ -544,42 +445,6 @@
],
"type": "object"
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"EventMsg": {
"description": "Response event from the agent NOTE: Make sure none of these values have optional types, as it will mess up the extension code-gen.",
"oneOf": [
@@ -3071,36 +2936,6 @@
],
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"LocalShellAction": {
"oneOf": [
{
@@ -3276,6 +3111,13 @@
}
]
},
"MessagePhase": {
"enum": [
"commentary",
"final_answer"
],
"type": "string"
},
"ModeKind": {
"description": "Initial collaboration mode to use when the TUI starts.",
"enum": [
@@ -3599,7 +3441,8 @@
"format": "int64",
"type": "integer"
}
]
],
"description": "ID of a request, which can be either a string or an integer."
},
"RequestUserInputQuestion": {
"properties": {
@@ -3655,22 +3498,21 @@
"Resource": {
"description": "A known resource that the server is capable of reading.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"mimeType": {
"type": [
"string",
@@ -3703,74 +3545,10 @@
],
"type": "object"
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"ResourceTemplate": {
"description": "A template description for resources available on the server.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"annotations": true,
"description": {
"type": [
"string",
@@ -3825,6 +3603,16 @@
],
"writeOnly": true
},
"phase": {
"anyOf": [
{
"$ref": "#/definitions/MessagePhase"
},
{
"type": "null"
}
]
},
"role": {
"type": "string"
},
@@ -4361,14 +4149,6 @@
}
]
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SandboxPolicy": {
"description": "Determines execution restrictions for model shell commands.",
"oneOf": [
@@ -4678,32 +4458,6 @@
],
"type": "string"
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byte_range": {
@@ -4727,27 +4481,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -4808,38 +4541,26 @@
"Tool": {
"description": "Definition for a tool the client can call.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/ToolAnnotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"inputSchema": {
"$ref": "#/definitions/ToolInputSchema"
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"inputSchema": true,
"name": {
"type": "string"
},
"outputSchema": {
"anyOf": [
{
"$ref": "#/definitions/ToolOutputSchema"
},
{
"type": "null"
}
]
},
"outputSchema": true,
"title": {
"type": [
"string",
@@ -4853,82 +4574,6 @@
],
"type": "object"
},
"ToolAnnotations": {
"description": "Additional properties describing a Tool to clients.\n\nNOTE: all properties in ToolAnnotations are **hints**. They are not guaranteed to provide a faithful description of tool behavior (including descriptive properties like `title`).\n\nClients should never make tool use decisions based on ToolAnnotations received from untrusted servers.",
"properties": {
"destructiveHint": {
"type": [
"boolean",
"null"
]
},
"idempotentHint": {
"type": [
"boolean",
"null"
]
},
"openWorldHint": {
"type": [
"boolean",
"null"
]
},
"readOnlyHint": {
"type": [
"boolean",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"ToolInputSchema": {
"description": "A JSON Schema object defining the expected parameters for the tool.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
},
"ToolOutputSchema": {
"description": "An optional JSON Schema object defining the structure of the tool's output returned in the structuredContent field of a CallToolResult.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
},
"TurnAbortReason": {
"enum": [
"interrupted",

View File

@@ -165,34 +165,6 @@
}
]
},
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AskForApproval": {
"description": "Determines the conditions under which the user is consulted to approve running the command proposed by Codex.",
"oneOf": [
@@ -226,36 +198,6 @@
}
]
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"AuthMode": {
"description": "Authentication mode for OpenAI-backed providers.",
"oneOf": [
@@ -298,27 +240,6 @@
},
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -362,10 +283,9 @@
"CallToolResult": {
"description": "The server's response to a tool call.",
"properties": {
"_meta": true,
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"isError": {
@@ -889,25 +809,6 @@
],
"type": "object"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"ContentItem": {
"oneOf": [
{
@@ -1099,42 +1000,6 @@
],
"type": "object"
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"ErrorNotification": {
"properties": {
"error": {
@@ -3714,36 +3579,6 @@
],
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"ItemCompletedNotification": {
"properties": {
"item": {
@@ -4037,9 +3872,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -4057,6 +3890,13 @@
],
"type": "string"
},
"MessagePhase": {
"enum": [
"commentary",
"final_answer"
],
"type": "string"
},
"ModeKind": {
"description": "Initial collaboration mode to use when the TUI starts.",
"enum": [
@@ -4641,7 +4481,8 @@
"format": "int64",
"type": "integer"
}
]
],
"description": "ID of a request, which can be either a string or an integer."
},
"RequestUserInputQuestion": {
"properties": {
@@ -4697,22 +4538,21 @@
"Resource": {
"description": "A known resource that the server is capable of reading.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"mimeType": {
"type": [
"string",
@@ -4745,74 +4585,10 @@
],
"type": "object"
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"ResourceTemplate": {
"description": "A template description for resources available on the server.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"annotations": true,
"description": {
"type": [
"string",
@@ -4867,6 +4643,16 @@
],
"writeOnly": true
},
"phase": {
"anyOf": [
{
"$ref": "#/definitions/MessagePhase"
},
{
"type": "null"
}
]
},
"role": {
"type": "string"
},
@@ -5403,14 +5189,6 @@
}
]
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SandboxPolicy": {
"description": "Determines execution restrictions for model shell commands.",
"oneOf": [
@@ -5874,32 +5652,6 @@
],
"type": "object"
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -5982,27 +5734,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"Thread": {
"properties": {
"cliVersion": {
@@ -6714,38 +6445,26 @@
"Tool": {
"description": "Definition for a tool the client can call.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/ToolAnnotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"inputSchema": {
"$ref": "#/definitions/ToolInputSchema"
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"inputSchema": true,
"name": {
"type": "string"
},
"outputSchema": {
"anyOf": [
{
"$ref": "#/definitions/ToolOutputSchema"
},
{
"type": "null"
}
]
},
"outputSchema": true,
"title": {
"type": [
"string",
@@ -6759,82 +6478,6 @@
],
"type": "object"
},
"ToolAnnotations": {
"description": "Additional properties describing a Tool to clients.\n\nNOTE: all properties in ToolAnnotations are **hints**. They are not guaranteed to provide a faithful description of tool behavior (including descriptive properties like `title`).\n\nClients should never make tool use decisions based on ToolAnnotations received from untrusted servers.",
"properties": {
"destructiveHint": {
"type": [
"boolean",
"null"
]
},
"idempotentHint": {
"type": [
"boolean",
"null"
]
},
"openWorldHint": {
"type": [
"boolean",
"null"
]
},
"readOnlyHint": {
"type": [
"boolean",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"ToolInputSchema": {
"description": "A JSON Schema object defining the expected parameters for the tool.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
},
"ToolOutputSchema": {
"description": "An optional JSON Schema object defining the structure of the tool's output returned in the structuredContent field of a CallToolResult.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
},
"Turn": {
"properties": {
"error": {

View File

@@ -93,34 +93,6 @@
}
]
},
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AskForApproval": {
"description": "Determines the conditions under which the user is consulted to approve running the command proposed by Codex.",
"oneOf": [
@@ -154,57 +126,6 @@
}
]
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -229,10 +150,9 @@
"CallToolResult": {
"description": "The server's response to a tool call.",
"properties": {
"_meta": true,
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"isError": {
@@ -390,25 +310,6 @@
}
]
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"ContentItem": {
"oneOf": [
{
@@ -544,42 +445,6 @@
],
"type": "object"
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"EventMsg": {
"description": "Response event from the agent NOTE: Make sure none of these values have optional types, as it will mess up the extension code-gen.",
"oneOf": [
@@ -3071,36 +2936,6 @@
],
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"LocalShellAction": {
"oneOf": [
{
@@ -3276,6 +3111,13 @@
}
]
},
"MessagePhase": {
"enum": [
"commentary",
"final_answer"
],
"type": "string"
},
"ModeKind": {
"description": "Initial collaboration mode to use when the TUI starts.",
"enum": [
@@ -3599,7 +3441,8 @@
"format": "int64",
"type": "integer"
}
]
],
"description": "ID of a request, which can be either a string or an integer."
},
"RequestUserInputQuestion": {
"properties": {
@@ -3655,22 +3498,21 @@
"Resource": {
"description": "A known resource that the server is capable of reading.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"mimeType": {
"type": [
"string",
@@ -3703,74 +3545,10 @@
],
"type": "object"
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"ResourceTemplate": {
"description": "A template description for resources available on the server.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"annotations": true,
"description": {
"type": [
"string",
@@ -3825,6 +3603,16 @@
],
"writeOnly": true
},
"phase": {
"anyOf": [
{
"$ref": "#/definitions/MessagePhase"
},
{
"type": "null"
}
]
},
"role": {
"type": "string"
},
@@ -4361,14 +4149,6 @@
}
]
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SandboxPolicy": {
"description": "Determines execution restrictions for model shell commands.",
"oneOf": [
@@ -4678,32 +4458,6 @@
],
"type": "string"
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byte_range": {
@@ -4727,27 +4481,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -4808,38 +4541,26 @@
"Tool": {
"description": "Definition for a tool the client can call.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/ToolAnnotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"inputSchema": {
"$ref": "#/definitions/ToolInputSchema"
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"inputSchema": true,
"name": {
"type": "string"
},
"outputSchema": {
"anyOf": [
{
"$ref": "#/definitions/ToolOutputSchema"
},
{
"type": "null"
}
]
},
"outputSchema": true,
"title": {
"type": [
"string",
@@ -4853,82 +4574,6 @@
],
"type": "object"
},
"ToolAnnotations": {
"description": "Additional properties describing a Tool to clients.\n\nNOTE: all properties in ToolAnnotations are **hints**. They are not guaranteed to provide a faithful description of tool behavior (including descriptive properties like `title`).\n\nClients should never make tool use decisions based on ToolAnnotations received from untrusted servers.",
"properties": {
"destructiveHint": {
"type": [
"boolean",
"null"
]
},
"idempotentHint": {
"type": [
"boolean",
"null"
]
},
"openWorldHint": {
"type": [
"boolean",
"null"
]
},
"readOnlyHint": {
"type": [
"boolean",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"ToolInputSchema": {
"description": "A JSON Schema object defining the expected parameters for the tool.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
},
"ToolOutputSchema": {
"description": "An optional JSON Schema object defining the structure of the tool's output returned in the structuredContent field of a CallToolResult.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
},
"TurnAbortReason": {
"enum": [
"interrupted",

View File

@@ -266,6 +266,13 @@
],
"type": "string"
},
"MessagePhase": {
"enum": [
"commentary",
"final_answer"
],
"type": "string"
},
"NewConversationParams": {
"properties": {
"approvalPolicy": {
@@ -437,6 +444,16 @@
],
"writeOnly": true
},
"phase": {
"anyOf": [
{
"$ref": "#/definitions/MessagePhase"
},
{
"type": "null"
}
]
},
"role": {
"type": "string"
},

View File

@@ -93,34 +93,6 @@
}
]
},
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AskForApproval": {
"description": "Determines the conditions under which the user is consulted to approve running the command proposed by Codex.",
"oneOf": [
@@ -154,57 +126,6 @@
}
]
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -229,10 +150,9 @@
"CallToolResult": {
"description": "The server's response to a tool call.",
"properties": {
"_meta": true,
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"isError": {
@@ -390,25 +310,6 @@
}
]
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"ContentItem": {
"oneOf": [
{
@@ -544,42 +445,6 @@
],
"type": "object"
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"EventMsg": {
"description": "Response event from the agent NOTE: Make sure none of these values have optional types, as it will mess up the extension code-gen.",
"oneOf": [
@@ -3071,36 +2936,6 @@
],
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"LocalShellAction": {
"oneOf": [
{
@@ -3276,6 +3111,13 @@
}
]
},
"MessagePhase": {
"enum": [
"commentary",
"final_answer"
],
"type": "string"
},
"ModeKind": {
"description": "Initial collaboration mode to use when the TUI starts.",
"enum": [
@@ -3599,7 +3441,8 @@
"format": "int64",
"type": "integer"
}
]
],
"description": "ID of a request, which can be either a string or an integer."
},
"RequestUserInputQuestion": {
"properties": {
@@ -3655,22 +3498,21 @@
"Resource": {
"description": "A known resource that the server is capable of reading.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"mimeType": {
"type": [
"string",
@@ -3703,74 +3545,10 @@
],
"type": "object"
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"ResourceTemplate": {
"description": "A template description for resources available on the server.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"annotations": true,
"description": {
"type": [
"string",
@@ -3825,6 +3603,16 @@
],
"writeOnly": true
},
"phase": {
"anyOf": [
{
"$ref": "#/definitions/MessagePhase"
},
{
"type": "null"
}
]
},
"role": {
"type": "string"
},
@@ -4361,14 +4149,6 @@
}
]
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SandboxPolicy": {
"description": "Determines execution restrictions for model shell commands.",
"oneOf": [
@@ -4678,32 +4458,6 @@
],
"type": "string"
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byte_range": {
@@ -4727,27 +4481,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -4808,38 +4541,26 @@
"Tool": {
"description": "Definition for a tool the client can call.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/ToolAnnotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"inputSchema": {
"$ref": "#/definitions/ToolInputSchema"
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"inputSchema": true,
"name": {
"type": "string"
},
"outputSchema": {
"anyOf": [
{
"$ref": "#/definitions/ToolOutputSchema"
},
{
"type": "null"
}
]
},
"outputSchema": true,
"title": {
"type": [
"string",
@@ -4853,82 +4574,6 @@
],
"type": "object"
},
"ToolAnnotations": {
"description": "Additional properties describing a Tool to clients.\n\nNOTE: all properties in ToolAnnotations are **hints**. They are not guaranteed to provide a faithful description of tool behavior (including descriptive properties like `title`).\n\nClients should never make tool use decisions based on ToolAnnotations received from untrusted servers.",
"properties": {
"destructiveHint": {
"type": [
"boolean",
"null"
]
},
"idempotentHint": {
"type": [
"boolean",
"null"
]
},
"openWorldHint": {
"type": [
"boolean",
"null"
]
},
"readOnlyHint": {
"type": [
"boolean",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"ToolInputSchema": {
"description": "A JSON Schema object defining the expected parameters for the tool.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
},
"ToolOutputSchema": {
"description": "An optional JSON Schema object defining the structure of the tool's output returned in the structuredContent field of a CallToolResult.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
},
"TurnAbortReason": {
"enum": [
"interrupted",

View File

@@ -93,34 +93,6 @@
}
]
},
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AskForApproval": {
"description": "Determines the conditions under which the user is consulted to approve running the command proposed by Codex.",
"oneOf": [
@@ -154,57 +126,6 @@
}
]
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -229,10 +150,9 @@
"CallToolResult": {
"description": "The server's response to a tool call.",
"properties": {
"_meta": true,
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"isError": {
@@ -390,25 +310,6 @@
}
]
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"ContentItem": {
"oneOf": [
{
@@ -544,42 +445,6 @@
],
"type": "object"
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"EventMsg": {
"description": "Response event from the agent NOTE: Make sure none of these values have optional types, as it will mess up the extension code-gen.",
"oneOf": [
@@ -3071,36 +2936,6 @@
],
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"LocalShellAction": {
"oneOf": [
{
@@ -3276,6 +3111,13 @@
}
]
},
"MessagePhase": {
"enum": [
"commentary",
"final_answer"
],
"type": "string"
},
"ModeKind": {
"description": "Initial collaboration mode to use when the TUI starts.",
"enum": [
@@ -3599,7 +3441,8 @@
"format": "int64",
"type": "integer"
}
]
],
"description": "ID of a request, which can be either a string or an integer."
},
"RequestUserInputQuestion": {
"properties": {
@@ -3655,22 +3498,21 @@
"Resource": {
"description": "A known resource that the server is capable of reading.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"mimeType": {
"type": [
"string",
@@ -3703,74 +3545,10 @@
],
"type": "object"
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"ResourceTemplate": {
"description": "A template description for resources available on the server.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"annotations": true,
"description": {
"type": [
"string",
@@ -3825,6 +3603,16 @@
],
"writeOnly": true
},
"phase": {
"anyOf": [
{
"$ref": "#/definitions/MessagePhase"
},
{
"type": "null"
}
]
},
"role": {
"type": "string"
},
@@ -4361,14 +4149,6 @@
}
]
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SandboxPolicy": {
"description": "Determines execution restrictions for model shell commands.",
"oneOf": [
@@ -4678,32 +4458,6 @@
],
"type": "string"
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byte_range": {
@@ -4727,27 +4481,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"ThreadId": {
"type": "string"
},
@@ -4808,38 +4541,26 @@
"Tool": {
"description": "Definition for a tool the client can call.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/ToolAnnotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"inputSchema": {
"$ref": "#/definitions/ToolInputSchema"
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"inputSchema": true,
"name": {
"type": "string"
},
"outputSchema": {
"anyOf": [
{
"$ref": "#/definitions/ToolOutputSchema"
},
{
"type": "null"
}
]
},
"outputSchema": true,
"title": {
"type": [
"string",
@@ -4853,82 +4574,6 @@
],
"type": "object"
},
"ToolAnnotations": {
"description": "Additional properties describing a Tool to clients.\n\nNOTE: all properties in ToolAnnotations are **hints**. They are not guaranteed to provide a faithful description of tool behavior (including descriptive properties like `title`).\n\nClients should never make tool use decisions based on ToolAnnotations received from untrusted servers.",
"properties": {
"destructiveHint": {
"type": [
"boolean",
"null"
]
},
"idempotentHint": {
"type": [
"boolean",
"null"
]
},
"openWorldHint": {
"type": [
"boolean",
"null"
]
},
"readOnlyHint": {
"type": [
"boolean",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"ToolInputSchema": {
"description": "A JSON Schema object defining the expected parameters for the tool.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
},
"ToolOutputSchema": {
"description": "An optional JSON Schema object defining the structure of the tool's output returned in the structuredContent field of a CallToolResult.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
},
"TurnAbortReason": {
"enum": [
"interrupted",

View File

@@ -1,85 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -263,61 +184,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -337,36 +203,6 @@
],
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -381,9 +217,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -468,95 +302,6 @@
}
]
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -580,27 +325,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"ThreadItem": {
"oneOf": [
{

View File

@@ -1,85 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -263,61 +184,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -337,36 +203,6 @@
],
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -381,9 +217,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -468,95 +302,6 @@
}
]
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -580,27 +325,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"ThreadItem": {
"oneOf": [
{

View File

@@ -1,34 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"McpAuthStatus": {
"enum": [
"unsupported",
@@ -77,22 +49,21 @@
"Resource": {
"description": "A known resource that the server is capable of reading.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"mimeType": {
"type": [
"string",
@@ -128,16 +99,7 @@
"ResourceTemplate": {
"description": "A template description for resources available on the server.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"annotations": true,
"description": {
"type": [
"string",
@@ -169,49 +131,29 @@
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"Tool": {
"description": "Definition for a tool the client can call.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/ToolAnnotations"
},
{
"type": "null"
}
]
},
"_meta": true,
"annotations": true,
"description": {
"type": [
"string",
"null"
]
},
"inputSchema": {
"$ref": "#/definitions/ToolInputSchema"
"icons": {
"items": true,
"type": [
"array",
"null"
]
},
"inputSchema": true,
"name": {
"type": "string"
},
"outputSchema": {
"anyOf": [
{
"$ref": "#/definitions/ToolOutputSchema"
},
{
"type": "null"
}
]
},
"outputSchema": true,
"title": {
"type": [
"string",
@@ -224,82 +166,6 @@
"name"
],
"type": "object"
},
"ToolAnnotations": {
"description": "Additional properties describing a Tool to clients.\n\nNOTE: all properties in ToolAnnotations are **hints**. They are not guaranteed to provide a faithful description of tool behavior (including descriptive properties like `title`).\n\nClients should never make tool use decisions based on ToolAnnotations received from untrusted servers.",
"properties": {
"destructiveHint": {
"type": [
"boolean",
"null"
]
},
"idempotentHint": {
"type": [
"boolean",
"null"
]
},
"openWorldHint": {
"type": [
"boolean",
"null"
]
},
"readOnlyHint": {
"type": [
"boolean",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
}
},
"type": "object"
},
"ToolInputSchema": {
"description": "A JSON Schema object defining the expected parameters for the tool.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
},
"ToolOutputSchema": {
"description": "An optional JSON Schema object defining the structure of the tool's output returned in the structuredContent field of a CallToolResult.",
"properties": {
"properties": true,
"required": {
"items": {
"type": "string"
},
"type": [
"array",
"null"
]
},
"type": {
"default": "object",
"type": "string"
}
},
"type": "object"
}
},
"properties": {

View File

@@ -1,6 +1,25 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"InputModality": {
"description": "Canonical user-input modality tags advertised by a model.",
"oneOf": [
{
"description": "Plain text turns and tool payloads.",
"enum": [
"text"
],
"type": "string"
},
{
"description": "Image attachments included in user turns.",
"enum": [
"image"
],
"type": "string"
}
]
},
"Model": {
"properties": {
"defaultReasoningEffort": {
@@ -15,6 +34,16 @@
"id": {
"type": "string"
},
"inputModalities": {
"default": [
"text",
"image"
],
"items": {
"$ref": "#/definitions/InputModality"
},
"type": "array"
},
"isDefault": {
"type": "boolean"
},

View File

@@ -233,6 +233,13 @@
],
"type": "string"
},
"MessagePhase": {
"enum": [
"commentary",
"final_answer"
],
"type": "string"
},
"ReasoningItemContent": {
"oneOf": [
{
@@ -324,6 +331,16 @@
],
"writeOnly": true
},
"phase": {
"anyOf": [
{
"$ref": "#/definitions/MessagePhase"
},
{
"type": "null"
}
]
},
"role": {
"type": "string"
},

View File

@@ -1,85 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -405,61 +326,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -479,36 +345,6 @@
],
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -523,9 +359,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -610,95 +444,6 @@
}
]
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -722,27 +467,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"ThreadItem": {
"oneOf": [
{

View File

@@ -5,34 +5,6 @@
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
"type": "string"
},
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AskForApproval": {
"enum": [
"untrusted",
@@ -42,57 +14,6 @@
],
"type": "string"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -418,61 +339,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -515,36 +381,6 @@
},
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -559,9 +395,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -665,69 +499,6 @@
],
"type": "string"
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SandboxPolicy": {
"oneOf": [
{
@@ -900,32 +671,6 @@
}
]
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -949,27 +694,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"Thread": {
"properties": {
"cliVersion": {

View File

@@ -1,85 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -405,61 +326,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -502,36 +368,6 @@
},
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -546,9 +382,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -633,69 +467,6 @@
}
]
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SessionSource": {
"oneOf": [
{
@@ -773,32 +544,6 @@
}
]
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -822,27 +567,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"Thread": {
"properties": {
"cliVersion": {

View File

@@ -1,85 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -405,61 +326,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -502,36 +368,6 @@
},
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -546,9 +382,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -633,69 +467,6 @@
}
]
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SessionSource": {
"oneOf": [
{
@@ -773,32 +544,6 @@
}
]
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -822,27 +567,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"Thread": {
"properties": {
"cliVersion": {

View File

@@ -242,6 +242,13 @@
],
"type": "string"
},
"MessagePhase": {
"enum": [
"commentary",
"final_answer"
],
"type": "string"
},
"Personality": {
"enum": [
"friendly",
@@ -340,6 +347,16 @@
],
"writeOnly": true
},
"phase": {
"anyOf": [
{
"$ref": "#/definitions/MessagePhase"
},
{
"type": "null"
}
]
},
"role": {
"type": "string"
},

View File

@@ -5,34 +5,6 @@
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
"type": "string"
},
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AskForApproval": {
"enum": [
"untrusted",
@@ -42,57 +14,6 @@
],
"type": "string"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -418,61 +339,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -515,36 +381,6 @@
},
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -559,9 +395,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -665,69 +499,6 @@
],
"type": "string"
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SandboxPolicy": {
"oneOf": [
{
@@ -900,32 +671,6 @@
}
]
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -949,27 +694,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"Thread": {
"properties": {
"cliVersion": {

View File

@@ -1,85 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -405,61 +326,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -502,36 +368,6 @@
},
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -546,9 +382,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -633,69 +467,6 @@
}
]
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SessionSource": {
"oneOf": [
{
@@ -773,32 +544,6 @@
}
]
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -822,27 +567,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"Thread": {
"properties": {
"cliVersion": {

View File

@@ -5,34 +5,6 @@
"description": "A path that is guaranteed to be absolute and normalized (though it is not guaranteed to be canonicalized or exist on the filesystem).\n\nIMPORTANT: When deserializing an `AbsolutePathBuf`, a base path must be set using [AbsolutePathBufGuard::new]. If no base path is set, the deserialization will fail unless the path being deserialized is already absolute.",
"type": "string"
},
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AskForApproval": {
"enum": [
"untrusted",
@@ -42,57 +14,6 @@
],
"type": "string"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -418,61 +339,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -515,36 +381,6 @@
},
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -559,9 +395,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -665,69 +499,6 @@
],
"type": "string"
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SandboxPolicy": {
"oneOf": [
{
@@ -900,32 +671,6 @@
}
]
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -949,27 +694,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"Thread": {
"properties": {
"cliVersion": {

View File

@@ -1,85 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -405,61 +326,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -502,36 +368,6 @@
},
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -546,9 +382,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -633,69 +467,6 @@
}
]
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SessionSource": {
"oneOf": [
{
@@ -773,32 +544,6 @@
}
]
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -822,27 +567,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"Thread": {
"properties": {
"cliVersion": {

View File

@@ -1,85 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -405,61 +326,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -502,36 +368,6 @@
},
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -546,9 +382,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -633,69 +467,6 @@
}
]
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"SessionSource": {
"oneOf": [
{
@@ -773,32 +544,6 @@
}
]
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -822,27 +567,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"Thread": {
"properties": {
"cliVersion": {

View File

@@ -1,85 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -405,61 +326,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -479,36 +345,6 @@
],
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -523,9 +359,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -610,95 +444,6 @@
}
]
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -722,27 +467,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"ThreadItem": {
"oneOf": [
{

View File

@@ -1,85 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -405,61 +326,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -479,36 +345,6 @@
],
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -523,9 +359,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -610,95 +444,6 @@
}
]
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -722,27 +467,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"ThreadItem": {
"oneOf": [
{

View File

@@ -1,85 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Annotations": {
"description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed",
"properties": {
"audience": {
"items": {
"$ref": "#/definitions/Role"
},
"type": [
"array",
"null"
]
},
"lastModified": {
"type": [
"string",
"null"
]
},
"priority": {
"format": "double",
"type": [
"number",
"null"
]
}
},
"type": "object"
},
"AudioContent": {
"description": "Audio provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"BlobResourceContents": {
"properties": {
"blob": {
"type": "string"
},
"mimeType": {
"type": [
"string",
"null"
]
},
"uri": {
"type": "string"
}
},
"required": [
"blob",
"uri"
],
"type": "object"
},
"ByteRange": {
"properties": {
"end": {
@@ -405,61 +326,6 @@
],
"type": "string"
},
"ContentBlock": {
"anyOf": [
{
"$ref": "#/definitions/TextContent"
},
{
"$ref": "#/definitions/ImageContent"
},
{
"$ref": "#/definitions/AudioContent"
},
{
"$ref": "#/definitions/ResourceLink"
},
{
"$ref": "#/definitions/EmbeddedResource"
}
]
},
"EmbeddedResource": {
"description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit of the LLM and/or the user.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"resource": {
"$ref": "#/definitions/EmbeddedResourceResource"
},
"type": {
"type": "string"
}
},
"required": [
"resource",
"type"
],
"type": "object"
},
"EmbeddedResourceResource": {
"anyOf": [
{
"$ref": "#/definitions/TextResourceContents"
},
{
"$ref": "#/definitions/BlobResourceContents"
}
]
},
"FileUpdateChange": {
"properties": {
"diff": {
@@ -479,36 +345,6 @@
],
"type": "object"
},
"ImageContent": {
"description": "An image provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"data": {
"type": "string"
},
"mimeType": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"data",
"mimeType",
"type"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -523,9 +359,7 @@
"McpToolCallResult": {
"properties": {
"content": {
"items": {
"$ref": "#/definitions/ContentBlock"
},
"items": true,
"type": "array"
},
"structuredContent": true
@@ -610,95 +444,6 @@
}
]
},
"ResourceLink": {
"description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"description": {
"type": [
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"name": {
"type": "string"
},
"size": {
"format": "int64",
"type": [
"integer",
"null"
]
},
"title": {
"type": [
"string",
"null"
]
},
"type": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"name",
"type",
"uri"
],
"type": "object"
},
"Role": {
"description": "The sender or recipient of messages and data in a conversation.",
"enum": [
"assistant",
"user"
],
"type": "string"
},
"TextContent": {
"description": "Text provided to or from an LLM.",
"properties": {
"annotations": {
"anyOf": [
{
"$ref": "#/definitions/Annotations"
},
{
"type": "null"
}
]
},
"text": {
"type": "string"
},
"type": {
"type": "string"
}
},
"required": [
"text",
"type"
],
"type": "object"
},
"TextElement": {
"properties": {
"byteRange": {
@@ -722,27 +467,6 @@
],
"type": "object"
},
"TextResourceContents": {
"properties": {
"mimeType": {
"type": [
"string",
"null"
]
},
"text": {
"type": "string"
},
"uri": {
"type": "string"
}
},
"required": [
"text",
"uri"
],
"type": "object"
},
"ThreadItem": {
"oneOf": [
{

View File

@@ -1,9 +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 { Role } from "./Role";
/**
* Optional annotations for the client. The client can use annotations to inform how objects are used or displayed
*/
export type Annotations = { audience?: Array<Role>, lastModified?: string, priority?: number, };

View File

@@ -1,9 +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 { Annotations } from "./Annotations";
/**
* Audio provided to or from an LLM.
*/
export type AudioContent = { annotations?: Annotations, data: string, mimeType: string, type: string, };

View File

@@ -1,5 +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.
export type BlobResourceContents = { blob: string, mimeType?: string, uri: string, };

View File

@@ -1,10 +1,9 @@
// 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 { ContentBlock } from "./ContentBlock";
import type { JsonValue } from "./serde_json/JsonValue";
/**
* The server's response to a tool call.
*/
export type CallToolResult = { content: Array<ContentBlock>, isError?: boolean, structuredContent?: JsonValue, };
export type CallToolResult = { content: Array<JsonValue>, structuredContent?: JsonValue, isError?: boolean, _meta?: JsonValue, };

View File

@@ -1,10 +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 { AudioContent } from "./AudioContent";
import type { EmbeddedResource } from "./EmbeddedResource";
import type { ImageContent } from "./ImageContent";
import type { ResourceLink } from "./ResourceLink";
import type { TextContent } from "./TextContent";
export type ContentBlock = TextContent | ImageContent | AudioContent | ResourceLink | EmbeddedResource;

View File

@@ -1,6 +1,5 @@
// 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 { RequestId } from "./RequestId";
export type ElicitationRequestEvent = { server_name: string, id: RequestId, message: string, };
export type ElicitationRequestEvent = { server_name: string, id: string | number, message: string, };

View File

@@ -1,13 +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 { Annotations } from "./Annotations";
import type { EmbeddedResourceResource } from "./EmbeddedResourceResource";
/**
* The contents of a resource, embedded into a prompt or tool call result.
*
* It is up to the client how best to render embedded resources for the benefit
* of the LLM and/or the user.
*/
export type EmbeddedResource = { annotations?: Annotations, resource: EmbeddedResourceResource, type: string, };

View File

@@ -1,7 +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 { BlobResourceContents } from "./BlobResourceContents";
import type { TextResourceContents } from "./TextResourceContents";
export type EmbeddedResourceResource = TextResourceContents | BlobResourceContents;

View File

@@ -1,9 +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 { Annotations } from "./Annotations";
/**
* An image provided to or from an LLM.
*/
export type ImageContent = { annotations?: Annotations, data: string, mimeType: string, type: string, };

View File

@@ -3,6 +3,6 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
/**
* The sender or recipient of messages and data in a conversation.
* Canonical user-input modality tags advertised by a model.
*/
export type Role = "assistant" | "user";
export type InputModality = "text" | "image";

View File

@@ -2,4 +2,4 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type TextResourceContents = { mimeType?: string, text: string, uri: string, };
export type MessagePhase = "commentary" | "final_answer";

View File

@@ -1,9 +1,9 @@
// 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 { Annotations } from "./Annotations";
import type { JsonValue } from "./serde_json/JsonValue";
/**
* A known resource that the server is capable of reading.
*/
export type Resource = { annotations?: Annotations, description?: string, mimeType?: string, name: string, size?: bigint, title?: string, uri: string, };
export type Resource = { annotations?: JsonValue, description?: string, mimeType?: string, name: string, size?: number, title?: string, uri: string, icons?: Array<JsonValue>, _meta?: JsonValue, };

View File

@@ -1,11 +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 { Annotations } from "./Annotations";
/**
* A resource that the server is capable of reading, included in a prompt or tool call result.
*
* Note: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.
*/
export type ResourceLink = { annotations?: Annotations, description?: string, mimeType?: string, name: string, size?: bigint, title?: string, type: string, uri: string, };

View File

@@ -1,9 +1,9 @@
// 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 { Annotations } from "./Annotations";
import type { JsonValue } from "./serde_json/JsonValue";
/**
* A template description for resources available on the server.
*/
export type ResourceTemplate = { annotations?: Annotations, description?: string, mimeType?: string, name: string, title?: string, uriTemplate: string, };
export type ResourceTemplate = { annotations?: JsonValue, uriTemplate: string, name: string, title?: string, description?: string, mimeType?: string, };

View File

@@ -6,11 +6,12 @@ import type { FunctionCallOutputPayload } from "./FunctionCallOutputPayload";
import type { GhostCommit } from "./GhostCommit";
import type { LocalShellAction } from "./LocalShellAction";
import type { LocalShellStatus } from "./LocalShellStatus";
import type { MessagePhase } from "./MessagePhase";
import type { ReasoningItemContent } from "./ReasoningItemContent";
import type { ReasoningItemReasoningSummary } from "./ReasoningItemReasoningSummary";
import type { WebSearchAction } from "./WebSearchAction";
export type ResponseItem = { "type": "message", role: string, content: Array<ContentItem>, end_turn?: boolean, } | { "type": "reasoning", summary: Array<ReasoningItemReasoningSummary>, content?: Array<ReasoningItemContent>, encrypted_content: string | null, } | { "type": "local_shell_call",
export type ResponseItem = { "type": "message", role: string, content: Array<ContentItem>, end_turn?: boolean, phase?: MessagePhase, } | { "type": "reasoning", summary: Array<ReasoningItemReasoningSummary>, content?: Array<ReasoningItemContent>, encrypted_content: string | null, } | { "type": "local_shell_call",
/**
* Set when using the Responses API.
*/

View File

@@ -1,9 +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 { Annotations } from "./Annotations";
/**
* Text provided to or from an LLM.
*/
export type TextContent = { annotations?: Annotations, text: string, type: string, };

View File

@@ -1,11 +1,9 @@
// 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 { ToolAnnotations } from "./ToolAnnotations";
import type { ToolInputSchema } from "./ToolInputSchema";
import type { ToolOutputSchema } from "./ToolOutputSchema";
import type { JsonValue } from "./serde_json/JsonValue";
/**
* Definition for a tool the client can call.
*/
export type Tool = { annotations?: ToolAnnotations, description?: string, inputSchema: ToolInputSchema, name: string, outputSchema?: ToolOutputSchema, title?: string, };
export type Tool = { name: string, title?: string, description?: string, inputSchema: JsonValue, outputSchema?: JsonValue, annotations?: JsonValue, icons?: Array<JsonValue>, _meta?: JsonValue, };

View File

@@ -1,15 +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.
/**
* Additional properties describing a Tool to clients.
*
* NOTE: all properties in ToolAnnotations are **hints**.
* They are not guaranteed to provide a faithful description of
* tool behavior (including descriptive properties like `title`).
*
* Clients should never make tool use decisions based on ToolAnnotations
* received from untrusted servers.
*/
export type ToolAnnotations = { destructiveHint?: boolean, idempotentHint?: boolean, openWorldHint?: boolean, readOnlyHint?: boolean, title?: string, };

View File

@@ -1,9 +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 { JsonValue } from "./serde_json/JsonValue";
/**
* A JSON Schema object defining the expected parameters for the tool.
*/
export type ToolInputSchema = { properties?: JsonValue, required?: Array<string>, type: string, };

View File

@@ -1,10 +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 { JsonValue } from "./serde_json/JsonValue";
/**
* An optional JSON Schema object defining the structure of the tool's output returned in
* the structuredContent field of a CallToolResult.
*/
export type ToolOutputSchema = { properties?: JsonValue, required?: Array<string>, type: string, };

View File

@@ -14,18 +14,15 @@ export type { AgentReasoningRawContentDeltaEvent } from "./AgentReasoningRawCont
export type { AgentReasoningRawContentEvent } from "./AgentReasoningRawContentEvent";
export type { AgentReasoningSectionBreakEvent } from "./AgentReasoningSectionBreakEvent";
export type { AgentStatus } from "./AgentStatus";
export type { Annotations } from "./Annotations";
export type { ApplyPatchApprovalParams } from "./ApplyPatchApprovalParams";
export type { ApplyPatchApprovalRequestEvent } from "./ApplyPatchApprovalRequestEvent";
export type { ApplyPatchApprovalResponse } from "./ApplyPatchApprovalResponse";
export type { ArchiveConversationParams } from "./ArchiveConversationParams";
export type { ArchiveConversationResponse } from "./ArchiveConversationResponse";
export type { AskForApproval } from "./AskForApproval";
export type { AudioContent } from "./AudioContent";
export type { AuthMode } from "./AuthMode";
export type { AuthStatusChangeNotification } from "./AuthStatusChangeNotification";
export type { BackgroundEventEvent } from "./BackgroundEventEvent";
export type { BlobResourceContents } from "./BlobResourceContents";
export type { ByteRange } from "./ByteRange";
export type { CallToolResult } from "./CallToolResult";
export type { CancelLoginChatGptParams } from "./CancelLoginChatGptParams";
@@ -44,7 +41,6 @@ export type { CollabWaitingBeginEvent } from "./CollabWaitingBeginEvent";
export type { CollabWaitingEndEvent } from "./CollabWaitingEndEvent";
export type { CollaborationMode } from "./CollaborationMode";
export type { CollaborationModeMask } from "./CollaborationModeMask";
export type { ContentBlock } from "./ContentBlock";
export type { ContentItem } from "./ContentItem";
export type { ContextCompactedEvent } from "./ContextCompactedEvent";
export type { ContextCompactionItem } from "./ContextCompactionItem";
@@ -55,8 +51,6 @@ export type { CustomPrompt } from "./CustomPrompt";
export type { DeprecationNoticeEvent } from "./DeprecationNoticeEvent";
export type { DynamicToolCallRequest } from "./DynamicToolCallRequest";
export type { ElicitationRequestEvent } from "./ElicitationRequestEvent";
export type { EmbeddedResource } from "./EmbeddedResource";
export type { EmbeddedResourceResource } from "./EmbeddedResourceResource";
export type { ErrorEvent } from "./ErrorEvent";
export type { EventMsg } from "./EventMsg";
export type { ExecApprovalRequestEvent } from "./ExecApprovalRequestEvent";
@@ -92,11 +86,11 @@ export type { GitDiffToRemoteParams } from "./GitDiffToRemoteParams";
export type { GitDiffToRemoteResponse } from "./GitDiffToRemoteResponse";
export type { GitSha } from "./GitSha";
export type { HistoryEntry } from "./HistoryEntry";
export type { ImageContent } from "./ImageContent";
export type { InitializeCapabilities } from "./InitializeCapabilities";
export type { InitializeParams } from "./InitializeParams";
export type { InitializeResponse } from "./InitializeResponse";
export type { InputItem } from "./InputItem";
export type { InputModality } from "./InputModality";
export type { InterruptConversationParams } from "./InterruptConversationParams";
export type { InterruptConversationResponse } from "./InterruptConversationResponse";
export type { ItemCompletedEvent } from "./ItemCompletedEvent";
@@ -122,6 +116,7 @@ export type { McpStartupStatus } from "./McpStartupStatus";
export type { McpStartupUpdateEvent } from "./McpStartupUpdateEvent";
export type { McpToolCallBeginEvent } from "./McpToolCallBeginEvent";
export type { McpToolCallEndEvent } from "./McpToolCallEndEvent";
export type { MessagePhase } from "./MessagePhase";
export type { ModeKind } from "./ModeKind";
export type { NetworkAccess } from "./NetworkAccess";
export type { NewConversationParams } from "./NewConversationParams";
@@ -152,7 +147,6 @@ export type { RequestUserInputEvent } from "./RequestUserInputEvent";
export type { RequestUserInputQuestion } from "./RequestUserInputQuestion";
export type { RequestUserInputQuestionOption } from "./RequestUserInputQuestionOption";
export type { Resource } from "./Resource";
export type { ResourceLink } from "./ResourceLink";
export type { ResourceTemplate } from "./ResourceTemplate";
export type { ResponseItem } from "./ResponseItem";
export type { ResumeConversationParams } from "./ResumeConversationParams";
@@ -164,7 +158,6 @@ export type { ReviewLineRange } from "./ReviewLineRange";
export type { ReviewOutputEvent } from "./ReviewOutputEvent";
export type { ReviewRequest } from "./ReviewRequest";
export type { ReviewTarget } from "./ReviewTarget";
export type { Role } from "./Role";
export type { SandboxMode } from "./SandboxMode";
export type { SandboxPolicy } from "./SandboxPolicy";
export type { SandboxSettings } from "./SandboxSettings";
@@ -191,9 +184,7 @@ export type { StepStatus } from "./StepStatus";
export type { StreamErrorEvent } from "./StreamErrorEvent";
export type { SubAgentSource } from "./SubAgentSource";
export type { TerminalInteractionEvent } from "./TerminalInteractionEvent";
export type { TextContent } from "./TextContent";
export type { TextElement } from "./TextElement";
export type { TextResourceContents } from "./TextResourceContents";
export type { ThreadId } from "./ThreadId";
export type { ThreadNameUpdatedEvent } from "./ThreadNameUpdatedEvent";
export type { ThreadRolledBackEvent } from "./ThreadRolledBackEvent";
@@ -201,9 +192,6 @@ export type { TokenCountEvent } from "./TokenCountEvent";
export type { TokenUsage } from "./TokenUsage";
export type { TokenUsageInfo } from "./TokenUsageInfo";
export type { Tool } from "./Tool";
export type { ToolAnnotations } from "./ToolAnnotations";
export type { ToolInputSchema } from "./ToolInputSchema";
export type { ToolOutputSchema } from "./ToolOutputSchema";
export type { Tools } from "./Tools";
export type { TurnAbortReason } from "./TurnAbortReason";
export type { TurnAbortedEvent } from "./TurnAbortedEvent";

View File

@@ -1,7 +1,6 @@
// 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 { ContentBlock } from "../ContentBlock";
import type { JsonValue } from "../serde_json/JsonValue";
export type McpToolCallResult = { content: Array<ContentBlock>, structuredContent: JsonValue | null, };
export type McpToolCallResult = { content: Array<JsonValue>, structuredContent: JsonValue | null, };

View File

@@ -1,7 +1,8 @@
// 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 { InputModality } from "../InputModality";
import type { ReasoningEffort } from "../ReasoningEffort";
import type { ReasoningEffortOption } from "./ReasoningEffortOption";
export type Model = { id: string, model: string, displayName: string, description: string, supportedReasoningEfforts: Array<ReasoningEffortOption>, defaultReasoningEffort: ReasoningEffort, supportsPersonality: boolean, isDefault: boolean, };
export type Model = { id: string, model: string, displayName: string, description: string, supportedReasoningEfforts: Array<ReasoningEffortOption>, defaultReasoningEffort: ReasoningEffort, inputModalities: Array<InputModality>, supportsPersonality: boolean, isDefault: boolean, };

View File

@@ -15,8 +15,13 @@ use codex_protocol::config_types::Verbosity;
use codex_protocol::config_types::WebSearchMode;
use codex_protocol::items::AgentMessageContent as CoreAgentMessageContent;
use codex_protocol::items::TurnItem as CoreTurnItem;
use codex_protocol::mcp::Resource as McpResource;
use codex_protocol::mcp::ResourceTemplate as McpResourceTemplate;
use codex_protocol::mcp::Tool as McpTool;
use codex_protocol::models::ResponseItem;
use codex_protocol::openai_models::InputModality;
use codex_protocol::openai_models::ReasoningEffort;
use codex_protocol::openai_models::default_input_modalities;
use codex_protocol::parse_command::ParsedCommand as CoreParsedCommand;
use codex_protocol::plan_tool::PlanItemArg as CorePlanItemArg;
use codex_protocol::plan_tool::StepStatus as CorePlanStepStatus;
@@ -41,10 +46,6 @@ use codex_protocol::user_input::ByteRange as CoreByteRange;
use codex_protocol::user_input::TextElement as CoreTextElement;
use codex_protocol::user_input::UserInput as CoreUserInput;
use codex_utils_absolute_path::AbsolutePathBuf;
use mcp_types::ContentBlock as McpContentBlock;
use mcp_types::Resource as McpResource;
use mcp_types::ResourceTemplate as McpResourceTemplate;
use mcp_types::Tool as McpTool;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
@@ -993,6 +994,8 @@ pub struct Model {
pub description: String,
pub supported_reasoning_efforts: Vec<ReasoningEffortOption>,
pub default_reasoning_effort: ReasoningEffort,
#[serde(default = "default_input_modalities")]
pub input_modalities: Vec<InputModality>,
#[serde(default)]
pub supports_personality: bool,
// Only one model should be marked as default.
@@ -2360,7 +2363,12 @@ impl From<CoreAgentStatus> for CollabAgentState {
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct McpToolCallResult {
pub content: Vec<McpContentBlock>,
// NOTE: `rmcp::model::Content` (and its `RawContent` variants) would be a more precise Rust
// representation of MCP content blocks. We intentionally use `serde_json::Value` here because
// this crate exports JSON schema + TS types (`schemars`/`ts-rs`), and the rmcp model types
// aren't set up to be schema/TS friendly (and would introduce heavier coupling to rmcp's Rust
// representations). Using `JsonValue` keeps the payload wire-shaped and easy to export.
pub content: Vec<JsonValue>,
pub structured_content: Option<JsonValue>,
}

View File

@@ -2,6 +2,7 @@ use anyhow::Context;
use anyhow::Result;
use serde_json::Map;
use serde_json::Value;
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::path::Path;
use std::path::PathBuf;
@@ -92,7 +93,49 @@ fn read_file_bytes(path: &Path) -> Result<Vec<u8>> {
fn canonicalize_json(value: &Value) -> Value {
match value {
Value::Array(items) => Value::Array(items.iter().map(canonicalize_json).collect()),
Value::Array(items) => {
// NOTE: We sort some JSON arrays to make schema fixture comparisons stable across
// platforms.
//
// In general, JSON array ordering is significant. However, this code path is used
// only by `schema_fixtures_match_generated` to compare our *vendored* JSON schema
// files against freshly generated output. Some parts of schema generation end up
// with non-deterministic ordering across platforms (often due to map iteration order
// upstream), which can cause Windows CI failures even when the generated schema is
// semantically equivalent.
//
// JSON Schema itself also contains a number of array-valued keywords whose ordering
// does not affect validation semantics (e.g. `required`, `type`, `enum`, `anyOf`,
// `oneOf`, `allOf`). That makes it reasonable to treat many schema-emitted arrays as
// order-insensitive for the purpose of fixture diffs.
//
// To avoid accidentally changing the meaning of arrays where order *could* matter
// (e.g. tuple validation / `prefixItems`-style arrays), we only sort arrays when we
// can derive a stable sort key for *every* element. If we cannot, we preserve the
// original ordering.
let items = items.iter().map(canonicalize_json).collect::<Vec<_>>();
let mut sortable = Vec::with_capacity(items.len());
for item in &items {
let Some(key) = schema_array_item_sort_key(item) else {
return Value::Array(items);
};
let stable = serde_json::to_string(item).unwrap_or_default();
sortable.push((key, stable));
}
let mut items = items.into_iter().zip(sortable).collect::<Vec<_>>();
items.sort_by(
|(_, (key_left, stable_left)), (_, (key_right, stable_right))| match key_left
.cmp(key_right)
{
Ordering::Equal => stable_left.cmp(stable_right),
other => other,
},
);
Value::Array(items.into_iter().map(|(item, _)| item).collect())
}
Value::Object(map) => {
let mut entries: Vec<_> = map.iter().collect();
entries.sort_by(|(left, _), (right, _)| left.cmp(right));
@@ -106,6 +149,25 @@ fn canonicalize_json(value: &Value) -> Value {
}
}
fn schema_array_item_sort_key(item: &Value) -> Option<String> {
match item {
Value::Null => Some("null".to_string()),
Value::Bool(b) => Some(format!("b:{b}")),
Value::Number(n) => Some(format!("n:{n}")),
Value::String(s) => Some(format!("s:{s}")),
Value::Object(map) => {
if let Some(Value::String(reference)) = map.get("$ref") {
Some(format!("ref:{reference}"))
} else if let Some(Value::String(title)) = map.get("title") {
Some(format!("title:{title}"))
} else {
None
}
}
Value::Array(_) => None,
}
}
fn collect_files_recursive(root: &Path) -> Result<BTreeMap<PathBuf, Vec<u8>>> {
let mut files = BTreeMap::new();
@@ -146,3 +208,29 @@ fn collect_files_recursive(root: &Path) -> Result<BTreeMap<PathBuf, Vec<u8>>> {
Ok(files)
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn canonicalize_json_sorts_string_arrays() {
let value = serde_json::json!(["b", "a"]);
let expected = serde_json::json!(["a", "b"]);
assert_eq!(canonicalize_json(&value), expected);
}
#[test]
fn canonicalize_json_sorts_schema_ref_arrays() {
let value = serde_json::json!([
{"$ref": "#/definitions/B"},
{"$ref": "#/definitions/A"}
]);
let expected = serde_json::json!([
{"$ref": "#/definitions/A"},
{"$ref": "#/definitions/B"}
]);
assert_eq!(canonicalize_json(&value), expected);
}
}

View File

@@ -175,7 +175,6 @@ dependencies = [
"base64",
"icu_decimal",
"icu_locale_core",
"mcp-types",
"mime_guess",
"serde",
"serde_json",
@@ -521,16 +520,6 @@ version = "0.4.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
[[package]]
name = "mcp-types"
version = "0.45.0"
source = "git+https://github.com/openai/codex.git?tag=rust-v0.45.0#a7c7869c23f88f6c468281e6f438ba4a91b81f26"
dependencies = [
"serde",
"serde_json",
"ts-rs",
]
[[package]]
name = "memchr"
version = "2.7.6"

View File

@@ -35,7 +35,6 @@ codex-utils-json-to-toml = { workspace = true }
chrono = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
mcp-types = { workspace = true }
tempfile = { workspace = true }
time = { workspace = true }
toml = { workspace = true }
@@ -60,7 +59,6 @@ axum = { workspace = true, default-features = false, features = [
base64 = { workspace = true }
codex-execpolicy = { workspace = true }
core_test_support = { workspace = true }
mcp-types = { workspace = true }
os_info = { workspace = true }
pretty_assertions = { workspace = true }
rmcp = { workspace = true, default-features = false, features = [

View File

@@ -1841,12 +1841,11 @@ mod tests {
use codex_core::protocol::RateLimitWindow;
use codex_core::protocol::TokenUsage;
use codex_core::protocol::TokenUsageInfo;
use codex_protocol::mcp::CallToolResult;
use codex_protocol::plan_tool::PlanItemArg;
use codex_protocol::plan_tool::StepStatus;
use mcp_types::CallToolResult;
use mcp_types::ContentBlock;
use mcp_types::TextContent;
use pretty_assertions::assert_eq;
use rmcp::model::Content;
use serde_json::Value as JsonValue;
use std::collections::HashMap;
use std::time::Duration;
@@ -2374,15 +2373,15 @@ mod tests {
#[tokio::test]
async fn test_construct_mcp_tool_call_end_notification_success() {
let content = vec![ContentBlock::TextContent(TextContent {
annotations: None,
text: "{\"resources\":[]}".to_string(),
r#type: "text".to_string(),
})];
let content = vec![
serde_json::to_value(Content::text("{\"resources\":[]}"))
.expect("content should serialize"),
];
let result = CallToolResult {
content: content.clone(),
is_error: Some(false),
structured_content: None,
meta: None,
};
let end_event = McpToolCallEndEvent {

View File

@@ -28,6 +28,7 @@ fn model_from_preset(preset: ModelPreset) -> Model {
preset.supported_reasoning_efforts,
),
default_reasoning_effort: preset.default_reasoning_effort,
input_modalities: preset.input_modalities,
supports_personality: preset.supports_personality,
is_default: preset.is_default,
}

View File

@@ -6,6 +6,7 @@ use codex_protocol::openai_models::ModelInfo;
use codex_protocol::openai_models::ModelPreset;
use codex_protocol::openai_models::ModelVisibility;
use codex_protocol::openai_models::TruncationPolicyConfig;
use codex_protocol::openai_models::default_input_modalities;
use serde_json::json;
use std::path::Path;
@@ -38,6 +39,7 @@ fn preset_to_info(preset: &ModelPreset, priority: i32) -> ModelInfo {
auto_compact_token_limit: None,
effective_context_window_percent: 95,
experimental_supported_tools: Vec::new(),
input_modalities: default_input_modalities(),
}
}
@@ -75,9 +77,11 @@ pub fn write_models_cache_with_models(
let cache_path = codex_home.join("models_cache.json");
// DateTime<Utc> serializes to RFC3339 format by default with serde
let fetched_at: DateTime<Utc> = Utc::now();
let client_version = codex_core::models_manager::client_version_to_whole();
let cache = json!({
"fetched_at": fetched_at,
"etag": null,
"client_version": client_version,
"models": models
});
std::fs::write(cache_path, serde_json::to_string_pretty(&cache)?)

View File

@@ -308,6 +308,7 @@ async fn test_list_and_resume_conversations() -> Result<()> {
text: fork_history_text.to_string(),
}],
end_turn: None,
phase: None,
}];
let resume_with_history_req_id = mcp
.send_resume_conversation_request(ResumeConversationParams {

View File

@@ -126,6 +126,7 @@ async fn auto_compaction_remote_emits_started_and_completed_items() -> Result<()
text: "REMOTE_COMPACT_SUMMARY".to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Compaction {
encrypted_content: "ENCRYPTED_COMPACTION_SUMMARY".to_string(),

View File

@@ -12,6 +12,7 @@ use codex_app_server_protocol::ModelListParams;
use codex_app_server_protocol::ModelListResponse;
use codex_app_server_protocol::ReasoningEffortOption;
use codex_app_server_protocol::RequestId;
use codex_protocol::openai_models::InputModality;
use codex_protocol::openai_models::ReasoningEffort;
use pretty_assertions::assert_eq;
use tempfile::TempDir;
@@ -72,6 +73,7 @@ async fn list_models_returns_all_models_with_large_limit() -> Result<()> {
},
],
default_reasoning_effort: ReasoningEffort::Medium,
input_modalities: vec![InputModality::Text, InputModality::Image],
supports_personality: false,
is_default: true,
},
@@ -100,6 +102,7 @@ async fn list_models_returns_all_models_with_large_limit() -> Result<()> {
},
],
default_reasoning_effort: ReasoningEffort::Medium,
input_modalities: vec![InputModality::Text, InputModality::Image],
supports_personality: false,
is_default: false,
},
@@ -120,6 +123,7 @@ async fn list_models_returns_all_models_with_large_limit() -> Result<()> {
},
],
default_reasoning_effort: ReasoningEffort::Medium,
input_modalities: vec![InputModality::Text, InputModality::Image],
supports_personality: false,
is_default: false,
},
@@ -154,6 +158,7 @@ async fn list_models_returns_all_models_with_large_limit() -> Result<()> {
},
],
default_reasoning_effort: ReasoningEffort::Medium,
input_modalities: vec![InputModality::Text, InputModality::Image],
supports_personality: false,
is_default: false,
},

View File

@@ -338,6 +338,7 @@ async fn thread_resume_supports_history_and_overrides() -> Result<()> {
text: history_text.to_string(),
}],
end_turn: None,
phase: None,
}];
// Resume with explicit history and override the model.

View File

@@ -40,6 +40,7 @@ owo-colors = { workspace = true }
regex-lite = { workspace = true }
serde_json = { workspace = true }
supports-color = { workspace = true }
tempfile = { workspace = true }
tokio = { workspace = true, features = [
"io-std",
"macros",
@@ -59,4 +60,3 @@ assert_matches = { workspace = true }
codex-utils-cargo-bin = { workspace = true }
predicates = { workspace = true }
pretty_assertions = { workspace = true }
tempfile = { workspace = true }

View File

@@ -0,0 +1,21 @@
use clap::Parser;
use std::path::PathBuf;
const DEFAULT_CODEX_DMG_URL: &str = "https://persistent.oaistatic.com/codex-app-prod/Codex.dmg";
#[derive(Debug, Parser)]
pub struct AppCommand {
/// Workspace path to open in Codex Desktop.
#[arg(value_name = "PATH", default_value = ".")]
pub path: PathBuf,
/// Override the macOS DMG download URL (advanced).
#[arg(long, default_value = DEFAULT_CODEX_DMG_URL)]
pub download_url: String,
}
#[cfg(target_os = "macos")]
pub async fn run_app(cmd: AppCommand) -> anyhow::Result<()> {
let workspace = std::fs::canonicalize(&cmd.path).unwrap_or(cmd.path);
crate::desktop_app::run_app_open_or_install(workspace, cmd.download_url).await
}

View File

@@ -0,0 +1,281 @@
use anyhow::Context as _;
use std::path::Path;
use std::path::PathBuf;
use tempfile::Builder;
use tokio::process::Command;
pub async fn run_mac_app_open_or_install(
workspace: PathBuf,
download_url: String,
) -> anyhow::Result<()> {
if let Some(app_path) = find_existing_codex_app_path() {
eprintln!(
"Opening Codex Desktop at {app_path}...",
app_path = app_path.display()
);
open_codex_app(&app_path, &workspace).await?;
return Ok(());
}
eprintln!("Codex Desktop not found; downloading installer...");
let installed_app = download_and_install_codex_to_user_applications(&download_url)
.await
.context("failed to download/install Codex Desktop")?;
eprintln!(
"Launching Codex Desktop from {installed_app}...",
installed_app = installed_app.display()
);
open_codex_app(&installed_app, &workspace).await?;
Ok(())
}
fn find_existing_codex_app_path() -> Option<PathBuf> {
candidate_codex_app_paths()
.into_iter()
.find(|candidate| candidate.is_dir())
}
fn candidate_codex_app_paths() -> Vec<PathBuf> {
let mut paths = vec![PathBuf::from("/Applications/Codex.app")];
if let Some(home) = std::env::var_os("HOME") {
paths.push(PathBuf::from(home).join("Applications").join("Codex.app"));
}
paths
}
async fn open_codex_app(app_path: &Path, workspace: &Path) -> anyhow::Result<()> {
eprintln!(
"Opening workspace {workspace}...",
workspace = workspace.display()
);
let status = Command::new("open")
.arg("-a")
.arg(app_path)
.arg(workspace)
.status()
.await
.context("failed to invoke `open`")?;
if status.success() {
return Ok(());
}
anyhow::bail!(
"`open -a {app_path} {workspace}` exited with {status}",
app_path = app_path.display(),
workspace = workspace.display()
);
}
async fn download_and_install_codex_to_user_applications(dmg_url: &str) -> anyhow::Result<PathBuf> {
let temp_dir = Builder::new()
.prefix("codex-app-installer-")
.tempdir()
.context("failed to create temp dir")?;
let tmp_root = temp_dir.path().to_path_buf();
let _temp_dir = temp_dir;
let dmg_path = tmp_root.join("Codex.dmg");
download_dmg(dmg_url, &dmg_path).await?;
eprintln!("Mounting Codex Desktop installer...");
let mount_point = mount_dmg(&dmg_path).await?;
eprintln!(
"Installer mounted at {mount_point}.",
mount_point = mount_point.display()
);
let result = async {
let app_in_volume = find_codex_app_in_mount(&mount_point)
.context("failed to locate Codex.app in mounted dmg")?;
install_codex_app_bundle(&app_in_volume).await
}
.await;
let detach_result = detach_dmg(&mount_point).await;
if let Err(err) = detach_result {
eprintln!(
"warning: failed to detach dmg at {mount_point}: {err}",
mount_point = mount_point.display()
);
}
result
}
async fn install_codex_app_bundle(app_in_volume: &Path) -> anyhow::Result<PathBuf> {
for applications_dir in candidate_applications_dirs()? {
eprintln!(
"Installing Codex Desktop into {applications_dir}...",
applications_dir = applications_dir.display()
);
std::fs::create_dir_all(&applications_dir).with_context(|| {
format!(
"failed to create applications dir {applications_dir}",
applications_dir = applications_dir.display()
)
})?;
let dest_app = applications_dir.join("Codex.app");
if dest_app.is_dir() {
return Ok(dest_app);
}
match copy_app_bundle(app_in_volume, &dest_app).await {
Ok(()) => return Ok(dest_app),
Err(err) => {
eprintln!(
"warning: failed to install Codex.app to {applications_dir}: {err}",
applications_dir = applications_dir.display()
);
}
}
}
anyhow::bail!("failed to install Codex.app to any applications directory");
}
fn candidate_applications_dirs() -> anyhow::Result<Vec<PathBuf>> {
let mut dirs = vec![PathBuf::from("/Applications")];
dirs.push(user_applications_dir()?);
Ok(dirs)
}
async fn download_dmg(url: &str, dest: &Path) -> anyhow::Result<()> {
eprintln!("Downloading installer...");
let status = Command::new("curl")
.arg("-fL")
.arg("--retry")
.arg("3")
.arg("--retry-delay")
.arg("1")
.arg("-o")
.arg(dest)
.arg(url)
.status()
.await
.context("failed to invoke `curl`")?;
if status.success() {
return Ok(());
}
anyhow::bail!("curl download failed with {status}");
}
async fn mount_dmg(dmg_path: &Path) -> anyhow::Result<PathBuf> {
let output = Command::new("hdiutil")
.arg("attach")
.arg("-nobrowse")
.arg("-readonly")
.arg(dmg_path)
.output()
.await
.context("failed to invoke `hdiutil attach`")?;
if !output.status.success() {
anyhow::bail!(
"`hdiutil attach` failed with {status}: {stderr}",
status = output.status,
stderr = String::from_utf8_lossy(&output.stderr)
);
}
let stdout = String::from_utf8_lossy(&output.stdout);
parse_hdiutil_attach_mount_point(&stdout)
.map(PathBuf::from)
.with_context(|| format!("failed to parse mount point from hdiutil output:\n{stdout}"))
}
async fn detach_dmg(mount_point: &Path) -> anyhow::Result<()> {
let status = Command::new("hdiutil")
.arg("detach")
.arg(mount_point)
.status()
.await
.context("failed to invoke `hdiutil detach`")?;
if status.success() {
return Ok(());
}
anyhow::bail!("hdiutil detach failed with {status}");
}
fn find_codex_app_in_mount(mount_point: &Path) -> anyhow::Result<PathBuf> {
let direct = mount_point.join("Codex.app");
if direct.is_dir() {
return Ok(direct);
}
for entry in std::fs::read_dir(mount_point).with_context(|| {
format!(
"failed to read {mount_point}",
mount_point = mount_point.display()
)
})? {
let entry = entry.context("failed to read mount directory entry")?;
let path = entry.path();
if path.extension().is_some_and(|ext| ext == "app") && path.is_dir() {
return Ok(path);
}
}
anyhow::bail!(
"no .app bundle found at {mount_point}",
mount_point = mount_point.display()
);
}
async fn copy_app_bundle(src_app: &Path, dest_app: &Path) -> anyhow::Result<()> {
let status = Command::new("ditto")
.arg(src_app)
.arg(dest_app)
.status()
.await
.context("failed to invoke `ditto`")?;
if status.success() {
return Ok(());
}
anyhow::bail!("ditto copy failed with {status}");
}
fn user_applications_dir() -> anyhow::Result<PathBuf> {
let home = std::env::var_os("HOME").context("HOME is not set")?;
Ok(PathBuf::from(home).join("Applications"))
}
fn parse_hdiutil_attach_mount_point(output: &str) -> Option<String> {
output.lines().find_map(|line| {
if !line.contains("/Volumes/") {
return None;
}
if let Some((_, mount)) = line.rsplit_once('\t') {
return Some(mount.trim().to_string());
}
line.split_whitespace()
.find(|field| field.starts_with("/Volumes/"))
.map(str::to_string)
})
}
#[cfg(test)]
mod tests {
use super::parse_hdiutil_attach_mount_point;
use pretty_assertions::assert_eq;
#[test]
fn parses_mount_point_from_tab_separated_hdiutil_output() {
let output = "/dev/disk2s1\tApple_HFS\tCodex\t/Volumes/Codex\n";
assert_eq!(
parse_hdiutil_attach_mount_point(output).as_deref(),
Some("/Volumes/Codex")
);
}
#[test]
fn parses_mount_point_with_spaces() {
let output = "/dev/disk2s1\tApple_HFS\tCodex Installer\t/Volumes/Codex Installer\n";
assert_eq!(
parse_hdiutil_attach_mount_point(output).as_deref(),
Some("/Volumes/Codex Installer")
);
}
}

View File

@@ -0,0 +1,11 @@
#[cfg(target_os = "macos")]
mod mac;
/// Run the app install/open logic for the current OS.
#[cfg(target_os = "macos")]
pub async fn run_app_open_or_install(
workspace: std::path::PathBuf,
download_url: String,
) -> anyhow::Result<()> {
mac::run_mac_app_open_or_install(workspace, download_url).await
}

View File

@@ -31,6 +31,10 @@ use std::io::IsTerminal;
use std::path::PathBuf;
use supports_color::Stream;
#[cfg(target_os = "macos")]
mod app_cmd;
#[cfg(target_os = "macos")]
mod desktop_app;
mod mcp_cmd;
#[cfg(not(windows))]
mod wsl_paths;
@@ -98,6 +102,10 @@ enum Subcommand {
/// [experimental] Run the app server or related tooling.
AppServer(AppServerCommand),
/// Launch the Codex desktop app (downloads the macOS installer if missing).
#[cfg(target_os = "macos")]
App(app_cmd::AppCommand),
/// Generate shell completion scripts.
Completion(CompletionCommand),
@@ -564,6 +572,10 @@ async fn cli_main(codex_linux_sandbox_exe: Option<PathBuf>) -> anyhow::Result<()
)?;
}
},
#[cfg(target_os = "macos")]
Some(Subcommand::App(app_cli)) => {
app_cmd::run_app(app_cli).await?;
}
Some(Subcommand::Resume(ResumeCommand {
session_id,
last,

View File

@@ -194,6 +194,7 @@ impl Stream for AggregatedStream {
text: std::mem::take(&mut this.cumulative),
}],
end_turn: None,
phase: None,
};
this.pending
.push_back(ResponseEvent::OutputItemDone(aggregated_message));

View File

@@ -387,6 +387,7 @@ mod tests {
text: "hi".to_string(),
}],
end_turn: None,
phase: None,
}];
let req = ChatRequestBuilder::new("gpt-test", "inst", &prompt_input, &[])
.conversation_id(Some("conv-1".into()))
@@ -414,6 +415,7 @@ mod tests {
text: "read these".to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::FunctionCall {
id: None,

View File

@@ -224,12 +224,14 @@ mod tests {
role: "assistant".into(),
content: Vec::new(),
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
role: "assistant".into(),
content: Vec::new(),
end_turn: None,
phase: None,
},
];

View File

@@ -331,6 +331,7 @@ async fn append_assistant_text(
role: "assistant".to_string(),
content: vec![],
end_turn: None,
phase: None,
};
*assistant_item = Some(item.clone());
let _ = tx_event

View File

@@ -429,6 +429,7 @@ mod tests {
use super::*;
use assert_matches::assert_matches;
use bytes::Bytes;
use codex_protocol::models::MessagePhase;
use codex_protocol::models::ResponseItem;
use futures::stream;
use pretty_assertions::assert_eq;
@@ -492,7 +493,8 @@ mod tests {
"item": {
"type": "message",
"role": "assistant",
"content": [{"type": "output_text", "text": "Hello"}]
"content": [{"type": "output_text", "text": "Hello"}],
"phase": "commentary"
}
})
.to_string();
@@ -523,8 +525,11 @@ mod tests {
assert_matches!(
&events[0],
Ok(ResponseEvent::OutputItemDone(ResponseItem::Message { role, .. }))
if role == "assistant"
Ok(ResponseEvent::OutputItemDone(ResponseItem::Message {
role,
phase: Some(MessagePhase::Commentary),
..
})) if role == "assistant"
);
assert_matches!(

View File

@@ -309,6 +309,7 @@ async fn streaming_client_retries_on_transport_error() -> Result<()> {
text: "hi".to_string(),
}],
end_turn: None,
phase: None,
}],
tools: Vec::<Value>::new(),
parallel_tool_calls: false,

View File

@@ -11,6 +11,7 @@ use codex_protocol::openai_models::ModelsResponse;
use codex_protocol::openai_models::ReasoningEffort;
use codex_protocol::openai_models::ReasoningEffortPreset;
use codex_protocol::openai_models::TruncationPolicyConfig;
use codex_protocol::openai_models::default_input_modalities;
use http::HeaderMap;
use http::Method;
use wiremock::Mock;
@@ -88,6 +89,7 @@ async fn models_client_hits_models_endpoint() {
auto_compact_token_limit: None,
effective_context_window_percent: 95,
experimental_supported_tools: Vec::new(),
input_modalities: default_input_modalities(),
}],
};

View File

@@ -45,6 +45,7 @@ codex-utils-pty = { workspace = true }
codex-utils-readiness = { workspace = true }
codex-utils-string = { workspace = true }
codex-windows-sandbox = { package = "codex-windows-sandbox", path = "../windows-sandbox-rs" }
dirs = { workspace = true }
dunce = { workspace = true }
encoding_rs = { workspace = true }
env-flags = { workspace = true }
@@ -56,7 +57,6 @@ indexmap = { workspace = true }
indoc = { workspace = true }
keyring = { workspace = true, features = ["crypto-rust"] }
libc = { workspace = true }
mcp-types = { workspace = true }
multimap = { workspace = true }
once_cell = { workspace = true }
os_info = { workspace = true }
@@ -64,6 +64,12 @@ rand = { workspace = true }
regex = { workspace = true }
regex-lite = { workspace = true }
reqwest = { workspace = true, features = ["json", "stream"] }
rmcp = { workspace = true, default-features = false, features = [
"base64",
"macros",
"schemars",
"server",
] }
schemars = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }

View File

@@ -1,10 +1,13 @@
use std::path::PathBuf;
use std::sync::Arc;
use std::sync::OnceLock;
use std::sync::RwLock;
use crate::api_bridge::CoreAuthProvider;
use crate::api_bridge::auth_provider_from_auth;
use crate::api_bridge::map_api_error;
use crate::auth::UnauthorizedRecovery;
use crate::turn_metadata::build_turn_metadata_header;
use codex_api::AggregateStreamExt;
use codex_api::ChatClient as ApiChatClient;
use codex_api::CompactClient as ApiCompactClient;
@@ -72,6 +75,13 @@ use crate::transport_manager::TransportManager;
pub const WEB_SEARCH_ELIGIBLE_HEADER: &str = "x-oai-web-search-eligible";
pub const X_CODEX_TURN_STATE_HEADER: &str = "x-codex-turn-state";
pub const X_CODEX_TURN_METADATA_HEADER: &str = "x-codex-turn-metadata";
#[derive(Debug, Default)]
struct TurnMetadataCache {
cwd: Option<PathBuf>,
header: Option<HeaderValue>,
}
#[derive(Debug)]
struct ModelClientState {
@@ -85,6 +95,7 @@ struct ModelClientState {
summary: ReasoningSummaryConfig,
session_source: SessionSource,
transport_manager: TransportManager,
turn_metadata_cache: Arc<RwLock<TurnMetadataCache>>,
}
#[derive(Debug, Clone)]
@@ -136,11 +147,13 @@ impl ModelClient {
summary,
session_source,
transport_manager,
turn_metadata_cache: Arc::new(RwLock::new(TurnMetadataCache::default())),
}),
}
}
pub fn new_session(&self) -> ModelClientSession {
pub fn new_session(&self, turn_metadata_cwd: Option<PathBuf>) -> ModelClientSession {
self.prewarm_turn_metadata_header(turn_metadata_cwd);
ModelClientSession {
state: Arc::clone(&self.state),
connection: None,
@@ -149,6 +162,38 @@ impl ModelClient {
turn_state: Arc::new(OnceLock::new()),
}
}
/// Refresh turn metadata in the background and update a cached header that request
/// builders can read without blocking.
fn prewarm_turn_metadata_header(&self, turn_metadata_cwd: Option<PathBuf>) {
let turn_metadata_cwd =
turn_metadata_cwd.map(|cwd| std::fs::canonicalize(&cwd).unwrap_or(cwd));
if let Ok(mut cache) = self.state.turn_metadata_cache.write()
&& cache.cwd != turn_metadata_cwd
{
cache.cwd = turn_metadata_cwd.clone();
cache.header = None;
}
let Some(cwd) = turn_metadata_cwd else {
return;
};
let turn_metadata_cache = Arc::clone(&self.state.turn_metadata_cache);
if let Ok(handle) = tokio::runtime::Handle::try_current() {
let _task = handle.spawn(async move {
let header = build_turn_metadata_header(cwd.as_path())
.await
.and_then(|value| HeaderValue::from_str(value.as_str()).ok());
if let Ok(mut cache) = turn_metadata_cache.write()
&& cache.cwd.as_ref() == Some(&cwd)
{
cache.header = header;
}
});
}
}
}
impl ModelClient {
@@ -257,6 +302,14 @@ impl ModelClient {
}
impl ModelClientSession {
fn turn_metadata_header(&self) -> Option<HeaderValue> {
self.state
.turn_metadata_cache
.try_read()
.ok()
.and_then(|cache| cache.header.clone())
}
/// Streams a single model turn using either the Responses or Chat
/// Completions wire API, depending on the configured provider.
///
@@ -332,6 +385,7 @@ impl ModelClientSession {
prompt: &Prompt,
compression: Compression,
) -> ApiResponsesOptions {
let turn_metadata_header = self.turn_metadata_header();
let model_info = &self.state.model_info;
let default_reasoning_effort = model_info.default_reasoning_level;
@@ -380,7 +434,11 @@ impl ModelClientSession {
store_override: None,
conversation_id: Some(conversation_id),
session_source: Some(self.state.session_source.clone()),
extra_headers: build_responses_headers(&self.state.config, Some(&self.turn_state)),
extra_headers: build_responses_headers(
&self.state.config,
Some(&self.turn_state),
turn_metadata_header.as_ref(),
),
compression,
turn_state: Some(Arc::clone(&self.turn_state)),
}
@@ -713,6 +771,7 @@ fn experimental_feature_headers(config: &Config) -> ApiHeaderMap {
fn build_responses_headers(
config: &Config,
turn_state: Option<&Arc<OnceLock<String>>>,
turn_metadata_header: Option<&HeaderValue>,
) -> ApiHeaderMap {
let mut headers = experimental_feature_headers(config);
headers.insert(
@@ -731,6 +790,9 @@ fn build_responses_headers(
{
headers.insert(X_CODEX_TURN_STATE_HEADER, header_value);
}
if let Some(header_value) = turn_metadata_header {
headers.insert(X_CODEX_TURN_METADATA_HEADER, header_value.clone());
}
headers
}

View File

@@ -50,6 +50,7 @@ use codex_protocol::dynamic_tools::DynamicToolSpec;
use codex_protocol::items::PlanItem;
use codex_protocol::items::TurnItem;
use codex_protocol::items::UserMessageItem;
use codex_protocol::mcp::CallToolResult;
use codex_protocol::models::BaseInstructions;
use codex_protocol::models::format_allow_prefixes;
use codex_protocol::openai_models::ModelInfo;
@@ -72,14 +73,12 @@ use codex_rmcp_client::OAuthCredentialsStoreMode;
use futures::future::BoxFuture;
use futures::prelude::*;
use futures::stream::FuturesOrdered;
use mcp_types::CallToolResult;
use mcp_types::ListResourceTemplatesRequestParams;
use mcp_types::ListResourceTemplatesResult;
use mcp_types::ListResourcesRequestParams;
use mcp_types::ListResourcesResult;
use mcp_types::ReadResourceRequestParams;
use mcp_types::ReadResourceResult;
use mcp_types::RequestId;
use rmcp::model::ListResourceTemplatesResult;
use rmcp::model::ListResourcesResult;
use rmcp::model::PaginatedRequestParam;
use rmcp::model::ReadResourceRequestParam;
use rmcp::model::ReadResourceResult;
use rmcp::model::RequestId;
use serde_json;
use serde_json::Value;
use tokio::sync::Mutex;
@@ -119,6 +118,7 @@ use crate::error::Result as CodexResult;
use crate::exec::StreamOutput;
use crate::exec_policy::ExecPolicyUpdateError;
use crate::feedback_tags;
use crate::git_info::get_git_repo_root;
use crate::instructions::UserInstructions;
use crate::mcp::CODEX_APPS_MCP_SERVER_NAME;
use crate::mcp::auth::compute_auth_statuses;
@@ -531,7 +531,6 @@ pub(crate) struct TurnContext {
pub(crate) truncation_policy: TruncationPolicy,
pub(crate) dynamic_tools: Vec<DynamicToolSpec>,
}
impl TurnContext {
pub(crate) fn resolve_path(&self, path: Option<String>) -> PathBuf {
path.as_ref()
@@ -1052,6 +1051,11 @@ impl Session {
state.get_total_token_usage(state.server_reasoning_included())
}
async fn get_estimated_token_count(&self, turn_context: &TurnContext) -> Option<i64> {
let state = self.state.lock().await;
state.history.estimate_token_count(turn_context)
}
pub(crate) async fn get_base_instructions(&self) -> BaseInstructions {
let state = self.state.lock().await;
BaseInstructions {
@@ -1835,6 +1839,7 @@ impl Session {
text: format!("Warning: {}", message.into()),
}],
end_turn: None,
phase: None,
};
self.record_conversation_items(ctx, &[item]).await;
@@ -2224,7 +2229,7 @@ impl Session {
pub async fn list_resources(
&self,
server: &str,
params: Option<ListResourcesRequestParams>,
params: Option<PaginatedRequestParam>,
) -> anyhow::Result<ListResourcesResult> {
self.services
.mcp_connection_manager
@@ -2237,7 +2242,7 @@ impl Session {
pub async fn list_resource_templates(
&self,
server: &str,
params: Option<ListResourceTemplatesRequestParams>,
params: Option<PaginatedRequestParam>,
) -> anyhow::Result<ListResourceTemplatesResult> {
self.services
.mcp_connection_manager
@@ -2250,7 +2255,7 @@ impl Session {
pub async fn read_resource(
&self,
server: &str,
params: ReadResourceRequestParams,
params: ReadResourceRequestParam,
) -> anyhow::Result<ReadResourceResult> {
self.services
.mcp_connection_manager
@@ -2577,10 +2582,10 @@ mod handlers {
use codex_protocol::config_types::ModeKind;
use codex_protocol::config_types::Settings;
use codex_protocol::dynamic_tools::DynamicToolResponse;
use codex_protocol::mcp::RequestId as ProtocolRequestId;
use codex_protocol::user_input::UserInput;
use codex_rmcp_client::ElicitationAction;
use codex_rmcp_client::ElicitationResponse;
use mcp_types::RequestId;
use std::path::PathBuf;
use std::sync::Arc;
use tracing::info;
@@ -2709,7 +2714,7 @@ mod handlers {
pub async fn resolve_elicitation(
sess: &Arc<Session>,
server_name: String,
request_id: RequestId,
request_id: ProtocolRequestId,
decision: codex_protocol::approvals::ElicitationAction,
) {
let action = match decision {
@@ -2724,6 +2729,12 @@ mod handlers {
ElicitationAction::Decline | ElicitationAction::Cancel => None,
};
let response = ElicitationResponse { action, content };
let request_id = match request_id {
ProtocolRequestId::String(value) => {
rmcp::model::NumberOrString::String(std::sync::Arc::from(value))
}
ProtocolRequestId::Integer(value) => rmcp::model::NumberOrString::Number(value),
};
if let Err(err) = sess
.resolve_elicitation(server_name, request_id, response)
.await
@@ -3304,6 +3315,7 @@ pub(crate) async fn run_turn(
let model_info = turn_context.client.get_model_info();
let auto_compact_limit = model_info.auto_compact_token_limit().unwrap_or(i64::MAX);
let total_usage_tokens = sess.get_total_token_usage().await;
let event = EventMsg::TurnStarted(TurnStartedEvent {
model_context_window: turn_context.client.get_model_context_window(),
collaboration_mode_kind: turn_context.collaboration_mode.mode,
@@ -3406,7 +3418,9 @@ pub(crate) async fn run_turn(
// many turns, from the perspective of the user, it is a single turn.
let turn_diff_tracker = Arc::new(tokio::sync::Mutex::new(TurnDiffTracker::new()));
let mut client_session = turn_context.client.new_session();
let mut client_session = turn_context
.client
.new_session(Some(turn_context.cwd.clone()));
loop {
// Note that pending_input would be something like a message the user
@@ -3457,6 +3471,19 @@ pub(crate) async fn run_turn(
let total_usage_tokens = sess.get_total_token_usage().await;
let token_limit_reached = total_usage_tokens >= auto_compact_limit;
let estimated_token_count =
sess.get_estimated_token_count(turn_context.as_ref()).await;
info!(
turn_id = %turn_context.sub_id,
total_usage_tokens,
estimated_token_count = ?estimated_token_count,
auto_compact_limit,
token_limit_reached,
needs_follow_up,
"post sampling token usage"
);
// as long as compaction works well in getting us way below the token limit, we shouldn't worry about being in an infinite loop.
if token_limit_reached && needs_follow_up {
run_auto_compact(&sess, &turn_context).await;
@@ -4469,8 +4496,6 @@ pub(super) fn get_last_assistant_message_from_turn(responses: &[ResponseItem]) -
#[cfg(test)]
pub(crate) use tests::make_session_and_context;
use crate::git_info::get_git_repo_root;
#[cfg(test)]
pub(crate) use tests::make_session_and_context_with_rx;
@@ -4516,8 +4541,7 @@ mod tests {
use std::time::Duration;
use tokio::time::sleep;
use mcp_types::ContentBlock;
use mcp_types::TextContent;
use codex_protocol::mcp::CallToolResult as McpCallToolResult;
use pretty_assertions::assert_eq;
use serde::Deserialize;
use serde_json::json;
@@ -4538,6 +4562,7 @@ mod tests {
text: text.to_string(),
}],
end_turn: None,
phase: None,
}
}
@@ -4819,6 +4844,7 @@ mod tests {
text: "turn 1 user".to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
@@ -4827,6 +4853,7 @@ mod tests {
text: "turn 1 assistant".to_string(),
}],
end_turn: None,
phase: None,
},
];
sess.record_into_history(&turn_1, tc.as_ref()).await;
@@ -4839,6 +4866,7 @@ mod tests {
text: "turn 2 user".to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
@@ -4847,6 +4875,7 @@ mod tests {
text: "turn 2 assistant".to_string(),
}],
end_turn: None,
phase: None,
},
];
sess.record_into_history(&turn_2, tc.as_ref()).await;
@@ -4879,6 +4908,7 @@ mod tests {
text: "turn 1 user".to_string(),
}],
end_turn: None,
phase: None,
}];
sess.record_into_history(&turn_1, tc.as_ref()).await;
@@ -5101,7 +5131,7 @@ mod tests {
#[test]
fn prefers_structured_content_when_present() {
let ctr = CallToolResult {
let ctr = McpCallToolResult {
// Content present but should be ignored because structured_content is set.
content: vec![text_block("ignored")],
is_error: None,
@@ -5109,6 +5139,7 @@ mod tests {
"ok": true,
"value": 42
})),
meta: None,
};
let got = FunctionCallOutputPayload::from(&ctr);
@@ -5147,10 +5178,11 @@ mod tests {
#[test]
fn falls_back_to_content_when_structured_is_null() {
let ctr = CallToolResult {
let ctr = McpCallToolResult {
content: vec![text_block("hello"), text_block("world")],
is_error: None,
structured_content: Some(serde_json::Value::Null),
meta: None,
};
let got = FunctionCallOutputPayload::from(&ctr);
@@ -5166,10 +5198,11 @@ mod tests {
#[test]
fn success_flag_reflects_is_error_true() {
let ctr = CallToolResult {
let ctr = McpCallToolResult {
content: vec![text_block("unused")],
is_error: Some(true),
structured_content: Some(json!({ "message": "bad" })),
meta: None,
};
let got = FunctionCallOutputPayload::from(&ctr);
@@ -5184,10 +5217,11 @@ mod tests {
#[test]
fn success_flag_true_with_no_error_and_content_used() {
let ctr = CallToolResult {
let ctr = McpCallToolResult {
content: vec![text_block("alpha")],
is_error: Some(false),
structured_content: None,
meta: None,
};
let got = FunctionCallOutputPayload::from(&ctr);
@@ -5238,11 +5272,10 @@ mod tests {
}
}
fn text_block(s: &str) -> ContentBlock {
ContentBlock::TextContent(TextContent {
annotations: None,
text: s.to_string(),
r#type: "text".to_string(),
fn text_block(s: &str) -> serde_json::Value {
json!({
"type": "text",
"text": s,
})
}
@@ -5825,6 +5858,7 @@ mod tests {
text: "first user".to_string(),
}],
end_turn: None,
phase: None,
};
live_history.record_items(std::iter::once(&user1), turn_context.truncation_policy);
rollout_items.push(RolloutItem::ResponseItem(user1.clone()));
@@ -5836,6 +5870,7 @@ mod tests {
text: "assistant reply one".to_string(),
}],
end_turn: None,
phase: None,
};
live_history.record_items(std::iter::once(&assistant1), turn_context.truncation_policy);
rollout_items.push(RolloutItem::ResponseItem(assistant1.clone()));
@@ -5861,6 +5896,7 @@ mod tests {
text: "second user".to_string(),
}],
end_turn: None,
phase: None,
};
live_history.record_items(std::iter::once(&user2), turn_context.truncation_policy);
rollout_items.push(RolloutItem::ResponseItem(user2.clone()));
@@ -5872,6 +5908,7 @@ mod tests {
text: "assistant reply two".to_string(),
}],
end_turn: None,
phase: None,
};
live_history.record_items(std::iter::once(&assistant2), turn_context.truncation_policy);
rollout_items.push(RolloutItem::ResponseItem(assistant2.clone()));
@@ -5897,6 +5934,7 @@ mod tests {
text: "third user".to_string(),
}],
end_turn: None,
phase: None,
};
live_history.record_items(std::iter::once(&user3), turn_context.truncation_policy);
rollout_items.push(RolloutItem::ResponseItem(user3));
@@ -5908,6 +5946,7 @@ mod tests {
text: "assistant reply three".to_string(),
}],
end_turn: None,
phase: None,
};
live_history.record_items(std::iter::once(&assistant3), turn_context.truncation_policy);
rollout_items.push(RolloutItem::ResponseItem(assistant3));

View File

@@ -311,6 +311,7 @@ fn build_compacted_history_with_limit(
text: message.clone(),
}],
end_turn: None,
phase: None,
});
}
@@ -325,6 +326,7 @@ fn build_compacted_history_with_limit(
role: "user".to_string(),
content: vec![ContentItem::InputText { text: summary_text }],
end_turn: None,
phase: None,
});
history
@@ -335,7 +337,9 @@ async fn drain_to_completed(
turn_context: &TurnContext,
prompt: &Prompt,
) -> CodexResult<()> {
let mut client_session = turn_context.client.new_session();
let mut client_session = turn_context
.client
.new_session(Some(turn_context.cwd.clone()));
let mut stream = client_session.stream(prompt).await?;
loop {
let maybe_event = stream.next().await;
@@ -414,6 +418,7 @@ mod tests {
text: "ignored".to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: Some("user".to_string()),
@@ -422,6 +427,7 @@ mod tests {
text: "first".to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Other,
];
@@ -442,6 +448,7 @@ mod tests {
.to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
@@ -450,6 +457,7 @@ mod tests {
text: "<ENVIRONMENT_CONTEXT>cwd=/tmp</ENVIRONMENT_CONTEXT>".to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
@@ -458,6 +466,7 @@ mod tests {
text: "real user message".to_string(),
}],
end_turn: None,
phase: None,
},
];
@@ -543,6 +552,7 @@ mod tests {
text: marker.clone(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
@@ -551,6 +561,7 @@ mod tests {
text: "real user message".to_string(),
}],
end_turn: None,
phase: None,
},
];

View File

@@ -3,6 +3,8 @@ use std::sync::Arc;
use crate::Prompt;
use crate::codex::Session;
use crate::codex::TurnContext;
use crate::context_manager::ContextManager;
use crate::context_manager::is_codex_generated_item;
use crate::error::Result as CodexResult;
use crate::protocol::CompactedItem;
use crate::protocol::EventMsg;
@@ -11,6 +13,7 @@ use crate::protocol::TurnStartedEvent;
use codex_protocol::items::ContextCompactionItem;
use codex_protocol::items::TurnItem;
use codex_protocol::models::ResponseItem;
use tracing::info;
pub(crate) async fn run_inline_remote_auto_compact_task(
sess: Arc<Session>,
@@ -45,7 +48,16 @@ async fn run_remote_compact_task_inner_impl(
let compaction_item = TurnItem::ContextCompaction(ContextCompactionItem::new());
sess.emit_turn_item_started(turn_context, &compaction_item)
.await;
let history = sess.clone_history().await;
let mut history = sess.clone_history().await;
let deleted_items =
trim_function_call_history_to_fit_context_window(&mut history, turn_context.as_ref());
if deleted_items > 0 {
info!(
turn_id = %turn_context.sub_id,
deleted_items,
"trimmed history items before remote compaction"
);
}
// Required to keep `/undo` available after compaction
let ghost_snapshots: Vec<ResponseItem> = history
@@ -86,3 +98,31 @@ async fn run_remote_compact_task_inner_impl(
.await;
Ok(())
}
fn trim_function_call_history_to_fit_context_window(
history: &mut ContextManager,
turn_context: &TurnContext,
) -> usize {
let mut deleted_items = 0usize;
let Some(context_window) = turn_context.client.get_model_context_window() else {
return deleted_items;
};
while history
.estimate_token_count(turn_context)
.is_some_and(|estimated_tokens| estimated_tokens > context_window)
{
let Some(last_item) = history.raw_items().last() else {
break;
};
if !is_codex_generated_item(last_item) {
break;
}
if !history.remove_last_item() {
break;
}
deleted_items += 1;
}
deleted_items
}

View File

@@ -93,24 +93,7 @@ impl ContextManager {
let base_tokens = i64::try_from(approx_token_count(&base_instructions)).unwrap_or(i64::MAX);
let items_tokens = self.items.iter().fold(0i64, |acc, item| {
acc + match item {
ResponseItem::GhostSnapshot { .. } => 0,
ResponseItem::Reasoning {
encrypted_content: Some(content),
..
}
| ResponseItem::Compaction {
encrypted_content: content,
} => {
let reasoning_bytes = estimate_reasoning_length(content.len());
i64::try_from(approx_tokens_from_byte_count(reasoning_bytes))
.unwrap_or(i64::MAX)
}
item => {
let serialized = serde_json::to_string(item).unwrap_or_default();
i64::try_from(approx_token_count(&serialized)).unwrap_or(i64::MAX)
}
}
acc.saturating_add(estimate_item_token_count(item))
});
Some(base_tokens.saturating_add(items_tokens))
@@ -128,6 +111,15 @@ impl ContextManager {
}
}
pub(crate) fn remove_last_item(&mut self) -> bool {
if let Some(removed) = self.items.pop() {
normalize::remove_corresponding_for(&mut self.items, &removed);
true
} else {
false
}
}
pub(crate) fn replace(&mut self, items: Vec<ResponseItem>) {
self.items = items;
}
@@ -207,36 +199,42 @@ impl ContextManager {
);
}
fn get_non_last_reasoning_items_tokens(&self) -> usize {
// get reasoning items excluding all the ones after the last user message
fn get_non_last_reasoning_items_tokens(&self) -> i64 {
// Get reasoning items excluding all the ones after the last user message.
let Some(last_user_index) = self
.items
.iter()
.rposition(|item| matches!(item, ResponseItem::Message { role, .. } if role == "user"))
else {
return 0usize;
return 0;
};
let total_reasoning_bytes = self
.items
self.items
.iter()
.take(last_user_index)
.filter_map(|item| {
if let ResponseItem::Reasoning {
encrypted_content: Some(content),
..
} = item
{
Some(content.len())
} else {
None
}
.filter(|item| {
matches!(
item,
ResponseItem::Reasoning {
encrypted_content: Some(_),
..
}
)
})
.map(estimate_reasoning_length)
.fold(0usize, usize::saturating_add);
.fold(0i64, |acc, item| {
acc.saturating_add(estimate_item_token_count(item))
})
}
let token_estimate = approx_tokens_from_byte_count(total_reasoning_bytes);
token_estimate as usize
fn get_trailing_codex_generated_items_tokens(&self) -> i64 {
let mut total = 0i64;
for item in self.items.iter().rev() {
if !is_codex_generated_item(item) {
break;
}
total = total.saturating_add(estimate_item_token_count(item));
}
total
}
/// When true, the server already accounted for past reasoning tokens and
@@ -247,10 +245,13 @@ impl ContextManager {
.as_ref()
.map(|info| info.last_token_usage.total_tokens)
.unwrap_or(0);
let trailing_codex_generated_tokens = self.get_trailing_codex_generated_items_tokens();
if server_reasoning_included {
last_tokens
last_tokens.saturating_add(trailing_codex_generated_tokens)
} else {
last_tokens.saturating_add(self.get_non_last_reasoning_items_tokens() as i64)
last_tokens
.saturating_add(self.get_non_last_reasoning_items_tokens())
.saturating_add(trailing_codex_generated_tokens)
}
}
@@ -332,6 +333,33 @@ fn estimate_reasoning_length(encoded_len: usize) -> usize {
.saturating_sub(650)
}
fn estimate_item_token_count(item: &ResponseItem) -> i64 {
match item {
ResponseItem::GhostSnapshot { .. } => 0,
ResponseItem::Reasoning {
encrypted_content: Some(content),
..
}
| ResponseItem::Compaction {
encrypted_content: content,
} => {
let reasoning_bytes = estimate_reasoning_length(content.len());
i64::try_from(approx_tokens_from_byte_count(reasoning_bytes)).unwrap_or(i64::MAX)
}
item => {
let serialized = serde_json::to_string(item).unwrap_or_default();
i64::try_from(approx_token_count(&serialized)).unwrap_or(i64::MAX)
}
}
}
pub(crate) fn is_codex_generated_item(item: &ResponseItem) -> bool {
matches!(
item,
ResponseItem::FunctionCallOutput { .. } | ResponseItem::CustomToolCallOutput { .. }
) || matches!(item, ResponseItem::Message { role, .. } if role == "developer")
}
pub(crate) fn is_user_turn_boundary(item: &ResponseItem) -> bool {
let ResponseItem::Message { role, content, .. } = item else {
return false;

View File

@@ -24,6 +24,7 @@ fn assistant_msg(text: &str) -> ResponseItem {
text: text.to_string(),
}],
end_turn: None,
phase: None,
}
}
@@ -43,6 +44,7 @@ fn user_msg(text: &str) -> ResponseItem {
text: text.to_string(),
}],
end_turn: None,
phase: None,
}
}
@@ -54,6 +56,24 @@ fn user_input_text_msg(text: &str) -> ResponseItem {
text: text.to_string(),
}],
end_turn: None,
phase: None,
}
}
fn function_call_output(call_id: &str, content: &str) -> ResponseItem {
ResponseItem::FunctionCallOutput {
call_id: call_id.to_string(),
output: FunctionCallOutputPayload {
content: content.to_string(),
..Default::default()
},
}
}
fn custom_tool_call_output(call_id: &str, output: &str) -> ResponseItem {
ResponseItem::CustomToolCallOutput {
call_id: call_id.to_string(),
output: output.to_string(),
}
}
@@ -97,6 +117,7 @@ fn filters_non_api_messages() {
text: "ignored".to_string(),
}],
end_turn: None,
phase: None,
};
let reasoning = reasoning_msg("thinking...");
h.record_items([&system, &reasoning, &ResponseItem::Other], policy);
@@ -127,6 +148,7 @@ fn filters_non_api_messages() {
text: "hi".to_string()
}],
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
@@ -135,6 +157,7 @@ fn filters_non_api_messages() {
text: "hello".to_string()
}],
end_turn: None,
phase: None,
}
]
);
@@ -162,6 +185,63 @@ fn non_last_reasoning_tokens_ignore_entries_after_last_user() {
assert_eq!(history.get_non_last_reasoning_items_tokens(), 32);
}
#[test]
fn trailing_codex_generated_tokens_stop_at_first_non_generated_item() {
let earlier_output = function_call_output("call-earlier", "earlier output");
let trailing_function_output = function_call_output("call-tail-1", "tail function output");
let trailing_custom_output = custom_tool_call_output("call-tail-2", "tail custom output");
let history = create_history_with_items(vec![
earlier_output,
user_msg("boundary item"),
trailing_function_output.clone(),
trailing_custom_output.clone(),
]);
let expected_tokens = estimate_item_token_count(&trailing_function_output)
.saturating_add(estimate_item_token_count(&trailing_custom_output));
assert_eq!(
history.get_trailing_codex_generated_items_tokens(),
expected_tokens
);
}
#[test]
fn trailing_codex_generated_tokens_exclude_function_call_tail() {
let history = create_history_with_items(vec![ResponseItem::FunctionCall {
id: None,
name: "not-generated".to_string(),
arguments: "{}".to_string(),
call_id: "call-tail".to_string(),
}]);
assert_eq!(history.get_trailing_codex_generated_items_tokens(), 0);
}
#[test]
fn total_token_usage_includes_only_trailing_codex_generated_items() {
let non_trailing_output = function_call_output("call-before-message", "not trailing");
let trailing_assistant = assistant_msg("assistant boundary");
let trailing_output = custom_tool_call_output("tool-tail", "trailing output");
let mut history = create_history_with_items(vec![
non_trailing_output,
user_msg("boundary"),
trailing_assistant,
trailing_output.clone(),
]);
history.update_token_info(
&TokenUsage {
total_tokens: 100,
..Default::default()
},
None,
);
assert_eq!(
history.get_total_token_usage(true),
100 + estimate_item_token_count(&trailing_output)
);
}
#[test]
fn get_history_for_prompt_drops_ghost_commits() {
let items = vec![ResponseItem::GhostSnapshot {
@@ -216,6 +296,30 @@ fn remove_first_item_removes_matching_call_for_output() {
assert_eq!(h.raw_items(), vec![]);
}
#[test]
fn remove_last_item_removes_matching_call_for_output() {
let items = vec![
user_msg("before tool call"),
ResponseItem::FunctionCall {
id: None,
name: "do_it".to_string(),
arguments: "{}".to_string(),
call_id: "call-delete-last".to_string(),
},
ResponseItem::FunctionCallOutput {
call_id: "call-delete-last".to_string(),
output: FunctionCallOutputPayload {
content: "ok".to_string(),
..Default::default()
},
},
];
let mut h = create_history_with_items(items);
assert!(h.remove_last_item());
assert_eq!(h.raw_items(), vec![user_msg("before tool call")]);
}
#[test]
fn replace_last_turn_images_replaces_tool_output_images() {
let items = vec![
@@ -262,6 +366,7 @@ fn replace_last_turn_images_does_not_touch_user_images() {
image_url: "data:image/png;base64,AAA".to_string(),
}],
end_turn: None,
phase: None,
}];
let mut history = create_history_with_items(items.clone());

View File

@@ -2,4 +2,5 @@ mod history;
mod normalize;
pub(crate) use history::ContextManager;
pub(crate) use history::is_codex_generated_item;
pub(crate) use history::is_user_turn_boundary;

View File

@@ -28,6 +28,7 @@ impl EnvironmentContext {
cwd,
// should compare all fields except shell
shell: _,
..
} = other;
self.cwd == *cwd
@@ -80,6 +81,7 @@ impl From<EnvironmentContext> for ResponseItem {
text: ec.serialize_to_xml(),
}],
end_turn: None,
phase: None,
}
}
}

View File

@@ -177,6 +177,7 @@ mod tests {
},
],
end_turn: None,
phase: None,
};
let turn_item = parse_turn_item(&item).expect("expected user message turn item");
@@ -219,6 +220,7 @@ mod tests {
},
],
end_turn: None,
phase: None,
};
let turn_item = parse_turn_item(&item).expect("expected user message turn item");
@@ -260,6 +262,7 @@ mod tests {
},
],
end_turn: None,
phase: None,
};
let turn_item = parse_turn_item(&item).expect("expected user message turn item");
@@ -289,6 +292,7 @@ mod tests {
text: "<user_instructions>test_text</user_instructions>".to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
@@ -297,6 +301,7 @@ mod tests {
text: "<environment_context>test_text</environment_context>".to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
@@ -305,6 +310,7 @@ mod tests {
text: "# AGENTS.md instructions for test_directory\n\n<INSTRUCTIONS>\ntest_text\n</INSTRUCTIONS>".to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
@@ -314,6 +320,7 @@ mod tests {
.to_string(),
}],
end_turn: None,
phase: None,
},
ResponseItem::Message {
id: None,
@@ -322,6 +329,7 @@ mod tests {
text: "<user_shell_command>echo 42</user_shell_command>".to_string(),
}],
end_turn: None,
phase: None,
},
];
@@ -340,6 +348,7 @@ mod tests {
text: "Hello from Codex".to_string(),
}],
end_turn: None,
phase: None,
};
let turn_item = parse_turn_item(&item).expect("expected agent message turn item");

View File

@@ -1,3 +1,4 @@
use std::collections::BTreeMap;
use std::collections::HashSet;
use std::path::Path;
use std::path::PathBuf;
@@ -109,6 +110,73 @@ pub async fn collect_git_info(cwd: &Path) -> Option<GitInfo> {
Some(git_info)
}
/// Collect fetch remotes in a multi-root-friendly format: {"origin": "https://..."}.
pub async fn get_git_remote_urls(cwd: &Path) -> Option<BTreeMap<String, String>> {
let is_git_repo = run_git_command_with_timeout(&["rev-parse", "--git-dir"], cwd)
.await?
.status
.success();
if !is_git_repo {
return None;
}
get_git_remote_urls_assume_git_repo(cwd).await
}
/// Collect fetch remotes without checking whether `cwd` is in a git repo.
pub async fn get_git_remote_urls_assume_git_repo(cwd: &Path) -> Option<BTreeMap<String, String>> {
let output = run_git_command_with_timeout(&["remote", "-v"], cwd).await?;
if !output.status.success() {
return None;
}
let stdout = String::from_utf8(output.stdout).ok()?;
parse_git_remote_urls(stdout.as_str())
}
/// Return the current HEAD commit hash without checking whether `cwd` is in a git repo.
pub async fn get_head_commit_hash(cwd: &Path) -> Option<String> {
let output = run_git_command_with_timeout(&["rev-parse", "HEAD"], cwd).await?;
if !output.status.success() {
return None;
}
let stdout = String::from_utf8(output.stdout).ok()?;
let hash = stdout.trim();
if hash.is_empty() {
None
} else {
Some(hash.to_string())
}
}
fn parse_git_remote_urls(stdout: &str) -> Option<BTreeMap<String, String>> {
let mut remotes = BTreeMap::new();
for line in stdout.lines() {
let Some(fetch_line) = line.strip_suffix(" (fetch)") else {
continue;
};
let Some((name, url_part)) = fetch_line
.split_once('\t')
.or_else(|| fetch_line.split_once(' '))
else {
continue;
};
let url = url_part.trim_start();
if !url.is_empty() {
remotes.insert(name.to_string(), url.to_string());
}
}
if remotes.is_empty() {
None
} else {
Some(remotes)
}
}
/// A minimal commit summary entry used for pickers (subject + timestamp + sha).
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CommitLogEntry {
@@ -185,11 +253,9 @@ pub async fn git_diff_to_remote(cwd: &Path) -> Option<GitDiffToRemote> {
/// Run a git command with a timeout to prevent blocking on large repositories
async fn run_git_command_with_timeout(args: &[&str], cwd: &Path) -> Option<std::process::Output> {
let result = timeout(
GIT_COMMAND_TIMEOUT,
Command::new("git").args(args).current_dir(cwd).output(),
)
.await;
let mut command = Command::new("git");
command.args(args).current_dir(cwd).kill_on_drop(true);
let result = timeout(GIT_COMMAND_TIMEOUT, command.output()).await;
match result {
Ok(Ok(output)) => Some(output),

View File

@@ -39,6 +39,7 @@ impl From<UserInstructions> for ResponseItem {
),
}],
end_turn: None,
phase: None,
}
}
}
@@ -73,6 +74,7 @@ impl From<SkillInstructions> for ResponseItem {
),
}],
end_turn: None,
phase: None,
}
}
}

View File

@@ -101,6 +101,7 @@ pub mod state_db;
pub mod terminal;
mod tools;
pub mod turn_diff_tracker;
mod turn_metadata;
pub use rollout::ARCHIVED_SESSIONS_SUBDIR;
pub use rollout::INTERACTIVE_SESSION_SOURCES;
pub use rollout::RolloutRecorder;
@@ -131,6 +132,7 @@ pub mod util;
pub use apply_patch::CODEX_APPLY_PATCH_ARG1;
pub use client::WEB_SEARCH_ELIGIBLE_HEADER;
pub use client::X_CODEX_TURN_METADATA_HEADER;
pub use command_safety::is_dangerous_command;
pub use command_safety::is_safe_command;
pub use exec_policy::ExecPolicyError;

View File

@@ -1,6 +1,5 @@
pub mod auth;
mod skill_dependencies;
pub(crate) use skill_dependencies::maybe_prompt_and_install_mcp_dependencies;
use std::collections::HashMap;
@@ -9,9 +8,12 @@ use std::path::PathBuf;
use std::time::Duration;
use async_channel::unbounded;
use codex_protocol::mcp::Resource;
use codex_protocol::mcp::ResourceTemplate;
use codex_protocol::mcp::Tool;
use codex_protocol::protocol::McpListToolsResponseEvent;
use codex_protocol::protocol::SandboxPolicy;
use mcp_types::Tool as McpTool;
use serde_json::Value;
use tokio_util::sync::CancellationToken;
use crate::AuthManager;
@@ -201,8 +203,8 @@ pub fn split_qualified_tool_name(qualified_name: &str) -> Option<(String, String
}
pub fn group_tools_by_server(
tools: &HashMap<String, McpTool>,
) -> HashMap<String, HashMap<String, McpTool>> {
tools: &HashMap<String, Tool>,
) -> HashMap<String, HashMap<String, Tool>> {
let mut grouped = HashMap::new();
for (qualified_name, tool) in tools {
if let Some((server_name, tool_name)) = split_qualified_tool_name(qualified_name) {
@@ -230,11 +232,96 @@ pub(crate) async fn collect_mcp_snapshot_from_manager(
.map(|(name, entry)| (name.clone(), entry.auth_status))
.collect();
let tools = tools
.into_iter()
.filter_map(|(name, tool)| match serde_json::to_value(tool.tool) {
Ok(value) => match Tool::from_mcp_value(value) {
Ok(tool) => Some((name, tool)),
Err(err) => {
tracing::warn!("Failed to convert MCP tool '{name}': {err}");
None
}
},
Err(err) => {
tracing::warn!("Failed to serialize MCP tool '{name}': {err}");
None
}
})
.collect();
let resources = resources
.into_iter()
.map(|(name, resources)| {
let resources = resources
.into_iter()
.filter_map(|resource| match serde_json::to_value(resource) {
Ok(value) => match Resource::from_mcp_value(value.clone()) {
Ok(resource) => Some(resource),
Err(err) => {
let (uri, resource_name) = match value {
Value::Object(obj) => (
obj.get("uri")
.and_then(|v| v.as_str().map(ToString::to_string)),
obj.get("name")
.and_then(|v| v.as_str().map(ToString::to_string)),
),
_ => (None, None),
};
tracing::warn!(
"Failed to convert MCP resource (uri={uri:?}, name={resource_name:?}): {err}"
);
None
}
},
Err(err) => {
tracing::warn!("Failed to serialize MCP resource: {err}");
None
}
})
.collect::<Vec<_>>();
(name, resources)
})
.collect();
let resource_templates = resource_templates
.into_iter()
.map(|(name, templates)| {
let templates = templates
.into_iter()
.filter_map(|template| match serde_json::to_value(template) {
Ok(value) => match ResourceTemplate::from_mcp_value(value.clone()) {
Ok(template) => Some(template),
Err(err) => {
let (uri_template, template_name) = match value {
Value::Object(obj) => (
obj.get("uriTemplate")
.or_else(|| obj.get("uri_template"))
.and_then(|v| v.as_str().map(ToString::to_string)),
obj.get("name")
.and_then(|v| v.as_str().map(ToString::to_string)),
),
_ => (None, None),
};
tracing::warn!(
"Failed to convert MCP resource template (uri_template={uri_template:?}, name={template_name:?}): {err}"
);
None
}
},
Err(err) => {
tracing::warn!("Failed to serialize MCP resource template: {err}");
None
}
})
.collect::<Vec<_>>();
(name, templates)
})
.collect();
McpListToolsResponseEvent {
tools: tools
.into_iter()
.map(|(name, tool)| (name, tool.tool))
.collect(),
tools,
resources,
resource_templates,
auth_statuses,
@@ -244,21 +331,18 @@ pub(crate) async fn collect_mcp_snapshot_from_manager(
#[cfg(test)]
mod tests {
use super::*;
use mcp_types::ToolInputSchema;
use pretty_assertions::assert_eq;
fn make_tool(name: &str) -> McpTool {
McpTool {
annotations: None,
description: None,
input_schema: ToolInputSchema {
properties: None,
required: None,
r#type: "object".to_string(),
},
fn make_tool(name: &str) -> Tool {
Tool {
name: name.to_string(),
output_schema: None,
title: None,
description: None,
input_schema: serde_json::json!({"type": "object", "properties": {}}),
output_schema: None,
annotations: None,
icons: None,
meta: None,
}
}

View File

@@ -23,6 +23,8 @@ use async_channel::Sender;
use codex_async_utils::CancelErr;
use codex_async_utils::OrCancelExt;
use codex_protocol::approvals::ElicitationRequestEvent;
use codex_protocol::mcp::CallToolResult;
use codex_protocol::mcp::RequestId as ProtocolRequestId;
use codex_protocol::protocol::Event;
use codex_protocol::protocol::EventMsg;
use codex_protocol::protocol::McpStartupCompleteEvent;
@@ -37,22 +39,23 @@ use codex_rmcp_client::SendElicitation;
use futures::future::BoxFuture;
use futures::future::FutureExt;
use futures::future::Shared;
use mcp_types::ClientCapabilities;
use mcp_types::Implementation;
use mcp_types::ListResourceTemplatesRequestParams;
use mcp_types::ListResourceTemplatesResult;
use mcp_types::ListResourcesRequestParams;
use mcp_types::ListResourcesResult;
use mcp_types::ReadResourceRequestParams;
use mcp_types::ReadResourceResult;
use mcp_types::RequestId;
use mcp_types::Resource;
use mcp_types::ResourceTemplate;
use mcp_types::Tool;
use rmcp::model::ClientCapabilities;
use rmcp::model::ElicitationCapability;
use rmcp::model::Implementation;
use rmcp::model::InitializeRequestParam;
use rmcp::model::ListResourceTemplatesResult;
use rmcp::model::ListResourcesResult;
use rmcp::model::PaginatedRequestParam;
use rmcp::model::ProtocolVersion;
use rmcp::model::ReadResourceRequestParam;
use rmcp::model::ReadResourceResult;
use rmcp::model::RequestId;
use rmcp::model::Resource;
use rmcp::model::ResourceTemplate;
use rmcp::model::Tool;
use serde::Deserialize;
use serde::Serialize;
use serde_json::json;
use sha1::Digest;
use sha1::Sha1;
use tokio::sync::Mutex;
@@ -198,7 +201,14 @@ impl ElicitationRequestManager {
id: "mcp_elicitation_request".to_string(),
msg: EventMsg::ElicitationRequest(ElicitationRequestEvent {
server_name,
id,
id: match id.clone() {
rmcp::model::NumberOrString::String(value) => {
ProtocolRequestId::String(value.to_string())
}
rmcp::model::NumberOrString::Number(value) => {
ProtocolRequestId::Integer(value)
}
},
message: elicitation.message,
}),
})
@@ -493,7 +503,7 @@ impl McpConnectionManager {
let mut cursor: Option<String> = None;
loop {
let params = cursor.as_ref().map(|next| ListResourcesRequestParams {
let params = cursor.as_ref().map(|next| PaginatedRequestParam {
cursor: Some(next.clone()),
});
let response = match client.list_resources(params, timeout).await {
@@ -558,11 +568,9 @@ impl McpConnectionManager {
let mut cursor: Option<String> = None;
loop {
let params = cursor
.as_ref()
.map(|next| ListResourceTemplatesRequestParams {
cursor: Some(next.clone()),
});
let params = cursor.as_ref().map(|next| PaginatedRequestParam {
cursor: Some(next.clone()),
});
let response = match client.list_resource_templates(params, timeout).await {
Ok(result) => result,
Err(err) => return (server_name_cloned, Err(err)),
@@ -615,7 +623,7 @@ impl McpConnectionManager {
server: &str,
tool: &str,
arguments: Option<serde_json::Value>,
) -> Result<mcp_types::CallToolResult> {
) -> Result<CallToolResult> {
let client = self.client_by_name(server).await?;
if !client.tool_filter.allows(tool) {
return Err(anyhow!(
@@ -623,18 +631,34 @@ impl McpConnectionManager {
));
}
client
let result: rmcp::model::CallToolResult = client
.client
.call_tool(tool.to_string(), arguments, client.tool_timeout)
.await
.with_context(|| format!("tool call failed for `{server}/{tool}`"))
.with_context(|| format!("tool call failed for `{server}/{tool}`"))?;
let content = result
.content
.into_iter()
.map(|content| {
serde_json::to_value(content)
.unwrap_or_else(|_| serde_json::Value::String("<content>".to_string()))
})
.collect();
Ok(CallToolResult {
content,
structured_content: result.structured_content,
is_error: result.is_error,
meta: result.meta.and_then(|meta| serde_json::to_value(meta).ok()),
})
}
/// List resources from the specified server.
pub async fn list_resources(
&self,
server: &str,
params: Option<ListResourcesRequestParams>,
params: Option<PaginatedRequestParam>,
) -> Result<ListResourcesResult> {
let managed = self.client_by_name(server).await?;
let timeout = managed.tool_timeout;
@@ -650,7 +674,7 @@ impl McpConnectionManager {
pub async fn list_resource_templates(
&self,
server: &str,
params: Option<ListResourceTemplatesRequestParams>,
params: Option<PaginatedRequestParam>,
) -> Result<ListResourceTemplatesResult> {
let managed = self.client_by_name(server).await?;
let client = managed.client.clone();
@@ -666,7 +690,7 @@ impl McpConnectionManager {
pub async fn read_resource(
&self,
server: &str,
params: ReadResourceRequestParams,
params: ReadResourceRequestParam,
) -> Result<ReadResourceResult> {
let managed = self.client_by_name(server).await?;
let client = managed.client.clone();
@@ -849,25 +873,25 @@ async fn start_server_task(
tx_event: Sender<Event>,
elicitation_requests: ElicitationRequestManager,
) -> Result<ManagedClient, StartupOutcomeError> {
let params = mcp_types::InitializeRequestParams {
let params = InitializeRequestParam {
capabilities: ClientCapabilities {
experimental: None,
roots: None,
sampling: None,
// https://modelcontextprotocol.io/specification/2025-06-18/client/elicitation#capabilities
// indicates this should be an empty object.
elicitation: Some(json!({})),
elicitation: Some(ElicitationCapability {
schema_validation: None,
}),
},
client_info: Implementation {
name: "codex-mcp-client".to_owned(),
version: env!("CARGO_PKG_VERSION").to_owned(),
title: Some("Codex".into()),
// This field is used by Codex when it is an MCP
// server: it should not be used when Codex is
// an MCP client.
user_agent: None,
icons: None,
website_url: None,
},
protocol_version: mcp_types::MCP_SCHEMA_VERSION.to_owned(),
protocol_version: ProtocolVersion::V_2025_06_18,
};
let send_elicitation = elicitation_requests.make_sender(server_name.clone(), tx_event);
@@ -964,7 +988,7 @@ async fn list_tools_for_client(
}
ToolInfo {
server_name: server_name.to_owned(),
tool_name: tool_def.name.clone(),
tool_name: tool_def.name.to_string(),
tool: tool_def,
connector_id: tool.connector_id,
connector_name,
@@ -1047,24 +1071,23 @@ mod mcp_init_error_display_tests {}
mod tests {
use super::*;
use codex_protocol::protocol::McpAuthStatus;
use mcp_types::ToolInputSchema;
use rmcp::model::JsonObject;
use std::collections::HashSet;
use std::sync::Arc;
fn create_test_tool(server_name: &str, tool_name: &str) -> ToolInfo {
ToolInfo {
server_name: server_name.to_string(),
tool_name: tool_name.to_string(),
tool: Tool {
annotations: None,
description: Some(format!("Test tool: {tool_name}")),
input_schema: ToolInputSchema {
properties: None,
required: None,
r#type: "object".to_string(),
},
name: tool_name.to_string(),
output_schema: None,
name: tool_name.to_string().into(),
title: None,
description: Some(format!("Test tool: {tool_name}").into()),
input_schema: Arc::new(JsonObject::default()),
output_schema: None,
annotations: None,
icons: None,
meta: None,
},
connector_id: None,
connector_name: None,

View File

@@ -10,6 +10,7 @@ use crate::protocol::EventMsg;
use crate::protocol::McpInvocation;
use crate::protocol::McpToolCallBeginEvent;
use crate::protocol::McpToolCallEndEvent;
use codex_protocol::mcp::CallToolResult;
use codex_protocol::models::FunctionCallOutputPayload;
use codex_protocol::models::ResponseInputItem;
use codex_protocol::protocol::AskForApproval;
@@ -18,7 +19,7 @@ use codex_protocol::request_user_input::RequestUserInputArgs;
use codex_protocol::request_user_input::RequestUserInputQuestion;
use codex_protocol::request_user_input::RequestUserInputQuestionOption;
use codex_protocol::request_user_input::RequestUserInputResponse;
use mcp_types::ToolAnnotations;
use rmcp::model::ToolAnnotations;
use std::sync::Arc;
/// Handles the specified tool call dispatches the appropriate
@@ -72,7 +73,7 @@ pub(crate) async fn handle_mcp_tool_call(
.await;
let start = Instant::now();
let result = sess
let result: Result<CallToolResult, String> = sess
.call_tool(&server, &tool_name, arguments_value.clone())
.await
.map_err(|e| format!("tool call error: {e:?}"));
@@ -134,7 +135,7 @@ pub(crate) async fn handle_mcp_tool_call(
let start = Instant::now();
// Perform the tool call.
let result = sess
let result: Result<CallToolResult, String> = sess
.call_tool(&server, &tool_name, arguments_value.clone())
.await
.map_err(|e| format!("tool call error: {e:?}"));
@@ -341,7 +342,7 @@ async fn notify_mcp_tool_call_skip(
call_id: &str,
invocation: McpInvocation,
message: String,
) -> Result<mcp_types::CallToolResult, String> {
) -> Result<CallToolResult, String> {
let tool_call_begin_event = EventMsg::McpToolCallBegin(McpToolCallBeginEvent {
call_id: call_id.to_string(),
invocation: invocation.clone(),

View File

@@ -27,7 +27,7 @@ impl ModelsCacheManager {
}
/// Attempt to load a fresh cache entry. Returns `None` if the cache doesn't exist or is stale.
pub(crate) async fn load_fresh(&self) -> Option<ModelsCache> {
pub(crate) async fn load_fresh(&self, expected_version: &str) -> Option<ModelsCache> {
let cache = match self.load().await {
Ok(cache) => cache?,
Err(err) => {
@@ -35,6 +35,9 @@ impl ModelsCacheManager {
return None;
}
};
if cache.client_version.as_deref() != Some(expected_version) {
return None;
}
if !cache.is_fresh(self.cache_ttl) {
return None;
}
@@ -42,10 +45,16 @@ impl ModelsCacheManager {
}
/// Persist the cache to disk, creating parent directories as needed.
pub(crate) async fn persist_cache(&self, models: &[ModelInfo], etag: Option<String>) {
pub(crate) async fn persist_cache(
&self,
models: &[ModelInfo],
etag: Option<String>,
client_version: String,
) {
let cache = ModelsCache {
fetched_at: Utc::now(),
etag,
client_version: Some(client_version),
models: models.to_vec(),
};
if let Err(err) = self.save_internal(&cache).await {
@@ -103,6 +112,20 @@ impl ModelsCacheManager {
f(&mut cache.fetched_at);
self.save_internal(&cache).await
}
#[cfg(test)]
/// Mutate the full cache contents for testing.
pub(crate) async fn mutate_cache_for_test<F>(&self, f: F) -> io::Result<()>
where
F: FnOnce(&mut ModelsCache),
{
let mut cache = match self.load().await? {
Some(cache) => cache,
None => return Err(io::Error::new(ErrorKind::NotFound, "cache not found")),
};
f(&mut cache);
self.save_internal(&cache).await
}
}
/// Serialized snapshot of models and metadata cached on disk.
@@ -111,6 +134,8 @@ pub(crate) struct ModelsCache {
pub(crate) fetched_at: DateTime<Utc>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) etag: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) client_version: Option<String>,
pub(crate) models: Vec<ModelInfo>,
}

View File

@@ -210,7 +210,7 @@ impl ModelsManager {
let transport = ReqwestTransport::new(build_reqwest_client());
let client = ModelsClient::new(transport, api_provider, api_auth);
let client_version = format_client_version_to_whole();
let client_version = crate::models_manager::client_version_to_whole();
let (models, etag) = timeout(
MODELS_REFRESH_TIMEOUT,
client.list_models(&client_version, HeaderMap::new()),
@@ -221,7 +221,9 @@ impl ModelsManager {
self.apply_remote_models(models.clone()).await;
*self.etag.write().await = etag.clone();
self.cache_manager.persist_cache(&models, etag).await;
self.cache_manager
.persist_cache(&models, etag, client_version)
.await;
Ok(())
}
@@ -255,7 +257,8 @@ impl ModelsManager {
async fn try_load_cache(&self) -> bool {
let _timer =
codex_otel::start_global_timer("codex.remote_models.load_cache.duration_ms", &[]);
let cache = match self.cache_manager.load_fresh().await {
let client_version = crate::models_manager::client_version_to_whole();
let cache = match self.cache_manager.load_fresh(&client_version).await {
Some(cache) => cache,
None => return false,
};
@@ -350,16 +353,6 @@ impl ModelsManager {
}
}
/// Convert a client version string to a whole version string (e.g. "1.2.3-alpha.4" -> "1.2.3")
fn format_client_version_to_whole() -> String {
format!(
"{}.{}.{}",
env!("CARGO_PKG_VERSION_MAJOR"),
env!("CARGO_PKG_VERSION_MINOR"),
env!("CARGO_PKG_VERSION_PATCH")
)
}
#[cfg(test)]
mod tests {
use super::*;
@@ -613,6 +606,75 @@ mod tests {
);
}
#[tokio::test]
async fn refresh_available_models_refetches_when_version_mismatch() {
let server = MockServer::start().await;
let initial_models = vec![remote_model("old", "Old", 1)];
let initial_mock = mount_models_once(
&server,
ModelsResponse {
models: initial_models.clone(),
},
)
.await;
let codex_home = tempdir().expect("temp dir");
let mut config = ConfigBuilder::default()
.codex_home(codex_home.path().to_path_buf())
.build()
.await
.expect("load default test config");
config.features.enable(Feature::RemoteModels);
let auth_manager = Arc::new(AuthManager::new(
codex_home.path().to_path_buf(),
false,
AuthCredentialsStoreMode::File,
));
let provider = provider_for(server.uri());
let manager =
ModelsManager::with_provider(codex_home.path().to_path_buf(), auth_manager, provider);
manager
.refresh_available_models(&config, RefreshStrategy::OnlineIfUncached)
.await
.expect("initial refresh succeeds");
manager
.cache_manager
.mutate_cache_for_test(|cache| {
let client_version = crate::models_manager::client_version_to_whole();
cache.client_version = Some(format!("{client_version}-mismatch"));
})
.await
.expect("cache mutation succeeds");
let updated_models = vec![remote_model("new", "New", 2)];
server.reset().await;
let refreshed_mock = mount_models_once(
&server,
ModelsResponse {
models: updated_models.clone(),
},
)
.await;
manager
.refresh_available_models(&config, RefreshStrategy::OnlineIfUncached)
.await
.expect("second refresh succeeds");
assert_models_contain(&manager.get_remote_models(&config).await, &updated_models);
assert_eq!(
initial_mock.requests().len(),
1,
"initial refresh should only hit /models once"
);
assert_eq!(
refreshed_mock.requests().len(),
1,
"version mismatch should fetch /models once"
);
}
#[tokio::test]
async fn refresh_available_models_drops_removed_remote_models() {
let server = MockServer::start().await;

View File

@@ -6,3 +6,13 @@ pub mod model_presets;
#[cfg(any(test, feature = "test-support"))]
pub use collaboration_mode_presets::test_builtin_collaboration_mode_presets;
/// Convert the client version string to a whole version string (e.g. "1.2.3-alpha.4" -> "1.2.3").
pub fn client_version_to_whole() -> String {
format!(
"{}.{}.{}",
env!("CARGO_PKG_VERSION_MAJOR"),
env!("CARGO_PKG_VERSION_MINOR"),
env!("CARGO_PKG_VERSION_PATCH")
)
}

View File

@@ -9,6 +9,7 @@ use codex_protocol::openai_models::ReasoningEffort;
use codex_protocol::openai_models::ReasoningEffortPreset;
use codex_protocol::openai_models::TruncationMode;
use codex_protocol::openai_models::TruncationPolicyConfig;
use codex_protocol::openai_models::default_input_modalities;
use crate::config::Config;
use crate::features::Feature;
@@ -66,6 +67,7 @@ macro_rules! model_info {
auto_compact_token_limit: None,
effective_context_window_percent: 95,
experimental_supported_tools: Vec::new(),
input_modalities: default_input_modalities(),
};
$(

View File

@@ -3,6 +3,7 @@ use codex_protocol::openai_models::ModelPreset;
use codex_protocol::openai_models::ModelUpgrade;
use codex_protocol::openai_models::ReasoningEffort;
use codex_protocol::openai_models::ReasoningEffortPreset;
use codex_protocol::openai_models::default_input_modalities;
use indoc::indoc;
use once_cell::sync::Lazy;
@@ -41,6 +42,7 @@ static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
upgrade: None,
show_in_picker: true,
supported_in_api: true,
input_modalities: default_input_modalities(),
},
ModelPreset {
id: "gpt-5.1-codex-max".to_string(),
@@ -71,6 +73,7 @@ static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
upgrade: Some(gpt_52_codex_upgrade()),
show_in_picker: true,
supported_in_api: true,
input_modalities: default_input_modalities(),
},
ModelPreset {
id: "gpt-5.1-codex-mini".to_string(),
@@ -94,6 +97,7 @@ static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
upgrade: Some(gpt_52_codex_upgrade()),
show_in_picker: true,
supported_in_api: true,
input_modalities: default_input_modalities(),
},
ModelPreset {
id: "gpt-5.2".to_string(),
@@ -124,6 +128,7 @@ static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
upgrade: Some(gpt_52_codex_upgrade()),
show_in_picker: true,
supported_in_api: true,
input_modalities: default_input_modalities(),
},
ModelPreset {
id: "bengalfox".to_string(),
@@ -154,6 +159,7 @@ static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
upgrade: None,
show_in_picker: false,
supported_in_api: true,
input_modalities: default_input_modalities(),
},
ModelPreset {
id: "boomslang".to_string(),
@@ -184,6 +190,7 @@ static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
upgrade: None,
show_in_picker: false,
supported_in_api: true,
input_modalities: default_input_modalities(),
},
// Deprecated models.
ModelPreset {
@@ -211,6 +218,7 @@ static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
upgrade: Some(gpt_52_codex_upgrade()),
show_in_picker: false,
supported_in_api: true,
input_modalities: default_input_modalities(),
},
ModelPreset {
id: "gpt-5-codex-mini".to_string(),
@@ -233,6 +241,7 @@ static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
upgrade: Some(gpt_52_codex_upgrade()),
show_in_picker: false,
supported_in_api: true,
input_modalities: default_input_modalities(),
},
ModelPreset {
id: "gpt-5.1-codex".to_string(),
@@ -260,6 +269,7 @@ static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
upgrade: Some(gpt_52_codex_upgrade()),
show_in_picker: false,
supported_in_api: true,
input_modalities: default_input_modalities(),
},
ModelPreset {
id: "gpt-5".to_string(),
@@ -290,6 +300,7 @@ static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
upgrade: Some(gpt_52_codex_upgrade()),
show_in_picker: false,
supported_in_api: true,
input_modalities: default_input_modalities(),
},
ModelPreset {
id: "gpt-5.1".to_string(),
@@ -316,6 +327,7 @@ static PRESETS: Lazy<Vec<ModelPreset>> = Lazy::new(|| {
upgrade: Some(gpt_52_codex_upgrade()),
show_in_picker: false,
supported_in_api: true,
input_modalities: default_input_modalities(),
},
]
});

View File

@@ -902,6 +902,7 @@ async fn test_updated_at_uses_file_mtime() -> Result<()> {
text: format!("reply-{idx}"),
}],
end_turn: None,
phase: None,
}),
};
writeln!(file, "{}", serde_json::to_string(&response_line)?)?;

Some files were not shown because too many files have changed in this diff Show More