Spaces:
Running
Running
File size: 6,810 Bytes
fcc734a 0d3d041 fcc734a 40853c6 fcc734a 40853c6 d22e6fd c0c69f5 4e3db9c d22e6fd 0d3d041 4e3db9c fcc734a 0d3d041 fcc734a a58e6a3 fcc734a 0d3d041 fcc734a 0d3d041 fcc734a 9bcfe23 fcc734a 0d3d041 8350b87 0d3d041 8350b87 fcc734a 0d3d041 fcc734a 0d3d041 fcc734a 9bcfe23 fcc734a 0d3d041 4e3db9c 0d3d041 4e3db9c 0d3d041 a58e6a3 fcc734a a58e6a3 0d3d041 d22e6fd a58e6a3 8350b87 fcc734a a58e6a3 2d52286 8350b87 2d52286 fcc734a a58e6a3 fcc734a 0d3d041 fcc734a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | """
Command center backend - handles tool-based agent launching and direct tools
"""
import json
import logging
from typing import List, Dict
logger = logging.getLogger(__name__)
# Tool definitions derived from agent registry
from .agents import get_tools, get_agent_type_map, get_tool_arg
from .tools import DIRECT_TOOL_REGISTRY
# Combine agent-launch tools with direct tools
TOOLS = get_tools() + [t["schema"] for t in DIRECT_TOOL_REGISTRY.values()]
MAX_TURNS = 10 # Limit conversation turns in command center
def stream_command_center(client, model: str, messages: List[Dict], extra_params: dict = None, abort_event=None, files_root: str = None):
"""
Stream command center responses with agent launching capabilities
Yields:
dict: Updates with type 'thinking', 'launch', 'done', or 'error'
"""
from .agents import call_llm
turns = 0
done = False
debug_call_number = 0
while not done and turns < MAX_TURNS:
# Check abort before each turn
if abort_event and abort_event.is_set():
yield {"type": "aborted"}
return
turns += 1
# LLM call with retries and debug events
response = None
for event in call_llm(client, model, messages, tools=TOOLS, extra_params=extra_params, abort_event=abort_event, call_number=debug_call_number):
if "_response" in event:
response = event["_response"]
debug_call_number = event["_call_number"]
else:
yield event
if event.get("type") in ("error", "aborted"):
return
if response is None:
return
# Get response
assistant_message = response.choices[0].message
content = assistant_message.content or ""
tool_calls = assistant_message.tool_calls or []
# Send thinking content if present
if content.strip():
yield {"type": "thinking", "content": content}
# Handle tool calls (agent launches + direct tools)
if tool_calls:
has_launches = False
for tool_call in tool_calls:
# Check abort between tool calls
if abort_event and abort_event.is_set():
yield {"type": "aborted"}
return
function_name = tool_call.function.name
# Parse arguments
try:
args = json.loads(tool_call.function.arguments)
except:
yield {"type": "error", "content": "Failed to parse tool arguments"}
return
# --- Direct tools (execute synchronously) ---
if function_name in DIRECT_TOOL_REGISTRY:
# Emit tool_start for frontend
yield {
"type": "tool_start",
"tool": function_name,
"args": args,
"tool_call_id": tool_call.id,
"arguments": tool_call.function.arguments,
"thinking": content,
}
# Execute the tool via registry
tool_entry = DIRECT_TOOL_REGISTRY[function_name]
result = tool_entry["execute"](args, {"files_root": files_root})
# Emit tool_result for frontend
yield {
"type": "tool_result",
"tool": function_name,
"tool_call_id": tool_call.id,
"result": result,
"response": result.get("content", ""),
}
# Add to message history so LLM can continue
messages.append({
"role": "assistant",
"content": content,
"tool_calls": [{
"id": tool_call.id,
"type": "function",
"function": {
"name": function_name,
"arguments": tool_call.function.arguments,
}
}]
})
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result.get("content", ""),
})
continue
# --- Agent launch tools ---
agent_type_map = get_agent_type_map()
agent_type = agent_type_map.get(function_name)
if agent_type:
has_launches = True
# Get the initial message using the registered arg name for this type
initial_message = args.get(get_tool_arg(agent_type)) or args.get("task") or args.get("message")
task_id = args.get("task_id", "")
# Send launch action to frontend
yield {
"type": "launch",
"agent_type": agent_type,
"initial_message": initial_message,
"task_id": task_id,
"tool_call_id": tool_call.id
}
# Add tool call to message history for context
messages.append({
"role": "assistant",
"content": content,
"tool_calls": [{
"id": tool_call.id,
"type": "function",
"function": {
"name": tool_call.function.name,
"arguments": tool_call.function.arguments,
}
}]
})
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": f"Launched {agent_type} agent with task: {initial_message}"
})
else:
yield {"type": "error", "content": f"Unknown tool: {function_name}"}
return
# If any agent launches happened, stop and let agents run
# If only direct tools, continue the loop so LLM can respond
if has_launches:
done = True
else:
# No tool calls - conversation complete
messages.append({"role": "assistant", "content": content})
done = True
# Send done signal
yield {"type": "done"}
|