Merge remote-tracking branch 'origin/main' into codex/pr27914-refresh

This commit is contained in:
Chris Bookholt
2026-06-22 10:54:48 -07:00
676 changed files with 32581 additions and 7097 deletions
+4 -1
View File
@@ -31,7 +31,10 @@ Keep these requirements in mind while migrating code to conform with the above g
* path reasoning must work before the related environment has come online
* URIs cannot explicitly encode the executor’s path convention or operating system
* users must not configure the environment’s OS/path convention explicitly
* URIs should not yet be stored in rollouts
* URIs should not yet be stored in rollouts, databases, or other persistent storage
* path conversion errors: fail-closed for security-relevant paths, fail-open for UI/diagnostics
* prefer small focused methods on `PathUri` or `LegacyAppPathString` over local helpers
* represent `PathUri` values as URIs in diagnostics
It is OK if the conversion between paths and URIs is somewhat lossy as long as it will do the right
thing for real users.
+1
View File
@@ -105,6 +105,7 @@ Codex maintains a context (history of messages) that is sent to the model in inf
Search for breaking changes in external integration surfaces:
- app-server APIs
- raw response item events (`rawResponseItem/*`), even while experimental
- CLI parameters
- configuration loading
- resuming sessions from existing rollouts
+8 -9
View File
@@ -2,18 +2,17 @@ module(name = "codex")
bazel_dep(name = "bazel_skylib", version = "1.9.0")
bazel_dep(name = "platforms", version = "1.0.0")
bazel_dep(name = "llvm", version = "0.7.1")
bazel_dep(name = "llvm", version = "0.7.9")
# The upstream LLVM archive contains a few unix-only symlink entries and is
# missing a couple of MinGW compatibility archives that windows-gnullvm needs
# during extraction and linking, so patch it until upstream grows native support.
# Patch hermetic LLVM for Codex's custom libc++ and Windows gnullvm runtime
# needs that have not landed upstream.
single_version_override(
module_name = "llvm",
patch_strip = 1,
patches = [
"//patches:llvm_rusty_v8_custom_libcxx.patch",
"//patches:llvm_windows_arm64_powl.patch",
"//patches:llvm_windows_symlink_extract.patch",
"//patches:llvm_windows_mingw_compat.patch",
],
)
@@ -31,11 +30,11 @@ register_toolchains("@llvm//toolchain:all")
osx = use_extension("@llvm//extensions:osx.bzl", "osx")
osx.from_archive(
sha256 = "1bde70c0b1c2ab89ff454acbebf6741390d7b7eb149ca2a3ca24cc9203a408b7",
strip_prefix = "Payload/Library/Developer/CommandLineTools/SDKs/MacOSX26.4.sdk",
sha256 = "5f044578cd78a3a9b9c965a42d56bad609ee5d252e1d4e6aa7c42fc3f35fee7b",
strip_prefix = "Payload/Library/Developer/CommandLineTools/SDKs/MacOSX26.5.sdk",
type = "pkg",
urls = [
"https://swcdn.apple.com/content/downloads/32/53/047-96692-A_OAHIHT53YB/ybtshxmrcju8m2qvw3w5elr4rajtg1x3y3/CLTools_macOSNMOS_SDK.pkg",
"https://swcdn.apple.com/content/downloads/09/08/047-91568-A_Y1CFZWQCD4/4xekpyz43i26dbp4enxfro8eb1q7wiujh5/CLTools_macOSNMOS_SDK.pkg",
],
)
osx.frameworks(names = [
@@ -80,7 +79,7 @@ use_repo(osx, "macos_sdk")
# Needed to disable xcode...
bazel_dep(name = "apple_support", version = "2.1.0")
bazel_dep(name = "rules_cc", version = "0.2.16")
bazel_dep(name = "rules_cc", version = "0.2.18")
single_version_override(
module_name = "rules_cc",
patch_strip = 1,
+9 -5
View File
@@ -45,6 +45,7 @@
"https://bcr.bazel.build/modules/bazel_features/1.34.0/MODULE.bazel": "e8475ad7c8965542e0c7aac8af68eb48c4af904be3d614b6aa6274c092c2ea1e",
"https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7",
"https://bcr.bazel.build/modules/bazel_features/1.42.0/MODULE.bazel": "e8ca15cb2639c5f12183db6dcb678735555d0cdd739b32a0418b6532b5e565f8",
"https://bcr.bazel.build/modules/bazel_features/1.43.0/MODULE.bazel": "defa2226f06ba20550d6548c3a2ea2a7929634437a52973869c20c225450eb91",
"https://bcr.bazel.build/modules/bazel_features/1.45.0/MODULE.bazel": "7daec6d87ab0703417486d4cb948af0b06f55d4d7c08cbb5978c80e79b538edf",
"https://bcr.bazel.build/modules/bazel_features/1.45.0/source.json": "635e4536e09ff125b8972e0fa239c135fde5f18701f7d5115680560651dfb41d",
"https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b",
@@ -63,6 +64,7 @@
"https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917",
"https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d",
"https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.0/MODULE.bazel": "2fb3fb53675f6adfc1ca5bfbd5cfb655ae350fba4706d924a8ec7e3ba945671c",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6",
"https://bcr.bazel.build/modules/bazel_skylib/1.8.2/MODULE.bazel": "69ad6927098316848b34a9142bcc975e018ba27f08c4ff403f50c1b6e646ca67",
"https://bcr.bazel.build/modules/bazel_skylib/1.9.0/MODULE.bazel": "72997b29dfd95c3fa0d0c48322d05590418edef451f8db8db5509c57875fb4b7",
@@ -87,8 +89,8 @@
"https://bcr.bazel.build/modules/libcap/2.27.bcr.1/source.json": "3b116cbdbd25a68ffb587b672205f6d353a4c19a35452e480d58fc89531e0a10",
"https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902",
"https://bcr.bazel.build/modules/llvm/0.7.0/MODULE.bazel": "3c07a4e5734b0ad41fe24dedaacbf3a35ce4377b7e1a21f24488a0c9ac4f1e6b",
"https://bcr.bazel.build/modules/llvm/0.7.1/MODULE.bazel": "74ac75efc6385b8a95d83bfa36ad399500f747c3d0f50287f9b6f9e854ec4814",
"https://bcr.bazel.build/modules/llvm/0.7.1/source.json": "0cac59d04dafa0ca1f70ea21cf1569e034ef8736c2c7510e834a9e8141d7e631",
"https://bcr.bazel.build/modules/llvm/0.7.9/MODULE.bazel": "452b272a6b5ecc8747db8e5b7fd9d6799ef0db17b8d437aa8d4dda4f56a3e9ea",
"https://bcr.bazel.build/modules/llvm/0.7.9/source.json": "0c098ab546a8c4b0a720dcb010714e13f9ba6ceab0d23a87b7f1083788928c31",
"https://bcr.bazel.build/modules/nlohmann_json/3.6.1/MODULE.bazel": "6f7b417dcc794d9add9e556673ad25cb3ba835224290f4f848f8e2db1e1fca74",
"https://bcr.bazel.build/modules/openssl/3.5.4.bcr.0/MODULE.bazel": "0f6b8f20b192b9ff0781406256150bcd46f19e66d807dcb0c540548439d6fc35",
"https://bcr.bazel.build/modules/openssl/3.5.4.bcr.0/source.json": "543ed7627cc18e6460b9c1ae4a1b6b1debc5a5e0aca878b00f7531c7186b73da",
@@ -143,7 +145,8 @@
"https://bcr.bazel.build/modules/rules_cc/0.2.13/MODULE.bazel": "eecdd666eda6be16a8d9dc15e44b5c75133405e820f620a234acc4b1fdc5aa37",
"https://bcr.bazel.build/modules/rules_cc/0.2.14/MODULE.bazel": "353c99ed148887ee89c54a17d4100ae7e7e436593d104b668476019023b58df8",
"https://bcr.bazel.build/modules/rules_cc/0.2.16/MODULE.bazel": "9242fa89f950c6ef7702801ab53922e99c69b02310c39fb6e62b2bd30df2a1d4",
"https://bcr.bazel.build/modules/rules_cc/0.2.16/source.json": "d03d5cde49376d87e14ec14b666c56075e5e3926930327fd5d0484a1ff2ac1cc",
"https://bcr.bazel.build/modules/rules_cc/0.2.18/MODULE.bazel": "4460ec36adc8f722a6a2a4ac9374cb91f2acebadaa93fc37966129afb3dece87",
"https://bcr.bazel.build/modules/rules_cc/0.2.18/source.json": "abad668ff2fd63ada1ac49bf386d37e27048b89a3465a6fd968bb832b00a09d3",
"https://bcr.bazel.build/modules/rules_cc/0.2.4/MODULE.bazel": "1ff1223dfd24f3ecf8f028446d4a27608aa43c3f41e346d22838a4223980b8cc",
"https://bcr.bazel.build/modules/rules_cc/0.2.8/MODULE.bazel": "f1df20f0bf22c28192a794f29b501ee2018fa37a3862a1a2132ae2940a23a642",
"https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
@@ -221,8 +224,9 @@
"https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216",
"https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91",
"https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/MODULE.bazel": "75aab2373a4bbe2a1260b9bf2a1ebbdbf872d3bd36f80bff058dccd82e89422f",
"https://bcr.bazel.build/modules/tar.bzl/0.10.4/MODULE.bazel": "e8f9ff79199e8d9eaad7f1b0a77ad74b30bb82d794b87d8ca942bead5de83ae9",
"https://bcr.bazel.build/modules/tar.bzl/0.10.4/source.json": "20143442376c03426f6135292ba02d825cb75308aa47e6bf42dd4cc5a435c2ff",
"https://bcr.bazel.build/modules/tar.bzl/0.9.0/MODULE.bazel": "452a22d7f02b1c9d7a22ab25edf20f46f3e1101f0f67dc4bfbf9a474ddf02445",
"https://bcr.bazel.build/modules/tar.bzl/0.9.0/source.json": "c732760a374831a2cf5b08839e4be75017196b4d796a5aa55235272ee17cd839",
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
"https://bcr.bazel.build/modules/with_cfg.bzl/0.12.0/MODULE.bazel": "b573395fe63aef4299ba095173e2f62ccfee5ad9bbf7acaa95dba73af9fc2b38",
"https://bcr.bazel.build/modules/with_cfg.bzl/0.12.0/source.json": "3f3fbaeafecaf629877ad152a2c9def21f8d330d91aa94c5dc75bbb98c10b8b8",
@@ -982,7 +986,7 @@
"git+https://github.com/juberti-oai/rust-sdks.git?rev=e2d1d1d230c6fc9df171ccb181423f957bb3c1f0#e2d1d1d230c6fc9df171ccb181423f957bb3c1f0_webrtc-sys-build": "{\"dependencies\":[{\"name\":\"anyhow\"},{\"name\":\"fs2\"},{\"name\":\"regex\"},{\"default_features\":false,\"features\":[\"rustls-tls-native-roots\",\"blocking\"],\"name\":\"reqwest\",\"optional\":false},{\"name\":\"scratch\"},{\"name\":\"semver\"},{\"name\":\"zip\"}],\"features\":{},\"strip_prefix\":\"webrtc-sys/build\"}",
"git+https://github.com/nornagon/crossterm?rev=87db8bfa6dc99427fd3b071681b07fc31c6ce995#87db8bfa6dc99427fd3b071681b07fc31c6ce995_crossterm": "{\"dependencies\":[{\"default_features\":true,\"features\":[],\"name\":\"bitflags\",\"optional\":false},{\"default_features\":false,\"features\":[],\"name\":\"futures-core\",\"optional\":true},{\"name\":\"parking_lot\"},{\"default_features\":true,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"filedescriptor\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":false,\"features\":[],\"name\":\"libc\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[\"os-poll\"],\"name\":\"mio\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":false,\"features\":[\"std\",\"stdio\",\"termios\"],\"name\":\"rustix\",\"optional\":false,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[],\"name\":\"signal-hook\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[\"support-v1_0\"],\"name\":\"signal-hook-mio\",\"optional\":true,\"target\":\"cfg(unix)\"},{\"default_features\":true,\"features\":[],\"name\":\"crossterm_winapi\",\"optional\":true,\"target\":\"cfg(windows)\"},{\"default_features\":true,\"features\":[\"winuser\",\"winerror\"],\"name\":\"winapi\",\"optional\":true,\"target\":\"cfg(windows)\"}],\"features\":{\"bracketed-paste\":[],\"default\":[\"bracketed-paste\",\"windows\",\"events\"],\"event-stream\":[\"dep:futures-core\",\"events\"],\"events\":[\"dep:mio\",\"dep:signal-hook\",\"dep:signal-hook-mio\"],\"serde\":[\"dep:serde\",\"bitflags/serde\"],\"use-dev-tty\":[\"filedescriptor\",\"rustix/process\"],\"windows\":[\"dep:winapi\",\"dep:crossterm_winapi\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/nornagon/ratatui?rev=9b2ad1298408c45918ee9f8241a6f95498cdbed2#9b2ad1298408c45918ee9f8241a6f95498cdbed2_ratatui": "{\"dependencies\":[{\"name\":\"bitflags\"},{\"name\":\"cassowary\"},{\"name\":\"compact_str\"},{\"default_features\":true,\"features\":[],\"name\":\"crossterm\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"document-features\",\"optional\":true},{\"name\":\"indoc\"},{\"name\":\"instability\"},{\"name\":\"itertools\"},{\"name\":\"lru\"},{\"default_features\":true,\"features\":[],\"name\":\"palette\",\"optional\":true},{\"name\":\"paste\"},{\"default_features\":true,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true},{\"default_features\":true,\"features\":[\"derive\"],\"name\":\"strum\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"termwiz\",\"optional\":true},{\"default_features\":true,\"features\":[\"local-offset\"],\"name\":\"time\",\"optional\":true},{\"name\":\"unicode-segmentation\"},{\"name\":\"unicode-truncate\"},{\"name\":\"unicode-width\"},{\"default_features\":true,\"features\":[],\"name\":\"termion\",\"optional\":true,\"target\":\"cfg(not(windows))\"}],\"features\":{\"all-widgets\":[\"widget-calendar\"],\"crossterm\":[\"dep:crossterm\"],\"default\":[\"crossterm\",\"underline-color\"],\"macros\":[],\"palette\":[\"dep:palette\"],\"scrolling-regions\":[],\"serde\":[\"dep:serde\",\"bitflags/serde\",\"compact_str/serde\"],\"termion\":[\"dep:termion\"],\"termwiz\":[\"dep:termwiz\"],\"underline-color\":[\"dep:crossterm\"],\"unstable\":[\"unstable-rendered-line-info\",\"unstable-widget-ref\",\"unstable-backend-writer\"],\"unstable-backend-writer\":[],\"unstable-rendered-line-info\":[],\"unstable-widget-ref\":[],\"widget-calendar\":[\"dep:time\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/openai-oss-forks/tokio-tungstenite?rev=132f5b39c862e3a970f731d709608b3e6276d5f6#132f5b39c862e3a970f731d709608b3e6276d5f6_tokio-tungstenite": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"sink\",\"std\"],\"name\":\"futures-util\",\"optional\":false},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"default_features\":false,\"features\":[],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":false,\"features\":[\"io-util\"],\"name\":\"tokio\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"tokio-native-tls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tokio-rustls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tungstenite\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\",\"tokio-rustls\",\"stream\",\"tungstenite/__rustls-tls\",\"handshake\"],\"connect\":[\"stream\",\"tokio/net\",\"handshake\"],\"default\":[\"connect\",\"handshake\"],\"handshake\":[\"tungstenite/handshake\"],\"native-tls\":[\"native-tls-crate\",\"tokio-native-tls\",\"stream\",\"tungstenite/native-tls\",\"handshake\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\",\"tungstenite/native-tls-vendored\"],\"proxy\":[\"tungstenite/proxy\",\"tokio/net\",\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"stream\":[],\"url\":[\"tungstenite/url\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/openai-oss-forks/tokio-tungstenite?rev=e5e64b86722c5453c4038131c3193faa49a648ad#e5e64b86722c5453c4038131c3193faa49a648ad_tokio-tungstenite": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"sink\",\"std\"],\"name\":\"futures-util\",\"optional\":false},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"default_features\":false,\"features\":[],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":false,\"features\":[\"io-util\"],\"name\":\"tokio\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"tokio-native-tls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tokio-rustls\",\"optional\":true},{\"default_features\":false,\"features\":[],\"name\":\"tungstenite\",\"optional\":false},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\",\"tokio-rustls\",\"stream\",\"tungstenite/__rustls-tls\",\"handshake\"],\"connect\":[\"stream\",\"tokio/net\",\"tokio/time\",\"handshake\"],\"default\":[\"connect\",\"handshake\"],\"handshake\":[\"tungstenite/handshake\"],\"native-tls\":[\"native-tls-crate\",\"tokio-native-tls\",\"stream\",\"tungstenite/native-tls\",\"handshake\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\",\"tungstenite/native-tls-vendored\"],\"proxy\":[\"tungstenite/proxy\",\"tokio/net\",\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"stream\":[],\"url\":[\"tungstenite/url\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/openai-oss-forks/tungstenite-rs?rev=9200079d3b54a1ff51072e24d81fd354f085156f#9200079d3b54a1ff51072e24d81fd354f085156f_tungstenite": "{\"dependencies\":[{\"name\":\"bytes\"},{\"default_features\":true,\"features\":[],\"name\":\"data-encoding\",\"optional\":true},{\"default_features\":false,\"features\":[\"zlib\"],\"name\":\"flate2\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"headers\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"http\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"httparse\",\"optional\":true},{\"name\":\"log\"},{\"default_features\":true,\"features\":[],\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\"},{\"name\":\"rand\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"rustls\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-native-certs\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"rustls-pki-types\",\"optional\":true},{\"default_features\":true,\"features\":[],\"name\":\"sha1\",\"optional\":true},{\"name\":\"thiserror\"},{\"default_features\":true,\"features\":[],\"name\":\"url\",\"optional\":true},{\"name\":\"utf-8\"},{\"default_features\":true,\"features\":[],\"name\":\"webpki-roots\",\"optional\":true}],\"features\":{\"__rustls-tls\":[\"rustls\",\"rustls-pki-types\"],\"default\":[\"handshake\"],\"deflate\":[\"headers\",\"flate2\"],\"handshake\":[\"data-encoding\",\"headers\",\"httparse\",\"sha1\"],\"headers\":[\"http\",\"dep:headers\"],\"native-tls\":[\"native-tls-crate\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate/vendored\"],\"proxy\":[\"handshake\"],\"rustls-tls-native-roots\":[\"__rustls-tls\",\"rustls-native-certs\"],\"rustls-tls-webpki-roots\":[\"__rustls-tls\",\"webpki-roots\"],\"url\":[\"dep:url\"]},\"strip_prefix\":\"\"}",
"git+https://github.com/rust-lang/rust-clippy?rev=20ce69b9a63bcd2756cd906fe0964d1e901e042a#20ce69b9a63bcd2756cd906fe0964d1e901e042a_clippy_utils": "{\"dependencies\":[{\"default_features\":false,\"features\":[],\"name\":\"arrayvec\",\"optional\":false},{\"name\":\"itertools\"},{\"name\":\"rustc_apfloat\"},{\"default_features\":true,\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":false}],\"features\":{},\"strip_prefix\":\"clippy_utils\"}",
"git2_0.20.4": "{\"dependencies\":[{\"name\":\"bitflags\",\"req\":\"^2.1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^4.4.13\"},{\"name\":\"libc\",\"req\":\"^0.2\"},{\"name\":\"libgit2-sys\",\"req\":\"^0.18.3\"},{\"name\":\"log\",\"req\":\"^0.4.8\"},{\"name\":\"openssl-probe\",\"optional\":true,\"req\":\"^0.1\",\"target\":\"cfg(all(unix, not(target_os = \\\"macos\\\")))\"},{\"name\":\"openssl-sys\",\"optional\":true,\"req\":\"^0.9.45\",\"target\":\"cfg(all(unix, not(target_os = \\\"macos\\\")))\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.1.0\"},{\"features\":[\"formatting\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3.37\"},{\"name\":\"url\",\"req\":\"^2.5.4\"}],\"features\":{\"default\":[\"ssh\",\"https\"],\"https\":[\"libgit2-sys/https\",\"openssl-sys\",\"openssl-probe\"],\"ssh\":[\"libgit2-sys/ssh\"],\"unstable\":[],\"vendored-libgit2\":[\"libgit2-sys/vendored\"],\"vendored-openssl\":[\"openssl-sys/vendored\",\"libgit2-sys/vendored-openssl\"],\"zlib-ng-compat\":[\"libgit2-sys/zlib-ng-compat\"]}}",
+8
View File
@@ -105,6 +105,14 @@ impl WineTestCommand {
}
impl WineTestProcess {
/// Returns the host path to this process's isolated Wine prefix.
pub fn prefix_path(&self) -> &Path {
let Some(processes) = self.processes.as_ref() else {
panic!("Wine process guard is missing");
};
processes.prefix.path()
}
/// Takes the piped standard output of the Wine process.
///
/// This may only be called once for a process created by
+4 -2
View File
@@ -2418,6 +2418,7 @@ version = "0.0.0"
dependencies = [
"base64 0.22.1",
"chrono",
"codex-agent-identity",
"codex-backend-client",
"codex-config",
"codex-core",
@@ -2808,6 +2809,7 @@ dependencies = [
"codex-utils-plugins",
"dirs",
"dunce",
"futures",
"pretty_assertions",
"serde",
"serde_json",
@@ -3289,6 +3291,7 @@ dependencies = [
"codex-plugin",
"codex-protocol",
"codex-rmcp-client",
"codex-utils-path-uri",
"codex-utils-plugins",
"futures",
"pretty_assertions",
@@ -4270,7 +4273,6 @@ name = "codex-utils-plugins"
version = "0.0.0"
dependencies = [
"codex-exec-server",
"codex-login",
"codex-utils-absolute-path",
"codex-utils-path-uri",
"serde",
@@ -13602,7 +13604,7 @@ dependencies = [
[[package]]
name = "tokio-tungstenite"
version = "0.28.0"
source = "git+https://github.com/openai-oss-forks/tokio-tungstenite?rev=132f5b39c862e3a970f731d709608b3e6276d5f6#132f5b39c862e3a970f731d709608b3e6276d5f6"
source = "git+https://github.com/openai-oss-forks/tokio-tungstenite?rev=e5e64b86722c5453c4038131c3193faa49a648ad#e5e64b86722c5453c4038131c3193faa49a648ad"
dependencies = [
"futures-util",
"log",
+1 -1
View File
@@ -546,7 +546,7 @@ opt-level = 0
# ratatui = { path = "../../ratatui" }
crossterm = { git = "https://github.com/nornagon/crossterm", rev = "87db8bfa6dc99427fd3b071681b07fc31c6ce995" }
ratatui = { git = "https://github.com/nornagon/ratatui", rev = "9b2ad1298408c45918ee9f8241a6f95498cdbed2" }
tokio-tungstenite = { git = "https://github.com/openai-oss-forks/tokio-tungstenite", rev = "132f5b39c862e3a970f731d709608b3e6276d5f6" }
tokio-tungstenite = { git = "https://github.com/openai-oss-forks/tokio-tungstenite", rev = "e5e64b86722c5453c4038131c3193faa49a648ad" }
tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "9200079d3b54a1ff51072e24d81fd354f085156f" }
# Uncomment to debug local changes.
+322 -82
View File
@@ -1,4 +1,6 @@
use std::collections::BTreeMap;
use std::error::Error as StdError;
use std::fmt;
use std::time::Duration;
use anyhow::Context;
@@ -34,21 +36,66 @@ const AGENT_TASK_REGISTRATION_TIMEOUT: Duration = Duration::from_secs(30);
const AGENT_IDENTITY_JWKS_TIMEOUT: Duration = Duration::from_secs(10);
const AGENT_IDENTITY_JWT_AUDIENCE: &str = "codex-app-server";
const AGENT_IDENTITY_JWT_ISSUER: &str = "https://chatgpt.com/codex-backend/agent-identity";
const AGENT_REGISTRATION_TIMEOUT: Duration = Duration::from_secs(15);
const PROD_AGENT_IDENTITY_AUTHAPI_BASE_URL: &str = "https://auth.openai.com/api/accounts";
const STAGING_AGENT_IDENTITY_AUTHAPI_BASE_URL: &str = "https://auth.api.openai.org/api/accounts";
const AGENT_IDENTITY_KEY_SEED_BYTES: usize = 64;
const AGENT_IDENTITY_KEY_DERIVATION_CONTEXT: &[u8] = b"codex-agent-identity-ed25519-v1";
/// Stored key material for a registered agent identity.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum ChatGptEnvironment {
#[default]
Production,
Staging,
}
impl ChatGptEnvironment {
pub fn from_chatgpt_base_url(chatgpt_base_url: &str) -> Result<Self> {
match chatgpt_base_url.trim_end_matches('/') {
"https://chatgpt.com"
| "https://chatgpt.com/backend-api"
| "https://chatgpt.com/codex"
| "https://chatgpt.com/backend-api/codex"
| "https://chat.openai.com"
| "https://chat.openai.com/backend-api"
| "https://chat.openai.com/codex"
| "https://chat.openai.com/backend-api/codex" => Ok(Self::Production),
"https://chatgpt-staging.com"
| "https://chatgpt-staging.com/backend-api"
| "https://chatgpt-staging.com/codex"
| "https://chatgpt-staging.com/backend-api/codex" => Ok(Self::Staging),
_ => anyhow::bail!(
"Agent Identity only supports production and staging ChatGPT environments"
),
}
}
pub fn chatgpt_base_url(self) -> &'static str {
match self {
Self::Production => "https://chatgpt.com/backend-api",
Self::Staging => "https://chatgpt-staging.com/backend-api",
}
}
pub fn agent_identity_authapi_base_url(self) -> &'static str {
match self {
Self::Production => PROD_AGENT_IDENTITY_AUTHAPI_BASE_URL,
Self::Staging => STAGING_AGENT_IDENTITY_AUTHAPI_BASE_URL,
}
}
}
/// Borrowed durable signing material for a registered agent identity.
///
/// This intentionally does not include a task id. Task ids are scoped to a
/// single Codex run, while the agent runtime id and private key are the
/// reusable identity material used to register and sign that run task.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AgentIdentityKey<'a> {
pub agent_runtime_id: &'a str,
pub private_key_pkcs8_base64: &'a str,
}
/// Task binding to use when constructing a task-scoped AgentAssertion.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AgentTaskAuthorizationTarget<'a> {
pub agent_runtime_id: &'a str,
pub task_id: &'a str,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct AgentBillOfMaterials {
pub agent_version: String,
@@ -103,23 +150,92 @@ struct RegisterTaskResponse {
encrypted_task_id_camel: Option<String>,
}
#[derive(Debug, Serialize)]
struct RegisterAgentRequest {
abom: AgentBillOfMaterials,
agent_public_key: String,
capabilities: Vec<String>,
ttl: Option<u64>,
}
#[derive(Debug, Deserialize)]
struct RegisterAgentResponse {
agent_runtime_id: String,
}
/// HTTP status failure returned by Agent Identity registration endpoints.
#[derive(Debug)]
pub struct AgentIdentityRegistrationHttpError {
operation: &'static str,
status: reqwest::StatusCode,
body: String,
}
impl AgentIdentityRegistrationHttpError {
fn new(operation: &'static str, status: reqwest::StatusCode, body: String) -> Self {
Self {
operation,
status,
body,
}
}
/// HTTP status returned by the registration endpoint.
pub fn status(&self) -> reqwest::StatusCode {
self.status
}
}
impl fmt::Display for AgentIdentityRegistrationHttpError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.body.is_empty() {
write!(f, "{} failed with status {}", self.operation, self.status)
} else {
write!(
f,
"{} failed with status {}: {}",
self.operation, self.status, self.body
)
}
}
}
impl StdError for AgentIdentityRegistrationHttpError {}
/// Returns whether an Agent Identity registration error is safe to retry.
pub fn is_retryable_registration_error(error: &anyhow::Error) -> bool {
error.chain().any(is_retryable_registration_cause)
}
fn is_retryable_registration_cause(cause: &(dyn StdError + 'static)) -> bool {
if let Some(error) = cause.downcast_ref::<AgentIdentityRegistrationHttpError>() {
return is_retryable_registration_status(error.status());
}
if let Some(error) = cause.downcast_ref::<reqwest::Error>() {
if let Some(status) = error.status() {
return is_retryable_registration_status(status);
}
return error.is_timeout() || error.is_connect() || error.is_request();
}
false
}
fn is_retryable_registration_status(status: reqwest::StatusCode) -> bool {
status == reqwest::StatusCode::TOO_MANY_REQUESTS || status.is_server_error()
}
pub fn authorization_header_for_agent_task(
key: AgentIdentityKey<'_>,
target: AgentTaskAuthorizationTarget<'_>,
task_id: &str,
) -> Result<String> {
anyhow::ensure!(
key.agent_runtime_id == target.agent_runtime_id,
"agent task runtime {} does not match stored agent identity {}",
target.agent_runtime_id,
key.agent_runtime_id
);
let timestamp = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true);
let envelope = AgentAssertionEnvelope {
agent_runtime_id: target.agent_runtime_id.to_string(),
task_id: target.task_id.to_string(),
agent_runtime_id: key.agent_runtime_id.to_string(),
task_id: task_id.to_string(),
timestamp: timestamp.clone(),
signature: sign_agent_assertion_payload(key, target.task_id, &timestamp)?,
signature: sign_agent_assertion_payload(key, task_id, &timestamp)?,
};
let serialized_assertion = serialize_agent_assertion(&envelope)?;
Ok(format!("AgentAssertion {serialized_assertion}"))
@@ -127,10 +243,10 @@ pub fn authorization_header_for_agent_task(
pub async fn fetch_agent_identity_jwks(
client: &reqwest::Client,
chatgpt_base_url: &str,
agent_identity_jwt_base_url: &str,
) -> Result<JwkSet> {
let response = client
.get(agent_identity_jwks_url(chatgpt_base_url))
.get(agent_identity_jwks_url(agent_identity_jwt_base_url))
.timeout(AGENT_IDENTITY_JWKS_TIMEOUT)
.send()
.await
@@ -195,7 +311,7 @@ pub fn sign_task_registration_payload(
pub async fn register_agent_task(
client: &reqwest::Client,
chatgpt_base_url: &str,
agent_identity_authapi_base_url: &str,
key: AgentIdentityKey<'_>,
) -> Result<String> {
let timestamp = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true);
@@ -203,7 +319,7 @@ pub async fn register_agent_task(
signature: sign_task_registration_payload(key, &timestamp)?,
timestamp,
};
let url = agent_task_registration_url(chatgpt_base_url, key.agent_runtime_id);
let url = agent_task_registration_url(agent_identity_authapi_base_url, key.agent_runtime_id);
let response = client
.post(url)
@@ -220,7 +336,12 @@ pub async fn register_agent_task(
} else {
body
};
anyhow::bail!("failed to register agent task with status {status}: {body}");
return Err(AgentIdentityRegistrationHttpError::new(
"agent task registration",
status,
body,
)
.into());
}
let response = response
@@ -231,6 +352,45 @@ pub async fn register_agent_task(
task_id_from_register_task_response(key, response)
}
pub async fn register_agent_identity(
client: &reqwest::Client,
agent_identity_authapi_base_url: &str,
access_token: &str,
is_fedramp_account: bool,
key_material: &GeneratedAgentKeyMaterial,
abom: AgentBillOfMaterials,
capabilities: Vec<String>,
) -> Result<String> {
let url = agent_registration_url(agent_identity_authapi_base_url);
let request = RegisterAgentRequest {
abom,
agent_public_key: key_material.public_key_ssh.clone(),
capabilities,
ttl: None,
};
let mut request_builder = client
.post(&url)
.bearer_auth(access_token)
.json(&request)
.timeout(AGENT_REGISTRATION_TIMEOUT);
if is_fedramp_account {
request_builder = request_builder.header("X-OpenAI-Fedramp", "true");
}
let response = request_builder
.send()
.await
.with_context(|| format!("failed to send agent identity registration request to {url}"))?
.error_for_status()
.with_context(|| format!("agent identity registration failed for {url}"))?
.json::<RegisterAgentResponse>()
.await
.with_context(|| format!("failed to parse agent identity response from {url}"))?;
Ok(response.agent_runtime_id)
}
fn task_id_from_register_task_response(
key: AgentIdentityKey<'_>,
response: RegisterTaskResponse,
@@ -260,10 +420,17 @@ pub fn decrypt_task_id_response(
}
pub fn generate_agent_key_material() -> Result<GeneratedAgentKeyMaterial> {
let mut secret_key_bytes = [0u8; 32];
let mut seed_material = [0u8; AGENT_IDENTITY_KEY_SEED_BYTES];
OsRng
.try_fill_bytes(&mut secret_key_bytes)
.context("failed to generate agent identity private key bytes")?;
.try_fill_bytes(&mut seed_material)
.context("failed to generate agent identity private key seed material")?;
// Ed25519 stores a 32-byte seed, so derive it from all sampled seed material.
let mut digest = Sha512::new();
digest.update(AGENT_IDENTITY_KEY_DERIVATION_CONTEXT);
digest.update(seed_material);
let digest = digest.finalize();
let mut secret_key_bytes = [0u8; 32];
secret_key_bytes.copy_from_slice(&digest[..32]);
let signing_key = SigningKey::from_bytes(&secret_key_bytes);
let private_key_pkcs8 = signing_key
.to_pkcs8_der()
@@ -296,23 +463,22 @@ pub fn curve25519_secret_key_from_private_key_pkcs8_base64(
Ok(curve25519_secret_key_from_signing_key(&signing_key))
}
pub fn agent_registration_url(chatgpt_base_url: &str) -> String {
let trimmed = chatgpt_base_url.trim_end_matches('/');
format!("{trimmed}/v1/agent/register")
pub fn agent_registration_url(agent_identity_authapi_base_url: &str) -> String {
agent_identity_authapi_url(agent_identity_authapi_base_url, "/v1/agent/register")
}
pub fn agent_task_registration_url(chatgpt_base_url: &str, agent_runtime_id: &str) -> String {
let trimmed = chatgpt_base_url.trim_end_matches('/');
format!("{trimmed}/v1/agent/{agent_runtime_id}/task/register")
pub fn agent_task_registration_url(
agent_identity_authapi_base_url: &str,
agent_runtime_id: &str,
) -> String {
agent_identity_authapi_url(
agent_identity_authapi_base_url,
&format!("/v1/agent/{agent_runtime_id}/task/register"),
)
}
pub fn agent_identity_biscuit_url(chatgpt_base_url: &str) -> String {
let trimmed = chatgpt_base_url.trim_end_matches('/');
format!("{trimmed}/authenticate_app_v2")
}
pub fn agent_identity_jwks_url(chatgpt_base_url: &str) -> String {
let trimmed = chatgpt_base_url.trim_end_matches('/');
pub fn agent_identity_jwks_url(agent_identity_jwt_base_url: &str) -> String {
let trimmed = agent_identity_jwt_base_url.trim_end_matches('/');
if trimmed.contains("/backend-api") {
format!("{trimmed}/wham/agent-identities/jwks")
} else {
@@ -320,15 +486,9 @@ pub fn agent_identity_jwks_url(chatgpt_base_url: &str) -> String {
}
}
pub fn agent_identity_request_id() -> Result<String> {
let mut request_id_bytes = [0u8; 16];
OsRng
.try_fill_bytes(&mut request_id_bytes)
.context("failed to generate agent identity request id")?;
Ok(format!(
"codex-agent-identity-{}",
URL_SAFE_NO_PAD.encode(request_id_bytes)
))
fn agent_identity_authapi_url(agent_identity_authapi_base_url: &str, api_path: &str) -> String {
let base_url = agent_identity_authapi_base_url.trim_end_matches('/');
format!("{base_url}{api_path}")
}
pub fn build_abom(session_source: SessionSource) -> AgentBillOfMaterials {
@@ -412,6 +572,24 @@ mod tests {
use super::*;
#[test]
fn register_task_request_uses_single_run_task_shape() {
let request = RegisterTaskRequest {
timestamp: "2026-04-23T00:00:00Z".to_string(),
signature: "signature".to_string(),
};
let serialized = serde_json::to_value(request).expect("serialize request");
assert_eq!(
serialized,
serde_json::json!({
"timestamp": "2026-04-23T00:00:00Z",
"signature": "signature",
})
);
}
#[test]
fn authorization_header_for_agent_task_serializes_signed_agent_assertion() {
let signing_key = SigningKey::from_bytes(&[7u8; 32]);
@@ -422,13 +600,9 @@ mod tests {
agent_runtime_id: "agent-123",
private_key_pkcs8_base64: &BASE64_STANDARD.encode(private_key.as_bytes()),
};
let target = AgentTaskAuthorizationTarget {
agent_runtime_id: "agent-123",
task_id: "task-123",
};
let header =
authorization_header_for_agent_task(key, target).expect("build agent assertion header");
let header = authorization_header_for_agent_task(key, "task-123")
.expect("build agent assertion header");
let token = header
.strip_prefix("AgentAssertion ")
.expect("agent assertion scheme");
@@ -464,31 +638,6 @@ mod tests {
.expect("signature should verify");
}
#[test]
fn authorization_header_for_agent_task_rejects_mismatched_runtime() {
let signing_key = SigningKey::from_bytes(&[7u8; 32]);
let private_key = signing_key
.to_pkcs8_der()
.expect("encode test key material");
let private_key_pkcs8_base64 = BASE64_STANDARD.encode(private_key.as_bytes());
let key = AgentIdentityKey {
agent_runtime_id: "agent-123",
private_key_pkcs8_base64: &private_key_pkcs8_base64,
};
let target = AgentTaskAuthorizationTarget {
agent_runtime_id: "agent-456",
task_id: "task-123",
};
let error = authorization_header_for_agent_task(key, target)
.expect_err("runtime mismatch should fail");
assert_eq!(
error.to_string(),
"agent task runtime agent-456 does not match stored agent identity agent-123"
);
}
#[test]
fn decode_agent_identity_jwt_reads_claims() {
let jwt = jwt_with_payload(serde_json::json!({
@@ -704,7 +853,98 @@ J1bwkqKZTB5dHolX9A58e/xXnfZ5P8f3Z83+Izap3FwqQulk7b1WO1MQcHuVg2NN
}
#[test]
fn agent_identity_jwks_url_uses_backend_api_base_url() {
fn chatgpt_environment_maps_known_urls_to_authapi() -> anyhow::Result<()> {
assert_eq!(
ChatGptEnvironment::from_chatgpt_base_url("https://chatgpt.com/backend-api/codex")?,
ChatGptEnvironment::Production
);
assert_eq!(
ChatGptEnvironment::Production.agent_identity_authapi_base_url(),
"https://auth.openai.com/api/accounts"
);
assert_eq!(
ChatGptEnvironment::from_chatgpt_base_url("https://chatgpt-staging.com/backend-api")?,
ChatGptEnvironment::Staging
);
assert_eq!(
ChatGptEnvironment::Staging.agent_identity_authapi_base_url(),
"https://auth.api.openai.org/api/accounts"
);
Ok(())
}
#[test]
fn chatgpt_environment_rejects_custom_urls() {
assert!(ChatGptEnvironment::from_chatgpt_base_url("http://localhost:8080").is_err(),);
}
#[test]
fn agent_registration_url_appends_to_authapi_base_url() {
assert_eq!(
agent_registration_url("https://auth.openai.com/api/accounts"),
"https://auth.openai.com/api/accounts/v1/agent/register"
);
assert_eq!(
agent_registration_url("http://localhost:8080"),
"http://localhost:8080/v1/agent/register"
);
assert_eq!(
agent_registration_url("http://localhost:8080/backend-api"),
"http://localhost:8080/backend-api/v1/agent/register"
);
}
#[test]
fn agent_task_registration_url_appends_to_authapi_base_url() {
assert_eq!(
agent_task_registration_url("https://auth.openai.com/api/accounts", "agent-runtime-id"),
"https://auth.openai.com/api/accounts/v1/agent/agent-runtime-id/task/register"
);
assert_eq!(
agent_task_registration_url(
"https://auth.openai.com/api/accounts/",
"agent-runtime-id"
),
"https://auth.openai.com/api/accounts/v1/agent/agent-runtime-id/task/register"
);
assert_eq!(
agent_task_registration_url("http://localhost:8080", "agent-runtime-id"),
"http://localhost:8080/v1/agent/agent-runtime-id/task/register"
);
}
#[test]
fn retryable_registration_error_accepts_429_and_5xx() {
let too_many_requests = anyhow::Error::new(AgentIdentityRegistrationHttpError::new(
"agent registration",
reqwest::StatusCode::TOO_MANY_REQUESTS,
"rate limited".to_string(),
));
let unavailable = anyhow::Error::new(AgentIdentityRegistrationHttpError::new(
"agent registration",
reqwest::StatusCode::SERVICE_UNAVAILABLE,
"try later".to_string(),
));
assert!(is_retryable_registration_error(&too_many_requests));
assert!(is_retryable_registration_error(&unavailable));
}
#[test]
fn retryable_registration_error_rejects_hard_failures() {
let forbidden = anyhow::Error::new(AgentIdentityRegistrationHttpError::new(
"agent registration",
reqwest::StatusCode::FORBIDDEN,
"not allowed".to_string(),
));
let malformed = anyhow::anyhow!("failed to sign registration request");
assert!(!is_retryable_registration_error(&forbidden));
assert!(!is_retryable_registration_error(&malformed));
}
#[test]
fn agent_identity_jwks_url_uses_agent_identity_jwt_route() {
assert_eq!(
agent_identity_jwks_url("https://chatgpt.com/backend-api"),
"https://chatgpt.com/backend-api/wham/agent-identities/jwks"
@@ -716,7 +956,7 @@ J1bwkqKZTB5dHolX9A58e/xXnfZ5P8f3Z83+Izap3FwqQulk7b1WO1MQcHuVg2NN
}
#[test]
fn agent_identity_jwks_url_uses_codex_api_base_url() {
fn agent_identity_jwks_url_uses_jwt_issuer_base_url() {
assert_eq!(
agent_identity_jwks_url("http://localhost:8080/api/codex"),
"http://localhost:8080/api/codex/agent-identities/jwks"
@@ -9,7 +9,11 @@ use crate::events::CodexCommandExecutionEventParams;
use crate::events::CodexCommandExecutionEventRequest;
use crate::events::CodexCompactionEventRequest;
use crate::events::CodexHookRunEventRequest;
use crate::events::CodexOnboardingExternalAgentImportFailureEventRequest;
use crate::events::CodexOnboardingExternalAgentImportFailureMetadata;
use crate::events::CodexPluginEventRequest;
use crate::events::CodexPluginInstallFailedEventRequest;
use crate::events::CodexPluginInstallFailedMetadata;
use crate::events::CodexPluginUsedEventRequest;
use crate::events::CodexReviewEventParams;
use crate::events::CodexReviewEventRequest;
@@ -51,10 +55,13 @@ use crate::facts::CompactionStatus;
use crate::facts::CompactionStrategy;
use crate::facts::CompactionTrigger;
use crate::facts::CustomAnalyticsFact;
use crate::facts::ExternalAgentConfigImportCompletedInput;
use crate::facts::ExternalAgentConfigImportFailureInput;
use crate::facts::HookRunFact;
use crate::facts::HookRunInput;
use crate::facts::InputError;
use crate::facts::InvocationType;
use crate::facts::PluginInstallFailedInput;
use crate::facts::PluginState;
use crate::facts::PluginStateChangedInput;
use crate::facts::PluginUsedInput;
@@ -178,6 +185,7 @@ fn sample_thread_with_metadata(
model_provider: "openai".to_string(),
created_at: 1,
updated_at: 2,
recency_at: Some(2),
status: AppServerThreadStatus::Idle,
path: None,
cwd: test_path_buf("/tmp").abs(),
@@ -216,6 +224,7 @@ fn sample_thread_start_response(
sandbox: AppServerSandboxPolicy::DangerFullAccess,
active_permission_profile: None,
reasoning_effort: None,
multi_agent_mode: Default::default(),
})
}
@@ -280,6 +289,7 @@ fn sample_thread_resume_response_with_source(
sandbox: AppServerSandboxPolicy::DangerFullAccess,
active_permission_profile: None,
reasoning_effort: None,
multi_agent_mode: Default::default(),
initial_turns_page: None,
})
}
@@ -766,6 +776,7 @@ fn sample_initialize_fact(connection_id: u64) -> AnalyticsFact {
experimental_api: false,
request_attestation: false,
opt_out_notification_methods: None,
mcp_server_openai_form_elicitation: false,
}),
},
product_client_id: DEFAULT_ORIGINATOR.to_string(),
@@ -823,7 +834,7 @@ fn sample_command_execution_item_with_id(
ThreadItem::CommandExecution {
id: id.to_string(),
command: "echo hi".to_string(),
cwd: test_path_buf("/tmp").abs(),
cwd: test_path_buf("/tmp").abs().into(),
process_id: Some("pid-1".to_string()),
source: CommandExecutionSource::Agent,
status,
@@ -1661,6 +1672,7 @@ async fn initialize_caches_client_and_thread_lifecycle_publishes_once_initialize
experimental_api: false,
request_attestation: false,
opt_out_notification_methods: None,
mcp_server_openai_form_elicitation: false,
}),
},
product_client_id: DEFAULT_ORIGINATOR.to_string(),
@@ -1810,6 +1822,7 @@ async fn compaction_event_ingests_custom_fact() {
experimental_api: false,
request_attestation: false,
opt_out_notification_methods: None,
mcp_server_openai_form_elicitation: false,
}),
},
product_client_id: DEFAULT_ORIGINATOR.to_string(),
@@ -1938,6 +1951,7 @@ async fn guardian_review_event_ingests_custom_fact_with_optional_target_item() {
experimental_api: false,
request_attestation: false,
opt_out_notification_methods: None,
mcp_server_openai_form_elicitation: false,
}),
},
product_client_id: DEFAULT_ORIGINATOR.to_string(),
@@ -3053,6 +3067,36 @@ fn plugin_management_event_serializes_expected_shape() {
);
}
#[test]
fn plugin_install_failed_event_serializes_expected_shape() {
let event = TrackEventRequest::PluginInstallFailed(CodexPluginInstallFailedEventRequest {
event_type: "codex_plugin_install_failed",
event_params: CodexPluginInstallFailedMetadata {
plugin: codex_plugin_metadata(sample_plugin_metadata()),
error_type: "store_io".to_string(),
},
});
let payload = serde_json::to_value(&event).expect("serialize plugin install failed event");
assert_eq!(
payload,
json!({
"event_type": "codex_plugin_install_failed",
"event_params": {
"plugin_id": "sample@test",
"plugin_name": "sample",
"marketplace_name": "test",
"has_skills": true,
"mcp_server_count": 2,
"connector_ids": ["calendar", "drive"],
"product_client_id": originator().value,
"error_type": "store_io"
}
})
);
}
#[test]
fn plugin_management_event_can_use_remote_plugin_id_override() {
let mut plugin = sample_plugin_metadata();
@@ -3420,6 +3464,191 @@ async fn reducer_ingests_plugin_state_changed_fact() {
);
}
#[tokio::test]
async fn reducer_ingests_plugin_install_failed_fact() {
let mut reducer = AnalyticsReducer::default();
let mut events = Vec::new();
reducer
.ingest(
AnalyticsFact::Custom(CustomAnalyticsFact::PluginInstallFailed(
PluginInstallFailedInput {
plugin: sample_plugin_metadata(),
error_type: "invalid_plugin".to_string(),
},
)),
&mut events,
)
.await;
let payload = serde_json::to_value(&events).expect("serialize events");
assert_eq!(
payload,
json!([{
"event_type": "codex_plugin_install_failed",
"event_params": {
"plugin_id": "sample@test",
"plugin_name": "sample",
"marketplace_name": "test",
"has_skills": true,
"mcp_server_count": 2,
"connector_ids": ["calendar", "drive"],
"product_client_id": originator().value,
"error_type": "invalid_plugin"
}
}])
);
}
#[tokio::test]
async fn reducer_ingests_plugin_install_failed_fact_without_detail() {
let mut reducer = AnalyticsReducer::default();
let mut events = Vec::new();
let plugin = PluginTelemetryMetadata {
plugin_id: PluginId::parse("unknown@openai-curated-remote").expect("valid plugin id"),
remote_plugin_id: Some("plugins~Plugin_00000000000000000000000000000000".to_string()),
capability_summary: None,
};
reducer
.ingest(
AnalyticsFact::Custom(CustomAnalyticsFact::PluginInstallFailed(
PluginInstallFailedInput {
plugin,
error_type: "remote_catalog_unexpected_status".to_string(),
},
)),
&mut events,
)
.await;
let payload = serde_json::to_value(&events).expect("serialize events");
assert_eq!(
payload,
json!([{
"event_type": "codex_plugin_install_failed",
"event_params": {
"plugin_id": "plugins~Plugin_00000000000000000000000000000000",
"plugin_name": "unknown",
"marketplace_name": "openai-curated-remote",
"has_skills": null,
"mcp_server_count": null,
"connector_ids": null,
"product_client_id": originator().value,
"error_type": "remote_catalog_unexpected_status"
}
}])
);
}
#[tokio::test]
async fn reducer_ingests_external_agent_config_import_completed_fact() {
let mut reducer = AnalyticsReducer::default();
let mut events = Vec::new();
reducer
.ingest(
AnalyticsFact::Custom(CustomAnalyticsFact::ExternalAgentConfigImportCompleted(
ExternalAgentConfigImportCompletedInput {
import_id: "import-1".to_string(),
source: "app_server".to_string(),
item_type: "PLUGINS".to_string(),
success_count: 2,
failed_count: 1,
},
)),
&mut events,
)
.await;
let payload = serde_json::to_value(&events).expect("serialize events");
assert_eq!(
payload,
json!([{
"event_type": "codex_onboarding_external_agent_import_complete",
"event_params": {
"import_id": "import-1",
"source": "app_server",
"type": "PLUGINS",
"success_count": 2,
"failed_count": 1,
"product_client_id": originator().value,
}
}])
);
}
#[test]
fn external_agent_config_import_failure_event_serializes_expected_shape() {
let event = TrackEventRequest::ExternalAgentConfigImportFailure(
CodexOnboardingExternalAgentImportFailureEventRequest {
event_type: "codex_onboarding_external_agent_import_failure",
event_params: CodexOnboardingExternalAgentImportFailureMetadata {
import_id: "import-1".to_string(),
source: "app_server".to_string(),
item_type: "SESSIONS".to_string(),
failure_stage: "session_missing".to_string(),
error_type: "session_missing".to_string(),
product_client_id: Some(originator().value),
},
},
);
let payload = serde_json::to_value(&event).expect("serialize import failure event");
assert_eq!(
payload,
json!({
"event_type": "codex_onboarding_external_agent_import_failure",
"event_params": {
"import_id": "import-1",
"source": "app_server",
"type": "SESSIONS",
"failure_stage": "session_missing",
"error_type": "session_missing",
"product_client_id": originator().value,
}
})
);
}
#[tokio::test]
async fn reducer_ingests_external_agent_config_import_failure_fact() {
let mut reducer = AnalyticsReducer::default();
let mut events = Vec::new();
reducer
.ingest(
AnalyticsFact::Custom(CustomAnalyticsFact::ExternalAgentConfigImportFailure(
ExternalAgentConfigImportFailureInput {
import_id: "import-1".to_string(),
source: "app_server".to_string(),
item_type: "SESSIONS".to_string(),
failure_stage: "session_missing".to_string(),
error_type: "session_missing".to_string(),
},
)),
&mut events,
)
.await;
let payload = serde_json::to_value(&events).expect("serialize events");
assert_eq!(
payload,
json!([{
"event_type": "codex_onboarding_external_agent_import_failure",
"event_params": {
"import_id": "import-1",
"source": "app_server",
"type": "SESSIONS",
"failure_stage": "session_missing",
"error_type": "session_missing",
"product_client_id": originator().value,
}
}])
);
}
#[test]
fn turn_event_serializes_expected_shape() {
let event = TrackEventRequest::TurnEvent(Box::new(CodexTurnEventRequest {
@@ -3895,6 +4124,7 @@ async fn turn_event_counts_completed_tool_items() {
tool: "search".to_string(),
status,
arguments: json!({}),
app_context: None,
mcp_app_resource_uri: None,
plugin_id: Some("sample@test".to_string()),
result: None,
+30
View File
@@ -11,8 +11,11 @@ use crate::facts::AppMentionedInput;
use crate::facts::AppUsedInput;
use crate::facts::CodexGoalEvent;
use crate::facts::CustomAnalyticsFact;
use crate::facts::ExternalAgentConfigImportCompletedInput;
use crate::facts::ExternalAgentConfigImportFailureInput;
use crate::facts::HookRunFact;
use crate::facts::HookRunInput;
use crate::facts::PluginInstallFailedInput;
use crate::facts::PluginState;
use crate::facts::PluginStateChangedInput;
use crate::facts::SkillInvocation;
@@ -343,6 +346,33 @@ impl AnalyticsEventsClient {
));
}
pub fn track_plugin_install_failed(&self, plugin: PluginTelemetryMetadata, error_type: String) {
self.record_fact(AnalyticsFact::Custom(
CustomAnalyticsFact::PluginInstallFailed(PluginInstallFailedInput {
plugin,
error_type,
}),
));
}
pub fn track_external_agent_config_import_completed(
&self,
input: ExternalAgentConfigImportCompletedInput,
) {
self.record_fact(AnalyticsFact::Custom(
CustomAnalyticsFact::ExternalAgentConfigImportCompleted(input),
));
}
pub fn track_external_agent_config_import_failure(
&self,
input: ExternalAgentConfigImportFailureInput,
) {
self.record_fact(AnalyticsFact::Custom(
CustomAnalyticsFact::ExternalAgentConfigImportFailure(input),
));
}
pub fn track_plugin_uninstalled(&self, plugin: PluginTelemetryMetadata) {
self.record_fact(AnalyticsFact::Custom(
CustomAnalyticsFact::PluginStateChanged(PluginStateChangedInput {
+4
View File
@@ -285,6 +285,7 @@ fn sample_thread(thread_id: &str) -> Thread {
model_provider: "openai".to_string(),
created_at: 1,
updated_at: 2,
recency_at: Some(2),
status: AppServerThreadStatus::Idle,
path: None,
cwd: test_path_buf("/tmp").abs(),
@@ -313,6 +314,7 @@ fn sample_thread_start_response() -> ClientResponsePayload {
sandbox: AppServerSandboxPolicy::DangerFullAccess,
active_permission_profile: None,
reasoning_effort: None,
multi_agent_mode: Default::default(),
})
}
@@ -330,6 +332,7 @@ fn sample_thread_resume_response() -> ClientResponsePayload {
sandbox: AppServerSandboxPolicy::DangerFullAccess,
active_permission_profile: None,
reasoning_effort: None,
multi_agent_mode: Default::default(),
initial_turns_page: None,
})
}
@@ -348,6 +351,7 @@ fn sample_thread_fork_response() -> ClientResponsePayload {
sandbox: AppServerSandboxPolicy::DangerFullAccess,
active_permission_profile: None,
reasoning_effort: None,
multi_agent_mode: Default::default(),
})
}
+50
View File
@@ -83,6 +83,9 @@ pub(crate) enum TrackEventRequest {
PluginUninstalled(CodexPluginEventRequest),
PluginEnabled(CodexPluginEventRequest),
PluginDisabled(CodexPluginEventRequest),
PluginInstallFailed(CodexPluginInstallFailedEventRequest),
ExternalAgentConfigImportCompleted(CodexOnboardingExternalAgentImportCompleteEventRequest),
ExternalAgentConfigImportFailure(CodexOnboardingExternalAgentImportFailureEventRequest),
}
impl TrackEventRequest {
@@ -954,6 +957,53 @@ pub(crate) struct CodexPluginEventRequest {
pub(crate) event_params: CodexPluginMetadata,
}
#[derive(Serialize)]
pub(crate) struct CodexPluginInstallFailedMetadata {
#[serde(flatten)]
pub(crate) plugin: CodexPluginMetadata,
pub(crate) error_type: String,
}
#[derive(Serialize)]
pub(crate) struct CodexPluginInstallFailedEventRequest {
pub(crate) event_type: &'static str,
pub(crate) event_params: CodexPluginInstallFailedMetadata,
}
#[derive(Serialize)]
pub(crate) struct CodexOnboardingExternalAgentImportCompleteMetadata {
pub(crate) import_id: String,
pub(crate) source: String,
#[serde(rename = "type")]
pub(crate) item_type: String,
pub(crate) success_count: usize,
pub(crate) failed_count: usize,
pub(crate) product_client_id: Option<String>,
}
#[derive(Serialize)]
pub(crate) struct CodexOnboardingExternalAgentImportCompleteEventRequest {
pub(crate) event_type: &'static str,
pub(crate) event_params: CodexOnboardingExternalAgentImportCompleteMetadata,
}
#[derive(Serialize)]
pub(crate) struct CodexOnboardingExternalAgentImportFailureMetadata {
pub(crate) import_id: String,
pub(crate) source: String,
#[serde(rename = "type")]
pub(crate) item_type: String,
pub(crate) failure_stage: String,
pub(crate) error_type: String,
pub(crate) product_client_id: Option<String>,
}
#[derive(Serialize)]
pub(crate) struct CodexOnboardingExternalAgentImportFailureEventRequest {
pub(crate) event_type: &'static str,
pub(crate) event_params: CodexOnboardingExternalAgentImportFailureMetadata,
}
#[derive(Serialize)]
pub(crate) struct CodexPluginUsedEventRequest {
pub(crate) event_type: &'static str,
+24
View File
@@ -504,6 +504,9 @@ pub(crate) enum CustomAnalyticsFact {
HookRun(HookRunInput),
PluginUsed(PluginUsedInput),
PluginStateChanged(PluginStateChangedInput),
PluginInstallFailed(PluginInstallFailedInput),
ExternalAgentConfigImportCompleted(ExternalAgentConfigImportCompletedInput),
ExternalAgentConfigImportFailure(ExternalAgentConfigImportFailureInput),
}
pub(crate) struct SkillInvokedInput {
@@ -542,6 +545,27 @@ pub(crate) struct PluginStateChangedInput {
pub state: PluginState,
}
pub(crate) struct PluginInstallFailedInput {
pub plugin: PluginTelemetryMetadata,
pub error_type: String,
}
pub struct ExternalAgentConfigImportCompletedInput {
pub import_id: String,
pub source: String,
pub item_type: String,
pub success_count: usize,
pub failed_count: usize,
}
pub struct ExternalAgentConfigImportFailureInput {
pub import_id: String,
pub source: String,
pub item_type: String,
pub failure_stage: String,
pub error_type: String,
}
#[derive(Clone, Copy)]
pub(crate) enum PluginState {
Installed,
+2
View File
@@ -36,6 +36,8 @@ pub use facts::CompactionReason;
pub use facts::CompactionStatus;
pub use facts::CompactionStrategy;
pub use facts::CompactionTrigger;
pub use facts::ExternalAgentConfigImportCompletedInput;
pub use facts::ExternalAgentConfigImportFailureInput;
pub use facts::GoalEventKind;
pub use facts::HookRunFact;
pub use facts::InputError;
+75
View File
@@ -21,7 +21,13 @@ use crate::events::CodexImageGenerationEventParams;
use crate::events::CodexImageGenerationEventRequest;
use crate::events::CodexMcpToolCallEventParams;
use crate::events::CodexMcpToolCallEventRequest;
use crate::events::CodexOnboardingExternalAgentImportCompleteEventRequest;
use crate::events::CodexOnboardingExternalAgentImportCompleteMetadata;
use crate::events::CodexOnboardingExternalAgentImportFailureEventRequest;
use crate::events::CodexOnboardingExternalAgentImportFailureMetadata;
use crate::events::CodexPluginEventRequest;
use crate::events::CodexPluginInstallFailedEventRequest;
use crate::events::CodexPluginInstallFailedMetadata;
use crate::events::CodexPluginUsedEventRequest;
use crate::events::CodexReviewEventParams;
use crate::events::CodexReviewEventRequest;
@@ -66,7 +72,10 @@ use crate::facts::AppUsedInput;
use crate::facts::CodexCompactionEvent;
use crate::facts::CodexGoalEvent;
use crate::facts::CustomAnalyticsFact;
use crate::facts::ExternalAgentConfigImportCompletedInput;
use crate::facts::ExternalAgentConfigImportFailureInput;
use crate::facts::HookRunInput;
use crate::facts::PluginInstallFailedInput;
use crate::facts::PluginState;
use crate::facts::PluginStateChangedInput;
use crate::facts::PluginUsedInput;
@@ -511,6 +520,15 @@ impl AnalyticsReducer {
CustomAnalyticsFact::PluginStateChanged(input) => {
self.ingest_plugin_state_changed(input, out);
}
CustomAnalyticsFact::PluginInstallFailed(input) => {
self.ingest_plugin_install_failed(input, out);
}
CustomAnalyticsFact::ExternalAgentConfigImportCompleted(input) => {
self.ingest_external_agent_config_import_completed(input, out);
}
CustomAnalyticsFact::ExternalAgentConfigImportFailure(input) => {
self.ingest_external_agent_config_import_failure(input, out);
}
},
}
}
@@ -775,6 +793,63 @@ impl AnalyticsReducer {
});
}
fn ingest_plugin_install_failed(
&mut self,
input: PluginInstallFailedInput,
out: &mut Vec<TrackEventRequest>,
) {
let PluginInstallFailedInput { plugin, error_type } = input;
out.push(TrackEventRequest::PluginInstallFailed(
CodexPluginInstallFailedEventRequest {
event_type: "codex_plugin_install_failed",
event_params: CodexPluginInstallFailedMetadata {
plugin: codex_plugin_metadata(plugin),
error_type,
},
},
));
}
fn ingest_external_agent_config_import_completed(
&mut self,
input: ExternalAgentConfigImportCompletedInput,
out: &mut Vec<TrackEventRequest>,
) {
out.push(TrackEventRequest::ExternalAgentConfigImportCompleted(
CodexOnboardingExternalAgentImportCompleteEventRequest {
event_type: "codex_onboarding_external_agent_import_complete",
event_params: CodexOnboardingExternalAgentImportCompleteMetadata {
import_id: input.import_id,
source: input.source,
item_type: input.item_type,
success_count: input.success_count,
failed_count: input.failed_count,
product_client_id: Some(originator().value),
},
},
));
}
fn ingest_external_agent_config_import_failure(
&mut self,
input: ExternalAgentConfigImportFailureInput,
out: &mut Vec<TrackEventRequest>,
) {
out.push(TrackEventRequest::ExternalAgentConfigImportFailure(
CodexOnboardingExternalAgentImportFailureEventRequest {
event_type: "codex_onboarding_external_agent_import_failure",
event_params: CodexOnboardingExternalAgentImportFailureMetadata {
import_id: input.import_id,
source: input.source,
item_type: input.item_type,
failure_stage: input.failure_stage,
error_type: input.error_type,
product_client_id: Some(originator().value),
},
},
));
}
async fn ingest_response(
&mut self,
connection_id: u64,
+31 -1
View File
@@ -350,6 +350,8 @@ pub struct InProcessClientStartArgs {
pub client_version: String,
/// Whether experimental APIs are requested at initialize time.
pub experimental_api: bool,
/// Whether MCP servers may send `openai/form` elicitation requests.
pub mcp_server_openai_form_elicitation: bool,
/// Notification methods this client opts out of receiving.
pub opt_out_notification_methods: Vec<String>,
/// Queue capacity for command/event channels (clamped to at least 1).
@@ -374,6 +376,7 @@ impl InProcessClientStartArgs {
} else {
Some(self.opt_out_notification_methods.clone())
},
mcp_server_openai_form_elicitation: self.mcp_server_openai_form_elicitation,
};
InitializeParams {
@@ -1044,6 +1047,7 @@ mod tests {
client_name: "codex-app-server-client-test".to_string(),
client_version: "0.0.0-test".to_string(),
experimental_api: true,
mcp_server_openai_form_elicitation: false,
opt_out_notification_methods: Vec::new(),
channel_capacity,
})
@@ -1237,11 +1241,25 @@ mod tests {
client_name: "codex-app-server-client-test".to_string(),
client_version: "0.0.0-test".to_string(),
experimental_api: true,
mcp_server_openai_form_elicitation: false,
opt_out_notification_methods: Vec::new(),
channel_capacity: 8,
}
}
#[test]
fn remote_initialize_params_forward_openai_form_capability() {
let mut args = test_remote_connect_args("ws://localhost/rpc".to_string());
args.mcp_server_openai_form_elicitation = true;
assert!(
args.initialize_params()
.capabilities
.expect("initialize capabilities")
.mcp_server_openai_form_elicitation
);
}
#[tokio::test]
async fn typed_request_roundtrip_works() {
let client = start_test_client(SessionSource::Exec).await;
@@ -1512,6 +1530,7 @@ mod tests {
client_name: "codex-app-server-client-test".to_string(),
client_version: "0.0.0-test".to_string(),
experimental_api: true,
mcp_server_openai_form_elicitation: false,
opt_out_notification_methods: Vec::new(),
channel_capacity: 8,
})
@@ -1600,6 +1619,7 @@ mod tests {
client_name: "codex-app-server-client-test".to_string(),
client_version: "0.0.0-test".to_string(),
experimental_api: true,
mcp_server_openai_form_elicitation: false,
opt_out_notification_methods: Vec::new(),
channel_capacity: 8,
})
@@ -1619,6 +1639,7 @@ mod tests {
client_name: "codex-app-server-client-test".to_string(),
client_version: "0.0.0-test".to_string(),
experimental_api: true,
mcp_server_openai_form_elicitation: false,
opt_out_notification_methods: Vec::new(),
channel_capacity: 8,
})
@@ -2189,7 +2210,7 @@ mod tests {
}
#[tokio::test]
async fn runtime_start_args_forward_environment_manager() {
async fn runtime_start_args_forward_environment_manager_and_openai_form_capability() {
let config = Arc::new(build_test_config().await);
let environment_manager = Arc::new(
EnvironmentManager::create_for_tests(
@@ -2222,12 +2243,20 @@ mod tests {
client_name: "codex-app-server-client-test".to_string(),
client_version: "0.0.0-test".to_string(),
experimental_api: true,
mcp_server_openai_form_elicitation: true,
opt_out_notification_methods: Vec::new(),
channel_capacity: DEFAULT_IN_PROCESS_CHANNEL_CAPACITY,
}
.into_runtime_start_args();
assert_eq!(runtime_args.config, config);
assert!(
runtime_args
.initialize
.capabilities
.expect("initialize capabilities")
.mcp_server_openai_form_elicitation
);
assert!(Arc::ptr_eq(
&runtime_args.environment_manager,
&environment_manager
@@ -2263,6 +2292,7 @@ mod tests {
client_name: "codex-app-server-client-test".to_string(),
client_version: "0.0.0-test".to_string(),
experimental_api: true,
mcp_server_openai_form_elicitation: false,
opt_out_notification_methods: Vec::new(),
channel_capacity: DEFAULT_IN_PROCESS_CHANNEL_CAPACITY,
}
+3 -1
View File
@@ -86,11 +86,12 @@ pub struct RemoteAppServerConnectArgs {
pub client_name: String,
pub client_version: String,
pub experimental_api: bool,
pub mcp_server_openai_form_elicitation: bool,
pub opt_out_notification_methods: Vec<String>,
pub channel_capacity: usize,
}
impl RemoteAppServerConnectArgs {
fn initialize_params(&self) -> InitializeParams {
pub(crate) fn initialize_params(&self) -> InitializeParams {
let capabilities = InitializeCapabilities {
experimental_api: self.experimental_api,
request_attestation: false,
@@ -99,6 +100,7 @@ impl RemoteAppServerConnectArgs {
} else {
Some(self.opt_out_notification_methods.clone())
},
mcp_server_openai_form_elicitation: self.mcp_server_openai_form_elicitation,
};
InitializeParams {
+100 -24
View File
@@ -643,7 +643,8 @@
"ConversationTextRole": {
"enum": [
"user",
"developer"
"developer",
"assistant"
],
"type": "string"
},
@@ -800,7 +801,7 @@
]
},
"includeHome": {
"description": "If true, include detection under the user's home (~/.claude, ~/.codex, etc.).",
"description": "If true, include detection under the user's home directory.",
"type": "boolean"
}
},
@@ -813,6 +814,13 @@
"$ref": "#/definitions/ExternalAgentConfigMigrationItem"
},
"type": "array"
},
"source": {
"description": "Source product that produced the migration items. Missing means unspecified.",
"type": [
"string",
"null"
]
}
},
"required": [
@@ -1264,6 +1272,10 @@
"description": "Opt into receiving experimental API methods and fields.",
"type": "boolean"
},
"mcpServerOpenaiFormElicitation": {
"description": "Allow downstream MCP servers to request OpenAI extended form elicitations.",
"type": "boolean"
},
"optOutNotificationMethods": {
"description": "Exact notification method names that should be suppressed for this connection (for example `thread/started`).",
"items": {
@@ -1748,6 +1760,15 @@
"ModelProviderCapabilitiesReadParams": {
"type": "object"
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
"none",
"explicitRequestOnly",
"proactive"
],
"type": "string"
},
"NetworkAccess": {
"enum": [
"restricted",
@@ -2107,13 +2128,6 @@
],
"type": "object"
},
"RealtimeConversationArchitecture": {
"enum": [
"realtimeapi",
"avas"
],
"type": "string"
},
"RealtimeConversationVersion": {
"enum": [
"v1",
@@ -2286,8 +2300,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -2339,6 +2352,12 @@
},
"type": "array"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -2387,6 +2406,12 @@
"null"
]
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -2435,8 +2460,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -2479,8 +2503,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -2534,8 +2557,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -2574,6 +2596,12 @@
"call_id": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -2612,8 +2640,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"input": {
"type": "string"
@@ -2659,6 +2686,12 @@
"call_id": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -2705,6 +2738,12 @@
"execution": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -2755,8 +2794,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -2791,7 +2829,10 @@
{
"properties": {
"id": {
"type": "string"
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
@@ -2824,7 +2865,6 @@
}
},
"required": [
"id",
"result",
"status",
"type"
@@ -2837,6 +2877,12 @@
"encrypted_content": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -2896,6 +2942,12 @@
"null"
]
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -4164,7 +4216,8 @@
"ThreadSortKey": {
"enum": [
"created_at",
"updated_at"
"updated_at",
"recency_at"
],
"type": "string"
},
@@ -6409,6 +6462,29 @@
"title": "Account/usage/readRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"account/workspaceMessages/read"
],
"title": "Account/workspaceMessages/readRequestMethod",
"type": "string"
},
"params": {
"type": "null"
}
},
"required": [
"id",
"method"
],
"title": "Account/workspaceMessages/readRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -547,7 +547,7 @@
"cwd": {
"anyOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
{
"type": "null"
@@ -557,6 +557,27 @@
],
"type": "object"
},
{
"properties": {
"_meta": true,
"message": {
"type": "string"
},
"mode": {
"enum": [
"openai/form"
],
"type": "string"
},
"requestedSchema": true
},
"required": [
"message",
"mode",
"requestedSchema"
],
"type": "object"
},
{
"properties": {
"_meta": true,
@@ -2396,6 +2396,29 @@
],
"type": "object"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -2560,6 +2583,39 @@
],
"type": "object"
},
"ModelSafetyBufferingUpdatedNotification": {
"properties": {
"model": {
"type": "string"
},
"reasons": {
"items": {
"type": "string"
},
"type": "array"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
},
"useCases": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"model",
"reasons",
"threadId",
"turnId",
"useCases"
],
"type": "object"
},
"ModelVerification": {
"enum": [
"trustedAccessForCyber"
@@ -2588,6 +2644,15 @@
],
"type": "object"
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
"none",
"explicitRequestOnly",
"proactive"
],
"type": "string"
},
"NetworkAccess": {
"enum": [
"restricted",
@@ -3582,6 +3647,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -3964,7 +4037,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -4058,6 +4131,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -4081,6 +4164,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -6558,6 +6642,26 @@
"title": "Turn/moderationMetadataNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"model/safetyBuffering/updated"
],
"title": "Model/safetyBuffering/updatedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/ModelSafetyBufferingUpdatedNotification"
}
},
"required": [
"method",
"params"
],
"title": "Model/safetyBuffering/updatedNotification",
"type": "object"
},
{
"properties": {
"method": {
+22 -1
View File
@@ -371,7 +371,7 @@
"cwd": {
"anyOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
{
"type": "null"
@@ -1390,6 +1390,27 @@
],
"type": "object"
},
{
"properties": {
"_meta": true,
"message": {
"type": "string"
},
"mode": {
"enum": [
"openai/form"
],
"type": "string"
},
"requestedSchema": true
},
"required": [
"message",
"mode",
"requestedSchema"
],
"type": "object"
},
{
"properties": {
"_meta": true,
@@ -1904,6 +1904,29 @@
"title": "Account/usage/readRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/v2/RequestId"
},
"method": {
"enum": [
"account/workspaceMessages/read"
],
"title": "Account/workspaceMessages/readRequestMethod",
"type": "string"
},
"params": {
"type": "null"
}
},
"required": [
"id",
"method"
],
"title": "Account/workspaceMessages/readRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -2378,7 +2401,7 @@
"cwd": {
"anyOf": [
{
"$ref": "#/definitions/v2/AbsolutePathBuf"
"$ref": "#/definitions/v2/LegacyAppPathString"
},
{
"type": "null"
@@ -2900,6 +2923,10 @@
"description": "Opt into receiving experimental API methods and fields.",
"type": "boolean"
},
"mcpServerOpenaiFormElicitation": {
"description": "Allow downstream MCP servers to request OpenAI extended form elicitations.",
"type": "boolean"
},
"optOutNotificationMethods": {
"description": "Exact notification method names that should be suppressed for this connection (for example `thread/started`).",
"items": {
@@ -3655,6 +3682,27 @@
],
"type": "object"
},
{
"properties": {
"_meta": true,
"message": {
"type": "string"
},
"mode": {
"enum": [
"openai/form"
],
"type": "string"
},
"requestedSchema": true
},
"required": [
"message",
"mode",
"requestedSchema"
],
"type": "object"
},
{
"properties": {
"_meta": true,
@@ -5066,6 +5114,26 @@
"title": "Turn/moderationMetadataNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"model/safetyBuffering/updated"
],
"title": "Model/safetyBuffering/updatedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/v2/ModelSafetyBufferingUpdatedNotification"
}
},
"required": [
"method",
"params"
],
"title": "Model/safetyBuffering/updatedNotification",
"type": "object"
},
{
"properties": {
"method": {
@@ -8707,7 +8775,8 @@
"ConversationTextRole": {
"enum": [
"user",
"developer"
"developer",
"assistant"
],
"type": "string"
},
@@ -9119,7 +9188,7 @@
]
},
"includeHome": {
"description": "If true, include detection under the user's home (~/.claude, ~/.codex, etc.).",
"description": "If true, include detection under the user's home directory.",
"type": "boolean"
}
},
@@ -9282,6 +9351,13 @@
"$ref": "#/definitions/v2/ExternalAgentConfigMigrationItem"
},
"type": "array"
},
"source": {
"description": "Source product that produced the migration items. Missing means unspecified.",
"type": [
"string",
"null"
]
}
},
"required": [
@@ -10301,6 +10377,28 @@
"title": "GetAccountTokenUsageResponse",
"type": "object"
},
"GetWorkspaceMessagesResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"featureEnabled": {
"description": "Whether the workspace-message backend route is available for this client.",
"type": "boolean"
},
"messages": {
"description": "Active workspace messages returned by the backend.",
"items": {
"$ref": "#/definitions/v2/WorkspaceMessage"
},
"type": "array"
}
},
"required": [
"featureEnabled",
"messages"
],
"title": "GetWorkspaceMessagesResponse",
"type": "object"
},
"GitInfo": {
"properties": {
"branch": {
@@ -12086,6 +12184,29 @@
"title": "McpServerToolCallResponse",
"type": "object"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -12503,6 +12624,41 @@
"title": "ModelReroutedNotification",
"type": "object"
},
"ModelSafetyBufferingUpdatedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"model": {
"type": "string"
},
"reasons": {
"items": {
"type": "string"
},
"type": "array"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
},
"useCases": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"model",
"reasons",
"threadId",
"turnId",
"useCases"
],
"title": "ModelSafetyBufferingUpdatedNotification",
"type": "object"
},
"ModelServiceTier": {
"properties": {
"description": {
@@ -12581,6 +12737,15 @@
"title": "ModelVerificationNotification",
"type": "object"
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
"none",
"explicitRequestOnly",
"proactive"
],
"type": "string"
},
"NetworkAccess": {
"enum": [
"restricted",
@@ -14274,13 +14439,6 @@
"title": "RawResponseItemCompletedNotification",
"type": "object"
},
"RealtimeConversationArchitecture": {
"enum": [
"realtimeapi",
"avas"
],
"type": "string"
},
"RealtimeConversationVersion": {
"enum": [
"v1",
@@ -14788,8 +14946,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -14841,6 +14998,12 @@
},
"type": "array"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -14889,6 +15052,12 @@
"null"
]
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -14937,8 +15106,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -14981,8 +15149,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -15036,8 +15203,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -15076,6 +15242,12 @@
"call_id": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -15114,8 +15286,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"input": {
"type": "string"
@@ -15161,6 +15332,12 @@
"call_id": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -15207,6 +15384,12 @@
"execution": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -15257,8 +15440,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -15293,7 +15475,10 @@
{
"properties": {
"id": {
"type": "string"
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
@@ -15326,7 +15511,6 @@
}
},
"required": [
"id",
"result",
"status",
"type"
@@ -15339,6 +15523,12 @@
"encrypted_content": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -15398,6 +15588,12 @@
"null"
]
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -16645,6 +16841,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -16949,9 +17153,9 @@
},
"instructionSources": {
"default": [],
"description": "Instruction source files currently loaded for this thread.",
"description": "Environment-native paths to instruction source files currently loaded for this thread.",
"items": {
"$ref": "#/definitions/v2/AbsolutePathBuf"
"$ref": "#/definitions/v2/LegacyAppPathString"
},
"type": "array"
},
@@ -17416,7 +17620,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/v2/AbsolutePathBuf"
"$ref": "#/definitions/v2/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -17510,6 +17714,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/v2/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -17533,6 +17747,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -18653,9 +18868,9 @@
},
"instructionSources": {
"default": [],
"description": "Instruction source files currently loaded for this thread.",
"description": "Environment-native paths to instruction source files currently loaded for this thread.",
"items": {
"$ref": "#/definitions/v2/AbsolutePathBuf"
"$ref": "#/definitions/v2/LegacyAppPathString"
},
"type": "array"
},
@@ -18904,7 +19119,8 @@
"ThreadSortKey": {
"enum": [
"created_at",
"updated_at"
"updated_at",
"recency_at"
],
"type": "string"
},
@@ -19069,9 +19285,9 @@
},
"instructionSources": {
"default": [],
"description": "Instruction source files currently loaded for this thread.",
"description": "Environment-native paths to instruction source files currently loaded for this thread.",
"items": {
"$ref": "#/definitions/v2/AbsolutePathBuf"
"$ref": "#/definitions/v2/LegacyAppPathString"
},
"type": "array"
},
@@ -20240,6 +20456,7 @@
"enum": [
"disabled",
"cached",
"indexed",
"live"
],
"type": "string"
@@ -20392,6 +20609,49 @@
"title": "WindowsWorldWritableWarningNotification",
"type": "object"
},
"WorkspaceMessage": {
"properties": {
"archivedAt": {
"description": "Unix timestamp (in seconds) when the message was archived.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"createdAt": {
"description": "Unix timestamp (in seconds) when the message was created.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"messageBody": {
"type": "string"
},
"messageId": {
"type": "string"
},
"messageType": {
"$ref": "#/definitions/v2/WorkspaceMessageType"
}
},
"required": [
"messageBody",
"messageId",
"messageType"
],
"type": "object"
},
"WorkspaceMessageType": {
"enum": [
"headline",
"announcement",
"unknown"
],
"type": "string"
},
"WriteStatus": {
"enum": [
"ok",
@@ -2913,6 +2913,29 @@
"title": "Account/usage/readRequest",
"type": "object"
},
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"account/workspaceMessages/read"
],
"title": "Account/workspaceMessages/readRequestMethod",
"type": "string"
},
"params": {
"type": "null"
}
},
"required": [
"id",
"method"
],
"title": "Account/workspaceMessages/readRequest",
"type": "object"
},
{
"properties": {
"id": {
@@ -4992,7 +5015,8 @@
"ConversationTextRole": {
"enum": [
"user",
"developer"
"developer",
"assistant"
],
"type": "string"
},
@@ -5404,7 +5428,7 @@
]
},
"includeHome": {
"description": "If true, include detection under the user's home (~/.claude, ~/.codex, etc.).",
"description": "If true, include detection under the user's home directory.",
"type": "boolean"
}
},
@@ -5567,6 +5591,13 @@
"$ref": "#/definitions/ExternalAgentConfigMigrationItem"
},
"type": "array"
},
"source": {
"description": "Source product that produced the migration items. Missing means unspecified.",
"type": [
"string",
"null"
]
}
},
"required": [
@@ -6697,6 +6728,28 @@
"title": "GetAccountTokenUsageResponse",
"type": "object"
},
"GetWorkspaceMessagesResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"featureEnabled": {
"description": "Whether the workspace-message backend route is available for this client.",
"type": "boolean"
},
"messages": {
"description": "Active workspace messages returned by the backend.",
"items": {
"$ref": "#/definitions/WorkspaceMessage"
},
"type": "array"
}
},
"required": [
"featureEnabled",
"messages"
],
"title": "GetWorkspaceMessagesResponse",
"type": "object"
},
"GitInfo": {
"properties": {
"branch": {
@@ -7432,6 +7485,10 @@
"description": "Opt into receiving experimental API methods and fields.",
"type": "boolean"
},
"mcpServerOpenaiFormElicitation": {
"description": "Allow downstream MCP servers to request OpenAI extended form elicitations.",
"type": "boolean"
},
"optOutNotificationMethods": {
"description": "Exact notification method names that should be suppressed for this connection (for example `thread/started`).",
"items": {
@@ -8531,6 +8588,29 @@
"title": "McpServerToolCallResponse",
"type": "object"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -8948,6 +9028,41 @@
"title": "ModelReroutedNotification",
"type": "object"
},
"ModelSafetyBufferingUpdatedNotification": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"model": {
"type": "string"
},
"reasons": {
"items": {
"type": "string"
},
"type": "array"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
},
"useCases": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"model",
"reasons",
"threadId",
"turnId",
"useCases"
],
"title": "ModelSafetyBufferingUpdatedNotification",
"type": "object"
},
"ModelServiceTier": {
"properties": {
"description": {
@@ -9026,6 +9141,15 @@
"title": "ModelVerificationNotification",
"type": "object"
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
"none",
"explicitRequestOnly",
"proactive"
],
"type": "string"
},
"NetworkAccess": {
"enum": [
"restricted",
@@ -10719,13 +10843,6 @@
"title": "RawResponseItemCompletedNotification",
"type": "object"
},
"RealtimeConversationArchitecture": {
"enum": [
"realtimeapi",
"avas"
],
"type": "string"
},
"RealtimeConversationVersion": {
"enum": [
"v1",
@@ -11233,8 +11350,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -11286,6 +11402,12 @@
},
"type": "array"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -11334,6 +11456,12 @@
"null"
]
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -11382,8 +11510,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -11426,8 +11553,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -11481,8 +11607,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -11521,6 +11646,12 @@
"call_id": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -11559,8 +11690,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"input": {
"type": "string"
@@ -11606,6 +11736,12 @@
"call_id": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -11652,6 +11788,12 @@
"execution": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -11702,8 +11844,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -11738,7 +11879,10 @@
{
"properties": {
"id": {
"type": "string"
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
@@ -11771,7 +11915,6 @@
}
},
"required": [
"id",
"result",
"status",
"type"
@@ -11784,6 +11927,12 @@
"encrypted_content": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -11843,6 +11992,12 @@
"null"
]
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -13338,6 +13493,26 @@
"title": "Turn/moderationMetadataNotification",
"type": "object"
},
{
"properties": {
"method": {
"enum": [
"model/safetyBuffering/updated"
],
"title": "Model/safetyBuffering/updatedNotificationMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/ModelSafetyBufferingUpdatedNotification"
}
},
"required": [
"method",
"params"
],
"title": "Model/safetyBuffering/updatedNotification",
"type": "object"
},
{
"properties": {
"method": {
@@ -14445,6 +14620,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -14749,9 +14932,9 @@
},
"instructionSources": {
"default": [],
"description": "Instruction source files currently loaded for this thread.",
"description": "Environment-native paths to instruction source files currently loaded for this thread.",
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": "array"
},
@@ -15216,7 +15399,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -15310,6 +15493,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -15333,6 +15526,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -16453,9 +16647,9 @@
},
"instructionSources": {
"default": [],
"description": "Instruction source files currently loaded for this thread.",
"description": "Environment-native paths to instruction source files currently loaded for this thread.",
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": "array"
},
@@ -16704,7 +16898,8 @@
"ThreadSortKey": {
"enum": [
"created_at",
"updated_at"
"updated_at",
"recency_at"
],
"type": "string"
},
@@ -16869,9 +17064,9 @@
},
"instructionSources": {
"default": [],
"description": "Instruction source files currently loaded for this thread.",
"description": "Environment-native paths to instruction source files currently loaded for this thread.",
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": "array"
},
@@ -18040,6 +18235,7 @@
"enum": [
"disabled",
"cached",
"indexed",
"live"
],
"type": "string"
@@ -18192,6 +18388,49 @@
"title": "WindowsWorldWritableWarningNotification",
"type": "object"
},
"WorkspaceMessage": {
"properties": {
"archivedAt": {
"description": "Unix timestamp (in seconds) when the message was archived.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"createdAt": {
"description": "Unix timestamp (in seconds) when the message was created.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"messageBody": {
"type": "string"
},
"messageId": {
"type": "string"
},
"messageType": {
"$ref": "#/definitions/WorkspaceMessageType"
}
},
"required": [
"messageBody",
"messageId",
"messageType"
],
"type": "object"
},
"WorkspaceMessageType": {
"enum": [
"headline",
"announcement",
"unknown"
],
"type": "string"
},
"WriteStatus": {
"enum": [
"ok",
@@ -30,6 +30,10 @@
"description": "Opt into receiving experimental API methods and fields.",
"type": "boolean"
},
"mcpServerOpenaiFormElicitation": {
"description": "Allow downstream MCP servers to request OpenAI extended form elicitations.",
"type": "boolean"
},
"optOutNotificationMethods": {
"description": "Exact notification method names that should be suppressed for this connection (for example `thread/started`).",
"items": {
@@ -809,6 +809,7 @@
"enum": [
"disabled",
"cached",
"indexed",
"live"
],
"type": "string"
@@ -503,6 +503,7 @@
"enum": [
"disabled",
"cached",
"indexed",
"live"
],
"type": "string"
@@ -12,7 +12,7 @@
]
},
"includeHome": {
"description": "If true, include detection under the user's home (~/.claude, ~/.codex, etc.).",
"description": "If true, include detection under the user's home directory.",
"type": "boolean"
}
},
@@ -184,6 +184,13 @@
"$ref": "#/definitions/ExternalAgentConfigMigrationItem"
},
"type": "array"
},
"source": {
"description": "Source product that produced the migration items. Missing means unspecified.",
"type": [
"string",
"null"
]
}
},
"required": [
@@ -0,0 +1,67 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"WorkspaceMessage": {
"properties": {
"archivedAt": {
"description": "Unix timestamp (in seconds) when the message was archived.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"createdAt": {
"description": "Unix timestamp (in seconds) when the message was created.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"messageBody": {
"type": "string"
},
"messageId": {
"type": "string"
},
"messageType": {
"$ref": "#/definitions/WorkspaceMessageType"
}
},
"required": [
"messageBody",
"messageId",
"messageType"
],
"type": "object"
},
"WorkspaceMessageType": {
"enum": [
"headline",
"announcement",
"unknown"
],
"type": "string"
}
},
"properties": {
"featureEnabled": {
"description": "Whether the workspace-message backend route is available for this client.",
"type": "boolean"
},
"messages": {
"description": "Active workspace messages returned by the backend.",
"items": {
"$ref": "#/definitions/WorkspaceMessage"
},
"type": "array"
}
},
"required": [
"featureEnabled",
"messages"
],
"title": "GetWorkspaceMessagesResponse",
"type": "object"
}
@@ -294,6 +294,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -687,7 +713,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -781,6 +807,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -804,6 +840,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -294,6 +294,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -687,7 +713,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -781,6 +807,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -804,6 +840,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -0,0 +1,35 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"model": {
"type": "string"
},
"reasons": {
"items": {
"type": "string"
},
"type": "array"
},
"threadId": {
"type": "string"
},
"turnId": {
"type": "string"
},
"useCases": {
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"model",
"reasons",
"threadId",
"turnId",
"useCases"
],
"title": "ModelSafetyBufferingUpdatedNotification",
"type": "object"
}
@@ -381,8 +381,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -434,6 +433,12 @@
},
"type": "array"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -482,6 +487,12 @@
"null"
]
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -530,8 +541,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -574,8 +584,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -629,8 +638,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -669,6 +677,12 @@
"call_id": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -707,8 +721,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"input": {
"type": "string"
@@ -754,6 +767,12 @@
"call_id": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -800,6 +819,12 @@
"execution": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -850,8 +875,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -886,7 +910,10 @@
{
"properties": {
"id": {
"type": "string"
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
@@ -919,7 +946,6 @@
}
},
"required": [
"id",
"result",
"status",
"type"
@@ -932,6 +958,12 @@
"encrypted_content": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -991,6 +1023,12 @@
"null"
]
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -431,6 +431,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -831,7 +857,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -925,6 +951,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -948,6 +984,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -536,6 +536,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -636,6 +662,15 @@
}
]
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
"none",
"explicitRequestOnly",
"proactive"
],
"type": "string"
},
"NetworkAccess": {
"enum": [
"restricted",
@@ -1055,6 +1090,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -1315,7 +1358,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -1409,6 +1452,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -1432,6 +1485,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -2323,9 +2377,9 @@
},
"instructionSources": {
"default": [],
"description": "Instruction source files currently loaded for this thread.",
"description": "Environment-native paths to instruction source files currently loaded for this thread.",
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": "array"
},
@@ -24,7 +24,8 @@
"ThreadSortKey": {
"enum": [
"created_at",
"updated_at"
"updated_at",
"recency_at"
],
"type": "string"
},
@@ -457,6 +457,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -870,6 +896,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -1130,7 +1164,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -1224,6 +1258,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -1247,6 +1291,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -457,6 +457,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -870,6 +896,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -1130,7 +1164,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -1224,6 +1258,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -1247,6 +1291,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -457,6 +457,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -870,6 +896,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -1130,7 +1164,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -1224,6 +1258,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -1247,6 +1291,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -452,8 +452,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -505,6 +504,12 @@
},
"type": "array"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -553,6 +558,12 @@
"null"
]
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -601,8 +612,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -645,8 +655,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -700,8 +709,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -740,6 +748,12 @@
"call_id": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -778,8 +792,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"input": {
"type": "string"
@@ -825,6 +838,12 @@
"call_id": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -871,6 +890,12 @@
"execution": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -921,8 +946,7 @@
"type": [
"string",
"null"
],
"writeOnly": true
]
},
"metadata": {
"anyOf": [
@@ -957,7 +981,10 @@
{
"properties": {
"id": {
"type": "string"
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
@@ -990,7 +1017,6 @@
}
},
"required": [
"id",
"result",
"status",
"type"
@@ -1003,6 +1029,12 @@
"encrypted_content": {
"type": "string"
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -1062,6 +1094,12 @@
"null"
]
},
"id": {
"type": [
"string",
"null"
]
},
"metadata": {
"anyOf": [
{
@@ -536,6 +536,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -636,6 +662,15 @@
}
]
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
"none",
"explicitRequestOnly",
"proactive"
],
"type": "string"
},
"NetworkAccess": {
"enum": [
"restricted",
@@ -1055,6 +1090,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -1315,7 +1358,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -1409,6 +1452,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -1432,6 +1485,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -2349,9 +2403,9 @@
},
"instructionSources": {
"default": [],
"description": "Instruction source files currently loaded for this thread.",
"description": "Environment-native paths to instruction source files currently loaded for this thread.",
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": "array"
},
@@ -457,6 +457,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -870,6 +896,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -1130,7 +1164,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -1224,6 +1258,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -1247,6 +1291,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -108,6 +108,15 @@
],
"type": "string"
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
"none",
"explicitRequestOnly",
"proactive"
],
"type": "string"
},
"NetworkAccess": {
"enum": [
"restricted",
@@ -194,6 +194,15 @@
"LegacyAppPathString": {
"type": "string"
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
"none",
"explicitRequestOnly",
"proactive"
],
"type": "string"
},
"Personality": {
"enum": [
"none",
@@ -536,6 +536,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -636,6 +662,15 @@
}
]
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
"none",
"explicitRequestOnly",
"proactive"
],
"type": "string"
},
"NetworkAccess": {
"enum": [
"restricted",
@@ -1055,6 +1090,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -1315,7 +1358,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -1409,6 +1452,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -1432,6 +1485,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -2323,9 +2377,9 @@
},
"instructionSources": {
"default": [],
"description": "Instruction source files currently loaded for this thread.",
"description": "Environment-native paths to instruction source files currently loaded for this thread.",
"items": {
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
},
"type": "array"
},
@@ -457,6 +457,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -870,6 +896,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -1130,7 +1164,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -1224,6 +1258,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -1247,6 +1291,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -457,6 +457,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -870,6 +896,14 @@
"description": "Usually the first user message in the thread, if available.",
"type": "string"
},
"recencyAt": {
"description": "Unix timestamp (in seconds) used for thread recency ordering.",
"format": "int64",
"type": [
"integer",
"null"
]
},
"sessionId": {
"description": "Session id shared by threads that belong to the same session tree.",
"type": "string"
@@ -1130,7 +1164,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -1224,6 +1258,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -1247,6 +1291,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -431,6 +431,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -831,7 +857,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -925,6 +951,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -948,6 +984,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -141,6 +141,15 @@
],
"type": "string"
},
"MultiAgentMode": {
"description": "Controls whether the model receives multi-agent delegation instructions and, when it does, whether it should only spawn sub-agents after an explicit user request or may delegate proactively when doing so would help. `none` leaves the multi-agent tools available without injecting delegation instructions.",
"enum": [
"none",
"explicitRequestOnly",
"proactive"
],
"type": "string"
},
"NetworkAccess": {
"enum": [
"restricted",
@@ -431,6 +431,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -831,7 +857,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -925,6 +951,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -948,6 +984,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
@@ -431,6 +431,32 @@
],
"type": "string"
},
"LegacyAppPathString": {
"type": "string"
},
"McpToolCallAppContext": {
"properties": {
"connectorId": {
"type": "string"
},
"linkId": {
"type": [
"string",
"null"
]
},
"resourceUri": {
"type": [
"string",
"null"
]
}
},
"required": [
"connectorId"
],
"type": "object"
},
"McpToolCallError": {
"properties": {
"message": {
@@ -831,7 +857,7 @@
"cwd": {
"allOf": [
{
"$ref": "#/definitions/AbsolutePathBuf"
"$ref": "#/definitions/LegacyAppPathString"
}
],
"description": "The command's working directory."
@@ -925,6 +951,16 @@
},
{
"properties": {
"appContext": {
"anyOf": [
{
"$ref": "#/definitions/McpToolCallAppContext"
},
{
"type": "null"
}
]
},
"arguments": true,
"durationMs": {
"description": "The duration of the MCP tool call in milliseconds.",
@@ -948,6 +984,7 @@
"type": "string"
},
"mcpAppResourceUri": {
"description": "Deprecated: use `appContext.resourceUri` instead.",
"type": [
"string",
"null"
File diff suppressed because one or more lines are too long
@@ -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 ConversationTextRole = "user" | "developer";
export type ConversationTextRole = "user" | "developer" | "assistant";
@@ -14,6 +14,10 @@ experimentalApi: boolean,
* Opt into `attestation/generate` requests for upstream `x-oai-attestation`.
*/
requestAttestation: boolean,
/**
* Allow downstream MCP servers to request OpenAI extended form elicitations.
*/
mcpServerOpenaiFormElicitation?: boolean,
/**
* Exact notification method names that should be suppressed for this
* connection (for example `thread/started`).
@@ -0,0 +1,11 @@
// 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.
/**
* Controls whether the model receives multi-agent delegation instructions and,
* when it does, whether it should only spawn sub-agents after an explicit user
* request or may delegate proactively when doing so would help. `none` leaves
* the multi-agent tools available without injecting delegation instructions.
*/
export type MultiAgentMode = "none" | "explicitRequestOnly" | "proactive";
@@ -12,8 +12,12 @@ import type { ReasoningItemReasoningSummary } from "./ReasoningItemReasoningSumm
import type { ResponseItemMetadata } from "./ResponseItemMetadata";
import type { WebSearchAction } from "./WebSearchAction";
export type ResponseItem = { "type": "message", role: string, content: Array<ContentItem>, phase?: MessagePhase, metadata?: ResponseItemMetadata, } | { "type": "agent_message", author: string, recipient: string, content: Array<AgentMessageInputContent>, metadata?: ResponseItemMetadata, } | { "type": "reasoning", summary: Array<ReasoningItemReasoningSummary>, content?: Array<ReasoningItemContent>, encrypted_content: string | null, metadata?: ResponseItemMetadata, } | { "type": "local_shell_call",
export type ResponseItem = { "type": "message", id?: string, role: string, content: Array<ContentItem>, phase?: MessagePhase, metadata?: ResponseItemMetadata, } | { "type": "agent_message", id?: string, author: string, recipient: string, content: Array<AgentMessageInputContent>, metadata?: ResponseItemMetadata, } | { "type": "reasoning", id?: string, summary: Array<ReasoningItemReasoningSummary>, content?: Array<ReasoningItemContent>, encrypted_content: string | null, metadata?: ResponseItemMetadata, } | { "type": "local_shell_call",
/**
* Legacy id field retained for compatibility with older payloads.
*/
id?: string,
/**
* Set when using the Responses API.
*/
call_id: string | null, status: LocalShellStatus, action: LocalShellAction, metadata?: ResponseItemMetadata, } | { "type": "function_call", name: string, namespace?: string, arguments: string, call_id: string, metadata?: ResponseItemMetadata, } | { "type": "tool_search_call", call_id: string | null, status?: string, execution: string, arguments: unknown, metadata?: ResponseItemMetadata, } | { "type": "function_call_output", call_id: string, output: FunctionCallOutputBody, metadata?: ResponseItemMetadata, } | { "type": "custom_tool_call", status?: string, call_id: string, name: string, input: string, metadata?: ResponseItemMetadata, } | { "type": "custom_tool_call_output", call_id: string, name?: string, output: FunctionCallOutputBody, metadata?: ResponseItemMetadata, } | { "type": "tool_search_output", call_id: string | null, status: string, execution: string, tools: unknown[], metadata?: ResponseItemMetadata, } | { "type": "web_search_call", status?: string, action?: WebSearchAction, metadata?: ResponseItemMetadata, } | { "type": "image_generation_call", id: string, status: string, revised_prompt?: string, result: string, metadata?: ResponseItemMetadata, } | { "type": "compaction", encrypted_content: string, metadata?: ResponseItemMetadata, } | { "type": "compaction_trigger", metadata?: ResponseItemMetadata, } | { "type": "context_compaction", encrypted_content?: string, metadata?: ResponseItemMetadata, } | { "type": "other" };
call_id: string | null, status: LocalShellStatus, action: LocalShellAction, metadata?: ResponseItemMetadata, } | { "type": "function_call", id?: string, name: string, namespace?: string, arguments: string, call_id: string, metadata?: ResponseItemMetadata, } | { "type": "tool_search_call", id?: string, call_id: string | null, status?: string, execution: string, arguments: unknown, metadata?: ResponseItemMetadata, } | { "type": "function_call_output", id?: string, call_id: string, output: FunctionCallOutputBody, metadata?: ResponseItemMetadata, } | { "type": "custom_tool_call", id?: string, status?: string, call_id: string, name: string, input: string, metadata?: ResponseItemMetadata, } | { "type": "custom_tool_call_output", id?: string, call_id: string, name?: string, output: FunctionCallOutputBody, metadata?: ResponseItemMetadata, } | { "type": "tool_search_output", id?: string, call_id: string | null, status: string, execution: string, tools: unknown[], metadata?: ResponseItemMetadata, } | { "type": "web_search_call", id?: string, status?: string, action?: WebSearchAction, metadata?: ResponseItemMetadata, } | { "type": "image_generation_call", id?: string, status: string, revised_prompt?: string, result: string, metadata?: ResponseItemMetadata, } | { "type": "compaction", id?: string, encrypted_content: string, metadata?: ResponseItemMetadata, } | { "type": "compaction_trigger", metadata?: ResponseItemMetadata, } | { "type": "context_compaction", id?: string, encrypted_content?: string, metadata?: ResponseItemMetadata, } | { "type": "other" };
File diff suppressed because one or more lines are too long
@@ -16,4 +16,4 @@ import type { ToolRequestUserInputParams } from "./v2/ToolRequestUserInputParams
/**
* Request initiated from the server and sent to the client.
*/
export type ServerRequest = { "method": "item/commandExecution/requestApproval", id: RequestId, params: CommandExecutionRequestApprovalParams, } | { "method": "item/fileChange/requestApproval", id: RequestId, params: FileChangeRequestApprovalParams, } | { "method": "item/tool/requestUserInput", id: RequestId, params: ToolRequestUserInputParams, } | { "method": "mcpServer/elicitation/request", id: RequestId, params: McpServerElicitationRequestParams, } | { "method": "item/permissions/requestApproval", id: RequestId, params: PermissionsRequestApprovalParams, } | { "method": "item/tool/call", id: RequestId, params: DynamicToolCallParams, } | { "method": "account/chatgptAuthTokens/refresh", id: RequestId, params: ChatgptAuthTokensRefreshParams, } | { "method": "attestation/generate", id: RequestId, params: AttestationGenerateParams, } | { "method": "applyPatchApproval", id: RequestId, params: ApplyPatchApprovalParams, } | { "method": "execCommandApproval", id: RequestId, params: ExecCommandApprovalParams, };
export type ServerRequest ={ "method": "item/commandExecution/requestApproval", id: RequestId, params: CommandExecutionRequestApprovalParams, } | { "method": "item/fileChange/requestApproval", id: RequestId, params: FileChangeRequestApprovalParams, } | { "method": "item/tool/requestUserInput", id: RequestId, params: ToolRequestUserInputParams, } | { "method": "mcpServer/elicitation/request", id: RequestId, params: McpServerElicitationRequestParams, } | { "method": "item/permissions/requestApproval", id: RequestId, params: PermissionsRequestApprovalParams, } | { "method": "item/tool/call", id: RequestId, params: DynamicToolCallParams, } | { "method": "account/chatgptAuthTokens/refresh", id: RequestId, params: ChatgptAuthTokensRefreshParams, } | { "method": "attestation/generate", id: RequestId, params: AttestationGenerateParams, } | { "method": "applyPatchApproval", id: RequestId, params: ApplyPatchApprovalParams, } | { "method": "execCommandApproval", id: RequestId, params: ExecCommandApprovalParams, };
@@ -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 WebSearchMode = "disabled" | "cached" | "live";
export type WebSearchMode = "disabled" | "cached" | "indexed" | "live";
+1 -1
View File
@@ -49,12 +49,12 @@ export type { LocalShellStatus } from "./LocalShellStatus";
export type { McpServerInfo } from "./McpServerInfo";
export type { MessagePhase } from "./MessagePhase";
export type { ModeKind } from "./ModeKind";
export type { MultiAgentMode } from "./MultiAgentMode";
export type { NetworkPolicyAmendment } from "./NetworkPolicyAmendment";
export type { NetworkPolicyRuleAction } from "./NetworkPolicyRuleAction";
export type { ParsedCommand } from "./ParsedCommand";
export type { Personality } from "./Personality";
export type { PlanType } from "./PlanType";
export type { RealtimeConversationArchitecture } from "./RealtimeConversationArchitecture";
export type { RealtimeConversationVersion } from "./RealtimeConversationVersion";
export type { RealtimeOutputModality } from "./RealtimeOutputModality";
export type { RealtimeVoice } from "./RealtimeVoice";
@@ -1,7 +1,7 @@
// 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 { AbsolutePathBuf } from "../AbsolutePathBuf";
import type { LegacyAppPathString } from "../LegacyAppPathString";
import type { CommandAction } from "./CommandAction";
import type { ExecPolicyAmendment } from "./ExecPolicyAmendment";
import type { NetworkApprovalContext } from "./NetworkApprovalContext";
@@ -34,7 +34,7 @@ networkApprovalContext?: NetworkApprovalContext | null, /**
command?: string | null, /**
* The command's working directory.
*/
cwd?: AbsolutePathBuf | null, /**
cwd?: LegacyAppPathString | null, /**
* Best-effort parsed command actions for friendly display.
*/
commandActions?: Array<CommandAction> | null, /**
@@ -4,7 +4,7 @@
export type ExternalAgentConfigDetectParams = {
/**
* If true, include detection under the user's home (~/.claude, ~/.codex, etc.).
* If true, include detection under the user's home directory.
*/
includeHome?: boolean,
/**
@@ -3,4 +3,8 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ExternalAgentConfigMigrationItem } from "./ExternalAgentConfigMigrationItem";
export type ExternalAgentConfigImportParams = { migrationItems: Array<ExternalAgentConfigMigrationItem>, };
export type ExternalAgentConfigImportParams = { migrationItems: Array<ExternalAgentConfigMigrationItem>,
/**
* Source product that produced the migration items. Missing means unspecified.
*/
source?: string | null, };
@@ -0,0 +1,14 @@
// 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 { WorkspaceMessage } from "./WorkspaceMessage";
export type GetWorkspaceMessagesResponse = {
/**
* Whether the workspace-message backend route is available for this client.
*/
featureEnabled: boolean,
/**
* Active workspace messages returned by the backend.
*/
messages: Array<WorkspaceMessage>, };
@@ -13,4 +13,4 @@ export type McpServerElicitationRequestParams = { threadId: string,
* context is app-server correlation rather than part of the protocol identity of the
* elicitation itself.
*/
turnId: string | null, serverName: string, } & ({ "mode": "form", _meta: JsonValue | null, message: string, requestedSchema: McpElicitationSchema, } | { "mode": "url", _meta: JsonValue | null, message: string, url: string, elicitationId: string, });
turnId: string | null, serverName: string, } & ({ "mode": "form", _meta: JsonValue | null, message: string, requestedSchema: McpElicitationSchema, } | { "mode": "openai/form", _meta: JsonValue | null, message: string, requestedSchema: JsonValue, } | { "mode": "url", _meta: JsonValue | null, message: string, url: string, elicitationId: string, });
@@ -0,0 +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.
export type McpToolCallAppContext = { connectorId: string, linkId: string | null, resourceUri: string | null, };
@@ -0,0 +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.
export type ModelSafetyBufferingUpdatedNotification = { threadId: string, turnId: string, model: string, useCases: Array<string>, reasons: Array<string>, };
@@ -41,6 +41,10 @@ createdAt: number,
* Unix timestamp (in seconds) when the thread was last updated.
*/
updatedAt: number,
/**
* Unix timestamp (in seconds) used for thread recency ordering.
*/
recencyAt: number | null,
/**
* Current runtime status for the thread.
*/
@@ -2,6 +2,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
import type { LegacyAppPathString } from "../LegacyAppPathString";
import type { ReasoningEffort } from "../ReasoningEffort";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
@@ -9,9 +10,9 @@ import type { SandboxPolicy } from "./SandboxPolicy";
import type { Thread } from "./Thread";
export type ThreadForkResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: string | null, cwd: AbsolutePathBuf, /**
* Instruction source files currently loaded for this thread.
* Environment-native paths to instruction source files currently loaded for this thread.
*/
instructionSources: Array<AbsolutePathBuf>, approvalPolicy: AskForApproval, /**
instructionSources: Array<LegacyAppPathString>, approvalPolicy: AskForApproval, /**
* Reviewer currently used for approval requests on this thread.
*/
approvalsReviewer: ApprovalsReviewer, /**
@@ -2,6 +2,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
import type { LegacyAppPathString } from "../LegacyAppPathString";
import type { MessagePhase } from "../MessagePhase";
import type { ReasoningEffort } from "../ReasoningEffort";
import type { JsonValue } from "../serde_json/JsonValue";
@@ -15,6 +16,7 @@ import type { DynamicToolCallOutputContentItem } from "./DynamicToolCallOutputCo
import type { DynamicToolCallStatus } from "./DynamicToolCallStatus";
import type { FileUpdateChange } from "./FileUpdateChange";
import type { HookPromptFragment } from "./HookPromptFragment";
import type { McpToolCallAppContext } from "./McpToolCallAppContext";
import type { McpToolCallError } from "./McpToolCallError";
import type { McpToolCallResult } from "./McpToolCallResult";
import type { McpToolCallStatus } from "./McpToolCallStatus";
@@ -32,7 +34,7 @@ command: string,
/**
* The command's working directory.
*/
cwd: AbsolutePathBuf,
cwd: LegacyAppPathString,
/**
* Identifier for the underlying PTY process (when available).
*/
@@ -54,7 +56,11 @@ exitCode: number | null,
/**
* The duration of the command execution in milliseconds.
*/
durationMs: number | null, } | { "type": "fileChange", id: string, changes: Array<FileUpdateChange>, status: PatchApplyStatus, } | { "type": "mcpToolCall", id: string, server: string, tool: string, status: McpToolCallStatus, arguments: JsonValue, mcpAppResourceUri?: string, pluginId: string | null, result: McpToolCallResult | null, error: McpToolCallError | null,
durationMs: number | null, } | { "type": "fileChange", id: string, changes: Array<FileUpdateChange>, status: PatchApplyStatus, } | { "type": "mcpToolCall", id: string, server: string, tool: string, status: McpToolCallStatus, arguments: JsonValue, appContext: McpToolCallAppContext | null,
/**
* Deprecated: use `appContext.resourceUri` instead.
*/
mcpAppResourceUri?: string, pluginId: string | null, result: McpToolCallResult | null, error: McpToolCallError | null,
/**
* The duration of the MCP tool call in milliseconds.
*/
@@ -2,6 +2,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
import type { LegacyAppPathString } from "../LegacyAppPathString";
import type { ReasoningEffort } from "../ReasoningEffort";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
@@ -9,9 +10,9 @@ import type { SandboxPolicy } from "./SandboxPolicy";
import type { Thread } from "./Thread";
export type ThreadResumeResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: string | null, cwd: AbsolutePathBuf, /**
* Instruction source files currently loaded for this thread.
* Environment-native paths to instruction source files currently loaded for this thread.
*/
instructionSources: Array<AbsolutePathBuf>, approvalPolicy: AskForApproval, /**
instructionSources: Array<LegacyAppPathString>, approvalPolicy: AskForApproval, /**
* Reviewer currently used for approval requests on this thread.
*/
approvalsReviewer: ApprovalsReviewer, /**
@@ -11,4 +11,4 @@ import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
import type { SandboxPolicy } from "./SandboxPolicy";
export type ThreadSettings = { cwd: AbsolutePathBuf, approvalPolicy: AskForApproval, approvalsReviewer: ApprovalsReviewer, sandboxPolicy: SandboxPolicy, activePermissionProfile: ActivePermissionProfile | null, model: string, modelProvider: string, serviceTier: string | null, effort: ReasoningEffort | null, summary: ReasoningSummary | null, collaborationMode: CollaborationMode, personality: Personality | null, };
export type ThreadSettings = {cwd: AbsolutePathBuf, approvalPolicy: AskForApproval, approvalsReviewer: ApprovalsReviewer, sandboxPolicy: SandboxPolicy, activePermissionProfile: ActivePermissionProfile | null, model: string, modelProvider: string, serviceTier: string | null, effort: ReasoningEffort | null, summary: ReasoningSummary | null, collaborationMode: CollaborationMode, personality: Personality | null};
@@ -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 ThreadSortKey = "created_at" | "updated_at";
export type ThreadSortKey = "created_at" | "updated_at" | "recency_at";
@@ -2,6 +2,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
import type { LegacyAppPathString } from "../LegacyAppPathString";
import type { ReasoningEffort } from "../ReasoningEffort";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AskForApproval } from "./AskForApproval";
@@ -9,9 +10,9 @@ import type { SandboxPolicy } from "./SandboxPolicy";
import type { Thread } from "./Thread";
export type ThreadStartResponse = {thread: Thread, model: string, modelProvider: string, serviceTier: string | null, cwd: AbsolutePathBuf, /**
* Instruction source files currently loaded for this thread.
* Environment-native paths to instruction source files currently loaded for this thread.
*/
instructionSources: Array<AbsolutePathBuf>, approvalPolicy: AskForApproval, /**
instructionSources: Array<LegacyAppPathString>, approvalPolicy: AskForApproval, /**
* Reviewer currently used for approval requests on this thread.
*/
approvalsReviewer: ApprovalsReviewer, /**
@@ -0,0 +1,14 @@
// 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 { WorkspaceMessageType } from "./WorkspaceMessageType";
export type WorkspaceMessage = { messageId: string, messageType: WorkspaceMessageType, messageBody: string,
/**
* Unix timestamp (in seconds) when the message was created.
*/
createdAt: number | null,
/**
* Unix timestamp (in seconds) when the message was archived.
*/
archivedAt: number | null, };
@@ -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 RealtimeConversationArchitecture = "realtimeapi" | "avas";
export type WorkspaceMessageType = "headline" | "announcement" | "unknown";
@@ -157,6 +157,7 @@ export type { GetAccountParams } from "./GetAccountParams";
export type { GetAccountRateLimitsResponse } from "./GetAccountRateLimitsResponse";
export type { GetAccountResponse } from "./GetAccountResponse";
export type { GetAccountTokenUsageResponse } from "./GetAccountTokenUsageResponse";
export type { GetWorkspaceMessagesResponse } from "./GetWorkspaceMessagesResponse";
export type { GitInfo } from "./GitInfo";
export type { GrantedPermissionProfile } from "./GrantedPermissionProfile";
export type { GuardianApprovalReview } from "./GuardianApprovalReview";
@@ -243,6 +244,7 @@ export type { McpServerStatusDetail } from "./McpServerStatusDetail";
export type { McpServerStatusUpdatedNotification } from "./McpServerStatusUpdatedNotification";
export type { McpServerToolCallParams } from "./McpServerToolCallParams";
export type { McpServerToolCallResponse } from "./McpServerToolCallResponse";
export type { McpToolCallAppContext } from "./McpToolCallAppContext";
export type { McpToolCallError } from "./McpToolCallError";
export type { McpToolCallProgressNotification } from "./McpToolCallProgressNotification";
export type { McpToolCallResult } from "./McpToolCallResult";
@@ -259,6 +261,7 @@ export type { ModelProviderCapabilitiesReadParams } from "./ModelProviderCapabil
export type { ModelProviderCapabilitiesReadResponse } from "./ModelProviderCapabilitiesReadResponse";
export type { ModelRerouteReason } from "./ModelRerouteReason";
export type { ModelReroutedNotification } from "./ModelReroutedNotification";
export type { ModelSafetyBufferingUpdatedNotification } from "./ModelSafetyBufferingUpdatedNotification";
export type { ModelServiceTier } from "./ModelServiceTier";
export type { ModelUpgradeInfo } from "./ModelUpgradeInfo";
export type { ModelVerification } from "./ModelVerification";
@@ -492,4 +495,6 @@ export type { WindowsSandboxSetupMode } from "./WindowsSandboxSetupMode";
export type { WindowsSandboxSetupStartParams } from "./WindowsSandboxSetupStartParams";
export type { WindowsSandboxSetupStartResponse } from "./WindowsSandboxSetupStartResponse";
export type { WindowsWorldWritableWarningNotification } from "./WindowsWorldWritableWarningNotification";
export type { WorkspaceMessage } from "./WorkspaceMessage";
export type { WorkspaceMessageType } from "./WorkspaceMessageType";
export type { WriteStatus } from "./WriteStatus";
+37 -13
View File
@@ -14,6 +14,9 @@ use crate::export_server_responses;
use crate::protocol::common::EXPERIMENTAL_CLIENT_METHOD_PARAM_TYPES;
use crate::protocol::common::EXPERIMENTAL_CLIENT_METHOD_RESPONSE_TYPES;
use crate::protocol::common::EXPERIMENTAL_CLIENT_METHODS;
use crate::protocol::common::EXPERIMENTAL_SERVER_METHOD_PARAM_TYPES;
use crate::protocol::common::EXPERIMENTAL_SERVER_METHOD_RESPONSE_TYPES;
use crate::protocol::common::EXPERIMENTAL_SERVER_METHODS;
use anyhow::Context;
use anyhow::Result;
use anyhow::anyhow;
@@ -249,10 +252,10 @@ fn filter_experimental_ts(out_dir: &Path) -> Result<()> {
let registered_fields = experimental_fields();
let experimental_method_types = experimental_method_types();
// Most generated TS files are filtered by schema processing, but
// `ClientRequest.ts` and any type with `#[experimental(...)]` fields need
// direct post-processing because they encode method/field information in
// file-local unions/interfaces.
filter_client_request_ts(out_dir, EXPERIMENTAL_CLIENT_METHODS)?;
// Request unions and types with `#[experimental(...)]` fields need direct
// post-processing because they encode method/field information locally.
filter_request_ts(out_dir, "ClientRequest.ts", EXPERIMENTAL_CLIENT_METHODS)?;
filter_request_ts(out_dir, "ServerRequest.ts", EXPERIMENTAL_SERVER_METHODS)?;
filter_experimental_type_fields_ts(out_dir, &registered_fields)?;
remove_generated_type_files(out_dir, &experimental_method_types, "ts")?;
Ok(())
@@ -261,10 +264,13 @@ fn filter_experimental_ts(out_dir: &Path) -> Result<()> {
pub(crate) fn filter_experimental_ts_tree(tree: &mut BTreeMap<PathBuf, String>) -> Result<()> {
let registered_fields = experimental_fields();
let experimental_method_types = experimental_method_types();
if let Some(content) = tree.get_mut(Path::new("ClientRequest.ts")) {
let filtered =
filter_client_request_ts_contents(std::mem::take(content), EXPERIMENTAL_CLIENT_METHODS);
*content = filtered;
for (file_name, experimental_methods) in [
("ClientRequest.ts", EXPERIMENTAL_CLIENT_METHODS),
("ServerRequest.ts", EXPERIMENTAL_SERVER_METHODS),
] {
if let Some(content) = tree.get_mut(Path::new(file_name)) {
*content = filter_request_ts_contents(std::mem::take(content), experimental_methods);
}
}
let mut fields_by_type_name: HashMap<String, HashSet<String>> = HashMap::new();
@@ -293,21 +299,21 @@ pub(crate) fn filter_experimental_ts_tree(tree: &mut BTreeMap<PathBuf, String>)
Ok(())
}
/// Removes union arms from `ClientRequest.ts` for methods marked experimental.
fn filter_client_request_ts(out_dir: &Path, experimental_methods: &[&str]) -> Result<()> {
let path = out_dir.join("ClientRequest.ts");
/// Removes union arms from a generated request type for methods marked experimental.
fn filter_request_ts(out_dir: &Path, file_name: &str, experimental_methods: &[&str]) -> Result<()> {
let path = out_dir.join(file_name);
if !path.exists() {
return Ok(());
}
let mut content =
fs::read_to_string(&path).with_context(|| format!("Failed to read {}", path.display()))?;
content = filter_client_request_ts_contents(content, experimental_methods);
content = filter_request_ts_contents(content, experimental_methods);
fs::write(&path, content).with_context(|| format!("Failed to write {}", path.display()))?;
Ok(())
}
fn filter_client_request_ts_contents(mut content: String, experimental_methods: &[&str]) -> String {
fn filter_request_ts_contents(mut content: String, experimental_methods: &[&str]) -> String {
let Some((prefix, body, suffix)) = split_type_alias(&content) else {
return content;
};
@@ -404,6 +410,7 @@ fn filter_experimental_schema(bundle: &mut Value) -> Result<()> {
filter_experimental_fields_in_root(bundle, &registered_fields);
filter_experimental_fields_in_definitions(bundle, &registered_fields);
prune_experimental_methods(bundle, EXPERIMENTAL_CLIENT_METHODS);
prune_experimental_methods(bundle, EXPERIMENTAL_SERVER_METHODS);
remove_experimental_method_type_definitions(bundle);
Ok(())
}
@@ -560,6 +567,8 @@ fn experimental_method_types() -> HashSet<String> {
collect_experimental_type_names(EXPERIMENTAL_CLIENT_METHOD_PARAM_TYPES, &mut type_names);
collect_experimental_type_names(EXPERIMENTAL_CLIENT_METHOD_RESPONSE_TYPES, &mut type_names);
collect_experimental_type_names(EXPERIMENTAL_CLIENT_METHOD_DEPENDENCY_TYPES, &mut type_names);
collect_experimental_type_names(EXPERIMENTAL_SERVER_METHOD_PARAM_TYPES, &mut type_names);
collect_experimental_type_names(EXPERIMENTAL_SERVER_METHOD_RESPONSE_TYPES, &mut type_names);
type_names
}
@@ -2118,6 +2127,13 @@ mod tests {
client_request_ts.contains("MockExperimentalMethodParams"),
false
);
let server_request_ts = std::str::from_utf8(
fixture_tree
.get(Path::new("ServerRequest.ts"))
.ok_or_else(|| anyhow::anyhow!("missing ServerRequest.ts fixture"))?,
)?;
assert_eq!(server_request_ts.contains("currentTime/read"), false);
assert_eq!(server_request_ts.contains("CurrentTimeReadParams"), false);
let typescript_index = std::str::from_utf8(
fixture_tree
.get(Path::new("index.ts"))
@@ -2138,6 +2154,14 @@ mod tests {
fixture_tree.contains_key(Path::new("v2/MockExperimentalMethodResponse.ts")),
false
);
assert_eq!(
fixture_tree.contains_key(Path::new("v2/CurrentTimeReadParams.ts")),
false
);
assert_eq!(
fixture_tree.contains_key(Path::new("v2/CurrentTimeReadResponse.ts")),
false
);
assert_eq!(
fixture_tree.contains_key(Path::new("v2/RemoteControlClient.ts")),
false
@@ -1022,6 +1022,12 @@ client_request_definitions! {
response: v2::GetAccountTokenUsageResponse,
},
GetWorkspaceMessages => "account/workspaceMessages/read" {
params: #[ts(type = "undefined")] #[serde(skip_serializing_if = "Option::is_none")] Option<()>,
serialization: None,
response: v2::GetWorkspaceMessagesResponse,
},
SendAddCreditsNudgeEmail => "account/sendAddCreditsNudgeEmail" {
params: v2::SendAddCreditsNudgeEmailParams,
serialization: global("account-auth"),
@@ -1184,7 +1190,8 @@ client_request_definitions! {
macro_rules! server_request_definitions {
(
$(
$(#[$variant_meta:meta])*
$(#[experimental($reason:expr)])?
$(#[doc = $variant_doc:literal])*
$variant:ident $(=> $wire:literal)? {
params: $params:ty,
response: $response:ty,
@@ -1197,7 +1204,7 @@ macro_rules! server_request_definitions {
#[serde(tag = "method", rename_all = "camelCase")]
pub enum ServerRequest {
$(
$(#[$variant_meta])*
$(#[doc = $variant_doc])*
$(#[serde(rename = $wire)] #[ts(rename = $wire)])?
$variant {
#[serde(rename = "id")]
@@ -1237,7 +1244,7 @@ macro_rules! server_request_definitions {
#[serde(tag = "method", rename_all = "camelCase")]
pub enum ServerResponse {
$(
$(#[$variant_meta])*
$(#[doc = $variant_doc])*
$(#[serde(rename = $wire)])?
$variant {
#[serde(rename = "id")]
@@ -1281,6 +1288,22 @@ macro_rules! server_request_definitions {
}
}
pub(crate) const EXPERIMENTAL_SERVER_METHODS: &[&str] = &[
$(
experimental_method_entry!($(#[experimental($reason)])? $(=> $wire)?),
)*
];
pub(crate) const EXPERIMENTAL_SERVER_METHOD_PARAM_TYPES: &[&str] = &[
$(
experimental_type_entry!($(#[experimental($reason)])? $params),
)*
];
pub(crate) const EXPERIMENTAL_SERVER_METHOD_RESPONSE_TYPES: &[&str] = &[
$(
experimental_type_entry!($(#[experimental($reason)])? $response),
)*
];
pub fn export_server_responses(
out_dir: &::std::path::Path,
) -> ::std::result::Result<(), ::ts_rs::ExportError> {
@@ -1470,6 +1493,13 @@ server_request_definitions! {
response: v2::AttestationGenerateResponse,
},
#[experimental("currentTime/read")]
/// Read the current time from an external clock owned by the client.
CurrentTimeRead => "currentTime/read" {
params: v2::CurrentTimeReadParams,
response: v2::CurrentTimeReadResponse,
},
/// DEPRECATED APIs below
/// Request to approve a patch.
/// This request is used for Turns started via the legacy APIs (i.e. SendUserTurn, SendUserMessage).
@@ -1631,6 +1661,7 @@ server_notification_definitions! {
ModelVerification => "model/verification" (v2::ModelVerificationNotification),
#[experimental("turn/moderationMetadata")]
TurnModerationMetadata => "turn/moderationMetadata" (v2::TurnModerationMetadataNotification),
ModelSafetyBufferingUpdated => "model/safetyBuffering/updated" (v2::ModelSafetyBufferingUpdatedNotification),
Warning => "warning" (v2::WarningNotification),
GuardianWarning => "guardianWarning" (v2::GuardianWarningNotification),
DeprecationNotice => "deprecationNotice" (v2::DeprecationNoticeNotification),
@@ -1676,9 +1707,9 @@ mod tests {
use codex_protocol::ThreadId;
use codex_protocol::account::AmazonBedrockCredentialSource;
use codex_protocol::account::PlanType;
use codex_protocol::config_types::MultiAgentMode;
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_READ_ONLY;
use codex_protocol::parse_command::ParsedCommand;
use codex_protocol::protocol::RealtimeConversationArchitecture;
use codex_protocol::protocol::RealtimeConversationVersion;
use codex_protocol::protocol::RealtimeOutputModality;
use codex_protocol::protocol::RealtimeVoice;
@@ -1988,6 +2019,7 @@ mod tests {
params: v2::EnvironmentAddParams {
environment_id: "remote-a".to_string(),
exec_server_url: "ws://127.0.0.1:8765".to_string(),
connect_timeout_ms: None,
},
};
assert_eq!(
@@ -2150,7 +2182,7 @@ mod tests {
}
#[test]
fn serialize_initialize_with_opt_out_notification_methods() -> Result<()> {
fn serialize_initialize_capabilities() -> Result<()> {
let request = ClientRequest::Initialize {
request_id: RequestId::Integer(42),
params: v1::InitializeParams {
@@ -2162,6 +2194,7 @@ mod tests {
capabilities: Some(v1::InitializeCapabilities {
experimental_api: true,
request_attestation: true,
mcp_server_openai_form_elicitation: true,
opt_out_notification_methods: Some(vec![
"thread/started".to_string(),
"item/agentMessage/delta".to_string(),
@@ -2183,6 +2216,7 @@ mod tests {
"capabilities": {
"experimentalApi": true,
"requestAttestation": true,
"mcpServerOpenaiFormElicitation": true,
"optOutNotificationMethods": [
"thread/started",
"item/agentMessage/delta"
@@ -2196,7 +2230,7 @@ mod tests {
}
#[test]
fn deserialize_initialize_with_opt_out_notification_methods() -> Result<()> {
fn deserialize_initialize_capabilities() -> Result<()> {
let request: ClientRequest = serde_json::from_value(json!({
"method": "initialize",
"id": 42,
@@ -2209,6 +2243,7 @@ mod tests {
"capabilities": {
"experimentalApi": true,
"requestAttestation": true,
"mcpServerOpenaiFormElicitation": true,
"optOutNotificationMethods": [
"thread/started",
"item/agentMessage/delta"
@@ -2230,6 +2265,7 @@ mod tests {
capabilities: Some(v1::InitializeCapabilities {
experimental_api: true,
request_attestation: true,
mcp_server_openai_form_elicitation: true,
opt_out_notification_methods: Some(vec![
"thread/started".to_string(),
"item/agentMessage/delta".to_string(),
@@ -2368,6 +2404,32 @@ mod tests {
Ok(())
}
#[test]
fn serialize_current_time_read_request() -> Result<()> {
let params = v2::CurrentTimeReadParams {
thread_id: "thread-123".to_string(),
};
let request = ServerRequest::CurrentTimeRead {
request_id: RequestId::Integer(10),
params: params.clone(),
};
assert_eq!(
json!({
"method": "currentTime/read",
"id": 10,
"params": {
"threadId": "thread-123"
}
}),
serde_json::to_value(&request)?,
);
let payload = ServerRequestPayload::CurrentTimeRead(params);
assert_eq!(request.id(), &RequestId::Integer(10));
assert_eq!(payload.request_with_id(RequestId::Integer(10)), request);
Ok(())
}
#[test]
fn serialize_server_response() -> Result<()> {
let response = ServerResponse::CommandExecutionRequestApproval {
@@ -2485,6 +2547,24 @@ mod tests {
Ok(())
}
#[test]
fn serialize_get_workspace_messages() -> Result<()> {
let request = ClientRequest::GetWorkspaceMessages {
request_id: RequestId::Integer(1),
params: None,
};
assert_eq!(request.id(), &RequestId::Integer(1));
assert_eq!(request.method(), "account/workspaceMessages/read");
assert_eq!(
json!({
"method": "account/workspaceMessages/read",
"id": 1,
}),
serde_json::to_value(&request)?,
);
Ok(())
}
#[test]
fn serialize_client_response() -> Result<()> {
let cwd = absolute_path("/tmp");
@@ -2501,6 +2581,7 @@ mod tests {
model_provider: "openai".to_string(),
created_at: 1,
updated_at: 2,
recency_at: Some(3),
status: v2::ThreadStatus::Idle,
path: None,
cwd: cwd.clone(),
@@ -2518,12 +2599,17 @@ mod tests {
service_tier: None,
cwd,
runtime_workspace_roots: Vec::new(),
instruction_sources: vec![absolute_path("/tmp/AGENTS.md")],
instruction_sources: vec![
codex_utils_path_uri::LegacyAppPathString::from_abs_path(&absolute_path(
"/tmp/AGENTS.md",
)),
],
approval_policy: v2::AskForApproval::OnFailure,
approvals_reviewer: v2::ApprovalsReviewer::User,
sandbox: v2::SandboxPolicy::DangerFullAccess,
active_permission_profile: None,
reasoning_effort: None,
multi_agent_mode: MultiAgentMode::ExplicitRequestOnly,
},
};
@@ -2544,6 +2630,7 @@ mod tests {
"modelProvider": "openai",
"createdAt": 1,
"updatedAt": 2,
"recencyAt": 3,
"status": {
"type": "idle"
},
@@ -2570,7 +2657,8 @@ mod tests {
"type": "dangerFullAccess"
},
"activePermissionProfile": null,
"reasoningEffort": null
"reasoningEffort": null,
"multiAgentMode": "explicitRequestOnly"
}
}),
serde_json::to_value(&response)?,
@@ -2899,6 +2987,7 @@ mod tests {
params: v2::EnvironmentAddParams {
environment_id: "remote-a".to_string(),
exec_server_url: "ws://127.0.0.1:8765".to_string(),
connect_timeout_ms: Some(300_000),
},
};
assert_eq!(
@@ -2907,7 +2996,8 @@ mod tests {
"id": 9,
"params": {
"environmentId": "remote-a",
"execServerUrl": "ws://127.0.0.1:8765"
"execServerUrl": "ws://127.0.0.1:8765",
"connectTimeoutMs": 300000
}
}),
serde_json::to_value(&request)?,
@@ -3079,9 +3169,10 @@ mod tests {
let request = ClientRequest::ThreadRealtimeStart {
request_id: RequestId::Integer(9),
params: v2::ThreadRealtimeStartParams {
architecture: Some(RealtimeConversationArchitecture::Avas),
client_managed_handoffs: Some(true),
codex_responses_as_items: None,
codex_response_item_prefix: None,
codex_response_handoff_prefix: Some("silent context".to_string()),
thread_id: "thr_123".to_string(),
model: Some("realtime-treatment-model".to_string()),
output_modality: RealtimeOutputModality::Audio,
@@ -3098,10 +3189,11 @@ mod tests {
"method": "thread/realtime/start",
"id": 9,
"params": {
"architecture": "avas",
"threadId": "thr_123",
"clientManagedHandoffs": true,
"codexResponsesAsItems": null,
"codexResponseItemPrefix": null,
"codexResponseHandoffPrefix": "silent context",
"model": "realtime-treatment-model",
"outputModality": "audio",
"includeStartupContext": false,
@@ -3122,9 +3214,10 @@ mod tests {
let default_prompt_request = ClientRequest::ThreadRealtimeStart {
request_id: RequestId::Integer(9),
params: v2::ThreadRealtimeStartParams {
architecture: None,
client_managed_handoffs: None,
codex_responses_as_items: None,
codex_response_item_prefix: None,
codex_response_handoff_prefix: None,
thread_id: "thr_123".to_string(),
model: None,
output_modality: RealtimeOutputModality::Audio,
@@ -3141,10 +3234,11 @@ mod tests {
"method": "thread/realtime/start",
"id": 9,
"params": {
"architecture": null,
"threadId": "thr_123",
"clientManagedHandoffs": null,
"codexResponsesAsItems": null,
"codexResponseItemPrefix": null,
"codexResponseHandoffPrefix": null,
"model": null,
"outputModality": "audio",
"includeStartupContext": null,
@@ -3160,9 +3254,10 @@ mod tests {
let null_prompt_request = ClientRequest::ThreadRealtimeStart {
request_id: RequestId::Integer(9),
params: v2::ThreadRealtimeStartParams {
architecture: None,
client_managed_handoffs: None,
codex_responses_as_items: None,
codex_response_item_prefix: None,
codex_response_handoff_prefix: None,
thread_id: "thr_123".to_string(),
model: None,
output_modality: RealtimeOutputModality::Audio,
@@ -3179,10 +3274,11 @@ mod tests {
"method": "thread/realtime/start",
"id": 9,
"params": {
"architecture": null,
"threadId": "thr_123",
"clientManagedHandoffs": null,
"codexResponsesAsItems": null,
"codexResponseItemPrefix": null,
"codexResponseHandoffPrefix": null,
"model": null,
"outputModality": "audio",
"includeStartupContext": null,
@@ -3277,6 +3373,33 @@ mod tests {
Ok(())
}
#[test]
fn serialize_model_safety_buffering_updated_notification() -> Result<()> {
let notification = ServerNotification::ModelSafetyBufferingUpdated(
v2::ModelSafetyBufferingUpdatedNotification {
thread_id: "thr_123".to_string(),
turn_id: "turn_123".to_string(),
model: "gpt-5.4".to_string(),
use_cases: vec!["cyber".to_string()],
reasons: vec!["user_risk".to_string()],
},
);
assert_eq!(
json!({
"method": "model/safetyBuffering/updated",
"params": {
"threadId": "thr_123",
"turnId": "turn_123",
"model": "gpt-5.4",
"useCases": ["cyber"],
"reasons": ["user_risk"]
}
}),
serde_json::to_value(&notification)?,
);
Ok(())
}
#[test]
fn serialize_thread_realtime_output_audio_delta_notification() -> Result<()> {
let notification = ServerNotification::ThreadRealtimeOutputAudioDelta(
@@ -3327,6 +3450,7 @@ mod tests {
params: v2::EnvironmentAddParams {
environment_id: "remote-a".to_string(),
exec_server_url: "ws://127.0.0.1:8765".to_string(),
connect_timeout_ms: None,
},
};
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&request);
@@ -3364,9 +3488,10 @@ mod tests {
let request = ClientRequest::ThreadRealtimeStart {
request_id: RequestId::Integer(1),
params: v2::ThreadRealtimeStartParams {
architecture: None,
client_managed_handoffs: None,
codex_responses_as_items: None,
codex_response_item_prefix: None,
codex_response_handoff_prefix: None,
thread_id: "thr_123".to_string(),
model: None,
output_modality: RealtimeOutputModality::Audio,
@@ -3475,6 +3600,7 @@ mod tests {
developer_instructions: None,
},
},
multi_agent_mode: Default::default(),
personality: None,
},
});
@@ -23,6 +23,7 @@ use crate::protocol::v2::PatchApplyStatus;
use crate::protocol::v2::PatchChangeKind;
use crate::protocol::v2::ThreadItem;
use codex_protocol::ThreadId;
use codex_protocol::parse_command::ParsedCommand;
use codex_protocol::protocol::ApplyPatchApprovalRequestEvent;
use codex_protocol::protocol::ExecApprovalRequestEvent;
use codex_protocol::protocol::ExecCommandBeginEvent;
@@ -34,8 +35,11 @@ use codex_protocol::protocol::PatchApplyBeginEvent;
use codex_protocol::protocol::PatchApplyEndEvent;
use codex_shell_command::parse_command::parse_command;
use codex_shell_command::parse_command::shlex_join;
use codex_utils_path_uri::PathConvention;
use codex_utils_path_uri::PathUri;
use std::collections::HashMap;
use std::path::PathBuf;
use tracing::warn;
pub fn build_file_change_approval_request_item(
payload: &ApplyPatchApprovalRequestEvent,
@@ -69,7 +73,7 @@ pub fn build_command_execution_approval_request_item(
ThreadItem::CommandExecution {
id: payload.call_id.clone(),
command: shlex_join(&payload.command),
cwd: payload.cwd.clone(),
cwd: payload.cwd.clone().into(),
process_id: None,
source: CommandExecutionSource::Agent,
status: CommandExecutionStatus::InProgress,
@@ -86,19 +90,15 @@ pub fn build_command_execution_approval_request_item(
}
pub fn build_command_execution_begin_item(payload: &ExecCommandBeginEvent) -> ThreadItem {
let command_actions = command_actions_for_path_uri(&payload.parsed_cmd, &payload.cwd);
ThreadItem::CommandExecution {
id: payload.call_id.clone(),
command: shlex_join(&payload.command),
cwd: payload.cwd.clone(),
cwd: payload.cwd.clone().into(),
process_id: payload.process_id.clone(),
source: payload.source.into(),
status: CommandExecutionStatus::InProgress,
command_actions: payload
.parsed_cmd
.iter()
.cloned()
.map(|parsed| CommandAction::from_core_with_cwd(parsed, &payload.cwd))
.collect(),
command_actions,
aggregated_output: None,
exit_code: None,
duration_ms: None,
@@ -112,26 +112,63 @@ pub fn build_command_execution_end_item(payload: &ExecCommandEndEvent) -> Thread
Some(payload.aggregated_output.clone())
};
let duration_ms = i64::try_from(payload.duration.as_millis()).unwrap_or(i64::MAX);
let command_actions = command_actions_for_path_uri(&payload.parsed_cmd, &payload.cwd);
ThreadItem::CommandExecution {
id: payload.call_id.clone(),
command: shlex_join(&payload.command),
cwd: payload.cwd.clone(),
cwd: payload.cwd.clone().into(),
process_id: payload.process_id.clone(),
source: payload.source.into(),
status: (&payload.status).into(),
command_actions: payload
.parsed_cmd
.iter()
.cloned()
.map(|parsed| CommandAction::from_core_with_cwd(parsed, &payload.cwd))
.collect(),
command_actions,
aggregated_output,
exit_code: Some(payload.exit_code),
duration_ms: Some(duration_ms),
}
}
fn command_actions_for_path_uri(parsed_cmd: &[ParsedCommand], cwd: &PathUri) -> Vec<CommandAction> {
// TODO(anp): Carry PathUri into CommandAction so foreign Read actions retain resolved paths.
// Until then, omit those actions rather than project a foreign cwd onto the host.
let native_cwd = if cwd.infer_path_convention() == Some(PathConvention::native()) {
cwd.to_abs_path().ok()
} else {
None
};
parsed_cmd
.iter()
.cloned()
.filter_map(|parsed| match parsed {
ParsedCommand::Read { cmd, name, path } => match native_cwd.as_ref() {
Some(native_cwd) => Some(CommandAction::Read {
command: cmd,
name,
path: native_cwd.join(path),
}),
None => {
warn!(
command = cmd,
%cwd,
"omitting read command action whose path cannot be resolved against a foreign cwd"
);
None
}
},
ParsedCommand::ListFiles { cmd, path } => {
Some(CommandAction::ListFiles { command: cmd, path })
}
ParsedCommand::Search { cmd, query, path } => Some(CommandAction::Search {
command: cmd,
query,
path,
}),
ParsedCommand::Unknown { cmd } => Some(CommandAction::Unknown { command: cmd }),
})
.collect()
}
/// Build a guardian-derived [`ThreadItem`].
///
/// Currently this only synthesizes [`ThreadItem::CommandExecution`] for
@@ -150,7 +187,7 @@ pub fn build_item_from_guardian_event(
Some(ThreadItem::CommandExecution {
id: id.clone(),
command,
cwd: cwd.clone(),
cwd: cwd.clone().into(),
process_id: None,
source: CommandExecutionSource::Agent,
status,
@@ -186,7 +223,7 @@ pub fn build_item_from_guardian_event(
Some(ThreadItem::CommandExecution {
id: id.clone(),
command,
cwd: cwd.clone(),
cwd: cwd.clone().into(),
process_id: None,
source: CommandExecutionSource::Agent,
status,
@@ -315,3 +352,7 @@ fn format_file_change_diff(change: &FileChange) -> String {
}
}
}
#[cfg(test)]
#[path = "item_builders_tests.rs"]
mod tests;
@@ -0,0 +1,41 @@
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn foreign_read_is_omitted_without_dropping_other_command_actions() {
#[cfg(windows)]
let cwd = PathUri::parse("file:///usr/local/src").expect("valid foreign POSIX cwd");
#[cfg(not(windows))]
let cwd = PathUri::parse("file:///C:/src").expect("valid foreign Windows cwd");
let parsed_cmd = vec![
ParsedCommand::Read {
cmd: "cat file.txt".to_string(),
name: "file.txt".to_string(),
path: PathBuf::from("file.txt"),
},
ParsedCommand::ListFiles {
cmd: "ls".to_string(),
path: Some("subdir".to_string()),
},
ParsedCommand::Search {
cmd: "rg needle".to_string(),
query: Some("needle".to_string()),
path: Some("src".to_string()),
},
];
assert_eq!(
command_actions_for_path_uri(&parsed_cmd, &cwd),
vec![
CommandAction::ListFiles {
command: "ls".to_string(),
path: Some("subdir".to_string()),
},
CommandAction::Search {
command: "rg needle".to_string(),
query: Some("needle".to_string()),
path: Some("src".to_string()),
},
]
);
}
@@ -10,6 +10,7 @@ use crate::protocol::v2::CollabAgentToolCallStatus;
use crate::protocol::v2::CommandExecutionStatus;
use crate::protocol::v2::DynamicToolCallOutputContentItem;
use crate::protocol::v2::DynamicToolCallStatus;
use crate::protocol::v2::McpToolCallAppContext;
use crate::protocol::v2::McpToolCallError;
use crate::protocol::v2::McpToolCallResult;
use crate::protocol::v2::McpToolCallStatus;
@@ -765,6 +766,14 @@ impl ThreadHistoryBuilder {
.arguments
.clone()
.unwrap_or(serde_json::Value::Null),
app_context: payload
.connector_id
.clone()
.map(|connector_id| McpToolCallAppContext {
connector_id,
link_id: payload.link_id.clone(),
resource_uri: payload.mcp_app_resource_uri.clone(),
}),
mcp_app_resource_uri: payload.mcp_app_resource_uri.clone(),
plugin_id: payload.plugin_id.clone(),
result: None,
@@ -807,6 +816,14 @@ impl ThreadHistoryBuilder {
.arguments
.clone()
.unwrap_or(serde_json::Value::Null),
app_context: payload
.connector_id
.clone()
.map(|connector_id| McpToolCallAppContext {
connector_id,
link_id: payload.link_id.clone(),
resource_uri: payload.mcp_app_resource_uri.clone(),
}),
mcp_app_resource_uri: payload.mcp_app_resource_uri.clone(),
plugin_id: payload.plugin_id.clone(),
result,
@@ -1567,7 +1584,6 @@ mod tests {
use codex_protocol::protocol::DynamicToolCallResponseEvent;
use codex_protocol::protocol::ExecCommandEndEvent;
use codex_protocol::protocol::ExecCommandSource;
use codex_protocol::protocol::ItemCompletedEvent;
use codex_protocol::protocol::ItemStartedEvent;
use codex_protocol::protocol::McpInvocation;
use codex_protocol::protocol::McpToolCallEndEvent;
@@ -2376,7 +2392,7 @@ mod tests {
turn_id: "turn-1".into(),
completed_at_ms: 0,
command: vec!["echo".into(), "hello world".into()],
cwd: test_path_buf("/tmp").abs(),
cwd: test_path_buf("/tmp").abs().into(),
parsed_cmd: vec![ParsedCommand::Unknown {
cmd: "echo hello world".into(),
}],
@@ -2397,7 +2413,9 @@ mod tests {
tool: "lookup".into(),
arguments: Some(serde_json::json!({"id":"123"})),
},
connector_id: None,
mcp_app_resource_uri: None,
link_id: None,
plugin_id: None,
duration: Duration::from_millis(8),
result: Err("boom".into()),
@@ -2427,7 +2445,7 @@ mod tests {
ThreadItem::CommandExecution {
id: "exec-1".into(),
command: "echo 'hello world'".into(),
cwd: test_path_buf("/tmp").abs(),
cwd: test_path_buf("/tmp").abs().into(),
process_id: Some("pid-1".into()),
source: CommandExecutionSource::Agent,
status: CommandExecutionStatus::Completed,
@@ -2447,6 +2465,7 @@ mod tests {
tool: "lookup".into(),
status: McpToolCallStatus::Failed,
arguments: serde_json::json!({"id":"123"}),
app_context: None,
mcp_app_resource_uri: None,
plugin_id: None,
result: None,
@@ -2475,7 +2494,9 @@ mod tests {
tool: "lookup".into(),
arguments: Some(serde_json::json!({"id":"123"})),
},
connector_id: Some("calendar".into()),
mcp_app_resource_uri: Some("ui://widget/lookup.html".into()),
link_id: Some("link_calendar".into()),
plugin_id: Some("sample@test".into()),
duration: Duration::from_millis(8),
result: Ok(CallToolResult {
@@ -2506,6 +2527,11 @@ mod tests {
tool: "lookup".into(),
status: McpToolCallStatus::Completed,
arguments: serde_json::json!({"id":"123"}),
app_context: Some(McpToolCallAppContext {
connector_id: "calendar".into(),
link_id: Some("link_calendar".into()),
resource_uri: Some("ui://widget/lookup.html".into()),
}),
mcp_app_resource_uri: Some("ui://widget/lookup.html".into()),
plugin_id: Some("sample@test".into()),
result: Some(Box::new(McpToolCallResult {
@@ -2616,7 +2642,7 @@ mod tests {
turn_id: "turn-1".into(),
completed_at_ms: 0,
command: vec!["ls".into()],
cwd: test_path_buf("/tmp").abs(),
cwd: test_path_buf("/tmp").abs().into(),
parsed_cmd: vec![ParsedCommand::Unknown { cmd: "ls".into() }],
source: ExecCommandSource::Agent,
interaction_input: None,
@@ -2658,7 +2684,7 @@ mod tests {
ThreadItem::CommandExecution {
id: "exec-declined".into(),
command: "ls".into(),
cwd: test_path_buf("/tmp").abs(),
cwd: test_path_buf("/tmp").abs().into(),
process_id: Some("pid-2".into()),
source: CommandExecutionSource::Agent,
status: CommandExecutionStatus::Declined,
@@ -2756,7 +2782,7 @@ mod tests {
ThreadItem::CommandExecution {
id: "guardian-exec".into(),
command: "rm -rf /tmp/guardian".into(),
cwd: test_path_buf("/tmp").abs(),
cwd: test_path_buf("/tmp").abs().into(),
process_id: None,
source: CommandExecutionSource::Agent,
status: CommandExecutionStatus::Declined,
@@ -2822,7 +2848,7 @@ mod tests {
ThreadItem::CommandExecution {
id: "guardian-execve".into(),
command: "/bin/rm -f /tmp/file.sqlite".into(),
cwd: test_path_buf("/tmp").abs(),
cwd: test_path_buf("/tmp").abs().into(),
process_id: None,
source: CommandExecutionSource::Agent,
status: CommandExecutionStatus::InProgress,
@@ -2882,7 +2908,7 @@ mod tests {
turn_id: "turn-a".into(),
completed_at_ms: 0,
command: vec!["echo".into(), "done".into()],
cwd: test_path_buf("/tmp").abs(),
cwd: test_path_buf("/tmp").abs().into(),
parsed_cmd: vec![ParsedCommand::Unknown {
cmd: "echo done".into(),
}],
@@ -2920,7 +2946,7 @@ mod tests {
ThreadItem::CommandExecution {
id: "exec-late".into(),
command: "echo done".into(),
cwd: test_path_buf("/tmp").abs(),
cwd: test_path_buf("/tmp").abs().into(),
process_id: Some("pid-42".into()),
source: CommandExecutionSource::Agent,
status: CommandExecutionStatus::Completed,
@@ -2980,7 +3006,7 @@ mod tests {
turn_id: "turn-missing".into(),
completed_at_ms: 0,
command: vec!["echo".into(), "done".into()],
cwd: test_path_buf("/tmp").abs(),
cwd: test_path_buf("/tmp").abs().into(),
parsed_cmd: vec![ParsedCommand::Unknown {
cmd: "echo done".into(),
}],
@@ -3314,6 +3340,9 @@ mod tests {
RolloutItem::Compacted(CompactedItem {
message: String::new(),
replacement_history: None,
window_number: None,
first_window_id: None,
previous_window_id: None,
window_id: None,
}),
RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent {
@@ -50,6 +50,9 @@ pub struct InitializeCapabilities {
/// Opt into `attestation/generate` requests for upstream `x-oai-attestation`.
#[serde(default)]
pub request_attestation: bool,
/// Allow downstream MCP servers to request OpenAI extended form elicitations.
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub mcp_server_openai_form_elicitation: bool,
/// Exact notification method names that should be suppressed for this
/// connection (for example `thread/started`).
#[ts(optional = nullable)]
@@ -314,6 +314,41 @@ pub struct GetAccountTokenUsageResponse {
pub daily_usage_buckets: Option<Vec<AccountTokenUsageDailyBucket>>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct GetWorkspaceMessagesResponse {
/// Whether the workspace-message backend route is available for this client.
pub feature_enabled: bool,
/// Active workspace messages returned by the backend.
pub messages: Vec<WorkspaceMessage>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct WorkspaceMessage {
pub message_id: String,
pub message_type: WorkspaceMessageType,
pub message_body: String,
/// Unix timestamp (in seconds) when the message was created.
#[ts(type = "number | null")]
pub created_at: Option<i64>,
/// Unix timestamp (in seconds) when the message was archived.
#[ts(type = "number | null")]
pub archived_at: Option<i64>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "snake_case")]
#[ts(export_to = "v2/", rename_all = "snake_case")]
pub enum WorkspaceMessageType {
Headline,
Announcement,
#[serde(other)]
Unknown,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
@@ -651,7 +651,7 @@ pub struct ExternalAgentConfigDetectResponse {
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ExternalAgentConfigDetectParams {
/// If true, include detection under the user's home (~/.claude, ~/.codex, etc.).
/// If true, include detection under the user's home directory.
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub include_home: bool,
/// Zero or more working directories to include for repo-scoped detection.
@@ -664,6 +664,9 @@ pub struct ExternalAgentConfigDetectParams {
#[ts(export_to = "v2/")]
pub struct ExternalAgentConfigImportParams {
pub migration_items: Vec<ExternalAgentConfigMigrationItem>,
/// Source product that produced the migration items. Missing means unspecified.
#[ts(optional = nullable)]
pub source: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
@@ -0,0 +1,20 @@
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
use ts_rs::TS;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct CurrentTimeReadParams {
pub thread_id: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct CurrentTimeReadResponse {
/// Current time as whole Unix seconds.
#[ts(type = "number")]
pub current_time_at: i64,
}
@@ -9,6 +9,10 @@ use ts_rs::TS;
pub struct EnvironmentAddParams {
pub environment_id: String,
pub exec_server_url: String,
/// Optional WebSocket connection timeout. The server default applies when omitted.
#[ts(type = "number | null")]
#[ts(optional = nullable)]
pub connect_timeout_ms: Option<u64>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
@@ -31,6 +31,7 @@ use codex_protocol::protocol::PatchApplyStatus as CorePatchApplyStatus;
use codex_protocol::protocol::ReviewDecision as CoreReviewDecision;
use codex_protocol::protocol::SubAgentActivityKind as CoreSubAgentActivityKind;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_path_uri::LegacyAppPathString;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
@@ -256,7 +257,7 @@ pub enum ThreadItem {
/// The command to be executed.
command: String,
/// The command's working directory.
cwd: AbsolutePathBuf,
cwd: LegacyAppPathString,
/// Identifier for the underlying PTY process (when available).
process_id: Option<String>,
#[serde(default)]
@@ -289,8 +290,10 @@ pub enum ThreadItem {
tool: String,
status: McpToolCallStatus,
arguments: JsonValue,
app_context: Option<McpToolCallAppContext>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional)]
/// Deprecated: use `appContext.resourceUri` instead.
mcp_app_resource_uri: Option<String>,
plugin_id: Option<String>,
result: Option<Box<McpToolCallResult>>,
@@ -383,6 +386,15 @@ pub enum ThreadItem {
ContextCompaction { id: String },
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase", export_to = "v2/")]
pub struct McpToolCallAppContext {
pub connector_id: String,
pub link_id: Option<String>,
pub resource_uri: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase", export_to = "v2/")]
@@ -876,6 +888,11 @@ impl From<CoreTurnItem> for ThreadItem {
tool: mcp.tool,
status: McpToolCallStatus::from(mcp.status),
arguments: mcp.arguments,
app_context: mcp.connector_id.map(|connector_id| McpToolCallAppContext {
connector_id,
link_id: mcp.link_id,
resource_uri: mcp.mcp_app_resource_uri.clone(),
}),
mcp_app_resource_uri: mcp.mcp_app_resource_uri,
plugin_id: mcp.plugin_id,
result: mcp.result.map(McpToolCallResult::from).map(Box::new),
@@ -1339,7 +1356,7 @@ pub struct CommandExecutionRequestApprovalParams {
/// The command's working directory.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional = nullable)]
pub cwd: Option<AbsolutePathBuf>,
pub cwd: Option<LegacyAppPathString>,
/// Best-effort parsed command actions for friendly display.
#[serde(default, skip_serializing_if = "Option::is_none")]
#[ts(optional = nullable)]
@@ -632,6 +632,15 @@ pub enum McpServerElicitationRequest {
message: String,
requested_schema: McpElicitationSchema,
},
#[serde(rename = "openai/form", rename_all = "camelCase")]
#[ts(rename = "openai/form", rename_all = "camelCase")]
OpenAiForm {
#[serde(rename = "_meta")]
#[ts(rename = "_meta")]
meta: Option<JsonValue>,
message: String,
requested_schema: JsonValue,
},
#[serde(rename_all = "camelCase")]
#[ts(rename_all = "camelCase")]
Url {
@@ -658,6 +667,15 @@ impl TryFrom<CoreElicitationRequest> for McpServerElicitationRequest {
message,
requested_schema: serde_json::from_value(requested_schema)?,
}),
CoreElicitationRequest::OpenAiForm {
meta,
message,
requested_schema,
} => Ok(Self::OpenAiForm {
meta,
message,
requested_schema,
}),
CoreElicitationRequest::Url {
meta,
message,
@@ -6,6 +6,7 @@ mod attestation;
mod collaboration_mode;
mod command_exec;
mod config;
mod current_time;
mod environment;
mod experimental_feature;
mod feedback;
@@ -32,6 +33,7 @@ pub use attestation::*;
pub use collaboration_mode::*;
pub use command_exec::*;
pub use config::*;
pub use current_time::*;
pub use environment::*;
pub use experimental_feature::*;
pub use feedback::*;
@@ -162,3 +162,14 @@ pub struct TurnModerationMetadataNotification {
pub turn_id: String,
pub metadata: JsonValue,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ModelSafetyBufferingUpdatedNotification {
pub thread_id: String,
pub turn_id: String,
pub model: String,
pub use_cases: Vec<String>,
pub reasons: Vec<String>,
}
@@ -1,6 +1,5 @@
use codex_protocol::protocol::ConversationTextRole;
use codex_protocol::protocol::RealtimeAudioFrame as CoreRealtimeAudioFrame;
use codex_protocol::protocol::RealtimeConversationArchitecture;
use codex_protocol::protocol::RealtimeConversationVersion;
use codex_protocol::protocol::RealtimeOutputModality;
use codex_protocol::protocol::RealtimeVoice;
@@ -67,15 +66,21 @@ impl From<ThreadRealtimeAudioChunk> for CoreRealtimeAudioFrame {
#[ts(export_to = "v2/")]
pub struct ThreadRealtimeStartParams {
pub thread_id: String,
/// Overrides the configured realtime architecture for this session only.
/// Leaves Codex response handoffs to the client's explicit append calls instead of forwarding
/// them automatically. Defaults to false.
#[ts(optional = nullable)]
pub architecture: Option<RealtimeConversationArchitecture>,
pub client_managed_handoffs: Option<bool>,
/// Sends automatic Codex responses as realtime conversation items instead of handoff appends.
#[ts(optional = nullable)]
pub codex_responses_as_items: Option<bool>,
/// Optional prefix added to automatic Codex response items when `codexResponsesAsItems` is true.
#[ts(optional = nullable)]
pub codex_response_item_prefix: Option<String>,
/// Optional prefix added to automatic V1 Codex commentary sent with
/// `conversation.handoff.append` when `codexResponsesAsItems` is not true. Final answers are
/// sent without the prefix.
#[ts(optional = nullable)]
pub codex_response_handoff_prefix: Option<String>,
/// Overrides the configured realtime model for this session only.
#[ts(optional = nullable)]
pub model: Option<String>,
@@ -1,5 +1,6 @@
use super::*;
use codex_protocol::approvals::ElicitationRequest as CoreElicitationRequest;
use codex_protocol::config_types::MultiAgentMode;
use codex_protocol::items::AgentMessageContent;
use codex_protocol::items::AgentMessageItem;
use codex_protocol::items::FileChangeItem;
@@ -36,6 +37,7 @@ use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_absolute_path::test_support::PathBufExt;
use codex_utils_absolute_path::test_support::test_path_buf;
use codex_utils_path_uri::LegacyAppPathString;
use codex_utils_path_uri::PathUri;
use pretty_assertions::assert_eq;
use serde_json::Value as JsonValue;
use serde_json::json;
@@ -174,6 +176,7 @@ fn thread_resume_response_round_trips_initial_turns_page() {
model_provider: "openai".to_string(),
created_at: 1,
updated_at: 1,
recency_at: Some(1),
status: ThreadStatus::Idle,
path: None,
cwd: absolute_path("tmp"),
@@ -197,6 +200,7 @@ fn thread_resume_response_round_trips_initial_turns_page() {
sandbox: SandboxPolicy::DangerFullAccess,
active_permission_profile: None,
reasoning_effort: None,
multi_agent_mode: Default::default(),
initial_turns_page: Some(TurnsPage {
data: Vec::new(),
next_cursor: Some("cursor_next".to_string()),
@@ -375,6 +379,7 @@ fn external_agent_config_import_params_accept_legacy_plugin_details() {
..Default::default()
}),
}],
source: None,
}
);
}
@@ -1899,6 +1904,40 @@ fn mcp_server_elicitation_request_from_core_form_request() {
);
}
#[test]
fn mcp_server_elicitation_request_from_core_openai_form_request() {
let requested_schema = json!({
"type": "object",
"properties": {
"template": {
"type": "openai/imagePicker",
"title": "Template",
"items": [{
"id": "monthly-review",
"title": "Monthly review",
"image": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciLz4=",
}],
},
},
"required": ["template"],
});
let request = McpServerElicitationRequest::try_from(CoreElicitationRequest::OpenAiForm {
meta: None,
message: "Choose a report".to_string(),
requested_schema: requested_schema.clone(),
})
.expect("OpenAI form request should convert");
assert_eq!(
request,
McpServerElicitationRequest::OpenAiForm {
meta: None,
message: "Choose a report".to_string(),
requested_schema,
}
);
}
#[test]
fn mcp_elicitation_schema_matches_mcp_2025_11_25_primitives() {
let schema: McpElicitationSchema = serde_json::from_value(json!({
@@ -2579,7 +2618,9 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
server: "server".to_string(),
tool: "tool".to_string(),
arguments: json!({"arg": "value"}),
connector_id: Some("calendar".to_string()),
mcp_app_resource_uri: Some("app://connector".to_string()),
link_id: Some("link_calendar".to_string()),
plugin_id: Some("sample@test".to_string()),
status: CoreMcpToolCallStatus::InProgress,
result: None,
@@ -2595,6 +2636,11 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
tool: "tool".to_string(),
status: McpToolCallStatus::InProgress,
arguments: json!({"arg": "value"}),
app_context: Some(McpToolCallAppContext {
connector_id: "calendar".to_string(),
link_id: Some("link_calendar".to_string()),
resource_uri: Some("app://connector".to_string()),
}),
mcp_app_resource_uri: Some("app://connector".to_string()),
plugin_id: Some("sample@test".to_string()),
result: None,
@@ -2608,7 +2654,9 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
server: "server".to_string(),
tool: "tool".to_string(),
arguments: JsonValue::Null,
connector_id: None,
mcp_app_resource_uri: None,
link_id: None,
plugin_id: None,
status: CoreMcpToolCallStatus::Completed,
result: Some(CallToolResult {
@@ -2629,6 +2677,7 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
tool: "tool".to_string(),
status: McpToolCallStatus::Completed,
arguments: JsonValue::Null,
app_context: None,
mcp_app_resource_uri: None,
plugin_id: None,
result: Some(Box::new(McpToolCallResult {
@@ -2642,6 +2691,49 @@ fn core_turn_item_into_thread_item_converts_supported_variants() {
);
}
#[test]
fn mcp_tool_call_app_context_serializes_connector_id() {
let item = ThreadItem::McpToolCall {
id: "mcp-1".to_string(),
server: "codex_apps".to_string(),
tool: "calendar.create_event".to_string(),
status: McpToolCallStatus::InProgress,
arguments: json!({}),
app_context: Some(McpToolCallAppContext {
connector_id: "calendar".to_string(),
link_id: Some("link_calendar".to_string()),
resource_uri: Some("app://connector".to_string()),
}),
mcp_app_resource_uri: Some("app://connector".to_string()),
plugin_id: None,
result: None,
error: None,
duration_ms: None,
};
assert_eq!(
serde_json::to_value(item).expect("MCP tool call should serialize"),
json!({
"type": "mcpToolCall",
"id": "mcp-1",
"server": "codex_apps",
"tool": "calendar.create_event",
"status": "inProgress",
"arguments": {},
"appContext": {
"connectorId": "calendar",
"linkId": "link_calendar",
"resourceUri": "app://connector",
},
"mcpAppResourceUri": "app://connector",
"pluginId": null,
"result": null,
"error": null,
"durationMs": null,
})
);
}
#[test]
fn user_input_into_core_preserves_image_detail() {
assert_eq!(
@@ -3596,16 +3688,69 @@ fn thread_lifecycle_responses_default_missing_optional_fields() {
serde_json::from_value(response.clone()).expect("thread/start response");
let resume: ThreadResumeResponse =
serde_json::from_value(response.clone()).expect("thread/resume response");
let fork: ThreadForkResponse = serde_json::from_value(response).expect("thread/fork response");
let fork: ThreadForkResponse =
serde_json::from_value(response.clone()).expect("thread/fork response");
assert_eq!(start.instruction_sources, Vec::<AbsolutePathBuf>::new());
assert_eq!(start.instruction_sources, Vec::<LegacyAppPathString>::new());
assert_eq!(start.thread.parent_thread_id, None);
assert_eq!(resume.instruction_sources, Vec::<AbsolutePathBuf>::new());
assert_eq!(fork.instruction_sources, Vec::<AbsolutePathBuf>::new());
assert_eq!(start.thread.recency_at, None);
assert_eq!(
resume.instruction_sources,
Vec::<LegacyAppPathString>::new()
);
assert_eq!(fork.instruction_sources, Vec::<LegacyAppPathString>::new());
assert_eq!(start.active_permission_profile, None);
assert_eq!(resume.active_permission_profile, None);
assert_eq!(resume.initial_turns_page, None);
assert_eq!(fork.active_permission_profile, None);
assert_eq!(
(
start.multi_agent_mode,
resume.multi_agent_mode,
fork.multi_agent_mode,
),
(
MultiAgentMode::ExplicitRequestOnly,
MultiAgentMode::ExplicitRequestOnly,
MultiAgentMode::ExplicitRequestOnly,
)
);
let foreign_source: LegacyAppPathString =
serde_json::from_value(json!(r"C:\workspace\AGENTS.md")).expect("foreign source");
let mut response_with_foreign_source = response;
response_with_foreign_source["instructionSources"] = json!([foreign_source.as_str()]);
let start: ThreadStartResponse = serde_json::from_value(response_with_foreign_source.clone())
.expect("thread/start response with foreign source");
let resume: ThreadResumeResponse = serde_json::from_value(response_with_foreign_source.clone())
.expect("thread/resume response with foreign source");
let fork: ThreadForkResponse = serde_json::from_value(response_with_foreign_source)
.expect("thread/fork response with foreign source");
assert_eq!(start.instruction_sources, vec![foreign_source.clone()]);
assert_eq!(resume.instruction_sources, vec![foreign_source.clone()]);
assert_eq!(fork.instruction_sources, vec![foreign_source]);
let foreign_source_uri =
PathUri::parse("file:///C:/workspace/AGENTS.md").expect("foreign source URI");
assert_eq!(
start.instruction_source_path_uris(),
vec![foreign_source_uri.clone()]
);
assert_eq!(
resume.instruction_source_path_uris(),
vec![foreign_source_uri.clone()]
);
assert_eq!(
fork.instruction_source_path_uris(),
vec![foreign_source_uri]
);
}
#[test]
fn thread_recency_sort_key_serializes_as_snake_case() {
assert_eq!(
serde_json::to_value(ThreadSortKey::RecencyAt).expect("sort key should serialize"),
json!("recency_at")
);
}
#[test]
@@ -3643,6 +3788,7 @@ fn turn_start_params_preserve_explicit_null_service_tier() {
summary: None,
output_schema: None,
collaboration_mode: None,
multi_agent_mode: None,
personality: None,
};
let serialized_without_override =
@@ -3650,6 +3796,50 @@ fn turn_start_params_preserve_explicit_null_service_tier() {
assert_eq!(serialized_without_override.get("serviceTier"), None);
}
#[test]
fn turn_start_params_round_trip_multi_agent_mode() {
let params: TurnStartParams = serde_json::from_value(json!({
"threadId": "thread_123",
"input": [],
"multiAgentMode": "proactive"
}))
.expect("params should deserialize");
assert_eq!(
params.multi_agent_mode,
Some(codex_protocol::config_types::MultiAgentMode::Proactive)
);
assert_eq!(
crate::experimental_api::ExperimentalApi::experimental_reason(&params),
Some("turn/start.multiAgentMode")
);
assert_eq!(
serde_json::to_value(params).expect("params should serialize")["multiAgentMode"],
"proactive"
);
}
#[test]
fn thread_start_params_round_trip_multi_agent_mode() {
let params: ThreadStartParams = serde_json::from_value(json!({
"multiAgentMode": "proactive"
}))
.expect("params should deserialize");
assert_eq!(
params.multi_agent_mode,
Some(codex_protocol::config_types::MultiAgentMode::Proactive)
);
assert_eq!(
crate::experimental_api::ExperimentalApi::experimental_reason(&params),
Some("thread/start.multiAgentMode")
);
assert_eq!(
serde_json::to_value(params).expect("params should serialize")["multiAgentMode"],
"proactive"
);
}
#[test]
fn thread_settings_update_params_preserve_explicit_null_service_tier() {
let params: ThreadSettingsUpdateParams = serde_json::from_value(json!({
@@ -14,6 +14,7 @@ use codex_experimental_api_macros::ExperimentalApi;
pub use codex_protocol::capabilities::CapabilityRootLocation;
pub use codex_protocol::capabilities::SelectedCapabilityRoot;
use codex_protocol::config_types::CollaborationMode;
use codex_protocol::config_types::MultiAgentMode;
use codex_protocol::config_types::Personality;
use codex_protocol::config_types::ReasoningSummary;
pub use codex_protocol::dynamic_tools::DynamicToolFunctionSpec;
@@ -26,6 +27,8 @@ use codex_protocol::protocol::ThreadGoalStatus as CoreThreadGoalStatus;
use codex_protocol::protocol::TokenUsage as CoreTokenUsage;
use codex_protocol::protocol::TokenUsageInfo as CoreTokenUsageInfo;
use codex_utils_absolute_path::AbsolutePathBuf;
use codex_utils_path_uri::LegacyAppPathString;
use codex_utils_path_uri::PathUri;
use schemars::JsonSchema;
use serde::Deserialize;
use serde::Serialize;
@@ -91,6 +94,12 @@ pub struct ThreadStartParams {
pub developer_instructions: Option<String>,
#[ts(optional = nullable)]
pub personality: Option<Personality>,
/// Set the initial multi-agent mode for this thread. `none` leaves the
/// multi-agent tools available without injecting mode instructions.
/// Omitted defaults to `explicitRequestOnly`.
#[experimental("thread/start.multiAgentMode")]
#[ts(optional = nullable)]
pub multi_agent_mode: Option<MultiAgentMode>,
#[ts(optional = nullable)]
pub ephemeral: Option<bool>,
#[ts(optional = nullable)]
@@ -161,9 +170,9 @@ pub struct ThreadStartResponse {
#[experimental("thread/start.runtimeWorkspaceRoots")]
#[serde(default)]
pub runtime_workspace_roots: Vec<AbsolutePathBuf>,
/// Instruction source files currently loaded for this thread.
/// Environment-native paths to instruction source files currently loaded for this thread.
#[serde(default)]
pub instruction_sources: Vec<AbsolutePathBuf>,
pub instruction_sources: Vec<LegacyAppPathString>,
#[experimental(nested)]
pub approval_policy: AskForApproval,
/// Reviewer currently used for approval requests on this thread.
@@ -177,6 +186,17 @@ pub struct ThreadStartResponse {
#[serde(default)]
pub active_permission_profile: Option<ActivePermissionProfile>,
pub reasoning_effort: Option<ReasoningEffort>,
/// Current multi-agent mode for this thread.
#[experimental("thread/start.multiAgentMode")]
#[serde(default)]
pub multi_agent_mode: MultiAgentMode,
}
impl ThreadStartResponse {
/// Parses valid absolute instruction source paths and omits malformed legacy values.
pub fn instruction_source_path_uris(&self) -> Vec<PathUri> {
instruction_source_path_uris(&self.instruction_sources)
}
}
#[derive(
@@ -230,6 +250,10 @@ pub struct ThreadSettingsUpdateParams {
#[experimental("thread/settings/update.collaborationMode")]
#[ts(optional = nullable)]
pub collaboration_mode: Option<CollaborationMode>,
/// Select the multi-agent mode for subsequent turns.
#[experimental("thread/settings/update.multiAgentMode")]
#[ts(optional = nullable)]
pub multi_agent_mode: Option<MultiAgentMode>,
/// Override the personality for subsequent turns.
#[ts(optional = nullable)]
pub personality: Option<Personality>,
@@ -240,7 +264,7 @@ pub struct ThreadSettingsUpdateParams {
#[ts(export_to = "v2/")]
pub struct ThreadSettingsUpdateResponse {}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ThreadSettings {
@@ -255,6 +279,10 @@ pub struct ThreadSettings {
pub effort: Option<ReasoningEffort>,
pub summary: Option<ReasoningSummary>,
pub collaboration_mode: CollaborationMode,
/// Current multi-agent mode for this thread.
#[experimental("thread/settings.multiAgentMode")]
#[serde(default)]
pub multi_agent_mode: MultiAgentMode,
pub personality: Option<Personality>,
}
@@ -375,9 +403,9 @@ pub struct ThreadResumeResponse {
#[experimental("thread/resume.runtimeWorkspaceRoots")]
#[serde(default)]
pub runtime_workspace_roots: Vec<AbsolutePathBuf>,
/// Instruction source files currently loaded for this thread.
/// Environment-native paths to instruction source files currently loaded for this thread.
#[serde(default)]
pub instruction_sources: Vec<AbsolutePathBuf>,
pub instruction_sources: Vec<LegacyAppPathString>,
#[experimental(nested)]
pub approval_policy: AskForApproval,
/// Reviewer currently used for approval requests on this thread.
@@ -391,12 +419,23 @@ pub struct ThreadResumeResponse {
#[serde(default)]
pub active_permission_profile: Option<ActivePermissionProfile>,
pub reasoning_effort: Option<ReasoningEffort>,
/// Current multi-agent mode for this thread.
#[experimental("thread/resume.multiAgentMode")]
#[serde(default)]
pub multi_agent_mode: MultiAgentMode,
/// `thread/turns/list` page returned when requested by `initialTurnsPage`.
#[experimental("thread/resume.initialTurnsPage")]
#[serde(default)]
pub initial_turns_page: Option<TurnsPage>,
}
impl ThreadResumeResponse {
/// Parses valid absolute instruction source paths and omits malformed legacy values.
pub fn instruction_source_path_uris(&self) -> Vec<PathUri> {
instruction_source_path_uris(&self.instruction_sources)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
@@ -523,9 +562,9 @@ pub struct ThreadForkResponse {
#[experimental("thread/fork.runtimeWorkspaceRoots")]
#[serde(default)]
pub runtime_workspace_roots: Vec<AbsolutePathBuf>,
/// Instruction source files currently loaded for this thread.
/// Environment-native paths to instruction source files currently loaded for this thread.
#[serde(default)]
pub instruction_sources: Vec<AbsolutePathBuf>,
pub instruction_sources: Vec<LegacyAppPathString>,
#[experimental(nested)]
pub approval_policy: AskForApproval,
/// Reviewer currently used for approval requests on this thread.
@@ -539,6 +578,34 @@ pub struct ThreadForkResponse {
#[serde(default)]
pub active_permission_profile: Option<ActivePermissionProfile>,
pub reasoning_effort: Option<ReasoningEffort>,
/// Current multi-agent mode for this thread.
#[experimental("thread/fork.multiAgentMode")]
#[serde(default)]
pub multi_agent_mode: MultiAgentMode,
}
impl ThreadForkResponse {
/// Parses valid absolute instruction source paths and omits malformed legacy values.
pub fn instruction_source_path_uris(&self) -> Vec<PathUri> {
instruction_source_path_uris(&self.instruction_sources)
}
}
fn instruction_source_path_uris(sources: &[LegacyAppPathString]) -> Vec<PathUri> {
// Instruction sources are advisory diagnostics. Warn and fail open so a malformed legacy
// path cannot fail thread start, resume, or fork.
sources
.iter()
.filter_map(|source| {
source.to_inferred_path_uri().or_else(|| {
tracing::warn!(
path = source.as_str(),
"ignoring invalid instruction source path from app-server"
);
None
})
})
.collect()
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
@@ -1086,6 +1153,7 @@ pub enum ThreadSourceKind {
pub enum ThreadSortKey {
CreatedAt,
UpdatedAt,
RecencyAt,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, JsonSchema, TS)]
@@ -152,6 +152,9 @@ pub struct Thread {
/// Unix timestamp (in seconds) when the thread was last updated.
#[ts(type = "number")]
pub updated_at: i64,
/// Unix timestamp (in seconds) used for thread recency ordering.
#[ts(type = "number | null")]
pub recency_at: Option<i64>,
/// Current runtime status for the thread.
pub status: ThreadStatus,
/// [UNSTABLE] Path to the thread on disk.
@@ -4,6 +4,7 @@ use super::SandboxPolicy;
use super::Turn;
use codex_experimental_api_macros::ExperimentalApi;
use codex_protocol::config_types::CollaborationMode;
use codex_protocol::config_types::MultiAgentMode;
use codex_protocol::config_types::Personality;
use codex_protocol::config_types::ReasoningSummary;
use codex_protocol::models::ImageDetail;
@@ -149,6 +150,13 @@ pub struct TurnStartParams {
#[experimental("turn/start.collaborationMode")]
#[ts(optional = nullable)]
pub collaboration_mode: Option<CollaborationMode>,
/// Controls multi-agent v2 delegation instructions. `none` leaves the
/// multi-agent tools available without injecting mode instructions. Omitted
/// keeps the loaded session's current mode.
#[experimental("turn/start.multiAgentMode")]
#[ts(optional = nullable)]
pub multi_agent_mode: Option<MultiAgentMode>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
+2 -1
View File
@@ -1668,6 +1668,7 @@ impl CodexClient {
.map(|method| (*method).to_string())
.collect(),
),
mcp_server_openai_form_elicitation: false,
}),
},
};
@@ -2092,7 +2093,7 @@ impl CodexClient {
println!("< command: {command}");
}
if let Some(cwd) = cwd.as_ref() {
println!("< cwd: {}", cwd.display());
println!("< cwd: {cwd}");
}
if let Some(command_actions) = command_actions.as_ref()
&& !command_actions.is_empty()
+1
View File
@@ -57,3 +57,4 @@ chrono = { workspace = true }
codex-config = { workspace = true }
pretty_assertions = { workspace = true }
tempfile = { workspace = true }
tokio = { workspace = true, features = ["test-util"] }
@@ -692,14 +692,14 @@ mod tests {
}
}
#[tokio::test]
#[tokio::test(start_paused = true)]
async fn initialize_timeout_closes_open_connection() {
let (server_event_tx, _server_event_rx) = mpsc::channel(CHANNEL_CAPACITY);
let (transport_event_tx, mut transport_event_rx) = mpsc::channel(1);
let shutdown_token = CancellationToken::new();
let client_tracker =
ClientTracker::new(server_event_tx, transport_event_tx, &shutdown_token);
let mut handle_message = tokio::spawn(async move {
let handle_message = tokio::spawn(async move {
let mut client_tracker = client_tracker;
client_tracker
.handle_message(initialize_envelope_with_stream_id(
@@ -709,13 +709,13 @@ mod tests {
.await
});
assert!(
timeout(Duration::from_millis(50), &mut handle_message)
.await
.expect("initialize timeout rollback should not wait for close delivery")
.expect("handle message task should not panic")
.is_err()
);
tokio::task::yield_now().await;
tokio::time::advance(
REMOTE_CONTROL_TRANSPORT_EVENT_SEND_TIMEOUT + Duration::from_millis(1),
)
.await;
assert!(handle_message.await.expect("handle message task").is_err());
let connection_id = match transport_event_rx.recv().await.expect("open event") {
TransportEvent::ConnectionOpened { connection_id, .. } => connection_id,
other => panic!("expected connection opened, got {other:?}"),

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