feat: focus Work tools by task intent

This commit is contained in:
wuyang
2026-07-26 14:22:46 +08:00
parent ae5f940a5d
commit f2282c7e7d
3 changed files with 85 additions and 3 deletions
+53 -1
View File
@@ -33,6 +33,8 @@ relevant verification, and report concrete results. Use tools instead of inventi
command output. A claim that a file was created, changed, executed, or tested must be backed by a command output. A claim that a file was created, changed, executed, or tested must be backed by a
successful tool result from this run. For scripts, reports, code, and other deliverables, create real successful tool result from this run. For scripts, reports, code, and other deliverables, create real
files under /workspace, inspect them after writing, run relevant checks, and cite their exact paths. files under /workspace, inspect them after writing, run relevant checks, and cite their exact paths.
For a code-and-report task, follow this order: write a real source file, read it, run that exact source
file with a complete command, write the report using only the measured output, then read the report.
Write source files with real line breaks rather than literal `\\n` escape sequences. If any command Write source files with real line breaks rather than literal `\\n` escape sequences. If any command
fails, inspect the failure, repair the underlying problem, and successfully rerun the relevant check; fails, inspect the failure, repair the underlying problem, and successfully rerun the relevant check;
never replace failed output with invented numbers, placeholders, or a hand-written success report. never replace failed output with invented numbers, placeholders, or a hand-written success report.
@@ -113,6 +115,32 @@ READ_ONLY_EXEC_COMMAND = re.compile(
r"^(?:cat|cut|diff|find|git\s+(?:diff|show|status)|grep|head|jq|ls|pwd|rg|sed\s+-n|stat|tail|wc)\b", r"^(?:cat|cut|diff|find|git\s+(?:diff|show|status)|grep|head|jq|ls|pwd|rg|sed\s+-n|stat|tail|wc)\b",
re.IGNORECASE, re.IGNORECASE,
) )
PROCESS_REQUEST = re.compile(
r"(服务器|服务|后台|常驻|网站|网页|\b(?:server|service|daemon|background|web\s*app)\b)",
re.IGNORECASE,
)
GIT_REQUEST = re.compile(
r"(仓库|提交|分支|\b(?:git|repo(?:sitory)?|commit|branch|pull request)\b)",
re.IGNORECASE,
)
MEMORY_REQUEST = re.compile(
r"(记住|记忆|偏好|忘记|\b(?:remember|memory|preference|forget)\b)",
re.IGNORECASE,
)
DELEGATION_REQUEST = re.compile(
r"(多\s*(?:agent|代理)|子代理|分工|并行调研|大型|架构|重构|迁移|"
r"\b(?:multi[- ]agent|sub[- ]agent|delegate|parallel research|architecture|migration|refactor)\b)",
re.IGNORECASE,
)
CORE_WORK_TOOLS = {
"workspace_status",
"list_files",
"read_file",
"search_files",
"write_file",
"apply_patch",
"exec",
}
def latest_user_text(messages: list[dict[str, Any]]) -> str: def latest_user_text(messages: list[dict[str, Any]]) -> str:
@@ -300,6 +328,26 @@ def is_substantive_execution(name: str, arguments: dict[str, Any]) -> bool:
return bool(command and not READ_ONLY_EXEC_COMMAND.match(command)) return bool(command and not READ_ONLY_EXEC_COMMAND.match(command))
def select_tool_specs(
specs: list[dict[str, Any]],
request_text: str,
*,
depth: int,
) -> list[dict[str, Any]]:
allowed = set(CORE_WORK_TOOLS)
if depth == 0:
allowed.add("update_plan")
if PROCESS_REQUEST.search(request_text):
allowed.update({"start_process", "poll_process", "cancel_process"})
if GIT_REQUEST.search(request_text):
allowed.update({"git_status", "git_diff"})
if MEMORY_REQUEST.search(request_text):
allowed.update({"remember", "recall_memory", "forget_memory"})
if depth == 0 and DELEGATION_REQUEST.search(request_text):
allowed.add("delegate_task")
return [spec for spec in specs if str((spec.get("function") or {}).get("name", "")) in allowed]
@dataclass(slots=True) @dataclass(slots=True)
class RunRecorder: class RunRecorder:
store: RuntimeStore store: RuntimeStore
@@ -403,8 +451,12 @@ class AgentLoop:
read_only: bool, read_only: bool,
) -> str: ) -> str:
max_iterations = min(spec.max_iterations, 8 if depth else spec.max_iterations) max_iterations = min(spec.max_iterations, 8 if depth else spec.max_iterations)
available_specs = self.tools.specs(read_only=read_only, allow_delegate=depth == 0)
request_text = latest_user_text(messages) request_text = latest_user_text(messages)
available_specs = select_tool_specs(
self.tools.specs(read_only=read_only, allow_delegate=depth == 0),
request_text,
depth=depth,
)
artifact_required = depth == 0 and bool(ARTIFACT_REQUEST.search(request_text)) artifact_required = depth == 0 and bool(ARTIFACT_REQUEST.search(request_text))
action_required = depth == 0 and bool(ACTION_REQUEST.search(request_text)) action_required = depth == 0 and bool(ACTION_REQUEST.search(request_text))
execution_required = depth == 0 and bool(EXECUTION_REQUEST.search(request_text)) execution_required = depth == 0 and bool(EXECUTION_REQUEST.search(request_text))
+3 -2
View File
@@ -92,7 +92,7 @@ TOOL_METADATA: dict[str, ToolMetadata] = {
), ),
"write_file": ToolMetadata( "write_file": ToolMetadata(
"write_file", "write_file",
"Write the complete UTF-8 contents of a workspace file.", "Write complete UTF-8 file contents. Use actual line breaks between source lines, not literal \\\\n text.",
object_schema( object_schema(
{ {
"path": {"type": "string", "maxLength": 4096}, "path": {"type": "string", "maxLength": 4096},
@@ -115,7 +115,8 @@ TOOL_METADATA: dict[str, ToolMetadata] = {
), ),
"exec": ToolMetadata( "exec": ToolMetadata(
"exec", "exec",
"Run a shell command in the isolated workspace.", "Run a complete non-interactive shell command. Name the script, pass -c code, or invoke a test; "
"bare python, node, or shells are rejected.",
object_schema( object_schema(
{ {
"command": {"type": "string"}, "command": {"type": "string"},
+29
View File
@@ -11,6 +11,7 @@ from agent_platform.runtime.loop import (
AgentLoop, AgentLoop,
is_substantive_execution, is_substantive_execution,
normalize_write_file_content, normalize_write_file_content,
select_tool_specs,
tool_event_details, tool_event_details,
) )
from agent_platform.runtime.tools import TOOL_METADATA from agent_platform.runtime.tools import TOOL_METADATA
@@ -45,6 +46,34 @@ def test_read_only_shell_commands_do_not_satisfy_execution_evidence() -> None:
assert is_substantive_execution("start_process", {"command": "python3 server.py"}) assert is_substantive_execution("start_process", {"command": "python3 server.py"})
def test_simple_script_task_receives_a_focused_tool_menu() -> None:
specs = [metadata.openai_spec() for metadata in TOOL_METADATA.values()]
selected = select_tool_specs(specs, "写脚本对比排序算法,给一个报告", depth=0)
names = {spec["function"]["name"] for spec in selected}
assert names == {
"workspace_status",
"list_files",
"read_file",
"search_files",
"write_file",
"apply_patch",
"exec",
"update_plan",
}
def test_complex_requests_enable_only_relevant_optional_tools() -> None:
specs = [metadata.openai_spec() for metadata in TOOL_METADATA.values()]
selected = select_tool_specs(
specs,
"重构 Git 仓库里的 web server,并记住这个偏好,分工并行调研",
depth=0,
)
names = {spec["function"]["name"] for spec in selected}
assert {"delegate_task", "git_status", "git_diff", "start_process", "poll_process"} <= names
assert {"remember", "recall_memory", "forget_memory"} <= names
class ScriptedProvider: class ScriptedProvider:
def __init__(self, responses: list[dict[str, Any]]) -> None: def __init__(self, responses: list[dict[str, Any]]) -> None:
self.responses = responses self.responses = responses