Skip to content

Commit f4de890

Browse files
committed
fix apply_patch tool
1 parent 8c9826c commit f4de890

1 file changed

Lines changed: 66 additions & 7 deletions

File tree

examples/batch-processing/server.py

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5683,11 +5683,24 @@ def _responses_tools_to_chat_tools(
56835683
else None
56845684
)
56855685
description = cast(Optional[str], tool.get("description")) or ""
5686+
text_tool_guidance = (
5687+
"This is a text tool. When calling it, the "
5688+
"`function.arguments` field itself must be the raw input string. "
5689+
"Do not wrap the input in JSON and do not use an object such as "
5690+
"'{\"input\": \"...\"}' or '{\"patch\": \"...\"}'."
5691+
)
56865692
if isinstance(syntax, str) and isinstance(definition, str):
56875693
if description:
5688-
description = f"{description}\n\n{syntax}:\n{definition}"
5694+
description = (
5695+
f"{description}\n\n{text_tool_guidance}\n\n"
5696+
f"{syntax}:\n{definition}"
5697+
)
56895698
else:
5690-
description = f"{syntax}:\n{definition}"
5699+
description = f"{text_tool_guidance}\n\n{syntax}:\n{definition}"
5700+
elif description:
5701+
description = f"{description}\n\n{text_tool_guidance}"
5702+
else:
5703+
description = text_tool_guidance
56915704
normalized_tools.append(
56925705
{
56935706
"type": "function",
@@ -5697,8 +5710,17 @@ def _responses_tools_to_chat_tools(
56975710
"description": description or None,
56985711
"parameters": {
56995712
"type": "object",
5700-
"properties": {},
5701-
"additionalProperties": True,
5713+
"properties": {
5714+
"input": {
5715+
"type": "string",
5716+
"description": (
5717+
"Raw input text for this tool. "
5718+
"For apply_patch, put the full patch here."
5719+
),
5720+
},
5721+
},
5722+
"required": ["input"],
5723+
"additionalProperties": False,
57025724
},
57035725
"strict": tool.get("strict"),
57045726
"content_type": "text",
@@ -6534,8 +6556,8 @@ def _ensure_tool_stream_item(
65346556
)
65356557
], item_state
65366558

6537-
@staticmethod
65386559
def _update_tool_stream_item(
6560+
self,
65396561
item: Dict[str, Any],
65406562
*,
65416563
call_id: Optional[str],
@@ -6554,12 +6576,41 @@ def _update_tool_stream_item(
65546576
item["name"] = current_name + name_delta
65556577
if isinstance(arguments_delta, str) and arguments_delta:
65566578
if item.get("type") == "custom_tool_call":
6557-
item["input"] = cast(str, item.get("input", "")) + arguments_delta
6579+
raw_arguments = cast(str, item.get("_raw_arguments", "")) + arguments_delta
6580+
item["_raw_arguments"] = raw_arguments
6581+
normalized_input = self._normalize_text_tool_payload(raw_arguments)
6582+
if normalized_input is not None:
6583+
item["input"] = normalized_input
65586584
else:
65596585
item["arguments"] = (
65606586
cast(str, item.get("arguments", "")) + arguments_delta
65616587
)
65626588

6589+
@staticmethod
6590+
def _normalize_text_tool_payload(payload: str) -> Optional[str]:
6591+
if payload == "":
6592+
return ""
6593+
stripped = payload.lstrip()
6594+
if not stripped:
6595+
return ""
6596+
if stripped[0] not in '{["':
6597+
return payload
6598+
try:
6599+
decoded = json.loads(payload)
6600+
except Exception:
6601+
return None
6602+
if isinstance(decoded, str):
6603+
return decoded
6604+
if isinstance(decoded, dict):
6605+
input_value = decoded.get("input")
6606+
if isinstance(input_value, str):
6607+
return input_value
6608+
if len(decoded) == 1:
6609+
sole_value = next(iter(decoded.values()))
6610+
if isinstance(sole_value, str):
6611+
return sole_value
6612+
return payload
6613+
65636614
def _finalize_response_stream_items(
65646615
self,
65656616
state: "OpenAIFormatter.ResponsesStream",
@@ -6645,6 +6696,7 @@ def _finalize_response_stream_items(
66456696
for tool_call_index in sorted(state.tool_items):
66466697
item_state = state.tool_items[tool_call_index]
66476698
item = item_state.item
6699+
item.pop("_raw_arguments", None)
66486700
if (
66496701
item.get("status") != "in_progress"
66506702
and item.get("type") != "custom_tool_call"
@@ -6772,6 +6824,7 @@ def convert_chat_chunk_to_response_events(
67726824
name=cast(Optional[str], function.get("name")),
67736825
)
67746826
events.extend(added)
6827+
previous_input = cast(str, item_state.item.get("input", ""))
67756828
self._update_tool_stream_item(
67766829
item_state.item,
67776830
call_id=cast(Optional[str], tool_call.get("id")),
@@ -6781,13 +6834,19 @@ def convert_chat_chunk_to_response_events(
67816834
arguments_delta = function.get("arguments")
67826835
if isinstance(arguments_delta, str) and arguments_delta:
67836836
if item_state.item.get("type") == "custom_tool_call":
6837+
current_input = cast(str, item_state.item.get("input", ""))
6838+
if not current_input or current_input == previous_input:
6839+
continue
6840+
delta_text = current_input
6841+
if current_input.startswith(previous_input):
6842+
delta_text = current_input[len(previous_input) :]
67846843
events.append(
67856844
self._response_event(
67866845
state,
67876846
"response.custom_tool_call_input.delta",
67886847
item_id=cast(str, item_state.item["id"]),
67896848
output_index=item_state.output_index,
6790-
delta=arguments_delta,
6849+
delta=delta_text,
67916850
)
67926851
)
67936852
continue

0 commit comments

Comments
 (0)