diff --git a/ai-hub/app/core/orchestration/architect.py b/ai-hub/app/core/orchestration/architect.py index 3905fef..2f255c9 100644 --- a/ai-hub/app/core/orchestration/architect.py +++ b/ai-hub/app/core/orchestration/architect.py @@ -105,6 +105,11 @@ async for event in executor.run_tools(processed_tc, safety, mesh_bridge): if "role" in event: messages.append(event) else: yield event + + if turn >= profile.autonomous_limit: + yield {"type": "status", "content": "Autonomous limit reached. Please provide more instructions if needed."} + else: + yield {"type": "status", "content": "Task complete."} except Exception as e: import traceback @@ -140,7 +145,23 @@ async for event in self.stream.end_stream(turn): if not (profile.buffer_content and event["type"] == "content"): yield event - yield {"type": "tool_calls_detected", "map": tc_map} + # Standardize tool calls for JSON serialization in the event stream + serializable_tc_map = {} + for idx, tc in tc_map.items(): + if hasattr(tc, "model_dump"): + serializable_tc_map[idx] = tc.model_dump() + else: + # Manual fallback for non-Pydantic objects + serializable_tc_map[idx] = { + "id": getattr(tc, "id", None), + "type": "function", + "function": { + "name": getattr(tc.function, "name", ""), + "arguments": getattr(tc.function, "arguments", "") + } + } + + yield {"type": "tool_calls_detected", "map": serializable_tc_map} yield {"type": "finish_reason", "reason": finish_reason} async def _handle_no_tools_branch(self, finish_reason, content, reasoning, profile, safety, tool_svc, ws_id, messages, events_out: list) -> bool: @@ -216,9 +237,15 @@ clean_tc = [] for tc in tool_calls: + # Handle both object and dict access (Migration to Serializable Swarm) + tc_id = tc.get("id") if isinstance(tc, dict) else getattr(tc, "id", None) + tc_func = tc.get("function", {}) if isinstance(tc, dict) else getattr(tc, "function", None) + func_name = tc_func.get("name") if isinstance(tc_func, dict) else getattr(tc_func, "name", "") + func_args = tc_func.get("arguments") if isinstance(tc_func, dict) else getattr(tc_func, "arguments", "") + clean_tc.append({ - "id": tc.id, "type": "function", - "function": {"name": tc.function.name, "arguments": tc.function.arguments} + "id": tc_id, "type": "function", + "function": {"name": func_name, "arguments": func_args} }) msg = {"role": "assistant", "content": content or None, "tool_calls": clean_tc} if reasoning: msg["reasoning_content"] = reasoning