Previously, we were running into an issue where we would run the `shell` tool call with a timeout of 10s, but it fired an elicitation asking for user approval, the time the user took to respond to the elicitation was counted agains the 10s timeout, so the `shell` tool call would fail with a timeout error unless the user is very fast! This PR addresses this issue by introducing a "stopwatch" abstraction that is used to manage the timeout. The idea is: - `Stopwatch::new()` is called with the _real_ timeout of the `shell` tool call. - `process_exec_tool_call()` is called with the `Cancellation` variant of `ExecExpiration` because it should not manage its own timeout in this case - the `Stopwatch` expiration is wired up to the `cancel_rx` passed to `process_exec_tool_call()` - when an elicitation for the `shell` tool call is received, the `Stopwatch` pauses - because it is possible for multiple elicitations to arrive concurrently, it keeps track of the number of "active pauses" and does not resume until that counter goes down to zero I verified that I can test the MCP server using `@modelcontextprotocol/inspector` and specify `git status` as the `command` with a timeout of 500ms and that the elicitation pops up and I have all the time in the world to respond whereas previous to this PR, that would not have been possible. --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/6973). * #7005 * __->__ #6973 * #6972
58 lines
1.3 KiB
TOML
58 lines
1.3 KiB
TOML
[package]
|
|
edition = "2024"
|
|
name = "codex-exec-server"
|
|
version = { workspace = true }
|
|
|
|
[[bin]]
|
|
name = "codex-execve-wrapper"
|
|
path = "src/bin/main_execve_wrapper.rs"
|
|
|
|
[[bin]]
|
|
name = "codex-exec-mcp-server"
|
|
path = "src/bin/main_mcp_server.rs"
|
|
|
|
[lib]
|
|
name = "codex_exec_server"
|
|
path = "src/lib.rs"
|
|
|
|
[lints]
|
|
workspace = true
|
|
|
|
[dependencies]
|
|
anyhow = { workspace = true }
|
|
async-trait = { workspace = true }
|
|
clap = { workspace = true, features = ["derive"] }
|
|
codex-core = { workspace = true }
|
|
libc = { workspace = true }
|
|
path-absolutize = { workspace = true }
|
|
rmcp = { workspace = true, default-features = false, features = [
|
|
"auth",
|
|
"elicitation",
|
|
"base64",
|
|
"client",
|
|
"macros",
|
|
"schemars",
|
|
"server",
|
|
"transport-child-process",
|
|
"transport-streamable-http-client-reqwest",
|
|
"transport-streamable-http-server",
|
|
"transport-io",
|
|
] }
|
|
serde = { workspace = true, features = ["derive"] }
|
|
serde_json = { workspace = true }
|
|
shlex = { workspace = true }
|
|
socket2 = { workspace = true }
|
|
tokio = { workspace = true, features = [
|
|
"io-std",
|
|
"macros",
|
|
"process",
|
|
"rt-multi-thread",
|
|
"signal",
|
|
] }
|
|
tokio-util = { workspace = true }
|
|
tracing = { workspace = true }
|
|
tracing-subscriber = { workspace = true, features = ["env-filter", "fmt"] }
|
|
|
|
[dev-dependencies]
|
|
pretty_assertions = { workspace = true }
|
|
tempfile = { workspace = true }
|