Skip to content

Add Codex Apps sediment file remapping#15197

Open
caseychow-oai wants to merge 40 commits intomainfrom
casey/openai-files-codex-apps
Open

Add Codex Apps sediment file remapping#15197
caseychow-oai wants to merge 40 commits intomainfrom
casey/openai-files-codex-apps

Conversation

@caseychow-oai
Copy link
Contributor

@caseychow-oai caseychow-oai commented Mar 19, 2026

Summary

  • bridge Codex Apps MCP declared file inputs/outputs through the OpenAI files flow behind the apps_file_bridge feature flag
  • upload local file path inputs for declared openai/fileParams fields and rewrite them into canonical OpenAI file payload objects
  • auto-download declared openai/fileOutputs sediment://{file_id} results into managed temp paths and expose the explicit download_openai_file tool when the feature is enabled
  • scope managed OpenAI file downloads to a per-session temp root and add that root to the session sandbox only when the feature is enabled

Notes

  • Remote MCP file references in the argument rewrite path must be explicit sediment://...; bare file_* / file-* strings are treated as local paths.
  • During cleanup, removing the earlier macOS-specific model_availability_nux test relaxation reproduced the local Bazel failure unexpected exit code from codex resume: 1; output: ^C, so that narrow allowance remains.
  • The test-only shell snapshot timing adjustment remains in suite::shell_snapshot::shell_command_snapshot_still_intercepts_apply_patch because removing it reproduced the macOS x86 local Bazel failure timed out waiting for file .../snapshot-apply.txt.

Verification

  • cargo test -p codex-core rewrite_single_argument_string_ -- --nocapture
  • cargo test -p codex-core openai_file_ -- --nocapture
  • cargo test -p codex-core mcp_tool_to_openai_tool_ -- --nocapture
  • cargo test -p codex-core prompt_tools_are_consistent_across_requests -- --nocapture
  • cargo test -p codex-core serialize_tool_search_output_tools_ -- --nocapture
  • cargo test -p codex-features
  • ~/.cargo/bin/just fmt

@caseychow-oai caseychow-oai force-pushed the casey/openai-files-codex-apps branch 3 times, most recently from 479d6f8 to ce24846 Compare March 20, 2026 18:54
Copy link
Collaborator

there's one real bug here: in rewrite_single_argument_string we parse bare file_*/file-* as OpenAI file IDs before trying to resolve a local path, so a local file like file_report.csv gets rewritten to sediment://file_report.csv instead of being uploaded. can we either require sediment:// for remote handles in this path, or check local path existence first?

also, can we split out the unrelated cleanup from this PR? the nextest / approval-matrix / code-mode timing changes, cargo-bin refactor, apply_patch fallback, and app-server fileChange test relaxation don't seem tied to the sediment bridge.

Copy link
Contributor Author

there's one real bug here: in rewrite_single_argument_string we parse bare file_*/file-* as OpenAI file IDs before trying to resolve a local path, so a local file like file_report.csv gets rewritten to sediment://file_report.csv instead of being uploaded. can we either require sediment:// for remote handles in this path, or check local path existence first?

will investigate

also, can we split out the unrelated cleanup from this PR? the nextest / approval-matrix / code-mode timing changes, cargo-bin refactor, apply_patch fallback, and app-server fileChange test relaxation don't seem tied to the sediment bridge.

wilco, was trying to remove as much of that as possible but kept breaking CI. if i can make it work without i'll try to remove

Copy link
Contributor Author

Removing local fallback entirely, we should always assume it's sediment:// for remote files here.

@caseychow-oai caseychow-oai force-pushed the casey/openai-files-codex-apps branch 3 times, most recently from e4acb53 to 3f800e2 Compare March 20, 2026 23:59
@caseychow-oai caseychow-oai force-pushed the casey/openai-files-codex-apps branch 2 times, most recently from f370d7f to 2c77356 Compare March 21, 2026 20:39
let interrupt_writer = writer_tx.clone();
let interrupt_task = tokio::spawn(async move {
sleep(Duration::from_secs(2)).await;
let interrupt_delay = if cfg!(target_os = "macos") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we clean up the unrelated diffs here and in other places.

sess: Arc<Session>,
turn_context: &Arc<TurnContext>,
call_id: String,
qualified_tool: QualifiedMcpTool<'_>,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need change the core flow here? Can we move the file transformation logic out of the core flow as much as possible? Essentially you only need to rewrite a few special params and I don't think you have to change the whole core flow to achieve that.

session,
turn,
call_id,
tool_name,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, do we have to change the core flow?

impl ToolSearchHandler {
pub fn new(tools: HashMap<String, ToolInfo>) -> Self {
Self { tools }
pub fn new(tools: HashMap<String, ToolInfo>, openai_file_bridge_enabled: bool) -> Self {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need to add it to tool search.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's two main things that we have to make sure to expose to the model, and the tool results seems to be the best thing. First is that we need to modify the parameter so that it is showing the model file shape instead of the path. The second is that we need to indicate to the model that that is what is happening on both the upload and the download flows.

I've gone ahead and tried to streamline it as much as possible to isolate it to just the case that we're caring about. If you feel like we can go further I'm happy to take a shot.


async fn wait_for_file_contents(path: &Path) -> Result<String> {
let deadline = Instant::now() + Duration::from_secs(5);
let file_wait_timeout = if cfg!(target_os = "macos") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also please clean up here.

}

impl Session {
fn add_session_openai_file_root_to_sandbox(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you confirm with @bolinfest if this is ok with the sandbox policy?

caseychow-oai and others added 6 commits March 23, 2026 21:13
Bridge Codex Apps file params and outputs through sediment handles, add a dedicated download tool, and harden test/runtime paths used during verification.

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
caseychow-oai and others added 28 commits March 23, 2026 21:13
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Tighten Codex Apps MCP file argument rewriting so remote handles must be explicit sediment:// URIs, and trim unrelated CI/test/runtime changes from this branch.

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <noreply@openai.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants