mirror of
https://github.com/openai/codex.git
synced 2026-04-24 14:45:27 +00:00
patch-tools
This commit is contained in:
@@ -609,178 +609,6 @@ async fn per_turn_overrides_keep_cached_prefix_and_key_constant() {
|
||||
assert_eq!(body2["input"], expected_body2);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn changing_approval_policy_mid_session_preserves_shell_tool_description_and_json() {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
let server = MockServer::start().await;
|
||||
|
||||
let sse = sse_completed("resp");
|
||||
let template = ResponseTemplate::new(200)
|
||||
.insert_header("content-type", "text/event-stream")
|
||||
.set_body_raw(sse, "text/event-stream");
|
||||
|
||||
// Expect two POSTs to /v1/responses
|
||||
Mock::given(method("POST"))
|
||||
.and(path("/v1/responses"))
|
||||
.respond_with(template)
|
||||
.expect(2)
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let model_provider = ModelProviderInfo {
|
||||
base_url: Some(format!("{}/v1", server.uri())),
|
||||
..built_in_model_providers()["openai"].clone()
|
||||
};
|
||||
|
||||
let cwd = TempDir::new().unwrap();
|
||||
let codex_home = TempDir::new().unwrap();
|
||||
let mut config = load_default_config_for_test(&codex_home);
|
||||
config.cwd = cwd.path().to_path_buf();
|
||||
config.model_provider = model_provider;
|
||||
config.user_instructions = Some("be consistent and helpful".to_string());
|
||||
// Keep toolset minimal/deterministic for this assertion
|
||||
config.include_apply_patch_tool = false;
|
||||
config.include_plan_tool = false;
|
||||
|
||||
let conversation_manager =
|
||||
ConversationManager::with_auth(CodexAuth::from_api_key("Test API Key"));
|
||||
let codex = conversation_manager
|
||||
.new_conversation(config)
|
||||
.await
|
||||
.expect("create new conversation")
|
||||
.conversation;
|
||||
|
||||
// First turn with default approval policy (on-request)
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
items: vec![InputItem::Text {
|
||||
text: "hello 1".into(),
|
||||
}],
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TaskComplete(_))).await;
|
||||
|
||||
// Change approval policy mid-session to Never
|
||||
codex
|
||||
.submit(Op::OverrideTurnContext {
|
||||
cwd: None,
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: None,
|
||||
model: None,
|
||||
effort: None,
|
||||
summary: None,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Second turn after overrides
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
items: vec![InputItem::Text {
|
||||
text: "hello 2".into(),
|
||||
}],
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TaskComplete(_))).await;
|
||||
|
||||
let requests = server.received_requests().await.unwrap();
|
||||
assert_eq!(requests.len(), 2, "expected two POST requests");
|
||||
|
||||
let body1 = requests[0].body_json::<serde_json::Value>().unwrap();
|
||||
let body2 = requests[1].body_json::<serde_json::Value>().unwrap();
|
||||
|
||||
// Extract the shell tool from the tools array in each request
|
||||
let find_shell = |body: &serde_json::Value| -> serde_json::Value {
|
||||
body["tools"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.find(|t| t["type"] == "function" && t["name"] == "shell")
|
||||
.cloned()
|
||||
.expect("shell tool present")
|
||||
};
|
||||
|
||||
let shell1 = find_shell(&body1);
|
||||
let shell2 = find_shell(&body2);
|
||||
|
||||
// Description must be stable across approval policy changes
|
||||
assert_eq!(
|
||||
shell1["description"],
|
||||
serde_json::json!("Runs a shell command and returns its output")
|
||||
);
|
||||
assert_eq!(shell1["description"], shell2["description"]);
|
||||
|
||||
// Raw JSON expectation for shell tool under on-request (ShellWithRequest)
|
||||
let expected_shell_on_request = serde_json::json!({
|
||||
"type": "function",
|
||||
"name": "shell",
|
||||
"description": "Runs a shell command and returns its output",
|
||||
"strict": false,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "The command to execute"
|
||||
},
|
||||
"workdir": {
|
||||
"type": "string",
|
||||
"description": "Working directory to execute the command in."
|
||||
},
|
||||
"timeout_ms": {
|
||||
"type": "number",
|
||||
"description": "Timeout for the command in milliseconds."
|
||||
},
|
||||
"with_escalated_permissions": {
|
||||
"type": "boolean",
|
||||
"description": "Request escalated permissions, only for when a command would otherwise be blocked by the sandbox."
|
||||
},
|
||||
"justification": {
|
||||
"type": "string",
|
||||
"description": "Required if and only if with_escalated_permissions == true. One sentence explaining why escalation is needed (e.g., write outside CWD, network fetch, git commit)."
|
||||
}
|
||||
},
|
||||
"required": ["command"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
});
|
||||
|
||||
// Raw JSON expectation for shell tool under never (DefaultShell)
|
||||
let expected_shell_never = serde_json::json!({
|
||||
"type": "function",
|
||||
"name": "shell",
|
||||
"description": "Runs a shell command and returns its output",
|
||||
"strict": false,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "The command to execute"
|
||||
},
|
||||
"workdir": {
|
||||
"type": "string",
|
||||
"description": "The working directory to execute the command in"
|
||||
},
|
||||
"timeout_ms": {
|
||||
"type": "number",
|
||||
"description": "The timeout for the command in milliseconds"
|
||||
}
|
||||
},
|
||||
"required": ["command"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(shell1, expected_shell_on_request);
|
||||
assert_eq!(shell2, expected_shell_never);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn tools_stable_across_all_approval_policy_transitions() {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
Reference in New Issue
Block a user