From c9a76e7fb36e5f3b2cbe269a633ba01cf5cab33b Mon Sep 17 00:00:00 2001 From: Shivering Ocelot Date: Sat, 3 Oct 2026 17:03:03 -0500 Subject: [PATCH] feat: respect tool policy, oai execute deferred tools --- backend/src/agents/expert.py | 18 +++++++++--------- backend/src/server/openai.py | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/backend/src/agents/expert.py b/backend/src/agents/expert.py index b3f97e5..1b5f53e 100644 --- a/backend/src/agents/expert.py +++ b/backend/src/agents/expert.py @@ -40,13 +40,15 @@ async def chat_completion_loop(app, run, messages, model_id=None, tools=None): run.emit_event('inference', msg) - if execute_tools and tool_calls: - for tc in tool_calls: - tool = next((t for t in tools if t.name == tc.tool_name), None) - if tool is None: - print(f"[agent] unknown tool name: {tc.tool_name}") - continue + for tc in tool_calls: + tool = next((t for t in tools if t.name == tc.tool_name), None) + if tool is None: + print(f"[agent] unknown tool name: {tc.tool_name}") + continue + if execute_tools: tc.result = await tool.execute_async(**tc.arguments) + else: + tc.tool = tool # By default, end if there's no calls else: break @@ -79,9 +81,7 @@ class ExpertAgent(Agent): # Provide the agent's default tools unless the run supplies its own. # Only agent-provided tools are executable within the loop. tools = run.input.get("tools", []) - if tools: - run.input['tool_policy'] = 'ignore' - else: + if run.input.get('tool_policy') != 'caller': tools += self.get_tools(run) print("Final tool object: " + repr(run.input.get('tools', []))) diff --git a/backend/src/server/openai.py b/backend/src/server/openai.py index 7172952..15fc853 100644 --- a/backend/src/server/openai.py +++ b/backend/src/server/openai.py @@ -49,17 +49,17 @@ def route_tool_call(call, tool_names): return deferred -async def execute_deferred(function_call): +async def execute_deferred(tc): """Execute a deferred (native) tool call. - The output must be stored on the call itself (``function_call.result``). + The output must be stored on the call itself (``tc.result``). - TODO: resolve the ToolSpec for ``function_call.tool_name`` from the + TODO: resolve the ToolSpec for ``tc.tool_name`` from the agent's native tools and dispatch through the existing tool infrastructure (ToolSpec.execute_async), recording the result or error on the call. Deferred execution needs more design work; stubbed for now. """ - pass + tc.result = await tc.tool.execute_async(**tc.arguments) def attach_run_handlers(run, tool_names):