Spaces:
Sleeping
Sleeping
Cyber Catalyst Team commited on
Commit ·
b708c13
1
Parent(s): 24e5442
fix: correctly indent agent tool execution block inside the round loop to prevent duplicate calls and rate limits
Browse files- backend.py +82 -82
backend.py
CHANGED
|
@@ -836,92 +836,92 @@ async def chat_completions(request: Request, authorization: str = Header(None)):
|
|
| 836 |
if choice.finish_reason == "tool_calls":
|
| 837 |
break
|
| 838 |
|
| 839 |
-
|
| 840 |
-
|
| 841 |
-
|
| 842 |
-
|
| 843 |
-
|
| 844 |
-
|
| 845 |
-
|
| 846 |
-
|
| 847 |
-
|
| 848 |
-
|
| 849 |
-
|
| 850 |
-
|
| 851 |
-
|
| 852 |
-
|
| 853 |
-
|
| 854 |
-
|
| 855 |
-
|
| 856 |
-
|
| 857 |
-
|
| 858 |
-
|
| 859 |
-
|
| 860 |
-
|
| 861 |
-
|
| 862 |
-
|
| 863 |
-
|
| 864 |
-
try:
|
| 865 |
-
func_args = json.loads(raw_args_str)
|
| 866 |
-
except json.JSONDecodeError:
|
| 867 |
-
# Attempt raw JSON repair
|
| 868 |
-
repaired_str = raw_args_str.strip()
|
| 869 |
-
if not repaired_str.startswith("{"):
|
| 870 |
-
repaired_str = "{" + repaired_str
|
| 871 |
-
if not repaired_str.endswith("}"):
|
| 872 |
-
repaired_str = repaired_str + "}"
|
| 873 |
try:
|
| 874 |
-
func_args = json.loads(
|
| 875 |
-
|
| 876 |
-
|
| 877 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 878 |
|
| 879 |
-
|
| 880 |
-
|
| 881 |
|
| 882 |
-
|
| 883 |
-
|
| 884 |
-
|
| 885 |
-
|
| 886 |
-
|
| 887 |
-
|
| 888 |
-
|
| 889 |
-
|
| 890 |
-
|
| 891 |
-
|
| 892 |
|
| 893 |
-
|
| 894 |
-
|
| 895 |
-
|
| 896 |
-
|
| 897 |
-
|
| 898 |
-
|
| 899 |
-
|
| 900 |
-
|
| 901 |
-
|
| 902 |
-
|
| 903 |
-
|
| 904 |
-
|
| 905 |
-
|
| 906 |
-
|
| 907 |
-
|
| 908 |
-
|
| 909 |
-
|
| 910 |
-
|
| 911 |
-
|
| 912 |
-
|
| 913 |
-
|
| 914 |
-
|
| 915 |
-
|
| 916 |
-
|
| 917 |
-
|
| 918 |
-
|
| 919 |
-
|
| 920 |
-
|
| 921 |
-
|
| 922 |
-
|
| 923 |
-
|
| 924 |
-
|
| 925 |
|
| 926 |
# Continue the agentic loop (model processes tool results)
|
| 927 |
|
|
|
|
| 836 |
if choice.finish_reason == "tool_calls":
|
| 837 |
break
|
| 838 |
|
| 839 |
+
# If no tool calls, we're done
|
| 840 |
+
if not tool_calls_raw:
|
| 841 |
+
await save_message(session_id, "assistant", full_content)
|
| 842 |
+
yield make_chunk(request_id, requested_model, finish_reason="stop")
|
| 843 |
+
yield "data: [DONE]\n\n"
|
| 844 |
+
return
|
| 845 |
+
|
| 846 |
+
# Execute tool calls
|
| 847 |
+
tool_calls_list = []
|
| 848 |
+
for idx in sorted(tool_calls_raw.keys()):
|
| 849 |
+
tc = tool_calls_raw[idx]
|
| 850 |
+
tool_calls_list.append({
|
| 851 |
+
"id": tc["id"],
|
| 852 |
+
"type": "function",
|
| 853 |
+
"function": {"name": tc["name"], "arguments": tc["arguments"]}
|
| 854 |
+
})
|
| 855 |
+
|
| 856 |
+
# Add assistant message with tool calls to history
|
| 857 |
+
assistant_msg = {"role": "assistant", "content": full_content or None, "tool_calls": tool_calls_list}
|
| 858 |
+
final_messages.append(assistant_msg)
|
| 859 |
+
|
| 860 |
+
# Execute each tool and add results
|
| 861 |
+
for tc in tool_calls_list:
|
| 862 |
+
func_name = tc["function"]["name"]
|
| 863 |
+
raw_args_str = tc["function"]["arguments"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 864 |
try:
|
| 865 |
+
func_args = json.loads(raw_args_str)
|
| 866 |
+
except json.JSONDecodeError:
|
| 867 |
+
# Attempt raw JSON repair
|
| 868 |
+
repaired_str = raw_args_str.strip()
|
| 869 |
+
if not repaired_str.startswith("{"):
|
| 870 |
+
repaired_str = "{" + repaired_str
|
| 871 |
+
if not repaired_str.endswith("}"):
|
| 872 |
+
repaired_str = repaired_str + "}"
|
| 873 |
+
try:
|
| 874 |
+
func_args = json.loads(repaired_str)
|
| 875 |
+
log_activity(f"Auto-fixed invalid JSON string for tool: {func_name}")
|
| 876 |
+
except:
|
| 877 |
+
func_args = {}
|
| 878 |
|
| 879 |
+
# Perform semantic repairs
|
| 880 |
+
repaired_args, repair_notes = repair_arguments(func_name, func_args)
|
| 881 |
|
| 882 |
+
# Log activity
|
| 883 |
+
log_activity(f"Tool execution: {func_name} args={repaired_args}")
|
| 884 |
+
if repair_notes:
|
| 885 |
+
for note in repair_notes:
|
| 886 |
+
log_activity(f"[Tool Repair] {note}")
|
| 887 |
+
|
| 888 |
+
# Show tool execution to user
|
| 889 |
+
yield make_chunk(request_id, requested_model, f"\n\n🔧 **{func_name}**")
|
| 890 |
+
if repair_notes:
|
| 891 |
+
yield make_chunk(request_id, requested_model, " *(Auto-Repaired)*")
|
| 892 |
|
| 893 |
+
if func_name == "run_bash" and "command" in repaired_args:
|
| 894 |
+
yield make_chunk(request_id, requested_model, f": `{repaired_args['command']}`\n")
|
| 895 |
+
elif func_name == "read_file" and "path" in repaired_args:
|
| 896 |
+
yield make_chunk(request_id, requested_model, f": `{repaired_args['path']}`\n")
|
| 897 |
+
elif func_name == "write_file" and "path" in repaired_args:
|
| 898 |
+
yield make_chunk(request_id, requested_model, f": `{repaired_args['path']}`\n")
|
| 899 |
+
elif func_name == "list_directory":
|
| 900 |
+
yield make_chunk(request_id, requested_model, f": `{repaired_args.get('path', '.')}`\n")
|
| 901 |
+
elif func_name == "grep_search":
|
| 902 |
+
yield make_chunk(request_id, requested_model, f": `{repaired_args.get('pattern', '')}`\n")
|
| 903 |
+
else:
|
| 904 |
+
yield make_chunk(request_id, requested_model, "\n")
|
| 905 |
+
|
| 906 |
+
# Execute the tool
|
| 907 |
+
result = await execute_tool(func_name, repaired_args)
|
| 908 |
+
|
| 909 |
+
# Append teaching note if repaired
|
| 910 |
+
if repair_notes:
|
| 911 |
+
result += f"\n\n[SYSTEM REPAIR NOTE: The harness automatically fixed formatting issues: {', '.join(repair_notes)}. Please strictly follow the tool's JSON schema in subsequent calls without these wrapping/formatting errors.]"
|
| 912 |
+
|
| 913 |
+
# Show truncated result to user
|
| 914 |
+
preview = result[:500] + ("..." if len(result) > 500 else "")
|
| 915 |
+
yield make_chunk(request_id, requested_model, f"```\n{preview}\n```\n")
|
| 916 |
+
|
| 917 |
+
# Add tool result to message history
|
| 918 |
+
final_messages.append({
|
| 919 |
+
"role": "tool",
|
| 920 |
+
"tool_call_id": tc["id"],
|
| 921 |
+
"content": result,
|
| 922 |
+
})
|
| 923 |
+
|
| 924 |
+
await save_message(session_id, "tool", result, tool_call_id=tc["id"])
|
| 925 |
|
| 926 |
# Continue the agentic loop (model processes tool results)
|
| 927 |
|