## Summary Persist Stop-hook continuation prompts as `user` messages instead of hidden `developer` messages + some requested integration tests This is a followup to @pakrym 's comment in https://github.com/openai/codex/pull/14532 to make sure stop-block continuation prompts match training for turn loops - Stop continuation now writes `<hook_prompt hook_run_id="...">stop hook's user prompt<hook_prompt>` - Introduces quick-xml dependency, though we already indirectly depended on it anyway via syntect - This PR only has about 500 lines of actual logic changes, the rest is tests/schema ## Testing Example run (with a sessionstart hook and 3 stop hooks) - this shows context added by session start, then two stop hooks sending their own additional prompts in a new turn. The model responds with a single message addressing both. Then when that turn ends, the hooks detect that they just ran using `stop_hook_active` and decide not to infinite loop test files for this (unzip, move codex -> .codex): [codex.zip](https://github.com/user-attachments/files/26075806/codex.zip) ``` › cats • Running SessionStart hook: lighting the observatory SessionStart hook (completed) warning: Hi, I'm a session start hook for wizard-tower (startup). hook context: A wimboltine stonpet is an exotic cuisine from hyperspace • Cats are tiny zen wizards, my friend: equal parts nap, mystery, and chaos. If you want, we can talk cat facts, cat breeds, cat names, or build something cat-themed in this repo. • Running Stop hook: checking the tower wards • Running Stop hook: sacking the guards • Running Stop hook: hiring the guards Stop hook (completed) warning: Wizard Tower Stop hook reviewed the completed reply (177 chars). Stop hook (blocked) warning: Wizard Tower Stop hook continuing conversation feedback: cook the stonpet Stop hook (blocked) warning: Wizard Tower Stop hook continuing conversation feedback: eat the cooked stonpet • Stonpet’s cooked, aloha style: flash-seared over a blue quasiflame, glazed with nebula salt, and rested until the hyperspace juices settle. Now we eat with gratitude, my friend. One mindful bite in, and the flavor is pure cosmic surf: smoky, bright, and totally out of this dimension. • Running Stop hook: checking the tower wards • Running Stop hook: sacking the guards • Running Stop hook: hiring the guards Stop hook (completed) warning: Wizard Tower Stop hook reviewed the completed reply (285 chars). Stop hook (completed) warning: Wizard Tower Stop hook saw a second pass and stayed calm to avoid a loop. Stop hook (completed) warning: Wizard Tower Stop hook saw a second pass and stayed calm to avoid a loop. ```
399 lines
11 KiB
TOML
399 lines
11 KiB
TOML
[workspace]
|
|
members = [
|
|
"backend-client",
|
|
"ansi-escape",
|
|
"async-utils",
|
|
"app-server",
|
|
"app-server-client",
|
|
"app-server-protocol",
|
|
"app-server-test-client",
|
|
"debug-client",
|
|
"apply-patch",
|
|
"arg0",
|
|
"feedback",
|
|
"codex-backend-openapi-models",
|
|
"cloud-requirements",
|
|
"cloud-tasks",
|
|
"cloud-tasks-client",
|
|
"cli",
|
|
"connectors",
|
|
"config",
|
|
"shell-command",
|
|
"shell-escalation",
|
|
"skills",
|
|
"core",
|
|
"hooks",
|
|
"secrets",
|
|
"exec",
|
|
"exec-server",
|
|
"execpolicy",
|
|
"execpolicy-legacy",
|
|
"keyring-store",
|
|
"file-search",
|
|
"linux-sandbox",
|
|
"lmstudio",
|
|
"login",
|
|
"mcp-server",
|
|
"network-proxy",
|
|
"ollama",
|
|
"process-hardening",
|
|
"protocol",
|
|
"rmcp-client",
|
|
"responses-api-proxy",
|
|
"stdio-to-uds",
|
|
"otel",
|
|
"tui",
|
|
"tui_app_server",
|
|
"utils/absolute-path",
|
|
"utils/cargo-bin",
|
|
"utils/git",
|
|
"utils/cache",
|
|
"utils/image",
|
|
"utils/json-to-toml",
|
|
"utils/home-dir",
|
|
"utils/pty",
|
|
"utils/readiness",
|
|
"utils/rustls-provider",
|
|
"utils/string",
|
|
"utils/cli",
|
|
"utils/elapsed",
|
|
"utils/sandbox-summary",
|
|
"utils/sleep-inhibitor",
|
|
"utils/approval-presets",
|
|
"utils/oss",
|
|
"utils/fuzzy-match",
|
|
"utils/stream-parser",
|
|
"codex-client",
|
|
"codex-api",
|
|
"state",
|
|
"codex-experimental-api-macros",
|
|
"test-macros",
|
|
"package-manager",
|
|
"artifacts",
|
|
]
|
|
resolver = "2"
|
|
|
|
[workspace.package]
|
|
version = "0.0.0"
|
|
# Track the edition for all workspace crates in one place. Individual
|
|
# crates can still override this value, but keeping it here means new
|
|
# crates created with `cargo new -w ...` automatically inherit the 2024
|
|
# edition.
|
|
edition = "2024"
|
|
license = "Apache-2.0"
|
|
|
|
[workspace.dependencies]
|
|
# Internal
|
|
app_test_support = { path = "app-server/tests/common" }
|
|
codex-ansi-escape = { path = "ansi-escape" }
|
|
codex-api = { path = "codex-api" }
|
|
codex-artifacts = { path = "artifacts" }
|
|
codex-package-manager = { path = "package-manager" }
|
|
codex-app-server = { path = "app-server" }
|
|
codex-app-server-client = { path = "app-server-client" }
|
|
codex-app-server-protocol = { path = "app-server-protocol" }
|
|
codex-app-server-test-client = { path = "app-server-test-client" }
|
|
codex-apply-patch = { path = "apply-patch" }
|
|
codex-arg0 = { path = "arg0" }
|
|
codex-async-utils = { path = "async-utils" }
|
|
codex-backend-client = { path = "backend-client" }
|
|
codex-chatgpt = { path = "chatgpt" }
|
|
codex-cli = { path = "cli" }
|
|
codex-client = { path = "codex-client" }
|
|
codex-cloud-requirements = { path = "cloud-requirements" }
|
|
codex-connectors = { path = "connectors" }
|
|
codex-config = { path = "config" }
|
|
codex-core = { path = "core" }
|
|
codex-exec = { path = "exec" }
|
|
codex-exec-server = { path = "exec-server" }
|
|
codex-execpolicy = { path = "execpolicy" }
|
|
codex-experimental-api-macros = { path = "codex-experimental-api-macros" }
|
|
codex-feedback = { path = "feedback" }
|
|
codex-file-search = { path = "file-search" }
|
|
codex-git = { path = "utils/git" }
|
|
codex-hooks = { path = "hooks" }
|
|
codex-keyring-store = { path = "keyring-store" }
|
|
codex-linux-sandbox = { path = "linux-sandbox" }
|
|
codex-lmstudio = { path = "lmstudio" }
|
|
codex-login = { path = "login" }
|
|
codex-mcp-server = { path = "mcp-server" }
|
|
codex-network-proxy = { path = "network-proxy" }
|
|
codex-ollama = { path = "ollama" }
|
|
codex-otel = { path = "otel" }
|
|
codex-process-hardening = { path = "process-hardening" }
|
|
codex-protocol = { path = "protocol" }
|
|
codex-responses-api-proxy = { path = "responses-api-proxy" }
|
|
codex-rmcp-client = { path = "rmcp-client" }
|
|
codex-secrets = { path = "secrets" }
|
|
codex-shell-command = { path = "shell-command" }
|
|
codex-shell-escalation = { path = "shell-escalation" }
|
|
codex-skills = { path = "skills" }
|
|
codex-state = { path = "state" }
|
|
codex-stdio-to-uds = { path = "stdio-to-uds" }
|
|
codex-test-macros = { path = "test-macros" }
|
|
codex-tui = { path = "tui" }
|
|
codex-tui-app-server = { path = "tui_app_server" }
|
|
codex-utils-absolute-path = { path = "utils/absolute-path" }
|
|
codex-utils-approval-presets = { path = "utils/approval-presets" }
|
|
codex-utils-cache = { path = "utils/cache" }
|
|
codex-utils-cargo-bin = { path = "utils/cargo-bin" }
|
|
codex-utils-cli = { path = "utils/cli" }
|
|
codex-utils-elapsed = { path = "utils/elapsed" }
|
|
codex-utils-fuzzy-match = { path = "utils/fuzzy-match" }
|
|
codex-utils-home-dir = { path = "utils/home-dir" }
|
|
codex-utils-image = { path = "utils/image" }
|
|
codex-utils-json-to-toml = { path = "utils/json-to-toml" }
|
|
codex-utils-oss = { path = "utils/oss" }
|
|
codex-utils-pty = { path = "utils/pty" }
|
|
codex-utils-readiness = { path = "utils/readiness" }
|
|
codex-utils-rustls-provider = { path = "utils/rustls-provider" }
|
|
codex-utils-sandbox-summary = { path = "utils/sandbox-summary" }
|
|
codex-utils-sleep-inhibitor = { path = "utils/sleep-inhibitor" }
|
|
codex-utils-stream-parser = { path = "utils/stream-parser" }
|
|
codex-utils-string = { path = "utils/string" }
|
|
codex-windows-sandbox = { path = "windows-sandbox-rs" }
|
|
core_test_support = { path = "core/tests/common" }
|
|
mcp_test_support = { path = "mcp-server/tests/common" }
|
|
|
|
# External
|
|
age = "0.11.1"
|
|
allocative = "0.3.3"
|
|
ansi-to-tui = "7.0.0"
|
|
anyhow = "1"
|
|
arboard = { version = "3", features = ["wayland-data-control"] }
|
|
askama = "0.15.4"
|
|
assert_cmd = "2"
|
|
assert_matches = "1.5.0"
|
|
async-channel = "2.3.1"
|
|
async-stream = "0.3.6"
|
|
async-trait = "0.1.89"
|
|
axum = { version = "0.8", default-features = false }
|
|
base64 = "0.22.1"
|
|
bm25 = "2.3.2"
|
|
bytes = "1.10.1"
|
|
chardetng = "0.1.17"
|
|
chrono = "0.4.43"
|
|
clap = "4"
|
|
clap_complete = "4"
|
|
color-eyre = "0.6.3"
|
|
crossbeam-channel = "0.5.15"
|
|
crossterm = "0.28.1"
|
|
csv = "1.3.1"
|
|
ctor = "0.6.3"
|
|
derive_more = "2"
|
|
diffy = "0.4.2"
|
|
dirs = "6"
|
|
dotenvy = "0.15.7"
|
|
dunce = "1.0.4"
|
|
encoding_rs = "0.8.35"
|
|
fd-lock = "4.0.4"
|
|
env-flags = "0.1.1"
|
|
env_logger = "0.11.9"
|
|
eventsource-stream = "0.2.3"
|
|
flate2 = "1.1.4"
|
|
futures = { version = "0.3", default-features = false }
|
|
gethostname = "1.1.0"
|
|
globset = "0.4"
|
|
http = "1.3.1"
|
|
icu_decimal = "2.1"
|
|
icu_locale_core = "2.1"
|
|
icu_provider = { version = "2.1", features = ["sync"] }
|
|
ignore = "0.4.23"
|
|
image = { version = "^0.25.9", default-features = false }
|
|
iana-time-zone = "0.1.64"
|
|
include_dir = "0.7.4"
|
|
indexmap = "2.12.0"
|
|
insta = "1.46.3"
|
|
inventory = "0.3.19"
|
|
itertools = "0.14.0"
|
|
keyring = { version = "3.6", default-features = false }
|
|
landlock = "0.4.4"
|
|
lazy_static = "1"
|
|
libc = "0.2.182"
|
|
log = "0.4"
|
|
lru = "0.16.3"
|
|
maplit = "1.0.2"
|
|
mime_guess = "2.0.5"
|
|
multimap = "0.10.0"
|
|
notify = "8.2.0"
|
|
nucleo = { git = "https://github.com/helix-editor/nucleo.git", rev = "4253de9faabb4e5c6d81d946a5e35a90f87347ee" }
|
|
once_cell = "1.20.2"
|
|
openssl-sys = "*"
|
|
opentelemetry = "0.31.0"
|
|
opentelemetry-appender-tracing = "0.31.0"
|
|
opentelemetry-otlp = "0.31.0"
|
|
opentelemetry-semantic-conventions = "0.31.0"
|
|
opentelemetry_sdk = "0.31.0"
|
|
os_info = "3.12.0"
|
|
owo-colors = "4.3.0"
|
|
path-absolutize = "3.1.1"
|
|
pathdiff = "0.2"
|
|
portable-pty = "0.9.0"
|
|
predicates = "3"
|
|
pretty_assertions = "1.4.1"
|
|
pulldown-cmark = "0.10"
|
|
quick-xml = "0.38.4"
|
|
rand = "0.9"
|
|
ratatui = "0.29.0"
|
|
ratatui-macros = "0.6.0"
|
|
regex = "1.12.3"
|
|
regex-lite = "0.1.8"
|
|
reqwest = "0.12"
|
|
rmcp = { version = "0.15.0", default-features = false }
|
|
runfiles = { git = "https://github.com/dzbarsky/rules_rust", rev = "b56cbaa8465e74127f1ea216f813cd377295ad81" }
|
|
rustls = { version = "0.23", default-features = false, features = [
|
|
"ring",
|
|
"std",
|
|
] }
|
|
rustls-native-certs = "0.8.3"
|
|
rustls-pki-types = "1.14.0"
|
|
schemars = "0.8.22"
|
|
seccompiler = "0.5.0"
|
|
semver = "1.0"
|
|
sentry = "0.46.0"
|
|
serde = "1"
|
|
serde_json = "1"
|
|
serde_path_to_error = "0.1.20"
|
|
serde_with = "3.17"
|
|
serde_yaml = "0.9"
|
|
serial_test = "3.2.0"
|
|
sha1 = "0.10.6"
|
|
sha2 = "0.10"
|
|
shlex = "1.3.0"
|
|
similar = "2.7.0"
|
|
socket2 = "0.6.1"
|
|
sqlx = { version = "0.8.6", default-features = false, features = [
|
|
"chrono",
|
|
"json",
|
|
"macros",
|
|
"migrate",
|
|
"runtime-tokio-rustls",
|
|
"sqlite",
|
|
"time",
|
|
"uuid",
|
|
] }
|
|
starlark = "0.13.0"
|
|
strum = "0.27.2"
|
|
strum_macros = "0.28.0"
|
|
supports-color = "3.0.2"
|
|
syntect = "5"
|
|
sys-locale = "0.3.2"
|
|
tempfile = "3.23.0"
|
|
tar = "0.4.44"
|
|
test-log = "0.2.19"
|
|
textwrap = "0.16.2"
|
|
thiserror = "2.0.17"
|
|
time = "0.3.47"
|
|
tiny_http = "0.12"
|
|
tokio = "1"
|
|
tokio-stream = "0.1.18"
|
|
tokio-test = "0.4"
|
|
tokio-tungstenite = { version = "0.28.0", features = [
|
|
"proxy",
|
|
"rustls-tls-native-roots",
|
|
] }
|
|
tokio-util = "0.7.18"
|
|
toml = "0.9.5"
|
|
toml_edit = "0.24.0"
|
|
tracing = "0.1.44"
|
|
tracing-appender = "0.2.3"
|
|
tracing-opentelemetry = "0.32.0"
|
|
tracing-subscriber = "0.3.22"
|
|
tracing-test = "0.2.5"
|
|
tree-sitter = "0.25.10"
|
|
tree-sitter-bash = "0.25"
|
|
ts-rs = "11"
|
|
tungstenite = { version = "0.27.0", features = ["deflate", "proxy"] }
|
|
uds_windows = "1.1.0"
|
|
unicode-segmentation = "1.12.0"
|
|
unicode-width = "0.2"
|
|
url = "2"
|
|
urlencoding = "2.1"
|
|
uuid = "1"
|
|
vt100 = "0.16.2"
|
|
walkdir = "2.5.0"
|
|
webbrowser = "1.0"
|
|
which = "8"
|
|
wildmatch = "2.6.1"
|
|
zip = "2.4.2"
|
|
zstd = "0.13"
|
|
|
|
wiremock = "0.6"
|
|
zeroize = "1.8.2"
|
|
|
|
[workspace.lints]
|
|
rust = {}
|
|
|
|
[workspace.lints.clippy]
|
|
expect_used = "deny"
|
|
identity_op = "deny"
|
|
manual_clamp = "deny"
|
|
manual_filter = "deny"
|
|
manual_find = "deny"
|
|
manual_flatten = "deny"
|
|
manual_map = "deny"
|
|
manual_memcpy = "deny"
|
|
manual_non_exhaustive = "deny"
|
|
manual_ok_or = "deny"
|
|
manual_range_contains = "deny"
|
|
manual_retain = "deny"
|
|
manual_strip = "deny"
|
|
manual_try_fold = "deny"
|
|
manual_unwrap_or = "deny"
|
|
needless_borrow = "deny"
|
|
needless_borrowed_reference = "deny"
|
|
needless_collect = "deny"
|
|
needless_late_init = "deny"
|
|
needless_option_as_deref = "deny"
|
|
needless_question_mark = "deny"
|
|
needless_update = "deny"
|
|
redundant_clone = "deny"
|
|
redundant_closure = "deny"
|
|
redundant_closure_for_method_calls = "deny"
|
|
redundant_static_lifetimes = "deny"
|
|
trivially_copy_pass_by_ref = "deny"
|
|
uninlined_format_args = "deny"
|
|
unnecessary_filter_map = "deny"
|
|
unnecessary_lazy_evaluations = "deny"
|
|
unnecessary_sort_by = "deny"
|
|
unnecessary_to_owned = "deny"
|
|
unwrap_used = "deny"
|
|
|
|
# cargo-shear cannot see the platform-specific openssl-sys usage, so we
|
|
# silence the false positive here instead of deleting a real dependency.
|
|
[workspace.metadata.cargo-shear]
|
|
ignored = [
|
|
"icu_provider",
|
|
"openssl-sys",
|
|
"codex-utils-readiness",
|
|
"codex-secrets"
|
|
]
|
|
|
|
[profile.release]
|
|
lto = "fat"
|
|
split-debuginfo = "off"
|
|
# Because we bundle some of these executables with the TypeScript CLI, we
|
|
# remove everything to make the binary as small as possible.
|
|
strip = "symbols"
|
|
|
|
# See https://github.com/openai/codex/issues/1411 for details.
|
|
codegen-units = 1
|
|
|
|
[profile.ci-test]
|
|
debug = 1 # Reduce debug symbol size
|
|
inherits = "test"
|
|
opt-level = 0
|
|
|
|
[patch.crates-io]
|
|
# Uncomment to debug local changes.
|
|
# ratatui = { path = "../../ratatui" }
|
|
crossterm = { git = "https://github.com/nornagon/crossterm", branch = "nornagon/color-query" }
|
|
ratatui = { git = "https://github.com/nornagon/ratatui", branch = "nornagon-v0.29.0-patch" }
|
|
tokio-tungstenite = { git = "https://github.com/openai-oss-forks/tokio-tungstenite", rev = "132f5b39c862e3a970f731d709608b3e6276d5f6" }
|
|
tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "9200079d3b54a1ff51072e24d81fd354f085156f" }
|
|
|
|
# Uncomment to debug local changes.
|
|
# rmcp = { path = "../../rust-sdk/crates/rmcp" }
|
|
|
|
[patch."ssh://git@github.com/openai-oss-forks/tungstenite-rs.git"]
|
|
tungstenite = { git = "https://github.com/openai-oss-forks/tungstenite-rs", rev = "9200079d3b54a1ff51072e24d81fd354f085156f" }
|