Merge 15676d1b00 into sapling-pr-archive-bolinfest

This commit is contained in:
Michael Bolin
2026-02-11 17:35:50 -08:00
committed by GitHub
38 changed files with 707 additions and 1064 deletions
+6 -3
View File
@@ -84,11 +84,13 @@ jobs:
shell: bash
run: |
set -euo pipefail
cpu_model="$(lscpu | awk -F: '/Model name/ {gsub(/^[ \t]+/, "", $2); print $2; exit}')"
total_ram="$(awk '/MemTotal/ {printf "%.1f GiB\n", $2 / 1024 / 1024}' /proc/meminfo)"
echo "Runner: ${RUNNER_NAME:-unknown}"
echo "OS: $(uname -a)"
echo "CPU model: $(lscpu | awk -F: '/Model name/ {gsub(/^[ \t]+/,\"\",$2); print $2; exit}')"
echo "CPU model: ${cpu_model}"
echo "Logical CPUs: $(nproc)"
echo "Total RAM: $(awk '/MemTotal/ {printf \"%.1f GiB\\n\", $2 / 1024 / 1024}' /proc/meminfo)"
echo "Total RAM: ${total_ram}"
echo "Disk usage:"
df -h .
- name: Print runner specs (macOS)
@@ -96,13 +98,14 @@ jobs:
shell: bash
run: |
set -euo pipefail
total_ram="$(sysctl -n hw.memsize | awk '{printf "%.1f GiB\n", $1 / 1024 / 1024 / 1024}')"
echo "Runner: ${RUNNER_NAME:-unknown}"
echo "OS: $(sw_vers -productName) $(sw_vers -productVersion)"
echo "Hardware model: $(sysctl -n hw.model)"
echo "CPU architecture: $(uname -m)"
echo "Logical CPUs: $(sysctl -n hw.logicalcpu)"
echo "Physical CPUs: $(sysctl -n hw.physicalcpu)"
echo "Total RAM: $(sysctl -n hw.memsize | awk '{printf \"%.1f GiB\\n\", $1 / 1024 / 1024 / 1024}')"
echo "Total RAM: ${total_ram}"
echo "Disk usage:"
df -h .
- name: Install Linux bwrap build dependencies
+100 -260
View File
@@ -430,9 +430,9 @@ dependencies = [
[[package]]
name = "arc-swap"
version = "1.8.1"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ded5f9a03ac8f24d1b8a25101ee812cd32cdc8c50a4c50237de2c4915850e73"
checksum = "51d03449bb8ca2cc2ef70869af31463d1ae5ccc8fa3e334b307203fbf815207e"
dependencies = [
"rustversion",
]
@@ -1227,9 +1227,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.57"
version = "4.5.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a"
checksum = "a75ca66430e33a14957acc24c5077b503e7d374151b2b4b3a10c83b4ceb4be0e"
dependencies = [
"clap_builder",
"clap_derive",
@@ -1237,9 +1237,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.57"
version = "4.5.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238"
checksum = "793207c7fa6300a0608d1080b858e5fdbe713cdc1c8db9fb17777d8a13e63df0"
dependencies = [
"anstream",
"anstyle",
@@ -1379,7 +1379,7 @@ dependencies = [
"time",
"tokio",
"tokio-tungstenite",
"toml 0.9.12+spec-1.1.0",
"toml 0.9.11+spec-1.1.0",
"tracing",
"tracing-subscriber",
"uuid",
@@ -1539,7 +1539,7 @@ dependencies = [
"supports-color 3.0.2",
"tempfile",
"tokio",
"toml 0.9.12+spec-1.1.0",
"toml 0.9.11+spec-1.1.0",
"tracing",
]
@@ -1585,7 +1585,7 @@ dependencies = [
"tempfile",
"thiserror 2.0.18",
"tokio",
"toml 0.9.12+spec-1.1.0",
"toml 0.9.11+spec-1.1.0",
"tracing",
]
@@ -1650,7 +1650,7 @@ dependencies = [
"sha2",
"thiserror 2.0.18",
"tokio",
"toml 0.9.12+spec-1.1.0",
"toml 0.9.11+spec-1.1.0",
]
[[package]]
@@ -1743,8 +1743,8 @@ dependencies = [
"tokio",
"tokio-tungstenite",
"tokio-util",
"toml 0.9.12+spec-1.1.0",
"toml_edit 0.24.1+spec-1.1.0",
"toml 0.9.11+spec-1.1.0",
"toml_edit 0.24.0+spec-1.1.0",
"tracing",
"tracing-subscriber",
"tracing-test",
@@ -2327,7 +2327,7 @@ dependencies = [
"tokio",
"tokio-stream",
"tokio-util",
"toml 0.9.12+spec-1.1.0",
"toml 0.9.11+spec-1.1.0",
"tracing",
"tracing-appender",
"tracing-subscriber",
@@ -2392,7 +2392,7 @@ dependencies = [
"codex-protocol",
"pretty_assertions",
"serde",
"toml 0.9.12+spec-1.1.0",
"toml 0.9.11+spec-1.1.0",
]
[[package]]
@@ -2430,7 +2430,7 @@ version = "0.0.0"
dependencies = [
"pretty_assertions",
"serde_json",
"toml 0.9.12+spec-1.1.0",
"toml 0.9.11+spec-1.1.0",
]
[[package]]
@@ -3386,9 +3386,9 @@ dependencies = [
[[package]]
name = "ena"
version = "0.14.4"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabffdaee24bd1bf95c5ef7cec31260444317e72ea56c4c91750e8b7ee58d5f1"
checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5"
dependencies = [
"log",
]
@@ -3708,9 +3708,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
[[package]]
name = "flate2"
version = "1.1.9"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369"
dependencies = [
"crc32fast",
"libz-sys",
@@ -4043,19 +4043,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "getrandom"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec"
dependencies = [
"cfg-if",
"libc",
"r-efi",
"wasip2",
"wasip3",
]
[[package]]
name = "gif"
version = "0.14.1"
@@ -4082,7 +4069,7 @@ dependencies = [
"bstr",
"log",
"regex-automata",
"regex-syntax 0.8.9",
"regex-syntax 0.8.8",
]
[[package]]
@@ -4388,7 +4375,7 @@ dependencies = [
"tokio",
"tokio-rustls",
"tower-service",
"webpki-roots 1.0.6",
"webpki-roots 1.0.5",
]
[[package]]
@@ -4422,13 +4409,14 @@ dependencies = [
[[package]]
name = "hyper-util"
version = "0.1.20"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0"
checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"http 1.4.0",
"http-body",
@@ -4661,12 +4649,6 @@ dependencies = [
"zerovec",
]
[[package]]
name = "id-arena"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]]
name = "ident_case"
version = "1.0.1"
@@ -4977,9 +4959,9 @@ checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "jiff"
version = "0.2.19"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d89a5b5e10d5a9ad6e5d1f4bd58225f655d6fe9767575a5e8ac5a6fe64e04495"
checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50"
dependencies = [
"jiff-static",
"log",
@@ -4990,9 +4972,9 @@ dependencies = [
[[package]]
name = "jiff-static"
version = "0.2.19"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff7a39c8862fc1369215ccf0a8f12dd4598c7f6484704359f0351bd617034dbf"
checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78"
dependencies = [
"proc-macro2",
"quote",
@@ -5136,17 +5118,11 @@ dependencies = [
"spin",
]
[[package]]
name = "leb128fmt"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]]
name = "libc"
version = "0.2.181"
version = "0.2.180"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5"
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
[[package]]
name = "libdbus-sys"
@@ -5406,9 +5382,9 @@ checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0"
[[package]]
name = "memchr"
version = "2.8.0"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "memoffset"
@@ -6566,16 +6542,6 @@ dependencies = [
"yansi",
]
[[package]]
name = "prettyplease"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
"syn 2.0.114",
]
[[package]]
name = "proc-macro-crate"
version = "3.4.0"
@@ -6632,16 +6598,16 @@ dependencies = [
[[package]]
name = "proptest"
version = "1.10.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532"
checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40"
dependencies = [
"bitflags 2.10.0",
"num-traits",
"rand 0.9.2",
"rand_chacha 0.9.0",
"rand_xorshift",
"regex-syntax 0.8.9",
"regex-syntax 0.8.8",
"unarray",
]
@@ -6670,9 +6636,9 @@ dependencies = [
[[package]]
name = "psl"
version = "2.1.188"
version = "2.1.184"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d75bca9da25cfdcd9528de22ed7870d1695b9e1c3ce55b7127a4a2b16fac"
checksum = "81dc6a90669f481b41cae3005c68efa36bef275b95aa9123a7af7f1c68c6e5b2"
dependencies = [
"psl-types",
]
@@ -7080,7 +7046,7 @@ dependencies = [
"rustls-pki-types",
"tokio",
"tokio-rustls",
"webpki-roots 1.0.6",
"webpki-roots 1.0.5",
"x509-parser",
]
@@ -7326,25 +7292,25 @@ dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax 0.8.9",
"regex-syntax 0.8.8",
]
[[package]]
name = "regex-automata"
version = "0.4.14"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.8.9",
"regex-syntax 0.8.8",
]
[[package]]
name = "regex-lite"
version = "0.1.9"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973"
checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da"
[[package]]
name = "regex-syntax"
@@ -7354,9 +7320,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "regex-syntax"
version = "0.8.9"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c"
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]]
name = "reqwest"
@@ -7404,7 +7370,7 @@ dependencies = [
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"webpki-roots 1.0.6",
"webpki-roots 1.0.5",
]
[[package]]
@@ -7687,9 +7653,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.23"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
[[package]]
name = "salsa20"
@@ -7956,11 +7922,10 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "sentry"
version = "0.46.2"
version = "0.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d92d893ba7469d361a6958522fa440e4e2bc8bf4c5803cd1bf40b9af63f8f9a8"
checksum = "2f925d575b468e88b079faf590a8dd0c9c99e2ec29e9bab663ceb8b45056312f"
dependencies = [
"cfg_aliases 0.2.1",
"httpdate",
"native-tls",
"reqwest",
@@ -7977,9 +7942,9 @@ dependencies = [
[[package]]
name = "sentry-actix"
version = "0.46.2"
version = "0.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56cb150fd6b55b3023714a3aaa1e3bdadfd44f164efc54fad69efc69aac36887"
checksum = "18bac0f6b8621fa0f85e298901e51161205788322e1a995e3764329020368058"
dependencies = [
"actix-http",
"actix-web",
@@ -7990,9 +7955,9 @@ dependencies = [
[[package]]
name = "sentry-backtrace"
version = "0.46.2"
version = "0.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f8784d0a27b5cd4b5f75769ffc84f0b7580e3c35e1af9cd83cb90b612d769cc"
checksum = "6cb1ef7534f583af20452b1b1bf610a60ed9c8dd2d8485e7bd064efc556a78fb"
dependencies = [
"backtrace",
"regex",
@@ -8001,9 +7966,9 @@ dependencies = [
[[package]]
name = "sentry-contexts"
version = "0.46.2"
version = "0.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e5eb42f4cd4f9fdfec9e3b07b25a4c9769df83d218a7e846658984d5948ad3e"
checksum = "ebd6be899d9938390b6d1ec71e2f53bd9e57b6a9d8b1d5b049e5c364e7da9078"
dependencies = [
"hostname",
"libc",
@@ -8015,9 +7980,9 @@ dependencies = [
[[package]]
name = "sentry-core"
version = "0.46.2"
version = "0.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0b1e7ca40f965db239da279bf278d87b7407469b98835f27f0c8e59ed189b06"
checksum = "26ab054c34b87f96c3e4701bea1888317cde30cc7e4a6136d2c48454ab96661c"
dependencies = [
"rand 0.9.2",
"sentry-types",
@@ -8028,9 +7993,9 @@ dependencies = [
[[package]]
name = "sentry-debug-images"
version = "0.46.2"
version = "0.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "002561e49ea3a9de316e2efadc40fae553921b8ff41448f02ea85fd135a778d6"
checksum = "5637ec550dc6f8c49a711537950722d3fc4baa6fd433c371912104eaff31e2a5"
dependencies = [
"findshlibs",
"sentry-core",
@@ -8038,9 +8003,9 @@ dependencies = [
[[package]]
name = "sentry-panic"
version = "0.46.2"
version = "0.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8906f8be87aea5ac7ef937323fb655d66607427f61007b99b7cb3504dc5a156c"
checksum = "3f02c7162f7b69b8de872b439d4696dc1d65f80b13ddd3c3831723def4756b63"
dependencies = [
"sentry-backtrace",
"sentry-core",
@@ -8048,9 +8013,9 @@ dependencies = [
[[package]]
name = "sentry-tracing"
version = "0.46.2"
version = "0.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b07eefe04486316c57aba08ab53dd44753c25102d1d3fe05775cc93a13262d9"
checksum = "e1dd47df349a80025819f3d25c3d2f751df705d49c65a4cdc0f130f700972a48"
dependencies = [
"bitflags 2.10.0",
"sentry-backtrace",
@@ -8061,9 +8026,9 @@ dependencies = [
[[package]]
name = "sentry-types"
version = "0.46.2"
version = "0.46.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567711f01f86a842057e1fc17779eba33a336004227e1a1e7e6cc2599e22e259"
checksum = "eecbd63e9d15a26a40675ed180d376fcb434635d2e33de1c24003f61e3e2230d"
dependencies = [
"debugid",
"hex",
@@ -8947,9 +8912,9 @@ dependencies = [
[[package]]
name = "system-configuration"
version = "0.7.0"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
dependencies = [
"bitflags 2.10.0",
"core-foundation 0.9.4",
@@ -8974,12 +8939,12 @@ checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
[[package]]
name = "tempfile"
version = "3.25.0"
version = "3.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1"
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
dependencies = [
"fastrand",
"getrandom 0.4.1",
"getrandom 0.3.4",
"once_cell",
"rustix 1.1.3",
"windows-sys 0.61.2",
@@ -9364,9 +9329,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.9.12+spec-1.1.0"
version = "0.9.11+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46"
dependencies = [
"indexmap 2.13.0",
"serde_core",
@@ -9400,9 +9365,9 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.24.1+spec-1.1.0"
version = "0.24.0+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01f2eadbbc6b377a847be05f60791ef1058d9f696ecb51d2c07fe911d8569d8e"
checksum = "8c740b185920170a6d9191122cafef7010bd6270a3824594bff6784c04d7f09e"
dependencies = [
"indexmap 2.13.0",
"toml_datetime",
@@ -9413,9 +9378,9 @@ dependencies = [
[[package]]
name = "toml_parser"
version = "1.0.7+spec-1.1.0"
version = "1.0.6+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1"
checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
dependencies = [
"winnow",
]
@@ -9616,9 +9581,9 @@ dependencies = [
[[package]]
name = "tracing-test"
version = "0.2.6"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19a4c448db514d4f24c5ddb9f73f2ee71bfb24c526cf0c570ba142d1119e0051"
checksum = "557b891436fe0d5e0e363427fc7f217abf9ccd510d5136549847bdcbcd011d68"
dependencies = [
"tracing-core",
"tracing-subscriber",
@@ -9627,9 +9592,9 @@ dependencies = [
[[package]]
name = "tracing-test-macro"
version = "0.2.6"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad06847b7afb65c7866a36664b75c40b895e318cea4f71299f013fb22965329d"
checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568"
dependencies = [
"quote",
"syn 2.0.114",
@@ -9643,7 +9608,7 @@ checksum = "78f873475d258561b06f1c595d93308a7ed124d9977cb26b148c2084a4a3cc87"
dependencies = [
"cc",
"regex",
"regex-syntax 0.8.9",
"regex-syntax 0.8.8",
"serde_json",
"streaming-iterator",
"tree-sitter-language",
@@ -9812,9 +9777,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
[[package]]
name = "unicode-ident"
version = "1.0.23"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "unicode-linebreak"
@@ -9902,9 +9867,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "ureq"
version = "3.2.0"
version = "3.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdc97a28575b85cfedf2a7e7d3cc64b3e11bd8ac766666318003abbacc7a21fc"
checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a"
dependencies = [
"base64 0.22.1",
"der",
@@ -10061,15 +10026,6 @@ dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasip3"
version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
dependencies = [
"wit-bindgen",
]
[[package]]
name = "wasite"
version = "0.1.0"
@@ -10135,28 +10091,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "wasm-encoder"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319"
dependencies = [
"leb128fmt",
"wasmparser",
]
[[package]]
name = "wasm-metadata"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909"
dependencies = [
"anyhow",
"indexmap 2.13.0",
"wasm-encoder",
"wasmparser",
]
[[package]]
name = "wasm-streams"
version = "0.4.2"
@@ -10170,18 +10104,6 @@ dependencies = [
"web-sys",
]
[[package]]
name = "wasmparser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe"
dependencies = [
"bitflags 2.10.0",
"hashbrown 0.15.5",
"indexmap 2.13.0",
"semver",
]
[[package]]
name = "wayland-backend"
version = "0.3.12"
@@ -10274,9 +10196,9 @@ dependencies = [
[[package]]
name = "webbrowser"
version = "1.1.0"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f00bb839c1cf1e3036066614cbdcd035ecf215206691ea646aa3c60a24f68f2"
checksum = "00f1243ef785213e3a32fa0396093424a3a6ea566f9948497e5a2309261a4c97"
dependencies = [
"core-foundation 0.10.1",
"jni",
@@ -10290,9 +10212,9 @@ dependencies = [
[[package]]
name = "webpki-root-certs"
version = "1.0.6"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca"
checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc"
dependencies = [
"rustls-pki-types",
]
@@ -10303,14 +10225,14 @@ version = "0.26.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9"
dependencies = [
"webpki-roots 1.0.6",
"webpki-roots 1.0.5",
]
[[package]]
name = "webpki-roots"
version = "1.0.6"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed"
checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c"
dependencies = [
"rustls-pki-types",
]
@@ -10953,88 +10875,6 @@ name = "wit-bindgen"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
dependencies = [
"wit-bindgen-rust-macro",
]
[[package]]
name = "wit-bindgen-core"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc"
dependencies = [
"anyhow",
"heck",
"wit-parser",
]
[[package]]
name = "wit-bindgen-rust"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21"
dependencies = [
"anyhow",
"heck",
"indexmap 2.13.0",
"prettyplease",
"syn 2.0.114",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
]
[[package]]
name = "wit-bindgen-rust-macro"
version = "0.51.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a"
dependencies = [
"anyhow",
"prettyplease",
"proc-macro2",
"quote",
"syn 2.0.114",
"wit-bindgen-core",
"wit-bindgen-rust",
]
[[package]]
name = "wit-component"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2"
dependencies = [
"anyhow",
"bitflags 2.10.0",
"indexmap 2.13.0",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder",
"wasm-metadata",
"wasmparser",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.244.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736"
dependencies = [
"anyhow",
"id-arena",
"indexmap 2.13.0",
"log",
"semver",
"serde",
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser",
]
[[package]]
name = "wl-clipboard-rs"
@@ -11229,18 +11069,18 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.39"
version = "0.8.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a"
checksum = "7456cf00f0685ad319c5b1693f291a650eaf345e941d082fc4e03df8a03996ac"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.39"
version = "0.8.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517"
checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0"
dependencies = [
"proc-macro2",
"quote",
@@ -11354,9 +11194,9 @@ dependencies = [
[[package]]
name = "zmij"
version = "1.0.20"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7"
checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445"
[[package]]
name = "zopfli"
@@ -175,6 +175,7 @@
"enum": [
"context_window_exceeded",
"usage_limit_exceeded",
"server_overloaded",
"internal_server_error",
"unauthorized",
"bad_request",
@@ -184,35 +185,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"model_cap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"model_cap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -373,6 +373,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -382,35 +383,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -515,6 +487,7 @@
"enum": [
"context_window_exceeded",
"usage_limit_exceeded",
"server_overloaded",
"internal_server_error",
"unauthorized",
"bad_request",
@@ -524,35 +497,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"model_cap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"model_cap"
],
"title": "ModelCapCodexErrorInfo2",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -1884,6 +1884,7 @@
"enum": [
"context_window_exceeded",
"usage_limit_exceeded",
"server_overloaded",
"internal_server_error",
"unauthorized",
"bad_request",
@@ -1893,35 +1894,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"model_cap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"model_cap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -10346,6 +10318,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -10355,35 +10328,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -175,6 +175,7 @@
"enum": [
"context_window_exceeded",
"usage_limit_exceeded",
"server_overloaded",
"internal_server_error",
"unauthorized",
"bad_request",
@@ -184,35 +185,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"model_cap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"model_cap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -175,6 +175,7 @@
"enum": [
"context_window_exceeded",
"usage_limit_exceeded",
"server_overloaded",
"internal_server_error",
"unauthorized",
"bad_request",
@@ -184,35 +185,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"model_cap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"model_cap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -175,6 +175,7 @@
"enum": [
"context_window_exceeded",
"usage_limit_exceeded",
"server_overloaded",
"internal_server_error",
"unauthorized",
"bad_request",
@@ -184,35 +185,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"model_cap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"model_cap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -8,6 +8,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -17,35 +18,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -27,6 +27,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -36,35 +37,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -40,6 +40,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -49,35 +50,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -27,6 +27,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -36,35 +37,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -27,6 +27,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -36,35 +37,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -40,6 +40,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -49,35 +50,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -27,6 +27,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -36,35 +37,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -40,6 +40,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -49,35 +50,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -27,6 +27,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -36,35 +37,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -27,6 +27,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -36,35 +37,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -27,6 +27,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -36,35 +37,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -27,6 +27,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -36,35 +37,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -27,6 +27,7 @@
"enum": [
"contextWindowExceeded",
"usageLimitExceeded",
"serverOverloaded",
"internalServerError",
"unauthorized",
"badRequest",
@@ -36,35 +37,6 @@
],
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"modelCap": {
"properties": {
"model": {
"type": "string"
},
"reset_after_seconds": {
"format": "uint64",
"minimum": 0.0,
"type": [
"integer",
"null"
]
}
},
"required": [
"model"
],
"type": "object"
}
},
"required": [
"modelCap"
],
"title": "ModelCapCodexErrorInfo",
"type": "object"
},
{
"additionalProperties": false,
"properties": {
@@ -5,4 +5,4 @@
/**
* Codex errors that we expose to clients.
*/
export type CodexErrorInfo = "context_window_exceeded" | "usage_limit_exceeded" | { "model_cap": { model: string, reset_after_seconds: bigint | null, } } | { "http_connection_failed": { http_status_code: number | null, } } | { "response_stream_connection_failed": { http_status_code: number | null, } } | "internal_server_error" | "unauthorized" | "bad_request" | "sandbox_error" | { "response_stream_disconnected": { http_status_code: number | null, } } | { "response_too_many_failed_attempts": { http_status_code: number | null, } } | "thread_rollback_failed" | "other";
export type CodexErrorInfo = "context_window_exceeded" | "usage_limit_exceeded" | "server_overloaded" | { "http_connection_failed": { http_status_code: number | null, } } | { "response_stream_connection_failed": { http_status_code: number | null, } } | "internal_server_error" | "unauthorized" | "bad_request" | "sandbox_error" | { "response_stream_disconnected": { http_status_code: number | null, } } | { "response_too_many_failed_attempts": { http_status_code: number | null, } } | "thread_rollback_failed" | "other";
@@ -8,4 +8,4 @@
* When an upstream HTTP status is available (for example, from the Responses API or a provider),
* it is forwarded in `httpStatusCode` on the relevant `codexErrorInfo` variant.
*/
export type CodexErrorInfo = "contextWindowExceeded" | "usageLimitExceeded" | { "modelCap": { model: string, reset_after_seconds: bigint | null, } } | { "httpConnectionFailed": { httpStatusCode: number | null, } } | { "responseStreamConnectionFailed": { httpStatusCode: number | null, } } | "internalServerError" | "unauthorized" | "badRequest" | "threadRollbackFailed" | "sandboxError" | { "responseStreamDisconnected": { httpStatusCode: number | null, } } | { "responseTooManyFailedAttempts": { httpStatusCode: number | null, } } | "other";
export type CodexErrorInfo = "contextWindowExceeded" | "usageLimitExceeded" | "serverOverloaded" | { "httpConnectionFailed": { httpStatusCode: number | null, } } | { "responseStreamConnectionFailed": { httpStatusCode: number | null, } } | "internalServerError" | "unauthorized" | "badRequest" | "threadRollbackFailed" | "sandboxError" | { "responseStreamDisconnected": { httpStatusCode: number | null, } } | { "responseTooManyFailedAttempts": { httpStatusCode: number | null, } } | "other";
@@ -89,10 +89,7 @@ macro_rules! v2_enum_from_core {
pub enum CodexErrorInfo {
ContextWindowExceeded,
UsageLimitExceeded,
ModelCap {
model: String,
reset_after_seconds: Option<u64>,
},
ServerOverloaded,
HttpConnectionFailed {
#[serde(rename = "httpStatusCode")]
#[ts(rename = "httpStatusCode")]
@@ -129,13 +126,7 @@ impl From<CoreCodexErrorInfo> for CodexErrorInfo {
match value {
CoreCodexErrorInfo::ContextWindowExceeded => CodexErrorInfo::ContextWindowExceeded,
CoreCodexErrorInfo::UsageLimitExceeded => CodexErrorInfo::UsageLimitExceeded,
CoreCodexErrorInfo::ModelCap {
model,
reset_after_seconds,
} => CodexErrorInfo::ModelCap {
model,
reset_after_seconds,
},
CoreCodexErrorInfo::ServerOverloaded => CodexErrorInfo::ServerOverloaded,
CoreCodexErrorInfo::HttpConnectionFailed { http_status_code } => {
CodexErrorInfo::HttpConnectionFailed { http_status_code }
}
@@ -120,6 +120,7 @@ async fn list_apps_uses_thread_feature_flag_when_thread_id_is_provided() -> Resu
format!(
r#"
chatgpt_base_url = "{server_url}"
mcp_oauth_credentials_store = "file"
[features]
connectors = false
@@ -791,6 +792,7 @@ fn write_connectors_config(codex_home: &std::path::Path, base_url: &str) -> std:
format!(
r#"
chatgpt_base_url = "{base_url}"
mcp_oauth_credentials_store = "file"
[features]
connectors = true
+2
View File
@@ -27,6 +27,8 @@ pub enum ApiError {
RateLimit(String),
#[error("invalid request: {message}")]
InvalidRequest { message: String },
#[error("server overloaded")]
ServerOverloaded,
}
impl From<RateLimitError> for ApiError {
+7
View File
@@ -239,6 +239,8 @@ pub fn process_responses_event(
.message
.unwrap_or_else(|| "Invalid request.".to_string());
response_error = ApiError::InvalidRequest { message };
} else if is_server_overloaded_error(&error) {
response_error = ApiError::ServerOverloaded;
} else {
let delay = try_parse_retry_after(&error);
let message = error.message.unwrap_or_default();
@@ -425,6 +427,11 @@ fn is_invalid_prompt_error(error: &Error) -> bool {
error.code.as_deref() == Some("invalid_prompt")
}
fn is_server_overloaded_error(error: &Error) -> bool {
error.code.as_deref() == Some("server_is_overloaded")
|| error.code.as_deref() == Some("slow_down")
}
fn rate_limit_regex() -> &'static regex_lite::Regex {
static RE: std::sync::OnceLock<regex_lite::Regex> = std::sync::OnceLock::new();
#[expect(clippy::unwrap_used)]
+33 -42
View File
@@ -10,7 +10,6 @@ use serde::Deserialize;
use crate::auth::CodexAuth;
use crate::error::CodexErr;
use crate::error::ModelCapError;
use crate::error::RetryLimitReachedError;
use crate::error::UnexpectedResponseError;
use crate::error::UsageLimitReachedError;
@@ -24,6 +23,7 @@ pub(crate) fn map_api_error(err: ApiError) -> CodexErr {
ApiError::UsageNotIncluded => CodexErr::UsageNotIncluded,
ApiError::Retryable { message, delay } => CodexErr::Stream(message, delay),
ApiError::Stream(msg) => CodexErr::Stream(msg, None),
ApiError::ServerOverloaded => CodexErr::ServerOverloaded,
ApiError::Api { status, message } => CodexErr::UnexpectedStatus(UnexpectedResponseError {
status,
body: message,
@@ -41,6 +41,19 @@ pub(crate) fn map_api_error(err: ApiError) -> CodexErr {
} => {
let body_text = body.unwrap_or_default();
if status == http::StatusCode::SERVICE_UNAVAILABLE
&& let Ok(value) = serde_json::from_str::<serde_json::Value>(&body_text)
&& matches!(
value
.get("error")
.and_then(|error| error.get("code"))
.and_then(serde_json::Value::as_str),
Some("server_is_overloaded" | "slow_down")
)
{
return CodexErr::ServerOverloaded;
}
if status == http::StatusCode::BAD_REQUEST {
if body_text
.contains("The image data you provided does not represent a valid image")
@@ -52,23 +65,6 @@ pub(crate) fn map_api_error(err: ApiError) -> CodexErr {
} else if status == http::StatusCode::INTERNAL_SERVER_ERROR {
CodexErr::InternalServerError
} else if status == http::StatusCode::TOO_MANY_REQUESTS {
if let Some(model) = headers
.as_ref()
.and_then(|map| map.get(MODEL_CAP_MODEL_HEADER))
.and_then(|value| value.to_str().ok())
.map(str::to_string)
{
let reset_after_seconds = headers
.as_ref()
.and_then(|map| map.get(MODEL_CAP_RESET_AFTER_HEADER))
.and_then(|value| value.to_str().ok())
.and_then(|value| value.parse::<u64>().ok());
return CodexErr::ModelCap(ModelCapError {
model,
reset_after_seconds,
});
}
if let Ok(err) = serde_json::from_str::<UsageErrorResponse>(&body_text) {
if err.error.error_type.as_deref() == Some("usage_limit_reached") {
let limit_id = extract_header(headers.as_ref(), ACTIVE_LIMIT_HEADER);
@@ -119,8 +115,6 @@ pub(crate) fn map_api_error(err: ApiError) -> CodexErr {
}
}
const MODEL_CAP_MODEL_HEADER: &str = "x-codex-model-cap-model";
const MODEL_CAP_RESET_AFTER_HEADER: &str = "x-codex-model-cap-reset-after-seconds";
const ACTIVE_LIMIT_HEADER: &str = "x-codex-active-limit";
const REQUEST_ID_HEADER: &str = "x-request-id";
const OAI_REQUEST_ID_HEADER: &str = "x-oai-request-id";
@@ -129,33 +123,30 @@ const CF_RAY_HEADER: &str = "cf-ray";
#[cfg(test)]
mod tests {
use super::*;
use codex_api::TransportError;
use http::HeaderMap;
use http::StatusCode;
use pretty_assertions::assert_eq;
#[test]
fn map_api_error_maps_model_cap_headers() {
let mut headers = HeaderMap::new();
headers.insert(
MODEL_CAP_MODEL_HEADER,
http::HeaderValue::from_static("boomslang"),
);
headers.insert(
MODEL_CAP_RESET_AFTER_HEADER,
http::HeaderValue::from_static("120"),
);
fn map_api_error_maps_server_overloaded() {
let err = map_api_error(ApiError::ServerOverloaded);
assert!(matches!(err, CodexErr::ServerOverloaded));
}
#[test]
fn map_api_error_maps_server_overloaded_from_503_body() {
let body = serde_json::json!({
"error": {
"code": "server_is_overloaded"
}
})
.to_string();
let err = map_api_error(ApiError::Transport(TransportError::Http {
status: StatusCode::TOO_MANY_REQUESTS,
status: http::StatusCode::SERVICE_UNAVAILABLE,
url: Some("http://example.com/v1/responses".to_string()),
headers: Some(headers),
body: Some(String::new()),
headers: None,
body: Some(body),
}));
let CodexErr::ModelCap(model_cap) = err else {
panic!("expected CodexErr::ModelCap, got {err:?}");
};
assert_eq!(model_cap.model, "boomslang");
assert_eq!(model_cap.reset_after_seconds, Some(120));
assert!(matches!(err, CodexErr::ServerOverloaded));
}
#[test]
@@ -173,7 +164,7 @@ mod tests {
})
.to_string();
let err = map_api_error(ApiError::Transport(TransportError::Http {
status: StatusCode::TOO_MANY_REQUESTS,
status: http::StatusCode::TOO_MANY_REQUESTS,
url: Some("http://example.com/v1/responses".to_string()),
headers: Some(headers),
body: Some(body),
+173 -4
View File
@@ -564,6 +564,80 @@ impl TurnContext {
})
}
pub(crate) async fn with_model(&self, model: String, models_manager: &ModelsManager) -> Self {
let mut config = (*self.config).clone();
config.model = Some(model.clone());
let model_info = models_manager.get_model_info(model.as_str(), &config).await;
let truncation_policy = model_info.truncation_policy.into();
let supported_reasoning_levels = model_info
.supported_reasoning_levels
.iter()
.map(|preset| preset.effort)
.collect::<Vec<_>>();
let reasoning_effort = if let Some(current_reasoning_effort) = self.reasoning_effort {
if supported_reasoning_levels.contains(&current_reasoning_effort) {
Some(current_reasoning_effort)
} else {
supported_reasoning_levels
.get(supported_reasoning_levels.len().saturating_sub(1) / 2)
.copied()
.or(model_info.default_reasoning_level)
}
} else {
supported_reasoning_levels
.get(supported_reasoning_levels.len().saturating_sub(1) / 2)
.copied()
.or(model_info.default_reasoning_level)
};
config.model_reasoning_effort = reasoning_effort;
let collaboration_mode =
self.collaboration_mode
.with_updates(Some(model.clone()), Some(reasoning_effort), None);
let features = self.features.clone();
let tools_config = ToolsConfig::new(&ToolsConfigParams {
model_info: &model_info,
features: &features,
web_search_mode: self.tools_config.web_search_mode,
});
Self {
sub_id: self.sub_id.clone(),
config: Arc::new(config),
auth_manager: self.auth_manager.clone(),
model_info: model_info.clone(),
otel_manager: self
.otel_manager
.clone()
.with_model(model.as_str(), model_info.slug.as_str()),
provider: self.provider.clone(),
reasoning_effort,
reasoning_summary: self.reasoning_summary,
session_source: self.session_source.clone(),
cwd: self.cwd.clone(),
developer_instructions: self.developer_instructions.clone(),
compact_prompt: self.compact_prompt.clone(),
user_instructions: self.user_instructions.clone(),
collaboration_mode,
personality: self.personality,
approval_policy: self.approval_policy,
sandbox_policy: self.sandbox_policy.clone(),
network: self.network.clone(),
windows_sandbox_level: self.windows_sandbox_level,
shell_environment_policy: self.shell_environment_policy.clone(),
tools_config,
features,
ghost_snapshot: self.ghost_snapshot.clone(),
final_output_json_schema: self.final_output_json_schema.clone(),
codex_linux_sandbox_exe: self.codex_linux_sandbox_exe.clone(),
tool_call_gate: Arc::new(ReadinessFlag::new()),
truncation_policy,
js_repl: Arc::clone(&self.js_repl),
dynamic_tools: self.dynamic_tools.clone(),
turn_metadata_header: self.turn_metadata_header.clone(),
}
}
pub(crate) fn resolve_path(&self, path: Option<String>) -> PathBuf {
path.as_ref()
.map(PathBuf::from)
@@ -3892,7 +3966,6 @@ pub(crate) async fn run_turn(
let model_info = turn_context.model_info.clone();
let auto_compact_limit = model_info.auto_compact_token_limit().unwrap_or(i64::MAX);
let total_usage_tokens = sess.get_total_token_usage().await;
let event = EventMsg::TurnStarted(TurnStartedEvent {
turn_id: turn_context.sub_id.clone(),
@@ -3900,9 +3973,11 @@ pub(crate) async fn run_turn(
collaboration_mode_kind: turn_context.collaboration_mode.mode,
});
sess.send_event(&turn_context, event).await;
if total_usage_tokens >= auto_compact_limit
&& run_auto_compact(&sess, &turn_context).await.is_err()
if run_pre_sampling_compact(&sess, &turn_context)
.await
.is_err()
{
error!("Failed to run pre-sampling compact");
return None;
}
@@ -4141,6 +4216,62 @@ pub(crate) async fn run_turn(
last_agent_message
}
async fn run_pre_sampling_compact(
sess: &Arc<Session>,
turn_context: &Arc<TurnContext>,
) -> CodexResult<()> {
let total_usage_tokens_before_compaction = sess.get_total_token_usage().await;
maybe_run_previous_model_inline_compact(
sess,
turn_context,
total_usage_tokens_before_compaction,
)
.await?;
let total_usage_tokens = sess.get_total_token_usage().await;
let auto_compact_limit = turn_context
.model_info
.auto_compact_token_limit()
.unwrap_or(i64::MAX);
// Compact if the total usage tokens are greater than the auto compact limit
if total_usage_tokens >= auto_compact_limit {
run_auto_compact(sess, turn_context).await?;
}
Ok(())
}
async fn maybe_run_previous_model_inline_compact(
sess: &Arc<Session>,
turn_context: &Arc<TurnContext>,
total_usage_tokens: i64,
) -> CodexResult<()> {
let Some(previous_model) = sess.previous_model().await else {
return Ok(());
};
let previous_turn_context = Arc::new(
turn_context
.with_model(previous_model, &sess.services.models_manager)
.await,
);
let Some(old_context_window) = previous_turn_context.model_context_window() else {
return Ok(());
};
let Some(new_context_window) = turn_context.model_context_window() else {
return Ok(());
};
let new_auto_compact_limit = turn_context
.model_info
.auto_compact_token_limit()
.unwrap_or(i64::MAX);
let should_run = total_usage_tokens > new_auto_compact_limit
&& previous_turn_context.model_info.slug != turn_context.model_info.slug
&& old_context_window > new_context_window;
if should_run {
run_auto_compact(sess, &previous_turn_context).await?;
}
Ok(())
}
async fn run_auto_compact(sess: &Arc<Session>, turn_context: &Arc<TurnContext>) -> CodexResult<()> {
if should_use_remote_compact_task(&turn_context.provider) {
run_inline_remote_auto_compact_task(Arc::clone(sess), Arc::clone(turn_context)).await?;
@@ -4400,7 +4531,7 @@ async fn built_tools(
None
};
if turn_context.config.features.enabled(Feature::SearchTool) {
if turn_context.config.features.enabled(Feature::Apps) {
let mut selected_mcp_tools =
if let Some(selected_tools) = sess.get_mcp_tool_selection().await {
filter_mcp_tools_by_name(mcp_tools.clone(), &selected_tools)
@@ -6112,6 +6243,44 @@ mod tests {
);
}
#[tokio::test]
async fn turn_context_with_model_updates_model_fields() {
let (session, mut turn_context) = make_session_and_context().await;
turn_context.reasoning_effort = Some(ReasoningEffortConfig::Minimal);
let updated = turn_context
.with_model("gpt-5.1".to_string(), &session.services.models_manager)
.await;
let expected_model_info = session
.services
.models_manager
.get_model_info("gpt-5.1", updated.config.as_ref())
.await;
assert_eq!(updated.config.model.as_deref(), Some("gpt-5.1"));
assert_eq!(updated.collaboration_mode.model(), "gpt-5.1");
assert_eq!(updated.model_info, expected_model_info);
assert_eq!(
updated.reasoning_effort,
Some(ReasoningEffortConfig::Medium)
);
assert_eq!(
updated.collaboration_mode.reasoning_effort(),
Some(ReasoningEffortConfig::Medium)
);
assert_eq!(
updated.config.model_reasoning_effort,
Some(ReasoningEffortConfig::Medium)
);
assert_eq!(
updated.truncation_policy,
expected_model_info.truncation_policy.into()
);
assert!(!Arc::ptr_eq(
&updated.tool_call_gate,
&turn_context.tool_call_gate
));
}
#[test]
fn falls_back_to_content_when_structured_is_null() {
let ctr = McpCallToolResult {
+7 -76
View File
@@ -113,8 +113,8 @@ pub enum CodexErr {
#[error("{0}")]
UsageLimitReached(UsageLimitReachedError),
#[error("{0}")]
ModelCap(ModelCapError),
#[error("Selected model is at capacity. Please try a different model.")]
ServerOverloaded,
#[error("{0}")]
ResponseStreamFailed(ResponseStreamFailed),
@@ -209,7 +209,7 @@ impl CodexErr {
| CodexErr::Spawn
| CodexErr::SessionConfiguredNotFirstEvent
| CodexErr::UsageLimitReached(_)
| CodexErr::ModelCap(_) => false,
| CodexErr::ServerOverloaded => false,
CodexErr::Stream(..)
| CodexErr::Timeout
| CodexErr::UnexpectedStatus(_)
@@ -470,30 +470,6 @@ impl std::fmt::Display for UsageLimitReachedError {
}
}
#[derive(Debug)]
pub struct ModelCapError {
pub(crate) model: String,
pub(crate) reset_after_seconds: Option<u64>,
}
impl std::fmt::Display for ModelCapError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut message = format!(
"Model {} is at capacity. Please try a different model.",
self.model
);
if let Some(seconds) = self.reset_after_seconds {
message.push_str(&format!(
" Try again in {}.",
format_duration_short(seconds)
));
} else {
message.push_str(" Try again later.");
}
write!(f, "{message}")
}
}
fn retry_suffix(resets_at: Option<&DateTime<Utc>>) -> String {
if let Some(resets_at) = resets_at {
let formatted = format_retry_timestamp(resets_at);
@@ -525,18 +501,6 @@ fn format_retry_timestamp(resets_at: &DateTime<Utc>) -> String {
}
}
fn format_duration_short(seconds: u64) -> String {
if seconds < 60 {
"less than a minute".to_string()
} else if seconds < 3600 {
format!("{}m", seconds / 60)
} else if seconds < 86_400 {
format!("{}h", seconds / 3600)
} else {
format!("{}d", seconds / 86_400)
}
}
fn day_suffix(day: u32) -> &'static str {
match day {
11..=13 => "th",
@@ -600,10 +564,7 @@ impl CodexErr {
CodexErr::UsageLimitReached(_)
| CodexErr::QuotaExceeded
| CodexErr::UsageNotIncluded => CodexErrorInfo::UsageLimitExceeded,
CodexErr::ModelCap(err) => CodexErrorInfo::ModelCap {
model: err.model.clone(),
reset_after_seconds: err.reset_after_seconds,
},
CodexErr::ServerOverloaded => CodexErrorInfo::ServerOverloaded,
CodexErr::RetryLimit(_) => CodexErrorInfo::ResponseTooManyFailedAttempts {
http_status_code: self.http_status_code_value(),
},
@@ -752,41 +713,11 @@ mod tests {
}
#[test]
fn model_cap_error_formats_message() {
let err = ModelCapError {
model: "boomslang".to_string(),
reset_after_seconds: Some(120),
};
assert_eq!(
err.to_string(),
"Model boomslang is at capacity. Please try a different model. Try again in 2m."
);
}
#[test]
fn model_cap_error_formats_message_without_reset() {
let err = ModelCapError {
model: "boomslang".to_string(),
reset_after_seconds: None,
};
assert_eq!(
err.to_string(),
"Model boomslang is at capacity. Please try a different model. Try again later."
);
}
#[test]
fn model_cap_error_maps_to_protocol() {
let err = CodexErr::ModelCap(ModelCapError {
model: "boomslang".to_string(),
reset_after_seconds: Some(30),
});
fn server_overloaded_maps_to_protocol() {
let err = CodexErr::ServerOverloaded;
assert_eq!(
err.to_codex_protocol_error(),
CodexErrorInfo::ModelCap {
model: "boomslang".to_string(),
reset_after_seconds: Some(30),
}
CodexErrorInfo::ServerOverloaded
);
}
+2 -2
View File
@@ -89,7 +89,7 @@ pub enum Feature {
/// Allow the model to request web searches that fetch cached content.
/// Takes precedence over `WebSearchRequest`.
WebSearchCached,
/// Allow the model to search MCP tools via BM25 before exposing them.
/// Legacy search-tool feature flag kept for backward compatibility.
SearchTool,
/// Use the bubblewrap-based Linux sandbox pipeline.
UseLinuxSandboxBwrap,
@@ -445,7 +445,7 @@ pub const FEATURES: &[FeatureSpec] = &[
FeatureSpec {
id: Feature::SearchTool,
key: "search_tool",
stage: Stage::UnderDevelopment,
stage: Stage::Removed,
default_enabled: false,
},
// Experimental program. Rendered in the `/experimental` menu for users.
+1 -1
View File
@@ -153,7 +153,7 @@ impl Session {
if !task_cancellation_token.is_cancelled() {
// Emit completion uniformly from spawn site so all tasks share the same lifecycle.
let sess = session_ctx.clone_session();
sess.on_task_finished(ctx_for_finish, last_agent_message)
sess.on_task_finished(Arc::clone(&ctx_for_finish), last_agent_message)
.await;
}
// Set previous model regardless of completion or interruption for model-switch handling.
+1 -1
View File
@@ -58,7 +58,7 @@ impl ToolsConfig {
let include_collab_tools = features.enabled(Feature::Collab);
let include_collaboration_modes_tools = features.enabled(Feature::CollaborationModes);
let request_rule_enabled = features.enabled(Feature::RequestRule);
let include_search_tool = features.enabled(Feature::SearchTool);
let include_search_tool = features.enabled(Feature::Apps);
let shell_type = if !features.enabled(Feature::ShellTool) {
ConfigShellToolType::Disabled
+327
View File
@@ -5,6 +5,7 @@ use codex_core::built_in_model_providers;
use codex_core::compact::SUMMARIZATION_PROMPT;
use codex_core::compact::SUMMARY_PREFIX;
use codex_core::config::Config;
use codex_core::features::Feature;
use codex_core::protocol::AskForApproval;
use codex_core::protocol::EventMsg;
use codex_core::protocol::ItemCompletedEvent;
@@ -16,9 +17,12 @@ use codex_core::protocol::SandboxPolicy;
use codex_core::protocol::WarningEvent;
use codex_protocol::config_types::ReasoningSummary;
use codex_protocol::items::TurnItem;
use codex_protocol::openai_models::ModelInfo;
use codex_protocol::openai_models::ModelsResponse;
use codex_protocol::user_input::UserInput;
use core_test_support::responses::ev_local_shell_call;
use core_test_support::responses::ev_reasoning_item;
use core_test_support::responses::mount_models_once;
use core_test_support::skip_if_no_network;
use core_test_support::test_codex::test_codex;
use core_test_support::wait_for_event;
@@ -110,6 +114,78 @@ fn non_openai_model_provider(server: &MockServer) -> ModelProviderInfo {
provider
}
fn model_info_with_context_window(slug: &str, context_window: i64) -> ModelInfo {
let models_response: ModelsResponse =
serde_json::from_str(include_str!("../../models.json")).expect("valid models.json");
let mut model_info = models_response
.models
.into_iter()
.find(|model| model.slug == slug)
.unwrap_or_else(|| panic!("model `{slug}` missing from models.json"));
model_info.context_window = Some(context_window);
model_info
}
fn assert_pre_sampling_switch_compaction_requests(
first: &serde_json::Value,
compact: &serde_json::Value,
follow_up: &serde_json::Value,
previous_model: &str,
next_model: &str,
) {
assert_eq!(first["model"].as_str(), Some(previous_model));
assert_eq!(compact["model"].as_str(), Some(previous_model));
assert_eq!(follow_up["model"].as_str(), Some(next_model));
let compact_body = compact.to_string();
assert!(
body_contains_text(&compact_body, SUMMARIZATION_PROMPT),
"pre-sampling compact request should include summarization prompt"
);
}
async fn assert_compaction_uses_turn_lifecycle_id(codex: &std::sync::Arc<codex_core::CodexThread>) {
let mut turn_started_id = None;
let mut turn_completed_id = None;
let mut compact_started_id = None;
let mut compact_completed_id = None;
while turn_completed_id.is_none() {
let event = codex.next_event().await.expect("next event");
match event.msg {
EventMsg::TurnStarted(_) => turn_started_id = Some(event.id.clone()),
EventMsg::ItemStarted(ItemStartedEvent {
item: TurnItem::ContextCompaction(_),
..
}) => compact_started_id = Some(event.id.clone()),
EventMsg::ItemCompleted(ItemCompletedEvent {
item: TurnItem::ContextCompaction(_),
..
}) => compact_completed_id = Some(event.id.clone()),
EventMsg::TurnComplete(_) => turn_completed_id = Some(event.id.clone()),
_ => {}
}
}
let turn_started_id = turn_started_id.expect("turn started id");
let turn_completed_id = turn_completed_id.expect("turn complete id");
assert_eq!(
turn_completed_id, turn_started_id,
"turn start and complete should use the same event id"
);
assert_eq!(
compact_started_id,
Some(turn_started_id.clone()),
"compaction item start should use the turn event id"
);
assert_eq!(
compact_completed_id,
Some(turn_started_id),
"compaction item completion should use the turn event id"
);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn summarize_context_three_requests_and_instructions() {
skip_if_no_network!();
@@ -1551,6 +1627,257 @@ async fn auto_compact_runs_after_resume_when_token_usage_is_over_limit() {
);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn pre_sampling_compact_runs_on_switch_to_smaller_context_model() {
skip_if_no_network!();
let server = MockServer::start().await;
let previous_model = "gpt-5.2-codex";
let next_model = "gpt-5.1-codex-max";
let models_mock = mount_models_once(
&server,
ModelsResponse {
models: vec![
model_info_with_context_window(previous_model, 273_000),
model_info_with_context_window(next_model, 125_000),
],
},
)
.await;
let request_log = mount_sse_sequence(
&server,
vec![
sse(vec![
ev_assistant_message("m1", "before switch"),
ev_completed_with_tokens("r1", 120_000),
]),
sse(vec![
ev_assistant_message("m2", "PRE_SAMPLING_SUMMARY"),
ev_completed_with_tokens("r2", 10),
]),
sse(vec![
ev_assistant_message("m3", "after switch"),
ev_completed_with_tokens("r3", 100),
]),
],
)
.await;
let model_provider = non_openai_model_provider(&server);
let mut builder = test_codex()
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
.with_model(previous_model)
.with_config(move |config| {
config.model_provider = model_provider;
set_test_compact_prompt(config);
config.features.enable(Feature::RemoteModels);
});
let test = builder.build(&server).await.expect("build test codex");
test.codex
.submit(Op::UserTurn {
items: vec![UserInput::Text {
text: "before switch".into(),
text_elements: Vec::new(),
}],
final_output_json_schema: None,
cwd: test.cwd.path().to_path_buf(),
approval_policy: AskForApproval::Never,
sandbox_policy: SandboxPolicy::DangerFullAccess,
model: previous_model.to_string(),
effort: None,
summary: ReasoningSummary::Auto,
collaboration_mode: None,
personality: None,
})
.await
.expect("submit first user turn");
wait_for_event(&test.codex, |event| {
matches!(event, EventMsg::TurnComplete(_))
})
.await;
test.codex
.submit(Op::UserTurn {
items: vec![UserInput::Text {
text: "after switch".into(),
text_elements: Vec::new(),
}],
final_output_json_schema: None,
cwd: test.cwd.path().to_path_buf(),
approval_policy: AskForApproval::Never,
sandbox_policy: SandboxPolicy::DangerFullAccess,
model: next_model.to_string(),
effort: None,
summary: ReasoningSummary::Auto,
collaboration_mode: None,
personality: None,
})
.await
.expect("submit second user turn");
assert_compaction_uses_turn_lifecycle_id(&test.codex).await;
let requests = request_log.requests();
assert_eq!(models_mock.requests().len(), 1);
assert_eq!(
requests.len(),
3,
"expected user, compact, and follow-up requests"
);
assert_pre_sampling_switch_compaction_requests(
&requests[0].body_json(),
&requests[1].body_json(),
&requests[2].body_json(),
previous_model,
next_model,
);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn pre_sampling_compact_runs_after_resume_and_switch_to_smaller_model() {
skip_if_no_network!();
let server = MockServer::start().await;
let previous_model = "gpt-5.2-codex";
let next_model = "gpt-5.1-codex-max";
let models_mock = mount_models_once(
&server,
ModelsResponse {
models: vec![
model_info_with_context_window(previous_model, 273_000),
model_info_with_context_window(next_model, 125_000),
],
},
)
.await;
let request_log = mount_sse_sequence(
&server,
vec![
sse(vec![
ev_assistant_message("m1", "before resume"),
ev_completed_with_tokens("r1", 120_000),
]),
sse(vec![
ev_assistant_message("m2", "PRE_SAMPLING_SUMMARY"),
ev_completed_with_tokens("r2", 10),
]),
sse(vec![
ev_assistant_message("m3", "after resume"),
ev_completed_with_tokens("r3", 100),
]),
],
)
.await;
let model_provider = non_openai_model_provider(&server);
let mut initial_builder = test_codex()
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
.with_model(previous_model)
.with_config(move |config| {
config.model_provider = model_provider;
set_test_compact_prompt(config);
config.features.enable(Feature::RemoteModels);
});
let initial = initial_builder
.build(&server)
.await
.expect("build initial test codex");
let home = initial.home.clone();
let rollout_path = initial
.session_configured
.rollout_path
.clone()
.expect("rollout path");
initial
.codex
.submit(Op::UserTurn {
items: vec![UserInput::Text {
text: "before resume".into(),
text_elements: Vec::new(),
}],
final_output_json_schema: None,
cwd: initial.cwd.path().to_path_buf(),
approval_policy: AskForApproval::Never,
sandbox_policy: SandboxPolicy::DangerFullAccess,
model: previous_model.to_string(),
effort: None,
summary: ReasoningSummary::Auto,
collaboration_mode: None,
personality: None,
})
.await
.expect("submit pre-resume turn");
wait_for_event(&initial.codex, |event| {
matches!(event, EventMsg::TurnComplete(_))
})
.await;
initial
.codex
.submit(Op::Shutdown)
.await
.expect("shutdown initial session");
wait_for_event(&initial.codex, |event| {
matches!(event, EventMsg::ShutdownComplete)
})
.await;
let model_provider = non_openai_model_provider(&server);
let mut resumed_builder = test_codex()
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
.with_model(previous_model)
.with_config(move |config| {
config.model_provider = model_provider;
set_test_compact_prompt(config);
config.features.enable(Feature::RemoteModels);
});
let resumed = resumed_builder
.resume(&server, home, rollout_path)
.await
.expect("resume codex");
resumed
.codex
.submit(Op::UserTurn {
items: vec![UserInput::Text {
text: "after resume".into(),
text_elements: Vec::new(),
}],
final_output_json_schema: None,
cwd: resumed.cwd.path().to_path_buf(),
approval_policy: AskForApproval::Never,
sandbox_policy: SandboxPolicy::DangerFullAccess,
model: next_model.to_string(),
effort: None,
summary: ReasoningSummary::Auto,
collaboration_mode: None,
personality: None,
})
.await
.expect("submit resumed user turn");
assert_compaction_uses_turn_lifecycle_id(&resumed.codex).await;
let requests = request_log.requests();
assert_eq!(models_mock.requests().len(), 1);
assert_eq!(
requests.len(),
3,
"expected user, compact, and follow-up requests"
);
assert_pre_sampling_switch_compaction_requests(
&requests[0].body_json(),
&requests[1].body_json(),
&requests[2].body_json(),
previous_model,
next_model,
);
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn auto_compact_persists_rollout_entries() {
skip_if_no_network!();
+5 -5
View File
@@ -111,7 +111,7 @@ async fn search_tool_flag_adds_tool() -> Result<()> {
.await;
let mut builder = test_codex().with_config(|config| {
config.features.enable(Feature::SearchTool);
config.features.enable(Feature::Apps);
});
let test = builder.build(&server).await?;
@@ -148,7 +148,7 @@ async fn search_tool_adds_developer_instructions() -> Result<()> {
.await;
let mut builder = test_codex().with_config(|config| {
config.features.enable(Feature::SearchTool);
config.features.enable(Feature::Apps);
});
let test = builder.build(&server).await?;
@@ -190,7 +190,7 @@ async fn search_tool_hides_mcp_tools_without_search() -> Result<()> {
let rmcp_test_server_bin = stdio_server_bin()?;
let mut builder = test_codex().with_config(move |config| {
config.features.enable(Feature::SearchTool);
config.features.enable(Feature::Apps);
let mut servers = config.mcp_servers.get().clone();
servers.insert(
"rmcp".to_string(),
@@ -273,7 +273,7 @@ async fn search_tool_selection_persists_within_turn_and_resets_next_turn() -> Re
let rmcp_test_server_bin = stdio_server_bin()?;
let mut builder = test_codex().with_config(move |config| {
config.features.enable(Feature::SearchTool);
config.features.enable(Feature::Apps);
let mut servers = config.mcp_servers.get().clone();
servers.insert(
"rmcp".to_string(),
@@ -401,7 +401,7 @@ async fn search_tool_selection_unions_results_within_turn() -> Result<()> {
let rmcp_test_server_bin = stdio_server_bin()?;
let mut builder = test_codex().with_config(move |config| {
config.features.enable(Feature::SearchTool);
config.features.enable(Feature::Apps);
let mut servers = config.mcp_servers.get().clone();
servers.insert(
"rmcp".to_string(),
+1 -4
View File
@@ -1130,10 +1130,7 @@ pub enum AgentStatus {
pub enum CodexErrorInfo {
ContextWindowExceeded,
UsageLimitExceeded,
ModelCap {
model: String,
reset_after_seconds: Option<u64>,
},
ServerOverloaded,
HttpConnectionFailed {
http_status_code: Option<u16>,
},
+10 -36
View File
@@ -441,23 +441,14 @@ enum ConnectorsCacheState {
#[derive(Debug)]
enum RateLimitErrorKind {
ModelCap {
model: String,
reset_after_seconds: Option<u64>,
},
ServerOverloaded,
UsageLimit,
Generic,
}
fn rate_limit_error_kind(info: &CodexErrorInfo) -> Option<RateLimitErrorKind> {
match info {
CodexErrorInfo::ModelCap {
model,
reset_after_seconds,
} => Some(RateLimitErrorKind::ModelCap {
model: model.clone(),
reset_after_seconds: *reset_after_seconds,
}),
CodexErrorInfo::ServerOverloaded => Some(RateLimitErrorKind::ServerOverloaded),
CodexErrorInfo::UsageLimitExceeded => Some(RateLimitErrorKind::UsageLimit),
CodexErrorInfo::ResponseTooManyFailedAttempts {
http_status_code: Some(429),
@@ -1605,18 +1596,14 @@ impl ChatWidget {
self.maybe_show_pending_rate_limit_prompt();
}
fn on_model_cap_error(&mut self, model: String, reset_after_seconds: Option<u64>) {
fn on_server_overloaded_error(&mut self, message: String) {
self.finalize_turn();
let mut message = format!("Model {model} is at capacity. Please try a different model.");
if let Some(seconds) = reset_after_seconds {
message.push_str(&format!(
" Try again in {}.",
format_duration_short(seconds)
));
let message = if message.trim().is_empty() {
"Codex is currently experiencing high load.".to_string()
} else {
message.push_str(" Try again later.");
}
message
};
self.add_to_history(history_cell::new_warning_event(message));
self.request_redraw();
@@ -3964,10 +3951,9 @@ impl ChatWidget {
&& let Some(kind) = rate_limit_error_kind(&info)
{
match kind {
RateLimitErrorKind::ModelCap {
model,
reset_after_seconds,
} => self.on_model_cap_error(model, reset_after_seconds),
RateLimitErrorKind::ServerOverloaded => {
self.on_server_overloaded_error(message)
}
RateLimitErrorKind::UsageLimit | RateLimitErrorKind::Generic => {
self.on_error(message)
}
@@ -7162,17 +7148,5 @@ pub(crate) fn show_review_commit_picker_with_entries(
});
}
fn format_duration_short(seconds: u64) -> String {
if seconds < 60 {
"less than a minute".to_string()
} else if seconds < 3600 {
format!("{}m", seconds / 60)
} else if seconds < 86_400 {
format!("{}h", seconds / 3600)
} else {
format!("{}d", seconds / 86_400)
}
}
#[cfg(test)]
pub(crate) mod tests;
+5 -8
View File
@@ -4096,7 +4096,7 @@ async fn model_picker_hides_show_in_picker_false_models_from_cache() {
}
#[tokio::test]
async fn model_cap_error_does_not_switch_models() {
async fn server_overloaded_error_does_not_switch_models() {
let (mut chat, mut rx, mut op_rx) = make_chatwidget_manual(Some("boomslang")).await;
chat.set_model("boomslang");
while rx.try_recv().is_ok() {}
@@ -4105,11 +4105,8 @@ async fn model_cap_error_does_not_switch_models() {
chat.handle_codex_event(Event {
id: "err-1".to_string(),
msg: EventMsg::Error(ErrorEvent {
message: "model cap".to_string(),
codex_error_info: Some(CodexErrorInfo::ModelCap {
model: "boomslang".to_string(),
reset_after_seconds: Some(120),
}),
message: "server overloaded".to_string(),
codex_error_info: Some(CodexErrorInfo::ServerOverloaded),
}),
});
@@ -4117,7 +4114,7 @@ async fn model_cap_error_does_not_switch_models() {
if let AppEvent::UpdateModel(model) = event {
assert_eq!(
model, "boomslang",
"did not expect model switch on model-cap error"
"did not expect model switch on server-overloaded error"
);
}
}
@@ -4126,7 +4123,7 @@ async fn model_cap_error_does_not_switch_models() {
if let Op::OverrideTurnContext { model, .. } = event {
assert!(
model.is_none(),
"did not expect OverrideTurnContext model update on model-cap error"
"did not expect OverrideTurnContext model update on server-overloaded error"
);
}
}