Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions codex-rs/core/src/chat_completions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,8 +690,7 @@ mod tests {
assert!(!call_id.is_empty(), "call_id should not be empty");
assert!(
call_id.starts_with("tool_call_"),
"unexpected fallback call_id prefix: {}",
call_id
"unexpected fallback call_id prefix: {call_id}"
);
}
}
Expand Down
7 changes: 6 additions & 1 deletion codex-rs/core/src/codex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2398,8 +2398,13 @@ async fn handle_function_call(
"failed to parse function arguments: {e:?}"
))
})?;
let patch = args.into_patch().map_err(|msg| {
FunctionCallError::RespondToModel(format!(
"unsupported apply_patch arguments: {msg}"
))
})?;
let exec_params = ExecParams {
command: vec!["apply_patch".to_string(), args.input.clone()],
command: vec!["apply_patch".to_string(), patch],
cwd: turn_context.cwd.clone(),
timeout_ms: None,
env: HashMap::new(),
Expand Down
34 changes: 32 additions & 2 deletions codex-rs/core/src/openai_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,38 @@ fn create_view_image_tool() -> OpenAiTool {
}
/// TODO(dylan): deprecate once we get rid of json tool
#[derive(Serialize, Deserialize)]
pub(crate) struct ApplyPatchToolArgs {
pub(crate) input: String,
#[serde(untagged)]
pub(crate) enum ApplyPatchToolArgs {
/// Preferred shape where the patch contents are carried in the `input` field.
Input { input: String },
/// Legacy payloads that used a `patch` field.
LegacyPatch { patch: String },
/// Some older clients pass a shell-style command array. Accept the second
/// element as the patch contents when present.
LegacyCommand { command: Vec<String> },
/// Bare string arguments emitted by certain OSS backends.
Raw(String),
}

impl ApplyPatchToolArgs {
pub(crate) fn into_patch(self) -> Result<String, String> {
match self {
ApplyPatchToolArgs::Input { input } => Ok(input),
ApplyPatchToolArgs::LegacyPatch { patch } => Ok(patch),
ApplyPatchToolArgs::LegacyCommand { command } => {
if command.len() < 2 {
return Err("apply_patch command array missing patch contents".to_string());
}
if command.first().map(String::as_str) != Some("apply_patch") {
return Err(
"apply_patch command array must start with `apply_patch`".to_string()
);
}
Ok(command[1].clone())
}
ApplyPatchToolArgs::Raw(raw) => Ok(raw),
}
}
}

/// Returns JSON values that are compatible with Function Calling in the
Expand Down
Loading