mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] default unknown contributed tools to mutating (#22143)
## Summary - make the shared `ToolExecutor::is_mutating` default conservative by returning `true` - update the trait docs to say read-only tools should opt out explicitly - add a regression test covering the default behavior ## Why Hosts use this signal for serialization and approval policy. Treating unknown contributed tools as read-only lets a write-capable tool accidentally bypass mutating-tool safeguards if it forgets to override the hook. ## Validation - not run, per request
This commit is contained in:
committed by
GitHub
Unverified
parent
ebd3d53451
commit
7e15e6db9e
@@ -72,8 +72,56 @@ pub trait ToolExecutor<C>: Send + Sync {
|
||||
/// Returns whether the call may mutate user state.
|
||||
///
|
||||
/// Hosts can use this conservative signal for serialization or approval
|
||||
/// policy. Context-free read tools should keep the default.
|
||||
/// policy. Read-only tools should override this default.
|
||||
fn is_mutating<'a>(&'a self, _call: &'a ToolCall<C>) -> BoolFuture<'a> {
|
||||
Box::pin(async { false })
|
||||
Box::pin(async { true })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
use std::task::Context;
|
||||
use std::task::Poll;
|
||||
use std::task::Wake;
|
||||
use std::task::Waker;
|
||||
|
||||
use super::*;
|
||||
use crate::JsonToolOutput;
|
||||
use crate::ToolInput;
|
||||
|
||||
struct DefaultMutatingExecutor;
|
||||
|
||||
impl ToolExecutor<()> for DefaultMutatingExecutor {
|
||||
fn execute<'a>(&'a self, _call: ToolCall<()>) -> ToolFuture<'a> {
|
||||
Box::pin(async {
|
||||
Ok(Box::new(JsonToolOutput::new(serde_json::json!(null))) as Box<dyn ToolOutput>)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct NoopWaker;
|
||||
|
||||
impl Wake for NoopWaker {
|
||||
fn wake(self: Arc<Self>) {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn contributed_tools_default_to_mutating() {
|
||||
let call = ToolCall {
|
||||
context: (),
|
||||
call_id: "call-default-mutating".to_string(),
|
||||
input: ToolInput::Function {
|
||||
arguments: "{}".to_string(),
|
||||
},
|
||||
};
|
||||
let mut future = DefaultMutatingExecutor.is_mutating(&call);
|
||||
let waker = Waker::from(Arc::new(NoopWaker));
|
||||
let mut context = Context::from_waker(&waker);
|
||||
|
||||
assert!(matches!(
|
||||
future.as_mut().poll(&mut context),
|
||||
Poll::Ready(true)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user