Files
云服务部-叶林立andDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> f9a7f743dd feat: 接入 Pi 内置 codemode,并修复全面审查发现的问题
- codemode:Tool Search 常驻(alwaysEnabled)、权限 allow(嵌套调用仍逐个过权限门)、
  tools.jsonc 登记使用规则;RTK 跳过 parentToolCallId 嵌套调用,避免丢失 bash
  structuredContent;Tool Search 目录过滤 hidden / codemode(script-only)exposure;
  扩展加载测试加载 builtin:codemode 并断言其常驻激活
- 搜索 key 不再经命令行参数传递:search-auth.mjs 改为 --set-stdin(先读校验再加锁),
  configure.sh 交互输入经管道、非交互用 --<provider> -
- CodeGraph 客户端监听子进程 stdin error,避免 EPIPE 未处理导致崩溃
- 移除 PI_TOOL_SEARCH/HERMES_MEMORY/RTK_CONFIG_PATH 环境变量入口,测试改用工厂 configPath 注入
- pi-subagents 固定 vitest / coverage-istanbul 4.1.10,修复 npm ls 版本冲突
- 补 pi-web-search / pi-worktree UPSTREAM.md 与 pi-minimal-footer AGENTS.md,
  files 白名单补齐并加测试;.codegraph/.gitignore 移出跟踪
- detect_kitty 优先识别官方安装目录

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-21 23:18:34 -07:00
..

pi-web-search

Unified web search and fetch for Pi. The main model only ever sees two tools — web_search and web_fetch — provider selection happens inside the extension.

  • web_search(query, max_results?, site?, published_after?, published_before?, depth?) routes each query to Tavily, Exa, or Keenable using the session's current main model (ctx.model + ctx.modelRegistry.complete), guided by per-provider rules. max_results defaults to 8 and is clamped to 1–20. Results include details.provider / details.routedBy for debugging.
  • web_fetch(urls, max_characters?) always reads pages via Exa (web_fetch_exa), degrading silently to Keenable then Tavily. max_characters defaults to 20,000 and is clamped to 1–100,000 per page; oversized fetch output is further bounded by pi-overflow downstream.

Providers (clients/)

Plain fetch calls — no MCP adapter, no upstream extension wrappers:

  • clients/tavily.ts — POST api.tavily.com/search|extract, Bearer key. Requires a tavily credential.
  • clients/keenable.ts — api.keenable.ai, keyless /public endpoints by default, a keenable credential raises rate limits. Adapted from @keenable/pi-search.
  • clients/exa.ts — JSON-RPC over mcp.exa.ai/mcp (Streamable HTTP): initialize once, cache mcp-session-id, tools/call per request, re-init on session expiry. An exa credential is optional (x-api-key header).

Keys live in Pi's auth.json as one api_key credential per provider (tavily, exa, keenable), read by auth.ts with upstream resolution semantics — literal values, $VAR/${VAR} interpolation, and !command indirection (e.g. "!op read op://Vault/Tavily/key"). configure.sh search writes them via its hidden interactive prompt or scripts/search-auth.mjs --set-stdin reading the key from stdin — a key is never accepted as a command-line argument (atomically, mode 600, preserving all other entries); process environment variables are not read directly — use "key": "$TAVILY_API_KEY" to indirect through env. KEENABLE_API_URL stays env-only, or can be stored in the keenable credential's env map.

Routing

router.ts asks the current model to answer with exactly one provider name, given a prompt containing the per-provider strengths and the query's requested filters. Decisions are cached per session (LRU, 32 entries). Failure paths are deterministic: an unroutable answer or a dead provider falls back across the remaining available providers — never a heuristic choice over the model.