mirror of
https://github.com/openai/codex.git
synced 2026-10-24 18:18:41 +00:00
test(core): cover code mode app file uploads
Add integration coverage that exercises Code Mode's nested MCP tool path through openai/fileParams rewriting for Codex Apps file uploads. Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
co-authored by
Codex
parent
46f30d0282
commit
5b0a195e48
@@ -15,11 +15,13 @@ use core_test_support::apps_test_server::DOCUMENT_EXTRACT_TEXT_RESOURCE_URI;
|
||||
use core_test_support::hooks::trust_discovered_hooks;
|
||||
use core_test_support::responses::ev_assistant_message;
|
||||
use core_test_support::responses::ev_completed;
|
||||
use core_test_support::responses::ev_custom_tool_call;
|
||||
use core_test_support::responses::ev_function_call_with_namespace;
|
||||
use core_test_support::responses::ev_response_created;
|
||||
use core_test_support::responses::mount_sse_sequence;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::Value;
|
||||
@@ -245,3 +247,139 @@ async fn codex_apps_file_params_upload_local_paths_before_mcp_tool_call() -> Res
|
||||
server.verify().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn code_mode_nested_mcp_file_params_upload_local_paths_before_tool_call() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let apps_server = AppsTestServer::mount(&server).await?;
|
||||
|
||||
Mock::given(method("POST"))
|
||||
.and(path("/files"))
|
||||
.and(header("chatgpt-account-id", "account_id"))
|
||||
.and(body_json(json!({
|
||||
"file_name": "report.txt",
|
||||
"file_size": 11,
|
||||
"use_case": "codex",
|
||||
})))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
|
||||
"file_id": "file_123",
|
||||
"upload_url": format!("{}/upload/file_123", server.uri()),
|
||||
})))
|
||||
.expect(1)
|
||||
.mount(&server)
|
||||
.await;
|
||||
Mock::given(method("PUT"))
|
||||
.and(path("/upload/file_123"))
|
||||
.and(header("content-length", "11"))
|
||||
.respond_with(ResponseTemplate::new(200))
|
||||
.expect(1)
|
||||
.mount(&server)
|
||||
.await;
|
||||
Mock::given(method("POST"))
|
||||
.and(path("/files/file_123/uploaded"))
|
||||
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
|
||||
"status": "success",
|
||||
"download_url": format!("{}/download/file_123", server.uri()),
|
||||
"file_name": "report.txt",
|
||||
"mime_type": "text/plain",
|
||||
"file_size_bytes": 11,
|
||||
})))
|
||||
.expect(1)
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let code = r#"
|
||||
const result = await tools.mcp__codex_apps__calendar_extract_text({
|
||||
file: "report.txt",
|
||||
});
|
||||
text(result.content?.[0]?.text ?? "missing result");
|
||||
"#;
|
||||
mount_sse_sequence(
|
||||
&server,
|
||||
vec![
|
||||
sse(vec![
|
||||
ev_response_created("resp-1"),
|
||||
ev_custom_tool_call("call-1", "exec", code),
|
||||
ev_completed("resp-1"),
|
||||
]),
|
||||
sse(vec![
|
||||
ev_response_created("resp-2"),
|
||||
ev_assistant_message("msg-1", "done"),
|
||||
ev_completed("resp-2"),
|
||||
]),
|
||||
],
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing())
|
||||
.with_config(move |config| {
|
||||
configure_apps(config, apps_server.chatgpt_base_url.as_str());
|
||||
config
|
||||
.features
|
||||
.enable(Feature::CodeMode)
|
||||
.expect("test config should allow feature update");
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
tokio::fs::write(test.cwd.path().join("report.txt"), b"hello world").await?;
|
||||
|
||||
test.submit_turn_with_approval_and_permission_profile(
|
||||
"Use code mode to extract the report text with the app tool.",
|
||||
AskForApproval::Never,
|
||||
PermissionProfile::Disabled,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let apps_tool_call = server
|
||||
.received_requests()
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.find_map(|request| {
|
||||
let body: Value = serde_json::from_slice(&request.body).ok()?;
|
||||
(request.url.path() == "/api/codex/apps"
|
||||
&& body.get("method").and_then(Value::as_str) == Some("tools/call")
|
||||
&& body.pointer("/params/name").and_then(Value::as_str)
|
||||
== Some("calendar_extract_text"))
|
||||
.then_some(body)
|
||||
})
|
||||
.expect("apps calendar_extract_text tools/call request should be recorded");
|
||||
|
||||
assert_eq!(
|
||||
apps_tool_call.pointer("/params/arguments/file"),
|
||||
Some(&json!({
|
||||
"download_url": format!("{}/download/file_123", server.uri()),
|
||||
"file_id": "file_123",
|
||||
"mime_type": "text/plain",
|
||||
"file_name": "report.txt",
|
||||
"uri": "sediment://file_123",
|
||||
"file_size_bytes": 11,
|
||||
}))
|
||||
);
|
||||
let codex_apps_meta = apps_tool_call
|
||||
.pointer("/params/_meta/_codex_apps")
|
||||
.expect("codex apps metadata should be forwarded");
|
||||
assert!(
|
||||
codex_apps_meta
|
||||
.pointer("/call_id")
|
||||
.and_then(Value::as_str)
|
||||
.is_some_and(|call_id| call_id.starts_with("exec-"))
|
||||
);
|
||||
assert_eq!(
|
||||
codex_apps_meta.pointer("/resource_uri"),
|
||||
Some(&json!(DOCUMENT_EXTRACT_TEXT_RESOURCE_URI))
|
||||
);
|
||||
assert_eq!(
|
||||
codex_apps_meta.pointer("/contains_mcp_source"),
|
||||
Some(&json!(true))
|
||||
);
|
||||
assert_eq!(
|
||||
codex_apps_meta.pointer("/connector_id"),
|
||||
Some(&json!("calendar"))
|
||||
);
|
||||
|
||||
server.verify().await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user