@heungtae/codex-chat-bridge 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Cargo.lock CHANGED
@@ -231,7 +231,7 @@ checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831"
231
231
 
232
232
  [[package]]
233
233
  name = "codex-chat-bridge"
234
- version = "0.1.4"
234
+ version = "0.1.5"
235
235
  dependencies = [
236
236
  "anyhow",
237
237
  "async-stream",
package/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "codex-chat-bridge"
3
- version = "0.1.4"
3
+ version = "0.1.5"
4
4
  edition = "2024"
5
5
  license = "Apache-2.0"
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heungtae/codex-chat-bridge",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Responses-to-chat/completions bridge for Codex workflows",
5
5
  "license": "Apache-2.0",
6
6
  "type": "commonjs",
package/src/main.rs CHANGED
@@ -744,6 +744,40 @@ fn map_responses_to_chat_request(
744
744
  }));
745
745
  }
746
746
  }
747
+ "function_call" => {
748
+ let name = item
749
+ .get("name")
750
+ .and_then(Value::as_str)
751
+ .unwrap_or_default();
752
+ if name.is_empty() {
753
+ warn!("ignoring function_call item with empty name");
754
+ continue;
755
+ }
756
+
757
+ let call_id = item
758
+ .get("call_id")
759
+ .and_then(Value::as_str)
760
+ .filter(|v| !v.trim().is_empty())
761
+ .map(ToString::to_string)
762
+ .unwrap_or_else(|| format!("call_{}", Uuid::now_v7()));
763
+ let arguments = item
764
+ .get("arguments")
765
+ .map(function_arguments_to_text)
766
+ .unwrap_or_else(|| "{}".to_string());
767
+
768
+ messages.push(json!({
769
+ "role": "assistant",
770
+ "content": "",
771
+ "tool_calls": [{
772
+ "id": call_id,
773
+ "type": "function",
774
+ "function": {
775
+ "name": name,
776
+ "arguments": arguments,
777
+ }
778
+ }]
779
+ }));
780
+ }
747
781
  "function_call_output" => {
748
782
  let call_id = item
749
783
  .get("call_id")
@@ -850,6 +884,13 @@ fn function_output_to_text(value: &Value) -> String {
850
884
  }
851
885
  }
852
886
 
887
+ fn function_arguments_to_text(value: &Value) -> String {
888
+ match value {
889
+ Value::String(s) => s.clone(),
890
+ other => other.to_string(),
891
+ }
892
+ }
893
+
853
894
  fn normalize_chat_tools(tools: Vec<Value>, drop_tool_types: &HashSet<String>) -> Vec<Value> {
854
895
  tools
855
896
  .into_iter()
@@ -1077,6 +1118,37 @@ mod tests {
1077
1118
  assert_eq!(messages[0]["tool_call_id"], "call_1");
1078
1119
  }
1079
1120
 
1121
+ #[test]
1122
+ fn map_supports_function_call_to_assistant_tool_call() {
1123
+ let input = json!({
1124
+ "model": "gpt-4.1",
1125
+ "input": [
1126
+ {
1127
+ "type": "function_call",
1128
+ "call_id": "call_1",
1129
+ "name": "get_weather",
1130
+ "arguments": "{\"city\":\"seoul\"}"
1131
+ }
1132
+ ],
1133
+ "tools": []
1134
+ });
1135
+
1136
+ let req = map_responses_to_chat_request(&input, &HashSet::new()).expect("should map");
1137
+ let messages = req
1138
+ .chat_request
1139
+ .get("messages")
1140
+ .and_then(Value::as_array)
1141
+ .expect("messages");
1142
+ assert_eq!(messages.len(), 1);
1143
+ assert_eq!(messages[0]["role"], "assistant");
1144
+ assert_eq!(messages[0]["tool_calls"][0]["id"], "call_1");
1145
+ assert_eq!(messages[0]["tool_calls"][0]["type"], "function");
1146
+ assert_eq!(
1147
+ messages[0]["tool_calls"][0]["function"]["name"],
1148
+ "get_weather"
1149
+ );
1150
+ }
1151
+
1080
1152
  #[test]
1081
1153
  fn map_defaults_tool_choice_when_invalid() {
1082
1154
  let input = json!({