feat(pi-web-search): 搜索凭据迁移到 Pi auth.json

三个搜索 key 改为 auth.json 中的 tavily/exa/keenable api_key 凭据,
pi-web-search/auth.ts 复刻上游 resolve-config-value 语义(!command、
$VAR 插值、credential env 优先、$$/$! 转义)并在每次调用时读取,
进程环境变量与 search.env 不再被直接读取。search_config.sh 重写为
scripts/search-auth.mjs 的薄封装:加锁原子写、权限 600、保留其他
凭据条目,支持 --migrate 从旧 search.env 一次性导入。

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
云服务部-叶林立
2026-10-19 20:39:13 -07:00
co-authored by Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
parent ee1e6999d7
commit 0c9823ef5c
20 changed files with 909 additions and 335 deletions
+5 -2
View File
@@ -2,9 +2,12 @@
* Exa client: direct JSON-RPC over the hosted endpoint https://mcp.exa.ai/mcp.
* This is a plain HTTPS POST client (no MCP adapter, no SDK): initialize once,
* cache the `mcp-session-id` response header, then POST `tools/call` per call.
* Keyless works; EXA_API_KEY is sent as the `x-api-key` header when present.
* Keyless works; the `exa` api_key credential from auth.json is sent as the
* `x-api-key` header when present.
*/
import { getSearchApiKey } from "../auth.ts";
export class ExaError extends Error {}
const EXA_MCP_URL = "https://mcp.exa.ai/mcp?tools=web_search_exa,web_search_advanced_exa,web_fetch_exa";
@@ -41,7 +44,7 @@ function baseHeaders(): Record<string, string> {
"content-type": "application/json",
accept: "application/json, text/event-stream",
};
const key = process.env.EXA_API_KEY?.trim();
const key = getSearchApiKey("exa");
if (key) headers["x-api-key"] = key;
return headers;
}