此前截断分散在多层且互相冲突:Pi bash 保留尾部 50KB,RTK 兜底截断又只留 开头 12000 字符(砍掉报错与完整输出路径),pi-chrome 截开头 30K,web_fetch 各 provider 不一致。新扩展统一负责"新结果给模型看多少": - capture.ts 最先加载暂存原文,index.ts 最后加载(system-prompt 之前) - 超过 24K 字符时原文落盘 <agentDir>/my-pi/pi-overflow/(700/600、原子写), 优先取 bash fullOutputPath 完整文件;模型看到 头 + 中段信号行 + 尾 的有界 视图,行号基于落盘原文、结尾永远可见 - overflow_query:按 id 正则搜索、行区间、jsonPath 只读查询,id 校验防穿越 - 收编:RTK truncate 默认关闭、删除 pi-chrome truncateText、web_fetch 默认 每页 20000(上限 100000)、web_search max_results 限定 1–20 - pi-compaction 遮蔽带 details.overflow.id 的结果时在占位符提示 overflow_query - 登记 tools.jsonc / routing / 权限 allow / tool-search 常驻与分组 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2.4 KiB
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_resultsdefaults to 8 and is clamped to 1–20. Results includedetails.provider/details.routedByfor debugging.web_fetch(urls, max_characters?)always reads pages via Exa (web_fetch_exa), degrading silently to Keenable then Tavily.max_charactersdefaults 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 atavilycredential.clients/keenable.ts—api.keenable.ai, keyless/publicendpoints by default, akeenablecredential raises rate limits. Adapted from@keenable/pi-search.clients/exa.ts— JSON-RPC overmcp.exa.ai/mcp(Streamable HTTP):initializeonce, cachemcp-session-id,tools/callper request, re-init on session expiry. Anexacredential is optional (x-api-keyheader).
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 (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.