mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-10-26 10:45:22 +00:00
feat(pi-web-search): 统一 web_search/web_fetch 并由主模型路由搜索厂商
7 个按厂商命名的搜索工具收敛为 2 个统一工具,schema 与提示词不再暴露 provider 概念:web_search 由当前主模型按内置规则在 Tavily/Exa/Keenable 间路由(会话内 LRU 缓存,失败按可用性降级),web_fetch 固定走 Exa 并 静默降级。三家均改为纯 fetch 直连——Exa 直接对 mcp.exa.ai 发 JSON-RPC 并缓存会话,彻底移除 pi-mcp-adapter、@tavily/pi-extension 与 @keenable/pi-search 依赖。 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
parent
6fe6cb29ae
commit
ee1e6999d7
@@ -32,9 +32,7 @@ Run `/tool-search-status` to inspect the current catalog source, pinned count, d
|
||||
| `ssh-remote-search` | `ssh_find`, `ssh_grep` |
|
||||
| `ssh-remote-shell` | `ssh_cd`, `ssh_bash` |
|
||||
| `code-intelligence` | CodeGraph and all LSP tools |
|
||||
| `web-tavily` | Tavily search/fetch |
|
||||
| `web-exa` | Exa search/advanced/fetch |
|
||||
| `web-keenable` | Keenable search/fetch |
|
||||
| `web-search` | `web_search`, `web_fetch` (pi-web-search unified tools) |
|
||||
| `context-execution` | `ctx_execute`, `ctx_execute_file`, `ctx_batch_execute` |
|
||||
| `context-knowledge` | Context indexing, searching, and web-doc ingestion |
|
||||
| `context-observability` | Context stats, doctor, and Insight |
|
||||
@@ -55,7 +53,7 @@ Pinned tools are removed from these dynamic groups at runtime. The defaults pin
|
||||
Call `tool_search` with an exact catalog group id when possible:
|
||||
|
||||
```json
|
||||
{ "group": "web-tavily" }
|
||||
{ "group": "web-search" }
|
||||
```
|
||||
|
||||
A workflow can atomically activate up to five exact groups in one call. The complete request must fit the configured group and tool limits; otherwise no active state is changed:
|
||||
@@ -114,7 +112,7 @@ Example override:
|
||||
```json
|
||||
{
|
||||
"groupOverrides": {
|
||||
"web-tavily": ["tavily_web_search", "tavily_web_fetch"],
|
||||
"web-search": ["web_search", "web_fetch"],
|
||||
"lsp": ["lsp_definition", "lsp_references", "lsp_hover", "lsp_symbols", "lsp_diagnostics"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,31 +77,13 @@ export const BUNDLE_GROUP_DEFINITIONS: BundleGroupDefinition[] = [
|
||||
tools: ["codegraph_explore", "lsp_definition", "lsp_references", "lsp_hover", "lsp_symbols", "lsp_diagnostics"],
|
||||
},
|
||||
{
|
||||
id: "web-tavily",
|
||||
title: "Tavily web discovery",
|
||||
summary: "Discover broad, current, or news-oriented web sources with Tavily and fetch selected pages.",
|
||||
useWhen: ["Keywords are uncertain, many candidate sources help, or current/news coverage is needed"],
|
||||
avoidWhen: ["Official technical sources or Chinese site/date constraints are more important"],
|
||||
keywords: ["tavily", "web", "news", "discovery", "网页", "新闻", "广泛搜索"],
|
||||
tools: ["tavily_web_search", "tavily_web_fetch"],
|
||||
},
|
||||
{
|
||||
id: "web-exa",
|
||||
title: "Exa precision research",
|
||||
summary: "Find precise official, technical, academic, company, or API sources with Exa and read selected pages.",
|
||||
useWhen: ["Source precision, official documentation, papers, releases, or advanced filters matter"],
|
||||
avoidWhen: ["Broad news discovery or Chinese policy search is the primary need"],
|
||||
keywords: ["exa", "official docs", "paper", "api", "research", "官方文档", "论文", "精确搜索"],
|
||||
tools: ["exa_web_search", "exa_web_search_advanced", "exa_web_fetch"],
|
||||
},
|
||||
{
|
||||
id: "web-keenable",
|
||||
title: "Keenable focused search",
|
||||
summary: "Search Chinese-language, site-restricted, policy, government, or date-filtered sources and fetch selected pages.",
|
||||
useWhen: ["Chinese pages, policies, government notices, domain restrictions, or publication dates matter"],
|
||||
avoidWhen: ["Broad international discovery or academic semantic search is a better fit"],
|
||||
keywords: ["keenable", "Chinese", "policy", "site", "date", "中文", "政策", "站点", "日期"],
|
||||
tools: ["keenable_search", "keenable_fetch"],
|
||||
id: "web-search",
|
||||
title: "Web search and fetch",
|
||||
summary: "Search the web for current or citable information and read selected pages as clean markdown.",
|
||||
useWhen: ["Current events, external facts, documentation, papers, or page content are needed"],
|
||||
avoidWhen: ["The answer is already in the workspace or local code tools suffice"],
|
||||
keywords: ["web", "search", "fetch", "news", "docs", "网页", "搜索", "新闻", "文档"],
|
||||
tools: ["web_search", "web_fetch"],
|
||||
},
|
||||
{
|
||||
id: "context-execution",
|
||||
|
||||
@@ -26,7 +26,7 @@ test("bundle seed names are unique and cover the declared my-pi tools", () => {
|
||||
assert.equal(result.coveredNames.size, names.length);
|
||||
assert.equal(result.catalog.tools.length, names.length);
|
||||
assert.equal(result.catalog.tools.find((card) => card.name === "ctx_purge")?.primaryGroup, "context-administration");
|
||||
assert.equal(result.catalog.tools.find((card) => card.name === "tavily_web_fetch")?.primaryGroup, "web-tavily");
|
||||
assert.equal(result.catalog.tools.find((card) => card.name === "web_fetch")?.primaryGroup, "web-search");
|
||||
assert.equal(result.catalog.tools.find((card) => card.name === "memory_search")?.primaryGroup, "memory-recall");
|
||||
assert.equal(result.catalog.tools.find((card) => card.name === "session_search")?.primaryGroup, "memory-recall");
|
||||
assert.equal(result.catalog.tools.find((card) => card.name === "memory_add")?.primaryGroup, "memory-management");
|
||||
@@ -51,11 +51,11 @@ test("bundle seed names are unique and cover the declared my-pi tools", () => {
|
||||
});
|
||||
|
||||
test("user overrides take priority and unknown tools retain deterministic fallback groups", () => {
|
||||
const tools = [tool("tavily_web_search"), tool("custom_analyze")];
|
||||
const configured = { maxToolsPerGroup: 8, groupOverrides: { preferred: ["tavily_web_search"] } };
|
||||
const tools = [tool("web_search"), tool("custom_analyze")];
|
||||
const configured = { maxToolsPerGroup: 8, groupOverrides: { preferred: ["web_search"] } };
|
||||
const hash = buildManifestHash(tools, configured);
|
||||
const result = createBundleCatalog(tools, hash, configured);
|
||||
assert.deepEqual(result.unknownTools.map((item) => item.name), ["custom_analyze"]);
|
||||
assert.equal(result.catalog.tools.find((card) => card.name === "tavily_web_search")?.primaryGroup, "preferred");
|
||||
assert.equal(result.catalog.tools.find((card) => card.name === "web_search")?.primaryGroup, "preferred");
|
||||
assert.equal(result.catalog.tools.find((card) => card.name === "custom_analyze")?.primaryGroup, "custom");
|
||||
});
|
||||
|
||||
@@ -174,8 +174,8 @@ test("builds and caches a validated catalog with the current model on first sear
|
||||
const prompts: string[] = [];
|
||||
const sourceTools = [
|
||||
sourceTool("read", "Read a file"),
|
||||
sourceTool("web_search", "Search the public web with filters and return sources"),
|
||||
sourceTool("web_fetch", "Fetch the complete content of a selected web page"),
|
||||
sourceTool("research_search", "Search the public web with filters and return sources"),
|
||||
sourceTool("research_fetch", "Fetch the complete content of a selected web page"),
|
||||
];
|
||||
const api = {
|
||||
getAllTools: () => sourceTools,
|
||||
@@ -197,12 +197,12 @@ test("builds and caches a validated catalog with the current model on first sear
|
||||
summary: "Search and fetch current web sources.",
|
||||
useWhen: ["Current external facts are needed"],
|
||||
avoidWhen: ["The answer is entirely local"],
|
||||
tools: ["web_search", "web_fetch"],
|
||||
tools: ["research_search", "research_fetch"],
|
||||
},
|
||||
],
|
||||
tools: [
|
||||
{ name: "web_search", summary: "Find web sources.", useWhen: ["Discover sources"], avoidWhen: [], keywords: ["search", "搜索"], primaryGroup: "web-research" },
|
||||
{ name: "web_fetch", summary: "Read a selected source.", useWhen: ["A URL is known"], avoidWhen: [], keywords: ["fetch", "抓取"], primaryGroup: "web-research" },
|
||||
{ name: "research_search", summary: "Find web sources.", useWhen: ["Discover sources"], avoidWhen: [], keywords: ["search", "搜索"], primaryGroup: "web-research" },
|
||||
{ name: "research_fetch", summary: "Read a selected source.", useWhen: ["A URL is known"], avoidWhen: [], keywords: ["fetch", "抓取"], primaryGroup: "web-research" },
|
||||
],
|
||||
};
|
||||
const usage = { input: 1, output: 1, cacheRead: 0, cacheWrite: 0, totalTokens: 2, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } };
|
||||
@@ -250,8 +250,8 @@ test("uses the precomputed bundle groups without calling a model", async () => {
|
||||
let modelCalls = 0;
|
||||
const sourceTools = [
|
||||
sourceTool("read", "Read a file"),
|
||||
sourceTool("tavily_web_search", "Search broadly for current web sources"),
|
||||
sourceTool("tavily_web_fetch", "Fetch a selected Tavily source"),
|
||||
sourceTool("web_search", "Search broadly for current web sources"),
|
||||
sourceTool("web_fetch", "Fetch a selected web source"),
|
||||
sourceTool("ctx_execute", "Run commands in a context sandbox"),
|
||||
sourceTool("ctx_execute_file", "Analyze a file in a context sandbox"),
|
||||
sourceTool("ctx_batch_execute", "Run a bounded command batch"),
|
||||
@@ -292,12 +292,12 @@ test("uses the precomputed bundle groups without calling a model", async () => {
|
||||
|
||||
const result = await registered.get("tool_search")?.execute(
|
||||
"call-2",
|
||||
{ query: "tavily_web_search" },
|
||||
{ query: "web_search" },
|
||||
undefined,
|
||||
undefined,
|
||||
ctx,
|
||||
);
|
||||
assert.equal(result?.details.loadedGroup, "web-tavily");
|
||||
assert.equal(result?.details.loadedGroup, "web-search");
|
||||
assert.equal(result?.details.catalogSource, "bundle");
|
||||
assert.equal(modelCalls, 0);
|
||||
await assert.rejects(readFile(join(agentDir, "my-pi", "tool-search", "catalog-v1.json"), "utf8"), /ENOENT/);
|
||||
@@ -337,8 +337,8 @@ test("loads an exact known group without waiting for unknown-tool model enrichme
|
||||
let modelCalls = 0;
|
||||
const sourceTools = [
|
||||
sourceTool("read", "Read a file"),
|
||||
sourceTool("tavily_web_search", "Search broadly for current web sources"),
|
||||
sourceTool("tavily_web_fetch", "Fetch a selected Tavily source"),
|
||||
sourceTool("web_search", "Search broadly for current web sources"),
|
||||
sourceTool("web_fetch", "Fetch a selected web source"),
|
||||
sourceTool("unrecognized_extra", "An unrecognized third-party capability"),
|
||||
];
|
||||
const api = {
|
||||
@@ -366,12 +366,12 @@ test("loads an exact known group without waiting for unknown-tool model enrichme
|
||||
|
||||
const result = await registered.get("tool_search")?.execute(
|
||||
"call-1",
|
||||
{ group: "web-tavily" },
|
||||
{ group: "web-search" },
|
||||
undefined,
|
||||
undefined,
|
||||
ctx,
|
||||
);
|
||||
assert.equal(result?.details.loadedGroup, "web-tavily");
|
||||
assert.equal(result?.details.loadedGroup, "web-search");
|
||||
assert.equal(result?.details.catalogSource, "hybrid");
|
||||
assert.equal(modelCalls, 0);
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user