mirror of
https://github.com/openai/codex.git
synced 2026-05-28 15:00:16 +00:00
Spill oversized PreToolUse additionalContext (#22529)
# Why `PreToolUse.additionalContext` became model-visible after #20692, but the hook-output spilling path from #21069 never picked up that newer lane. As a result, oversized `PreToolUse` context could bypass the truncation/spill treatment that already applies to the other hook outputs Codex forwards to the model. # What - Run `PreToolUseOutcome.additional_contexts` through `maybe_spill_texts(...)` - Add an integration test proving a large `PreToolUse.additionalContext` is replaced with a truncated preview plus spill-file pointer, while the full text is preserved on disk.
This commit is contained in:
@@ -1064,6 +1064,67 @@ async fn session_start_hook_spills_large_additional_context() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn pre_tool_use_hook_spills_large_additional_context() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let call_id = "pretooluse-shell-command-large-context";
|
||||
let command = "printf pre-tool-output".to_string();
|
||||
let args = serde_json::json!({ "command": command });
|
||||
let responses = mount_sse_sequence(
|
||||
&server,
|
||||
vec![
|
||||
sse(vec![
|
||||
ev_response_created("resp-1"),
|
||||
core_test_support::responses::ev_function_call(
|
||||
call_id,
|
||||
"shell_command",
|
||||
&serde_json::to_string(&args)?,
|
||||
),
|
||||
ev_completed("resp-1"),
|
||||
]),
|
||||
sse(vec![
|
||||
ev_response_created("resp-2"),
|
||||
ev_assistant_message("msg-1", "pre hook context observed"),
|
||||
ev_completed("resp-2"),
|
||||
]),
|
||||
],
|
||||
)
|
||||
.await;
|
||||
let additional_context = "remember the pre tool reef ".repeat(800);
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_pre_build_hook({
|
||||
let additional_context = additional_context.clone();
|
||||
move |home| {
|
||||
if let Err(error) =
|
||||
write_pre_tool_use_hook(home, Some("^Bash$"), "context", &additional_context)
|
||||
{
|
||||
panic!("failed to write pre tool use hook test fixture: {error}");
|
||||
}
|
||||
}
|
||||
})
|
||||
.with_config(trust_discovered_hooks);
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
test.submit_turn("run the shell command with large pre hook context")
|
||||
.await?;
|
||||
|
||||
let requests = responses.requests();
|
||||
assert_eq!(requests.len(), 2);
|
||||
let developer_messages = requests[1].message_input_texts("developer");
|
||||
let developer_message = developer_messages
|
||||
.iter()
|
||||
.find(|message| spilled_hook_output_path(message).is_some())
|
||||
.context("spilled developer hook message")?;
|
||||
assert!(developer_message.contains("tokens truncated"));
|
||||
let path = spilled_hook_output_path(developer_message).context("spill path")?;
|
||||
assert_eq!(fs::read_to_string(path)?, additional_context);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn stop_hook_spills_large_continuation_prompt() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
@@ -4,8 +4,6 @@ pub(crate) mod dispatcher;
|
||||
pub(crate) mod output_parser;
|
||||
pub(crate) mod schema_loader;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::events::compact::PostCompactRequest;
|
||||
use crate::events::compact::PreCompactOutcome;
|
||||
use crate::events::compact::PreCompactRequest;
|
||||
@@ -32,6 +30,7 @@ use codex_protocol::protocol::HookRunSummary;
|
||||
use codex_protocol::protocol::HookSource;
|
||||
use codex_protocol::protocol::HookTrustStatus;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct CommandShell {
|
||||
@@ -180,7 +179,13 @@ impl ClaudeHooksEngine {
|
||||
}
|
||||
|
||||
pub(crate) async fn run_pre_tool_use(&self, request: PreToolUseRequest) -> PreToolUseOutcome {
|
||||
crate::events::pre_tool_use::run(&self.handlers, &self.shell, request).await
|
||||
let session_id = request.session_id;
|
||||
let mut outcome =
|
||||
crate::events::pre_tool_use::run(&self.handlers, &self.shell, request).await;
|
||||
outcome.additional_contexts = self
|
||||
.maybe_spill_texts(session_id, outcome.additional_contexts)
|
||||
.await;
|
||||
outcome
|
||||
}
|
||||
|
||||
pub(crate) async fn run_permission_request(
|
||||
|
||||
Reference in New Issue
Block a user