feat(core): Wire tool toggles to AI provider tool declaration payload
This commit is contained in:
23
ai_client.py
23
ai_client.py
@@ -286,15 +286,26 @@ def _list_anthropic_models() -> list[str]:
|
|||||||
|
|
||||||
TOOL_NAME = "run_powershell"
|
TOOL_NAME = "run_powershell"
|
||||||
|
|
||||||
|
_agent_tools: dict = {}
|
||||||
|
|
||||||
|
def set_agent_tools(tools: dict):
|
||||||
|
global _agent_tools, _CACHED_ANTHROPIC_TOOLS
|
||||||
|
_agent_tools = tools
|
||||||
|
_CACHED_ANTHROPIC_TOOLS = None
|
||||||
|
|
||||||
def _build_anthropic_tools() -> list[dict]:
|
def _build_anthropic_tools() -> list[dict]:
|
||||||
"""Build the full Anthropic tools list: run_powershell + MCP file tools."""
|
"""Build the full Anthropic tools list: run_powershell + MCP file tools."""
|
||||||
mcp_tools = []
|
mcp_tools = []
|
||||||
for spec in mcp_client.MCP_TOOL_SPECS:
|
for spec in mcp_client.MCP_TOOL_SPECS:
|
||||||
|
if _agent_tools.get(spec["name"], True):
|
||||||
mcp_tools.append({
|
mcp_tools.append({
|
||||||
"name": spec["name"],
|
"name": spec["name"],
|
||||||
"description": spec["description"],
|
"description": spec["description"],
|
||||||
"input_schema": spec["parameters"],
|
"input_schema": spec["parameters"],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
tools_list = mcp_tools
|
||||||
|
if _agent_tools.get(TOOL_NAME, True):
|
||||||
powershell_tool = {
|
powershell_tool = {
|
||||||
"name": TOOL_NAME,
|
"name": TOOL_NAME,
|
||||||
"description": (
|
"description": (
|
||||||
@@ -316,7 +327,12 @@ def _build_anthropic_tools() -> list[dict]:
|
|||||||
},
|
},
|
||||||
"cache_control": {"type": "ephemeral"},
|
"cache_control": {"type": "ephemeral"},
|
||||||
}
|
}
|
||||||
return mcp_tools + [powershell_tool]
|
tools_list.append(powershell_tool)
|
||||||
|
elif tools_list:
|
||||||
|
# Anthropic requires the LAST tool to have cache_control for the prefix caching to work optimally on tools
|
||||||
|
tools_list[-1]["cache_control"] = {"type": "ephemeral"}
|
||||||
|
|
||||||
|
return tools_list
|
||||||
|
|
||||||
|
|
||||||
_ANTHROPIC_TOOLS = _build_anthropic_tools()
|
_ANTHROPIC_TOOLS = _build_anthropic_tools()
|
||||||
@@ -338,6 +354,8 @@ def _gemini_tool_declaration():
|
|||||||
|
|
||||||
# MCP file tools
|
# MCP file tools
|
||||||
for spec in mcp_client.MCP_TOOL_SPECS:
|
for spec in mcp_client.MCP_TOOL_SPECS:
|
||||||
|
if not _agent_tools.get(spec["name"], True):
|
||||||
|
continue
|
||||||
props = {}
|
props = {}
|
||||||
for pname, pdef in spec["parameters"].get("properties", {}).items():
|
for pname, pdef in spec["parameters"].get("properties", {}).items():
|
||||||
props[pname] = types.Schema(
|
props[pname] = types.Schema(
|
||||||
@@ -355,6 +373,7 @@ def _gemini_tool_declaration():
|
|||||||
))
|
))
|
||||||
|
|
||||||
# PowerShell tool
|
# PowerShell tool
|
||||||
|
if _agent_tools.get(TOOL_NAME, True):
|
||||||
declarations.append(types.FunctionDeclaration(
|
declarations.append(types.FunctionDeclaration(
|
||||||
name=TOOL_NAME,
|
name=TOOL_NAME,
|
||||||
description=(
|
description=(
|
||||||
@@ -375,7 +394,7 @@ def _gemini_tool_declaration():
|
|||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
|
||||||
return types.Tool(function_declarations=declarations)
|
return types.Tool(function_declarations=declarations) if declarations else None
|
||||||
|
|
||||||
|
|
||||||
def _run_script(script: str, base_dir: str) -> str:
|
def _run_script(script: str, base_dir: str) -> str:
|
||||||
|
|||||||
1
gui.py
1
gui.py
@@ -1203,6 +1203,7 @@ class App:
|
|||||||
if global_sp: combined_sp.append(global_sp.strip())
|
if global_sp: combined_sp.append(global_sp.strip())
|
||||||
if project_sp: combined_sp.append(project_sp.strip())
|
if project_sp: combined_sp.append(project_sp.strip())
|
||||||
ai_client.set_custom_system_prompt("\n\n".join(combined_sp))
|
ai_client.set_custom_system_prompt("\n\n".join(combined_sp))
|
||||||
|
ai_client.set_agent_tools(self.project.get("agent", {}).get("tools", {}))
|
||||||
temp = dpg.get_value("ai_temperature") if dpg.does_item_exist("ai_temperature") else 0.0
|
temp = dpg.get_value("ai_temperature") if dpg.does_item_exist("ai_temperature") else 0.0
|
||||||
max_tok = dpg.get_value("ai_max_tokens") if dpg.does_item_exist("ai_max_tokens") else 8192
|
max_tok = dpg.get_value("ai_max_tokens") if dpg.does_item_exist("ai_max_tokens") else 8192
|
||||||
trunc = dpg.get_value("ai_history_trunc") if dpg.does_item_exist("ai_history_trunc") else 8000
|
trunc = dpg.get_value("ai_history_trunc") if dpg.does_item_exist("ai_history_trunc") else 8000
|
||||||
|
|||||||
23
tests/test_agent_tools_wiring.py
Normal file
23
tests/test_agent_tools_wiring.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import pytest
|
||||||
|
from ai_client import set_agent_tools, _build_anthropic_tools
|
||||||
|
|
||||||
|
def test_agent_tools_wiring():
|
||||||
|
# Only enable read_file and run_powershell
|
||||||
|
agent_tools = {
|
||||||
|
"run_powershell": True,
|
||||||
|
"read_file": True,
|
||||||
|
"list_directory": False,
|
||||||
|
"search_files": False,
|
||||||
|
"get_file_summary": False,
|
||||||
|
"web_search": False,
|
||||||
|
"fetch_url": False
|
||||||
|
}
|
||||||
|
set_agent_tools(agent_tools)
|
||||||
|
|
||||||
|
anth_tools = _build_anthropic_tools()
|
||||||
|
tool_names = [t["name"] for t in anth_tools]
|
||||||
|
|
||||||
|
assert "read_file" in tool_names
|
||||||
|
assert "run_powershell" in tool_names
|
||||||
|
assert "list_directory" not in tool_names
|
||||||
|
assert "web_search" not in tool_names
|
||||||
Reference in New Issue
Block a user