feat(agent): 预设本机工具、stdio MCP 传输与多轮上下文

- 预设 12 个本机工具并默认启用,装好即是可操作电脑的 Agent、无需总控配置或安装:
  文件与文件夹的查看/读取/写入/建目录/移动/删除(默认不覆盖、删目录需 recursive、
  拒绝删除系统目录与用户根目录)、用默认程序打开网址或文件、时间与时区换算
  (tzdata 已随包内置)、查看进程、屏幕截图、读写剪贴板。
- 工具下发改为通用:任意 HTTP MCP 服务与 stdio 本机命令(Agent 拉起子进程,
  容忍 stdout 噪声,命令缺失或进程崩溃会明确回报),支持多工具并存、
  定义未变更时复用连接、替换/删除/退出时回收子进程。
- 多轮上下文:task_dispatch.history 作为此前的 user/assistant 文本拼接到本次请求前,
  OpenAI 兼容、Anthropic、Gemini 分别适配;Agent 侧独立校验与限幅。
- 工具级实时进度以 progress 事件回传;使用预设工具的任务标记为 builtin 执行来源。
- Skill 与历史内容上限与总控对齐,多个已批准 Skill 不再被静默截断。
- 修复 build.ps1 缺 UTF-8 BOM 导致 build.bat 在 PowerShell 5.1 下语法报错。
This commit is contained in:
toot
2026-09-16 15:31:00 +08:00
parent aa57ea69de
commit 9e01cbbec0
21 changed files with 2110 additions and 144 deletions
+41 -1
View File
@@ -50,10 +50,50 @@ def test_provider_image_payloads(monkeypatch):
assert captured[2]["contents"][0]["parts"][1]["inline_data"]["mime_type"] == "image/png"
def test_anthropic_and_gemini_receive_the_conversation_history(monkeypatch):
captured: list[dict[str, object]] = []
class Response:
def __init__(self, payload):
self.payload = payload
def __enter__(self):
return self
def __exit__(self, *_):
return False
def read(self):
return json.dumps(self.payload).encode()
def fake_urlopen(request, timeout):
captured.append(json.loads(request.data.decode()))
if request.full_url.endswith("/messages"):
return Response({"content": [{"type": "text", "text": "好的"}]})
return Response({"candidates": [{"content": {"parts": [{"text": "好的"}]}}]})
monkeypatch.setattr("mulit_agent_app.infrastructure.provider_factory.urlopen", fake_urlopen)
history = (("user", "下载到 D:\\demo"), ("assistant", "已下载到 D:\\demo\\a.zip"))
assert AnthropicProvider("https://example", "model", Credentials()).generate("把它复制到 D:\\target", history=history) == "好的"
assert GeminiProvider("https://example", "model", Credentials()).generate("把它复制到 D:\\target", history=history) == "好的"
assert captured[0]["messages"] == [
{"role": "user", "content": "下载到 D:\\demo"},
{"role": "assistant", "content": "已下载到 D:\\demo\\a.zip"},
{"role": "user", "content": [{"type": "text", "text": "把它复制到 D:\\target"}]},
]
assert captured[1]["contents"] == [
{"role": "user", "parts": [{"text": "下载到 D:\\demo"}]},
{"role": "model", "parts": [{"text": "已下载到 D:\\demo\\a.zip"}]},
{"role": "user", "parts": [{"text": "把它复制到 D:\\target"}]},
]
def test_anthropic_and_gemini_complete_local_tool_calls(monkeypatch):
responses = {
"anthropic": [
{"content": [{"type": "tool_use", "id": "anthropic-call", "input": {"command": "Write-Output anth"}}]},
{"content": [{"type": "tool_use", "id": "anthropic-call", "name": "run_powershell", "input": {"command": "Write-Output anth"}}]},
{"content": [{"type": "text", "text": "Anthropic 已执行。"}]},
],
"gemini": [