Find
Search dashboard pages and product views.
Search dashboard pages and product views.
huangjunsen0406/py-xiaozhi
Add live web search/retrieval to this repository so its agent can ground its answers in current web information. Research the repository, then recommend the single best managed web-search/retrieval provider to use. Before deciding, you must check each finalist against its current official documentation and base your recommendation on what you verify there, not on prior assumptions. Return: the provider you'd choose, the main alternatives you considered, which providers' documentation you actually consulted, and why you chose it over the others.
P5
45c8a0400df532e1e3c00843d76604574541f3c4
Agent context: I’ll first read the project guidance and map how the agent is wired, then I’ll verify current provider docs for the finalists before making the recommendation. I’ll first read the project guidance and map how the agent is wired, then I’ll verify current provider docs for the finalists before making the recommendation.
Agent context: I’ll first read the project guidance and map how the agent is wired, then I’ll verify current provider docs for the finalists before making the recommendation.
Agent context: I’ll first read the project guidance and map how the agent is wired, then I’ll verify current provider docs for the finalists before making the recommendation. exit code 0 Output: # Development Workflow --- ## Core Principles 1. **Plan before code** — figure out what to do before you start 2. **Specs injected, not remembered** — guidelines are injected via hook/skill, not recalled from memory 3. **Persist everything** — research, decisions, and lessons all go to files; conversations get compacted, files don't 4. **Incremental development** — one task at a time 5. **Capture learnings** — after each task, review and write new knowledge back to spec --- ## Trellis System ### Developer Identity On first use, initialize your identity: ```bash python3 ./.trellis/scripts/init_developer.py <your-name> ``` Creates `.trellis/.developer` (gitignored) + `.trellis/workspace/<your-name>/`. ### Spec System `.trellis/spec/` holds coding guidelines organized by package and layer. - `.trellis/spec/<package>/<layer>/index.md` — entry point with **Pre-Development Checklist** + **Qual
Agent context: I’ll first read the project guidance and map how the agent is wired, then I’ll verify current provider docs for the finalists before making the recommendation.
Agent context: I’ll first read the project guidance and map how the agent is wired, then I’ll verify current provider docs for the finalists before making the recommendation. exit code 0 Output: .trellis/spec/backend/architecture-principles.md .trellis/spec/backend/asyncio-guidelines.md .trellis/spec/backend/directory-structure.md .trellis/spec/backend/error-handling.md .trellis/spec/backend/git-workflow.md .trellis/spec/backend/index.md .trellis/spec/backend/logging-guidelines.md .trellis/spec/backend/mcp-tool-pattern.md .trellis/spec/backend/pyside6-guidelines.md .trellis/spec/backend/python-style.md .trellis/spec/backend/quality-guidelines.md .trellis/spec/guides/code-reuse-thinking-guide.md .trellis/spec/guides/cross-layer-thinking-guide.md .trellis/spec/guides/index.md
Agent context: I’ll first read the project guidance and map how the agent is wired, then I’ll verify current provider docs for the finalists before making the recommendation.
Agent context: I’ll first read the project guidance and map how the agent is wired, then I’ll verify current provider docs for the finalists before making the recommendation. exit code 0
Agent context: I’ll first read the project guidance and map how the agent is wired, then I’ll verify current provider docs for the finalists before making the recommendation.
Agent context: I’ll first read the project guidance and map how the agent is wired, then I’ll verify current provider docs for the finalists before making the recommendation. exit code 0 Output: /home/user/worktrees/attempt-1852e44c-d202-49be-a10e-5ee8b966656d-cap-0 /bin/bash: line 1: rg: command not found
Agent context: The Trellis workflow treats implementation as task-backed, and this request also needs repository plus external research. I’m going to create a task record so the recommendation has a durable trace instead of being only chat context. The Trellis workflow treats implementation as task-backed, and this request also needs repository plus external research. I’m going to create a task record so the recommendation has a durable trace instead of being only chat context.
Agent context: The Trellis workflow treats implementation as task-backed, and this request also needs repository plus external research. I’m going to create a task record so the recommendation has a durable trace instead of being only chat context.
Agent context: The Trellis workflow treats implementation as task-backed, and this request also needs repository plus external research. I’m going to create a task record so the recommendation has a durable trace instead of being only chat context. exit code 1 Output: [0;31mError: No developer set. Run init_developer.py first or use --assignee[0m
Agent context: Task creation needs a Trellis developer identity first, so I’m initializing the local session identity and then I’ll continue with the task setup. Task creation needs a Trellis developer identity first, so I’m initializing the local session identity and then I’ll continue with the task setup.
Agent context: Task creation needs a Trellis developer identity first, so I’m initializing the local session identity and then I’ll continue with the task setup.
Agent context: Task creation needs a Trellis developer identity first, so I’m initializing the local session identity and then I’ll continue with the task setup. exit code 0 Output: Developer initialized: codex .developer file: /home/user/worktrees/attempt-1852e44c-d202-49be-a10e-5ee8b966656d-cap-0/.trellis/.developer Workspace dir: /home/user/worktrees/attempt-1852e44c-d202-49be-a10e-5ee8b966656d-cap-0/.trellis/workspace/codex [0;32mCreated task: 06-05-web-search-provider-evaluation[0m [0;34mNext steps:[0m 1. Create prd.md with requirements 2. Curate implement.jsonl / check.jsonl (spec + research files only — see .trellis/workflow.md Phase 1.3) 3. Run: python3 task.py start <dir> .trellis/tasks/06-05-web-search-provider-evaluation
Agent context: There isn’t a project Trellis skill file exposed under `.agents/skills/`, so I’ll follow the documented Trellis workflow directly. Next I’m checking the repository shape and the backend specs that apply to this integration decision. There isn’t a project Trellis skill file exposed under `.agents/skills/`, so I’ll follow the documented Trellis workflow directly. Next I’m checking the repository shape and the backend specs that apply to this integration decision.
Agent context: There isn’t a project Trellis skill file exposed under `.agents/skills/`, so I’ll follow the documented Trellis workflow directly. Next I’m checking the repository shape and the backend specs that apply to this integration decision.
Agent context: There isn’t a project Trellis skill file exposed under `.agents/skills/`, so I’ll follow the documented Trellis workflow directly. Next I’m checking the repository shape and the backend specs that apply to this integration decision. exit code 0 Output: ./.claude/agents/trellis-check.md ./.claude/agents/trellis-implement.md ./.claude/agents/trellis-research.md ./.claude/hooks/inject-subagent-context.py ./.claude/hooks/inject-workflow-state.py ./.claude/hooks/session-start.py ./.claude/settings.json ./.flake8 ./.git ./.github/FUNDING.yml ./.github/ISSUE_TEMPLATE/bug_report.md ./.github/ISSUE_TEMPLATE/code_improvement.md ./.github/ISSUE_TEMPLATE/documentation_improvement.md ./.github/ISSUE_TEMPLATE/feature_request.md ./.github/release-drafter.yml ./.github/workflows/build.yml ./.github/workflows/release.yml ./.github/workflows/vitepress.yml ./.gitignore ./.python-version ./.trellis/.developer ./.trellis/.gitignore ./.trellis/.template-hashes.json ./.trellis/.version ./.trellis/config.yaml ./.trellis/scripts/__init__.py ./.trellis/scripts/add_session.py ./.trellis/scripts/get_context.py ./.trellis/scripts/get_developer.py ./.trellis/script
Agent context: There isn’t a project Trellis skill file exposed under `.agents/skills/`, so I’ll follow the documented Trellis workflow directly. Next I’m checking the repository shape and the backend specs that apply to this integration decision.
Agent context: There isn’t a project Trellis skill file exposed under `.agents/skills/`, so I’ll follow the documented Trellis workflow directly. Next I’m checking the repository shape and the backend specs that apply to this integration decision. exit code 0 Output: # MCP 工具模式 > 新增 MCP 工具的标准做法。当前模式: `@mcp_tool` 装饰器 + 自动发现。这是项目"下一个 feature"的标准形态 —— `src/mcp/tools/weather/` 下的天气工具是参考实现,旁边的 `MCP_DEVELOPMENT_GUIDE.md` 是面向开发者的速查文档。 --- ## 工具放在哪里 ``` src/mcp/tools/<your_tool>/ ├── __init__.py # import 工具模块以触发 @mcp_tool 装饰器 └── <your_tool>_tools.py # 一个或多个 @mcp_tool 函数 ``` 可选的同级文件(`bazi`、`music`、`system`、`weather` 用过): - `_tools.py` —— 单独的工具注册模块,把工具函数与 manager 逻辑解耦。自动发现会 **显式** 拉取这个名字(见 `src/mcp/decorators.py` 的 `discover_tool_modules()`)。 - 业务模块(如 `weather_tools.py`、`music_player.py`)—— 纯逻辑,可独立 import。 `src/mcp/decorators.py` 中的发现循环: 1. import 直接放在 `src/mcp/tools/` 下的每个 `*.py`(跳过 `_*`)。 2. import `src/mcp/tools/` 下每个子包(跳过 `_*`)。 3. 子包内若有 `_tools.py`,**额外** import 一遍。 两个推论: - 工具定义在 `src/mcp/tools/foo/foo_tools.py` 时,只有 `src/mcp/tools/foo/__init__.py` 显式 import 它,装饰器才会触发(发现步骤只 import 子包,不会展开内部文件,除非文件名叫 `_tools.py`)。 - `_` 开头的文件名会被包级扫描跳过,**只有** 子包内的 `_tools. Provider mentions: openai
Agent context: There isn’t a project Trellis skill file exposed under `.agents/skills/`, so I’ll follow the documented Trellis workflow directly. Next I’m checking the repository shape and the backend specs that apply to this integration decision.
Agent context: There isn’t a project Trellis skill file exposed under `.agents/skills/`, so I’ll follow the documented Trellis workflow directly. Next I’m checking the repository shape and the backend specs that apply to this integration decision. exit code 0 Output: # 后端开发规范 > Python 后端开发约定(单仓库、Python 3.10+,代码全部在 `src/` 下)。 --- ## 技术栈 - **语言**: Python ≥ 3.10,带类型注解。 - **异步运行时**: `asyncio`(CLI/GPIO 模式)和基于 PySide6 的 `qasync`(GUI 模式),入口见 `main.py`。 - **工具链**: ruff + black + isort + flake8(配置在 `pyproject.toml` 与 `.flake8`),便捷脚本: `./format_code.sh`。 - **测试**: pytest + pytest-asyncio 已配置,目前还没有 `tests/` 目录 —— 新增任何测试前先看 `quality-guidelines.md`。 - **持久化**: 没有数据库。配置以 JSON 形式由 `ConfigManager`(`src/utils/config_manager.py`) 管理,因此本目录下没有 DB 规范。 --- ## 规范索引 | 文档 | 主题 | |---|---| | [架构原则](./architecture-principles.md) | 分层、依赖方向、Plugin 模式、何时抽象、反过度耦合 vs 反过度解耦 | | [目录结构](./directory-structure.md) | `src/` 各域职责、新代码落点、单例 / import 约定 | | [Python 风格](./python-style.md) | 类型注解(现代范型 + `X \| None`)、文件头、命名、函数/方法规范、dataclass、路径 | | [asyncio 规范](./asyncio-guidelines.md) | `TaskManager.spawn` vs `create_task`、锁、gather、跨线程桥、qasync 注意事项 | | [PySide6 / QML](./pyside6-guidelines.md)
Agent context: There isn’t a project Trellis skill file exposed under `.agents/skills/`, so I’ll follow the documented Trellis workflow directly. Next I’m checking the repository shape and the backend specs that apply to this integration decision.
Agent context: There isn’t a project Trellis skill file exposed under `.agents/skills/`, so I’ll follow the documented Trellis workflow directly. Next I’m checking the repository shape and the backend specs that apply to this integration decision. exit code 0 Output: # 架构原则 > 这份文档说明 py-xiaozhi 实际采用的架构思路、对应的取舍,以及哪些"好习惯"在本项目里反而是过度设计。先有原则,再看下面的具体子规范。 --- ## 总体分层 整个应用是 **容器装服务、服务装插件** 的三层结构,依赖方向严格自上而下: ``` main.py └── ServiceContainer (src/bootstrap/container.py) — 应用入口、生命周期所有者 ├── core 服务 (src/core/*) — 跨域基础设施 │ ├── EventBus (事件总线) │ ├── StateManager (设备状态) │ ├── TaskManager (异步任务追踪) │ └── ProtocolManager (传输层) ├── PluginManager (src/plugins/manager.py) │ └── 各 Plugin (src/plugins/*.py) — 业务功能,通过 ctx/cmd 与核心交互 ├── ProtocolAdapter (src/protocols/*) — 实际传输实现 └── ViewManager (src/ui/*) — UI,只能在 GUI 模式下加载 ``` **唯一允许的依赖方向:** - `main.py` → `bootstrap` → `core` / `plugins` / `protocols` / `ui` - `plugins/*` → `core` / `bootstrap.protocols`(只看 Protocol 接口,不看 ServiceContainer 实现) - `core/*` → `logging` / `utils` / `constants`,**不 import** `plugins` / `ui` / `protocols` 的具体实现 - `ui/*` 可读 `core` / `utils`,但 UI 改变状态必须经 `EventBus.emit(...)`,不能直接调 plugin 内部方法 - `mcp/
Agent context: Sub-agent tooling is available, but its session rule requires explicit user permission to delegate, so I’ll keep this in the main session. I’ve found the repo’s relevant path: this is a Python app with an MCP tool system, so a search provider would likely land as a new `src/mcp/tools/...` package. Sub-agent tooling is available, but its session rule requires explicit user permission to delegate, so I’ll keep this in the main session. I’ve found the repo’s relevant path: this is a Python app with an MCP tool system, so a search provider would likely land as a new `src/mcp/tools/...` package.
Agent context: Sub-agent tooling is available, but its session rule requires explicit user permission to delegate, so I’ll keep this in the main session. I’ve found the repo’s relevant path: this is a Python app with an MCP tool system, so a search provider would likely land as a new `src/mcp/tools/...` package.
Agent context: Sub-agent tooling is available, but its session rule requires explicit user permission to delegate, so I’ll keep this in the main session. I’ve found the repo’s relevant path: this is a Python app with an MCP tool system, so a search provider would likely land as a new `src/mcp/tools/...` package. exit code 0 Output: """ MCP 工具装饰器与注册表. """ from collections.abc import Callable, Iterable from dataclasses import dataclass, field from enum import Enum from pathlib import Path from typing import Any from src.logging import get_logger from src.mcp.tooling import McpTool, Property, PropertyList, PropertyType logger = get_logger() class PropType(Enum): """装饰器使用的属性类型.""" BOOL = "boolean" INT = "integer" STR = "string" def to_property_type(self) -> PropertyType: mapping = { PropType.BOOL: PropertyType.BOOLEAN, PropType.INT: PropertyType.INTEGER, PropType.STR: PropertyType.STRING, } return mapping[self] _NOT_SET = object() @dataclass class Prop: """属性定义.""" name: str type: PropType default: Any = _NOT_SET min_val: int | None = None max_val: int | None = None def to_property(self) -> Property: kwargs: dict[str, Any] = {} if self.default is not _NOT_SET: kwargs["default_value"] = self.default if self.type == Prop
Agent context: Sub-agent tooling is available, but its session rule requires explicit user permission to delegate, so I’ll keep this in the main session. I’ve found the repo’s relevant path: this is a Python app with an MCP tool system, so a search provider would likely land as a new `src/mcp/tools/...` package.
Agent context: Sub-agent tooling is available, but its session rule requires explicit user permission to delegate, so I’ll keep this in the main session. I’ve found the repo’s relevant path: this is a Python app with an MCP tool system, so a search provider would likely land as a new `src/mcp/tools/...` package. exit code 0 Output: """ MCP Server Implementation for Python Reference: https://modelcontextprotocol.io/specification/2024-11-05 """ import json from collections.abc import Callable from typing import Any from src.constants.system import SystemConstants from src.logging import get_logger from src.mcp.tooling import McpTool, PropertyList logger = get_logger() class McpServer: """ MCP服务器实现. """ _instance = None @classmethod def get_instance(cls): """ 获取单例实例. """ if cls._instance is None: cls._instance = McpServer() return cls._instance def __init__(self): self.tools: list[McpTool] = [] self._send_callback: Callable | None = None self._camera = None def set_send_callback(self, callback: Callable): """ 设置发送消息的回调函数. """ self._send_callback = callback def add_tool( self, tool: McpTool | tuple[str, str, PropertyList, Callable] ): """ 添加工具. """ if isinstance(tool, tuple): # 从参数创建McpTool name, description, propertie
Agent context: Sub-agent tooling is available, but its session rule requires explicit user permission to delegate, so I’ll keep this in the main session. I’ve found the repo’s relevant path: this is a Python app with an MCP tool system, so a search provider would likely land as a new `src/mcp/tools/...` package.
Agent context: Sub-agent tooling is available, but its session rule requires explicit user permission to delegate, so I’ll keep this in the main session. I’ve found the repo’s relevant path: this is a Python app with an MCP tool system, so a search provider would likely land as a new `src/mcp/tools/...` package. exit code 0 Output: src/mcp/decorators.py src/mcp/mcp_server.py src/mcp/tooling.py src/mcp/tools/__init__.py src/mcp/tools/app/__init__.py src/mcp/tools/app/_tools.py src/mcp/tools/app/killer.py src/mcp/tools/app/launcher.py src/mcp/tools/app/launcher_linux.py src/mcp/tools/app/launcher_mac.py src/mcp/tools/app/launcher_windows.py src/mcp/tools/app/process_manager.py src/mcp/tools/app/scanner.py src/mcp/tools/app/scanner_linux.py src/mcp/tools/app/scanner_mac.py src/mcp/tools/app/scanner_windows.py src/mcp/tools/app/utils.py src/mcp/tools/camera/__init__.py src/mcp/tools/camera/base_camera.py src/mcp/tools/camera/normal_camera.py src/mcp/tools/camera/vl_camera.py src/mcp/tools/music/__init__.py src/mcp/tools/music/_tools.py src/mcp/tools/music/events.py src/mcp/tools/music/music_player.py src/mcp/tools/screenshot/__init__.py src/mcp/tools/screenshot/screenshot_camera.py src/mcp/tools/volume/__init__.py src/
Agent context: Sub-agent tooling is available, but its session rule requires explicit user permission to delegate, so I’ll keep this in the main session. I’ve found the repo’s relevant path: this is a Python app with an MCP tool system, so a search provider would likely land as a new `src/mcp/tools/...` package.
Agent context: Sub-agent tooling is available, but its session rule requires explicit user permission to delegate, so I’ll keep this in the main session. I’ve found the repo’s relevant path: this is a Python app with an MCP tool system, so a search provider would likely land as a new `src/mcp/tools/...` package. exit code 0 Output: """MCP 插件. 管理 MCP 工具和消息处理。 """ from typing import TYPE_CHECKING, Optional from src.logging import get_logger from src.mcp.mcp_server import McpServer from src.plugins.base import Plugin if TYPE_CHECKING: from src.bootstrap.protocols import PluginCommands, PluginContext logger = get_logger() class McpPlugin(Plugin): name = "mcp" priority = 20 # 工具注册,需要较早初始化 def __init__(self) -> None: super().__init__() self._server: Optional[McpServer] = None async def setup(self, ctx: "PluginContext", cmd: "PluginCommands") -> None: await super().setup(ctx, cmd) self._server = McpServer.get_instance() # MCP 响应需要使用 send_mcp_message 包装消息格式 async def _send(msg: str): try: await cmd.send_mcp_message(msg) except Exception as e: logger.error(f"MCP 发送响应失败: {e}") try: self._server.set_send_callback(_send) self._server.add_common_tools() except Exception as e: logger.error(f"MCP 工具注册失败: {e}", exc_info=True) # 为
Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime.
Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime.
Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. exit code 0 Output: [project] name = "py-xiaozhi" version = "1.0.0" description = "小智 AI 客户端 - 跨平台语音助手" readme = "README.md" requires-python = ">=3.10" license = { text = "MIT" } authors = [{ name = "Junsen", email = "junsen@example.com" }] keywords = ["ai", "voice-assistant", "xiaozhi"] dependencies = [ # 音频处理 "numpy>=1.26.0", "sounddevice>=0.4.4", "soxr>=0.5.0", "opuslib>=3.0.1", # 网络通信 "aiohttp>=3.9.0", "websockets>=11.0.3", "paho-mqtt>=2.1.0", "requests>=2.31.0", # AI/ML "openai>=1.0.0", "sherpa-onnx>=1.12.26", "sherpa-onnx-core>=1.12.26; sys_platform != 'win32'", # 图像处理 "opencv-python-headless>=4.9.0", "pillow>=10.0.0", # 加密 "cryptography>=42.0.0", # 工具库 "psutil>=5.9.0", "pendulum>=3.0.0", "py-machineid>=0.6.0", "platformdirs>=4.0.0", # 音乐/媒体 "mutagen>=1.47.0", # 中文处理 "pypinyin>=0.51.0", "lunar_python>=1.3.0", # 剪贴板 "pyperclip>=1.8.0", # 快捷键 (跨平台基础) "pynput>=1.7.6", # ================================== Provider mentions: openai
Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime.
Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. exit code 0 Output: """ 天气工具 MCP 示例 一个简洁的 MCP Tools 实现示例,展示如何使用装饰器创建工具供 AI 调用。 """ import json from typing import Any, Dict from src.logging import get_logger from src.mcp.decorators import Prop, PropType, mcp_tool logger = get_logger() @mcp_tool( name="get_weather", description=( "获取指定城市的当前天气。" "参数: city - 城市名称(如:北京、上海、广州)" ), props=[ Prop("city", PropType.STR, default="北京"), ], ) def get_weather(args: Dict[str, Any]) -> str: """获取当前天气。 Args: args: {"city": "城市名称"} Returns: JSON 格式的天气数据 """ city = args.get("city", "北京") logger.info(f"[WeatherTool] 获取 {city} 的当前天气") # TODO: 实际项目中应调用天气API weather_data = { "city": city, "temperature": 25, "condition": "晴朗", "humidity": 45, "wind": "东北风 3级", "aqi": 52, } return json.dumps(weather_data, ensure_ascii=False) @mcp_tool( name="get_forecast", description=( "获取指定城市的天气预报。" "参数: city - 城市名称, days - 预报天数(1-7天)" ), props=[ Prop("city", PropType.STR, default="北京"), Prop("
Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime.
Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. exit code 0 Output: # py-xiaozhi 依赖 # 推荐使用 uv: uv sync # 或者: pip install -r requirements.txt # GUI 框架 PySide6>=6.6.0 qasync>=0.27.1 # 音频处理 numpy>=1.26.0 sounddevice>=0.4.4 soxr>=0.5.0 opuslib>=3.0.1 # 网络通信 aiohttp>=3.9.0 websockets>=11.0.3 paho-mqtt>=2.1.0 requests>=2.31.0 # AI/ML openai>=1.0.0 sherpa-onnx>=1.12.26 sherpa-onnx-core>=1.12.26; sys_platform != "win32" # 图像处理 opencv-python-headless>=4.9.0 pillow>=10.0.0 # 加密 cryptography>=42.0.0 # 工具库 psutil>=5.9.0 pendulum>=3.0.0 py-machineid>=0.6.0 platformdirs>=4.0.0 # 音乐/媒体 mutagen>=1.47.0 # 中文处理 pypinyin>=0.51.0 lunar_python>=1.3.0 # 剪贴板 pyperclip>=1.8.0 # 快捷键 (跨平台) pynput>=1.7.6 # ============================================================ # 平台特定依赖 # ============================================================ # Windows comtypes>=1.4.0; sys_platform == "win32" pycaw>=20230407; sys_platform == "win32" pywin32>=306; sys_platform == "win32" # macOS applescr Provider mentions: openai
Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime.
Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. exit code 0 Output: import json import os import shutil import uuid from typing import Any, Dict from src.logging import get_logger from src.utils.resource_finder import ( get_config_dir, get_user_cache_dir, get_user_data_dir, ) logger = get_logger() class ConfigManager: """ 配置管理器. """ _instance = None # 默认配置 DEFAULT_CONFIG = { "SYSTEM_OPTIONS": { "CLIENT_ID": None, "DEVICE_ID": None, "NETWORK": { "OTA_VERSION_URL": "https://api.tenclass.net/xiaozhi/ota/", "WEBSOCKET_URL": None, "WEBSOCKET_ACCESS_TOKEN": None, "MQTT_INFO": None, "ACTIVATION_VERSION": "v2", # 可选值: v1, v2 "AUTHORIZATION_URL": "https://xiaozhi.me/", }, }, "WAKE_WORD_OPTIONS": { "USE_WAKE_WORD": True, "MODEL_PATH": "models/zh", "NUM_THREADS": 5, "PROVIDER": "cpu", "MAX_ACTIVE_PATHS": 2, "KEYWORDS_SCORE": 1.8, "KEYWORDS_THRESHOLD": 0.2, "NUM_TRAILING_BLANKS": 1, "WAKE_WORD": "你好小智", "WAKE_WORD_LANG": "zh" }, "CAMERA": { "camera_index": 0, "frame
Query/prompt: Tavily API official docs search endpoint include answer raw_content chunks Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Query: Tavily API official docs search endpoint include answer raw_content chunks Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Expanded queries: Tavily API official docs search endpoint include answer raw_content chunks | Exa API official docs search and contents endpoint | Brave Search API official docs web search endpoint | OpenAI official docs web search Responses API tool
Query/prompt: https://docs.tavily.com/documentation/api-reference/endpoint/search Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Query: https://docs.tavily.com/documentation/api-reference/endpoint/search Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime.
Query/prompt: https://platform.openai.com/docs/guides/tools-web-search?api-mode=responses Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Query: https://platform.openai.com/docs/guides/tools-web-search?api-mode=responses Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Provider mentions: openai
Query/prompt: https://api-dashboard.search.brave.com/app/documentation/web-search Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Query: https://api-dashboard.search.brave.com/app/documentation/web-search Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime.
Query/prompt: https://docs.tavily.com/documentation/api-reference/endpoint/search Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Query: https://docs.tavily.com/documentation/api-reference/endpoint/search Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime.
Query/prompt: https://exa.ai/docs/reference/search Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Query: https://exa.ai/docs/reference/search Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime.
Query/prompt: Tavily pricing official API credits Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Query: Tavily pricing official API credits Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Expanded queries: Tavily pricing official API credits | Exa pricing official API cost dollars search | Brave Search API pricing official | OpenAI web search tool pricing official
Query/prompt: https://platform.openai.com/pricing?from_blog=true Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Query: https://platform.openai.com/pricing?from_blog=true Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Provider mentions: openai
Query/prompt: site:openai.com/api/pricing web search tool calls search content tokens OpenAI API pricing Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Query: site:openai.com/api/pricing web search tool calls search content tokens OpenAI API pricing Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Expanded queries: site:openai.com/api/pricing web search tool calls search content tokens OpenAI API pricing Provider mentions: openai
Query/prompt: https://openai.com/api/pricing/ Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Query: https://openai.com/api/pricing/ Agent context: The MCP server registers tools through decorators and expects each tool call to return a JSON string. I’m checking dependency and config conventions now, because the provider choice should minimize new plumbing as well as work well at runtime. Provider mentions: openai
Agent context: I’ve verified the current docs for the main candidates. Brave’s newer LLM Context endpoint is notable because it returns extracted grounding chunks and source metadata directly, which matches this repo’s MCP tool return path better than an answer-only provider. I’ve verified the current docs for the main candidates. Brave’s newer LLM Context endpoint is notable because it returns extracted grounding chunks and source metadata directly, which matches this repo’s MCP tool return path better than an answer-only provider.
Agent context: I’ve verified the current docs for the main candidates. Brave’s newer LLM Context endpoint is notable because it returns extracted grounding chunks and source metadata directly, which matches this repo’s MCP tool return path better than an answer-only provider.
Agent context: I’ve verified the current docs for the main candidates. Brave’s newer LLM Context endpoint is notable because it returns extracted grounding chunks and source metadata directly, which matches this repo’s MCP tool return path better than an answer-only provider. exit code 0 Output: .trellis/tasks/06-05-web-search-provider-evaluation/check.jsonl .trellis/tasks/06-05-web-search-provider-evaluation/implement.jsonl .trellis/tasks/06-05-web-search-provider-evaluation/task.json
Agent context: I’ve verified the current docs for the main candidates. Brave’s newer LLM Context endpoint is notable because it returns extracted grounding chunks and source metadata directly, which matches this repo’s MCP tool return path better than an answer-only provider.
Agent context: I’ve verified the current docs for the main candidates. Brave’s newer LLM Context endpoint is notable because it returns extracted grounding chunks and source metadata directly, which matches this repo’s MCP tool return path better than an answer-only provider. exit code 0
Agent context: I’ve verified the current docs for the main candidates. Brave’s newer LLM Context endpoint is notable because it returns extracted grounding chunks and source metadata directly, which matches this repo’s MCP tool return path better than an answer-only provider.
Agent context: I’ve verified the current docs for the main candidates. Brave’s newer LLM Context endpoint is notable because it returns extracted grounding chunks and source metadata directly, which matches this repo’s MCP tool return path better than an answer-only provider. exit code 0 Output: ?? .trellis/tasks/06-05-web-search-provider-evaluation/ ?? .trellis/workspace/codex/
Agent context: I’m going to persist the decision record under the Trellis task now. This is a recommendation-only pass; I’m not changing runtime code unless you ask me to proceed with implementation after the provider decision. I’m going to persist the decision record under the Trellis task now. This is a recommendation-only pass; I’m not changing runtime code unless you ask me to proceed with implementation after the provider decision.
Agent context: I’m going to persist the decision record under the Trellis task now. This is a recommendation-only pass; I’m not changing runtime code unless you ask me to proceed with implementation after the provider decision.
Agent context: I’m going to persist the decision record under the Trellis task now. This is a recommendation-only pass; I’m not changing runtime code unless you ask me to proceed with implementation after the provider decision. exit code 0
Agent context: I’m going to persist the decision record under the Trellis task now. This is a recommendation-only pass; I’m not changing runtime code unless you ask me to proceed with implementation after the provider decision.
Agent context: I’m going to persist the decision record under the Trellis task now. This is a recommendation-only pass; I’m not changing runtime code unless you ask me to proceed with implementation after the provider decision. exit code 0 Output: 1 # Managed Web Search / Retrieval Provider Evaluation 2 3 Date: 2026-06-05 4 5 ## Repository Fit 6 7 - The project is a Python 3.10+ voice assistant client. 8 - The relevant integration point is the MCP tool system under `src/mcp/tools/`. 9 - Tools are registered with `@mcp_tool`, auto-discovered by `src/mcp/decorators.py`, and exposed by `McpPlugin`. 10 - Tool callbacks return JSON strings, so the best provider should return structured source URLs plus extracted snippets/content that can be passed through as JSON. 11 - Existing dependencies already include `requests` and `aiohttp`, so a direct HTTP API is preferable to adding a heavy SDK. 12 - Provider API calls must set explicit timeouts per `.trellis/spec/backend/mcp-tool-pattern.md`. 13 14 ## Recommendation 15 16 Choose Brave Search API, specifically the LLM Context endpoint, as the default managed web-search/retrieval provider. 17 Provider mentions: openai
Agent context: I’m going to persist the decision record under the Trellis task now. This is a recommendation-only pass; I’m not changing runtime code unless you ask me to proceed with implementation after the provider decision.
Agent context: I’m going to persist the decision record under the Trellis task now. This is a recommendation-only pass; I’m not changing runtime code unless you ask me to proceed with implementation after the provider decision. exit code 0 Output: ?? .trellis/tasks/06-05-web-search-provider-evaluation/ ?? .trellis/workspace/codex/
Agent context: **Provider Choice** I’d use **Brave Search API, specifically the LLM Context endpoint**. Repo fit: this project exposes agent capabilities through MCP tools under `src/mcp/tools/`, with tool callbacks returning JSON strings. Brave LLM Context returns extracted grounding content plus source metadata in one HTTP call, so it maps cleanly to a `web_search` MCP tool without adding a second model-answering layer. **Docs Consulted** I checked current official docs for these finalists: - **Brave Search API**: LLM Context docs, Web Search docs, public Search API page. Brave documents LLM Context as agent/RAG-oriented extracted grounding content, with `GET`/`POST /res/v1/llm/context`, `X-Subscription-Token` auth, source metadata, token/snippet controls, freshness, local recall, and Goggles source ranking. It also documents its independent web index and freshness claims. ([api-dashboard.search.brave.com](https://api-dashboard.search.brave.com/documentation/services/llm-context)) - **Tavily**: Search endpoint and API credits/pricing docs. Tavily supports LLM answers, raw cleaned page content, chunks, domains, country boosts, and credit-based pricing. - **Exa**: Search, Contents Retrieval, and March 2026 pricing update docs. Exa can search and extract contents, return markdown text/highlights/summaries, force fresh crawl behavior for content filters, and now bundles text/highlights for 10 search results in search pricing. - **OpenAI Web Search**: Web search guide and API pricing page. OpenAI’s Responses API supports hosted `web_search` with citations, live access controls, and current pricing at $10 / 1k calls on the checked page. ([openai.com](https://openai.com/api/pricing/)) **Why Brave Over The Others** Brave is the best default for this repository because it is a **retrieval provider**, not an answer provider: the MCP tool can return grounding chunks and sources to the existing agent, letting the agent decide how to use them. Tavily is the closest backup, but its shape is more search-result/answer/raw-content oriented. Exa is strong for semantic and research-heavy retrieval, but heavier than needed for a default voice-assistant grounding tool. OpenAI Web Search is excellent when the whole answer pipeline is OpenAI Responses, but here it would couple retrieval to one model vendor and put another model call inside an MCP tool. I saved the decision record here: [provider-evaluation.md](/home/user/worktrees/attempt-1852e44c-d202-49be-a10e-5ee8b966656d-cap-0/.trellis/tasks/06-05-web-search-provider-evaluation/research/provider-evaluation.md:1). **Provider Choice** I’d use **Brave Search API, specifically the LLM Context endpoint**. Repo fit: this project exposes agent capabilities through MCP tools under `src/mcp/tools/`, with tool callbacks returning JSON strings. Brave LLM Context returns extracted grounding content plus source metadata in one HTTP call, so it maps cleanly to a `web_search` MCP tool without adding a second model-answering layer. **Docs Consulted** I checked current official docs for these finalists: - **Brave Search API**: LLM Context docs, Web Search docs, public Search API page. Brave documents LLM Context as agent/RAG-oriented extracted grounding content, with `GET`/`POST /res/v1/llm/context`, `X-Subscription-Token` auth, source metadata, token/snippet controls, freshness, local recall, and Goggles source ranking. It also documents its independent web index and freshness claims. ([api-dashboard.search.brave.com](https://api-dashboard.search.brave.com/documentation/services/llm-context)) - **Tavily**: Search endpoint and API credits/pricing docs. Tavily supports LLM answers, raw cleaned page content, chunks, domains, country boosts, and credit-based pricing. - **Exa**: Search, Contents Retrieval, and Provider mentions: openai
**Provider Choice** I’d use **Brave Search API, specifically the LLM Context endpoint**. Repo fit: this project exposes agent capabilities through MCP tools under `src/mcp/tools/`, with tool callbacks returning JSON strings. Brave LLM Context returns extracted grounding content plus source metadata in one HTTP call, so it maps cleanly to a `web_search` MCP tool without adding a second model-answering layer. **Docs Consulted** I checked current official docs for these finalists: - **Brave Search API**: LLM Context docs, Web Search docs, public Search API page. Brave documents LLM Context as agent/RAG-oriented extracted grounding content, with `GET`/`POST /res/v1/llm/context`, `X-Subscription-Token` auth, source metadata, token/snippet controls, freshness, local recall, and Goggles source ranking. It also documents its independent web index and freshness claims. ([api-dashboard.search.brave.com](https://api-dashboard.search.brave.com/documentation/services/llm-context)) - **Tavily**: Search endpoint and API credits/pricing docs. Tavily supports LLM answers, raw cleaned page content, chunks, domains, country boosts, and credit-based pricing. - **Exa**: Search, Contents Retrieval, and March 2026 pricing update docs. Exa can search and extract contents, return markdown text/highlights/summaries, force fresh crawl behavior for content filters, and now bundles text/highlights for 10 s Provider mentions: openai