@astralyn/pi 0.84.13 → 0.84.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/dist/extensions/web-search/constants.d.ts +2 -2
- package/dist/extensions/web-search/constants.d.ts.map +1 -1
- package/dist/extensions/web-search/constants.js +4 -5
- package/dist/extensions/web-search/constants.js.map +1 -1
- package/dist/extensions/web-search/execute.d.ts +13 -0
- package/dist/extensions/web-search/execute.d.ts.map +1 -0
- package/dist/extensions/web-search/execute.js +101 -0
- package/dist/extensions/web-search/execute.js.map +1 -0
- package/dist/extensions/web-search/format.d.ts +12 -0
- package/dist/extensions/web-search/format.d.ts.map +1 -0
- package/dist/extensions/web-search/format.js +88 -0
- package/dist/extensions/web-search/format.js.map +1 -0
- package/dist/extensions/web-search/index.js +2 -2
- package/dist/extensions/web-search/index.js.map +1 -1
- package/dist/extensions/web-search/providers/deepseek.d.ts +0 -2
- package/dist/extensions/web-search/providers/deepseek.d.ts.map +1 -1
- package/dist/extensions/web-search/providers/deepseek.js +51 -34
- package/dist/extensions/web-search/providers/deepseek.js.map +1 -1
- package/dist/extensions/web-search/providers/http.d.ts.map +1 -1
- package/dist/extensions/web-search/providers/http.js +68 -6
- package/dist/extensions/web-search/providers/http.js.map +1 -1
- package/dist/extensions/web-search/providers/minimax.d.ts +0 -2
- package/dist/extensions/web-search/providers/minimax.d.ts.map +1 -1
- package/dist/extensions/web-search/providers/minimax.js +33 -52
- package/dist/extensions/web-search/providers/minimax.js.map +1 -1
- package/dist/extensions/web-search/render.d.ts +1 -2
- package/dist/extensions/web-search/render.d.ts.map +1 -1
- package/dist/extensions/web-search/render.js +6 -12
- package/dist/extensions/web-search/render.js.map +1 -1
- package/dist/extensions/web-search/results.d.ts +28 -0
- package/dist/extensions/web-search/results.d.ts.map +1 -0
- package/dist/extensions/web-search/results.js +154 -0
- package/dist/extensions/web-search/results.js.map +1 -0
- package/dist/extensions/web-search/schema.d.ts +0 -2
- package/dist/extensions/web-search/schema.d.ts.map +1 -1
- package/dist/extensions/web-search/schema.js +4 -25
- package/dist/extensions/web-search/schema.js.map +1 -1
- package/dist/extensions/web-search/types.d.ts +0 -62
- package/dist/extensions/web-search/types.d.ts.map +1 -1
- package/dist/extensions/web-search/types.js.map +1 -1
- package/docs/bundled/extensions/web-search.md +6 -10
- package/docs/docs.json +4 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/extensions/web-search/fusion.d.ts +0 -36
- package/dist/extensions/web-search/fusion.d.ts.map +0 -1
- package/dist/extensions/web-search/fusion.js +0 -272
- package/dist/extensions/web-search/fusion.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@ This file records `@astralyn/pi` releases beginning with the first Fork-owned re
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.84.14] - 2026-09-01
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Simplified `web_search` tool metadata so its capability description, session-wide routing guidance, and conditional result instructions live in their canonical prompt layers.
|
|
12
|
+
- Reworked dual-provider result fusion to use reciprocal-rank scoring, preserving high-ranked unique results from both engines instead of allowing the first provider to fill the output cap.
|
|
13
|
+
- Reworded search-result trust labels: provider overlap is now described as `found by MiniMax & DeepSeek`, and generated analysis is explicitly labeled `DeepSeek Search Synthesis`, avoiding claims of independent verification or authority.
|
|
14
|
+
|
|
15
|
+
### Removed
|
|
16
|
+
|
|
17
|
+
- Removed the `allowed_domains` and `blocked_domains` parameters from `web_search`, together with provider-specific query rewriting and local URL filtering.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Scoped `web_search` citation guidance to successful tool results instead of injecting it into every session through `promptGuidelines`. Result payloads now ask naturally for relevant URL citations only when structured sources exist, without requiring a `Sources:` heading or Markdown link format.
|
|
22
|
+
- Preserved caller cancellation across concurrent searches, fixed URL normalization around trailing path/query slashes, upgraded fallback URL titles during deduplication, and restored the warning renderer for disabled results.
|
|
23
|
+
- Added strict local bounds and Markdown-safe formatting for provider-controlled titles, URLs, snippets, synthesis, related searches, and errors; oversized or malformed source responses no longer flow unbounded into the model context.
|
|
24
|
+
|
|
7
25
|
## [0.84.13] - 2026-09-01
|
|
8
26
|
|
|
9
27
|
### Added
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
import type { SearchEngineType } from "./types.ts";
|
|
5
5
|
export declare const WEB_SEARCH_TOOL_NAME = "web_search";
|
|
6
6
|
export declare const WEB_SEARCH_LABEL = "Web Search";
|
|
7
|
-
export declare const WEB_SEARCH_DESCRIPTION = "Search the web
|
|
8
|
-
export declare const WEB_SEARCH_PROMPT_SNIPPET = "Search the web for
|
|
7
|
+
export declare const WEB_SEARCH_DESCRIPTION = "Search the live web through configured MiniMax and DeepSeek providers. When both are available, searches run concurrently and results are deduplicated and fused. Returns up to 12 source URLs with bounded titles and snippets, plus related searches and optional synthesis; partial provider failures still return successful results.";
|
|
8
|
+
export declare const WEB_SEARCH_PROMPT_SNIPPET = "Search the live web for current information";
|
|
9
9
|
export declare const WEB_SEARCH_DISABLED_MESSAGE = "Web search is disabled: Neither MiniMax nor DeepSeek API Key was found in auth.json or environment variables. Please add credentials via auth.json or environment variables (MINIMAX_API_KEY, DEEPSEEK_API_KEY).";
|
|
10
10
|
/** Canonical display label for the contributing engine set ("" when none). */
|
|
11
11
|
export declare function getEngineLabel(engine: SearchEngineType | undefined): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/extensions/web-search/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,eAAO,MAAM,oBAAoB,eAAe,CAAC;AACjD,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAE7C,eAAO,MAAM,sBAAsB,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/extensions/web-search/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,eAAO,MAAM,oBAAoB,eAAe,CAAC;AACjD,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAE7C,eAAO,MAAM,sBAAsB,8UACyS,CAAC;AAE7U,eAAO,MAAM,yBAAyB,gDAAgD,CAAC;AAEvF,eAAO,MAAM,2BAA2B,qNAC2K,CAAC;AAEpN,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,GAAG,MAAM,CAK3E;AAED,wBAAgB,4BAA4B,IAAI,MAAM,EAAE,CAMvD"}
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const WEB_SEARCH_TOOL_NAME = "web_search";
|
|
5
5
|
export const WEB_SEARCH_LABEL = "Web Search";
|
|
6
|
-
export const WEB_SEARCH_DESCRIPTION = "Search the web
|
|
7
|
-
export const WEB_SEARCH_PROMPT_SNIPPET = "Search the web for
|
|
6
|
+
export const WEB_SEARCH_DESCRIPTION = "Search the live web through configured MiniMax and DeepSeek providers. When both are available, searches run concurrently and results are deduplicated and fused. Returns up to 12 source URLs with bounded titles and snippets, plus related searches and optional synthesis; partial provider failures still return successful results.";
|
|
7
|
+
export const WEB_SEARCH_PROMPT_SNIPPET = "Search the live web for current information";
|
|
8
8
|
export const WEB_SEARCH_DISABLED_MESSAGE = "Web search is disabled: Neither MiniMax nor DeepSeek API Key was found in auth.json or environment variables. Please add credentials via auth.json or environment variables (MINIMAX_API_KEY, DEEPSEEK_API_KEY).";
|
|
9
9
|
/** Canonical display label for the contributing engine set ("" when none). */
|
|
10
10
|
export function getEngineLabel(engine) {
|
|
@@ -19,9 +19,8 @@ export function getEngineLabel(engine) {
|
|
|
19
19
|
export function getWebSearchPromptGuidelines() {
|
|
20
20
|
const currentYearMonth = new Date().toISOString().slice(0, 7);
|
|
21
21
|
return [
|
|
22
|
-
"Use `web_search`
|
|
23
|
-
|
|
24
|
-
`IMPORTANT: The current date is ${currentYearMonth}. Use the current year in search queries when seeking recent documentation, releases, or current events.`,
|
|
22
|
+
"Use `web_search` for current information, recent releases, live documentation, and other freshness-sensitive facts beyond your training cutoff.",
|
|
23
|
+
`When using \`web_search\` for freshness-sensitive topics, account for the current date (${currentYearMonth}) and include the year in the query when useful.`,
|
|
25
24
|
];
|
|
26
25
|
}
|
|
27
26
|
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/extensions/web-search/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,CAAC,MAAM,oBAAoB,GAAG,YAAY,CAAC;AACjD,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC;AAE7C,MAAM,CAAC,MAAM,sBAAsB,GAClC,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/extensions/web-search/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,CAAC,MAAM,oBAAoB,GAAG,YAAY,CAAC;AACjD,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC;AAE7C,MAAM,CAAC,MAAM,sBAAsB,GAClC,2UAA2U,CAAC;AAE7U,MAAM,CAAC,MAAM,yBAAyB,GAAG,6CAA6C,CAAC;AAEvF,MAAM,CAAC,MAAM,2BAA2B,GACvC,kNAAkN,CAAC;AAEpN,8EAA8E;AAC9E,MAAM,UAAU,cAAc,CAAC,MAAoC;IAClE,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,oBAAoB,CAAC;IACnD,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC3C,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,UAAU,CAAC;IAC7C,OAAO,EAAE,CAAC;AACX,CAAC;AAED,MAAM,UAAU,4BAA4B;IAC3C,MAAM,gBAAgB,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9D,OAAO;QACN,iJAAiJ;QACjJ,2FAA2F,gBAAgB,kDAAkD;KAC7J,CAAC;AACH,CAAC","sourcesContent":["/**\n * constants.ts — web_search tool identity, descriptions, and model-facing guidelines.\n */\n\nimport type { SearchEngineType } from \"./types.ts\";\n\nexport const WEB_SEARCH_TOOL_NAME = \"web_search\";\nexport const WEB_SEARCH_LABEL = \"Web Search\";\n\nexport const WEB_SEARCH_DESCRIPTION =\n\t\"Search the live web through configured MiniMax and DeepSeek providers. When both are available, searches run concurrently and results are deduplicated and fused. Returns up to 12 source URLs with bounded titles and snippets, plus related searches and optional synthesis; partial provider failures still return successful results.\";\n\nexport const WEB_SEARCH_PROMPT_SNIPPET = \"Search the live web for current information\";\n\nexport const WEB_SEARCH_DISABLED_MESSAGE =\n\t\"Web search is disabled: Neither MiniMax nor DeepSeek API Key was found in auth.json or environment variables. Please add credentials via auth.json or environment variables (MINIMAX_API_KEY, DEEPSEEK_API_KEY).\";\n\n/** Canonical display label for the contributing engine set (\"\" when none). */\nexport function getEngineLabel(engine: SearchEngineType | undefined): string {\n\tif (engine === \"dual\") return \"MiniMax & DeepSeek\";\n\tif (engine === \"minimax\") return \"MiniMax\";\n\tif (engine === \"deepseek\") return \"DeepSeek\";\n\treturn \"\";\n}\n\nexport function getWebSearchPromptGuidelines(): string[] {\n\tconst currentYearMonth = new Date().toISOString().slice(0, 7);\n\treturn [\n\t\t\"Use `web_search` for current information, recent releases, live documentation, and other freshness-sensitive facts beyond your training cutoff.\",\n\t\t`When using \\`web_search\\` for freshness-sensitive topics, account for the current date (${currentYearMonth}) and include the year in the query when useful.`,\n\t];\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider orchestration and execution-state construction for web_search.
|
|
3
|
+
*/
|
|
4
|
+
import type { AgentToolUpdateCallback } from "../../core/extensions/types.ts";
|
|
5
|
+
import type { WebSearchParams } from "./schema.ts";
|
|
6
|
+
import type { ResolvedSearchCredentials, WebSearchDetails } from "./types.ts";
|
|
7
|
+
export interface WebSearchExecution {
|
|
8
|
+
formattedOutput: string;
|
|
9
|
+
details: WebSearchDetails;
|
|
10
|
+
}
|
|
11
|
+
/** Execute all configured search providers and combine their successful results. */
|
|
12
|
+
export declare function executeWebSearch(params: WebSearchParams, credentials: ResolvedSearchCredentials, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<WebSearchDetails>): Promise<WebSearchExecution>;
|
|
13
|
+
//# sourceMappingURL=execute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../../src/extensions/web-search/execute.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAO9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAwB,yBAAyB,EAAoB,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEtH,MAAM,WAAW,kBAAkB;IAClC,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,gBAAgB,CAAC;CAC1B;AAED,oFAAoF;AACpF,wBAAsB,gBAAgB,CACrC,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,yBAAyB,EACtC,MAAM,CAAC,EAAE,WAAW,EACpB,QAAQ,CAAC,EAAE,uBAAuB,CAAC,gBAAgB,CAAC,GAClD,OAAO,CAAC,kBAAkB,CAAC,CAmG7B"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider orchestration and execution-state construction for web_search.
|
|
3
|
+
*/
|
|
4
|
+
import { configuredEngine } from "./auth.js";
|
|
5
|
+
import { getEngineLabel, WEB_SEARCH_DISABLED_MESSAGE } from "./constants.js";
|
|
6
|
+
import { formatSearchOutput } from "./format.js";
|
|
7
|
+
import { searchDeepSeek } from "./providers/deepseek.js";
|
|
8
|
+
import { searchMiniMax } from "./providers/minimax.js";
|
|
9
|
+
import { boundSingleLineText, fuseSearchHits, MAX_ERROR_MESSAGE_LENGTH, MAX_QUERY_LENGTH } from "./results.js";
|
|
10
|
+
/** Execute all configured search providers and combine their successful results. */
|
|
11
|
+
export async function executeWebSearch(params, credentials, signal, onUpdate) {
|
|
12
|
+
const startTime = Date.now();
|
|
13
|
+
const query = boundSingleLineText(params.query, MAX_QUERY_LENGTH) ?? "";
|
|
14
|
+
const engine = configuredEngine(credentials);
|
|
15
|
+
if (!query) {
|
|
16
|
+
const details = {
|
|
17
|
+
query: "",
|
|
18
|
+
durationMs: 0,
|
|
19
|
+
status: "error",
|
|
20
|
+
engine,
|
|
21
|
+
totalHits: 0,
|
|
22
|
+
hits: [],
|
|
23
|
+
errorMessage: "Search query must not be empty.",
|
|
24
|
+
};
|
|
25
|
+
return { formattedOutput: formatSearchOutput(query, details), details };
|
|
26
|
+
}
|
|
27
|
+
if (engine === "none") {
|
|
28
|
+
const details = {
|
|
29
|
+
query,
|
|
30
|
+
durationMs: 0,
|
|
31
|
+
status: "disabled",
|
|
32
|
+
engine: "none",
|
|
33
|
+
totalHits: 0,
|
|
34
|
+
hits: [],
|
|
35
|
+
errorMessage: WEB_SEARCH_DISABLED_MESSAGE,
|
|
36
|
+
};
|
|
37
|
+
return { formattedOutput: formatSearchOutput(query, details), details };
|
|
38
|
+
}
|
|
39
|
+
signal?.throwIfAborted();
|
|
40
|
+
onUpdate?.({
|
|
41
|
+
content: [{ type: "text", text: `Searching for "${query}" via ${getEngineLabel(engine)}...` }],
|
|
42
|
+
details: {
|
|
43
|
+
query,
|
|
44
|
+
durationMs: 0,
|
|
45
|
+
status: "success",
|
|
46
|
+
engine,
|
|
47
|
+
totalHits: 0,
|
|
48
|
+
hits: [],
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
const searches = [];
|
|
52
|
+
if (credentials.minimax) {
|
|
53
|
+
searches.push(searchMiniMax({
|
|
54
|
+
query,
|
|
55
|
+
apiKey: credentials.minimax.key,
|
|
56
|
+
apiHost: credentials.minimax.host,
|
|
57
|
+
signal,
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
if (credentials.deepseek) {
|
|
61
|
+
searches.push(searchDeepSeek({ query, apiKey: credentials.deepseek.key, signal }));
|
|
62
|
+
}
|
|
63
|
+
const settledResults = await Promise.allSettled(searches);
|
|
64
|
+
signal?.throwIfAborted();
|
|
65
|
+
const durationMs = Date.now() - startTime;
|
|
66
|
+
const successfulResults = [];
|
|
67
|
+
const errors = [];
|
|
68
|
+
for (const result of settledResults) {
|
|
69
|
+
if (result.status === "fulfilled")
|
|
70
|
+
successfulResults.push(result.value);
|
|
71
|
+
else
|
|
72
|
+
errors.push(result.reason instanceof Error ? result.reason.message : String(result.reason));
|
|
73
|
+
}
|
|
74
|
+
if (successfulResults.length === 0) {
|
|
75
|
+
const details = {
|
|
76
|
+
query,
|
|
77
|
+
durationMs,
|
|
78
|
+
status: "error",
|
|
79
|
+
engine,
|
|
80
|
+
totalHits: 0,
|
|
81
|
+
hits: [],
|
|
82
|
+
errorMessage: boundSingleLineText(errors.join(" | "), MAX_ERROR_MESSAGE_LENGTH) ?? "All search engines failed",
|
|
83
|
+
};
|
|
84
|
+
return { formattedOutput: formatSearchOutput(query, details), details };
|
|
85
|
+
}
|
|
86
|
+
const { hits, relatedSearches, deepseekSynthesis } = fuseSearchHits(successfulResults);
|
|
87
|
+
const respondedSources = new Set(successfulResults.map((result) => result.source));
|
|
88
|
+
const contributingEngine = respondedSources.size > 1 ? "dual" : respondedSources.has("MiniMax") ? "minimax" : "deepseek";
|
|
89
|
+
const details = {
|
|
90
|
+
query,
|
|
91
|
+
durationMs,
|
|
92
|
+
status: "success",
|
|
93
|
+
engine: contributingEngine,
|
|
94
|
+
totalHits: hits.length,
|
|
95
|
+
hits,
|
|
96
|
+
relatedSearches,
|
|
97
|
+
deepseekSynthesis,
|
|
98
|
+
};
|
|
99
|
+
return { formattedOutput: formatSearchOutput(query, details), details };
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=execute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../../src/extensions/web-search/execute.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Provider orchestration and execution-state construction for web_search.\n */\n\nimport type { AgentToolUpdateCallback } from \"../../core/extensions/types.ts\";\nimport { configuredEngine } from \"./auth.ts\";\nimport { getEngineLabel, WEB_SEARCH_DISABLED_MESSAGE } from \"./constants.ts\";\nimport { formatSearchOutput } from \"./format.ts\";\nimport { searchDeepSeek } from \"./providers/deepseek.ts\";\nimport { searchMiniMax } from \"./providers/minimax.ts\";\nimport { boundSingleLineText, fuseSearchHits, MAX_ERROR_MESSAGE_LENGTH, MAX_QUERY_LENGTH } from \"./results.ts\";\nimport type { WebSearchParams } from \"./schema.ts\";\nimport type { ProviderSearchResult, ResolvedSearchCredentials, SearchEngineType, WebSearchDetails } from \"./types.ts\";\n\nexport interface WebSearchExecution {\n\tformattedOutput: string;\n\tdetails: WebSearchDetails;\n}\n\n/** Execute all configured search providers and combine their successful results. */\nexport async function executeWebSearch(\n\tparams: WebSearchParams,\n\tcredentials: ResolvedSearchCredentials,\n\tsignal?: AbortSignal,\n\tonUpdate?: AgentToolUpdateCallback<WebSearchDetails>,\n): Promise<WebSearchExecution> {\n\tconst startTime = Date.now();\n\tconst query = boundSingleLineText(params.query, MAX_QUERY_LENGTH) ?? \"\";\n\tconst engine = configuredEngine(credentials);\n\n\tif (!query) {\n\t\tconst details: WebSearchDetails = {\n\t\t\tquery: \"\",\n\t\t\tdurationMs: 0,\n\t\t\tstatus: \"error\",\n\t\t\tengine,\n\t\t\ttotalHits: 0,\n\t\t\thits: [],\n\t\t\terrorMessage: \"Search query must not be empty.\",\n\t\t};\n\t\treturn { formattedOutput: formatSearchOutput(query, details), details };\n\t}\n\n\tif (engine === \"none\") {\n\t\tconst details: WebSearchDetails = {\n\t\t\tquery,\n\t\t\tdurationMs: 0,\n\t\t\tstatus: \"disabled\",\n\t\t\tengine: \"none\",\n\t\t\ttotalHits: 0,\n\t\t\thits: [],\n\t\t\terrorMessage: WEB_SEARCH_DISABLED_MESSAGE,\n\t\t};\n\t\treturn { formattedOutput: formatSearchOutput(query, details), details };\n\t}\n\n\tsignal?.throwIfAborted();\n\tonUpdate?.({\n\t\tcontent: [{ type: \"text\", text: `Searching for \"${query}\" via ${getEngineLabel(engine)}...` }],\n\t\tdetails: {\n\t\t\tquery,\n\t\t\tdurationMs: 0,\n\t\t\tstatus: \"success\",\n\t\t\tengine,\n\t\t\ttotalHits: 0,\n\t\t\thits: [],\n\t\t},\n\t});\n\n\tconst searches: Promise<ProviderSearchResult>[] = [];\n\tif (credentials.minimax) {\n\t\tsearches.push(\n\t\t\tsearchMiniMax({\n\t\t\t\tquery,\n\t\t\t\tapiKey: credentials.minimax.key,\n\t\t\t\tapiHost: credentials.minimax.host,\n\t\t\t\tsignal,\n\t\t\t}),\n\t\t);\n\t}\n\tif (credentials.deepseek) {\n\t\tsearches.push(searchDeepSeek({ query, apiKey: credentials.deepseek.key, signal }));\n\t}\n\n\tconst settledResults = await Promise.allSettled(searches);\n\tsignal?.throwIfAborted();\n\tconst durationMs = Date.now() - startTime;\n\tconst successfulResults: ProviderSearchResult[] = [];\n\tconst errors: string[] = [];\n\n\tfor (const result of settledResults) {\n\t\tif (result.status === \"fulfilled\") successfulResults.push(result.value);\n\t\telse errors.push(result.reason instanceof Error ? result.reason.message : String(result.reason));\n\t}\n\n\tif (successfulResults.length === 0) {\n\t\tconst details: WebSearchDetails = {\n\t\t\tquery,\n\t\t\tdurationMs,\n\t\t\tstatus: \"error\",\n\t\t\tengine,\n\t\t\ttotalHits: 0,\n\t\t\thits: [],\n\t\t\terrorMessage: boundSingleLineText(errors.join(\" | \"), MAX_ERROR_MESSAGE_LENGTH) ?? \"All search engines failed\",\n\t\t};\n\t\treturn { formattedOutput: formatSearchOutput(query, details), details };\n\t}\n\n\tconst { hits, relatedSearches, deepseekSynthesis } = fuseSearchHits(successfulResults);\n\tconst respondedSources = new Set(successfulResults.map((result) => result.source));\n\tconst contributingEngine: SearchEngineType =\n\t\trespondedSources.size > 1 ? \"dual\" : respondedSources.has(\"MiniMax\") ? \"minimax\" : \"deepseek\";\n\tconst details: WebSearchDetails = {\n\t\tquery,\n\t\tdurationMs,\n\t\tstatus: \"success\",\n\t\tengine: contributingEngine,\n\t\ttotalHits: hits.length,\n\t\thits,\n\t\trelatedSearches,\n\t\tdeepseekSynthesis,\n\t};\n\n\treturn { formattedOutput: formatSearchOutput(query, details), details };\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-facing and expanded-TUI Markdown formatting for web_search results.
|
|
3
|
+
*/
|
|
4
|
+
import type { WebSearchDetails } from "./types.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Sources, synthesis, and related-search sections shared by model output and
|
|
7
|
+
* the expanded TUI. This function adds no model instructions.
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatResultsMarkdown(details: WebSearchDetails): string;
|
|
10
|
+
/** Format a structured result payload for the main agent. */
|
|
11
|
+
export declare function formatSearchOutput(query: string, details: WebSearchDetails): string;
|
|
12
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/extensions/web-search/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgBH,OAAO,KAAK,EAAE,gBAAgB,EAAgB,MAAM,YAAY,CAAC;AAuCjE;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAiCvE;AAED,6DAA6D;AAC7D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAwBnF"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-facing and expanded-TUI Markdown formatting for web_search results.
|
|
3
|
+
*/
|
|
4
|
+
import { getEngineLabel, WEB_SEARCH_DISABLED_MESSAGE } from "./constants.js";
|
|
5
|
+
import { boundMultilineText, boundSingleLineText, MAX_ERROR_MESSAGE_LENGTH, MAX_OUTPUT_HITS, MAX_QUERY_LENGTH, MAX_RELATED_SEARCH_LENGTH, MAX_RELATED_SEARCHES, MAX_SNIPPET_LENGTH, MAX_SYNTHESIS_LENGTH, MAX_TITLE_LENGTH, normalizeUrl, } from "./results.js";
|
|
6
|
+
function escapeMarkdownText(text) {
|
|
7
|
+
return text
|
|
8
|
+
.replace(/\\/g, "\\\\")
|
|
9
|
+
.replace(/\[/g, "\\[")
|
|
10
|
+
.replace(/\]/g, "\\]")
|
|
11
|
+
.replace(/</g, "\\<")
|
|
12
|
+
.replace(/>/g, "\\>");
|
|
13
|
+
}
|
|
14
|
+
function formatHit(hit) {
|
|
15
|
+
const url = normalizeUrl(hit.url);
|
|
16
|
+
if (!url)
|
|
17
|
+
return undefined;
|
|
18
|
+
const sources = Array.isArray(hit.sources)
|
|
19
|
+
? [...new Set(hit.sources.filter((source) => source === "MiniMax" || source === "DeepSeek"))]
|
|
20
|
+
: [];
|
|
21
|
+
return {
|
|
22
|
+
title: escapeMarkdownText(boundSingleLineText(hit.title, MAX_TITLE_LENGTH) ?? url),
|
|
23
|
+
url,
|
|
24
|
+
snippet: boundSingleLineText(hit.snippet, MAX_SNIPPET_LENGTH),
|
|
25
|
+
sources,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function usableHits(details) {
|
|
29
|
+
return details.hits
|
|
30
|
+
.map(formatHit)
|
|
31
|
+
.filter((hit) => hit !== undefined)
|
|
32
|
+
.slice(0, MAX_OUTPUT_HITS);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Sources, synthesis, and related-search sections shared by model output and
|
|
36
|
+
* the expanded TUI. This function adds no model instructions.
|
|
37
|
+
*/
|
|
38
|
+
export function formatResultsMarkdown(details) {
|
|
39
|
+
const parts = [];
|
|
40
|
+
const hits = usableHits(details);
|
|
41
|
+
if (hits.length > 0) {
|
|
42
|
+
parts.push(`## Web Sources (${hits.length} found via ${getEngineLabel(details.engine)})\n`);
|
|
43
|
+
hits.forEach((hit, index) => {
|
|
44
|
+
const sourceTag = hit.sources.length > 1 ? ` — *(found by ${hit.sources.join(" & ")})*` : "";
|
|
45
|
+
parts.push(`${index + 1}. **[${hit.title}](<${hit.url}>)**${sourceTag}`);
|
|
46
|
+
if (hit.snippet)
|
|
47
|
+
parts.push(` - ${escapeMarkdownText(hit.snippet)}`);
|
|
48
|
+
});
|
|
49
|
+
parts.push("");
|
|
50
|
+
}
|
|
51
|
+
const synthesis = boundMultilineText(details.deepseekSynthesis, MAX_SYNTHESIS_LENGTH);
|
|
52
|
+
if (synthesis) {
|
|
53
|
+
parts.push("## DeepSeek Search Synthesis\n");
|
|
54
|
+
parts.push(escapeMarkdownText(synthesis));
|
|
55
|
+
parts.push("");
|
|
56
|
+
}
|
|
57
|
+
const relatedSearches = details.relatedSearches
|
|
58
|
+
?.map((related) => boundSingleLineText(related, MAX_RELATED_SEARCH_LENGTH))
|
|
59
|
+
.filter((related) => related !== undefined)
|
|
60
|
+
.slice(0, MAX_RELATED_SEARCHES);
|
|
61
|
+
if (relatedSearches && relatedSearches.length > 0) {
|
|
62
|
+
parts.push("## Related Searches\n");
|
|
63
|
+
parts.push(relatedSearches.map((related) => `- ${escapeMarkdownText(related)}`).join("\n"));
|
|
64
|
+
parts.push("");
|
|
65
|
+
}
|
|
66
|
+
return parts.join("\n");
|
|
67
|
+
}
|
|
68
|
+
/** Format a structured result payload for the main agent. */
|
|
69
|
+
export function formatSearchOutput(query, details) {
|
|
70
|
+
if (details.status === "disabled")
|
|
71
|
+
return WEB_SEARCH_DISABLED_MESSAGE;
|
|
72
|
+
const boundedQuery = boundSingleLineText(query, MAX_QUERY_LENGTH) ?? "";
|
|
73
|
+
if (details.status === "error") {
|
|
74
|
+
const errorMessage = boundSingleLineText(details.errorMessage, MAX_ERROR_MESSAGE_LENGTH) ?? "Unknown search error";
|
|
75
|
+
return `Web search failed for "${boundedQuery}": ${errorMessage}`;
|
|
76
|
+
}
|
|
77
|
+
const hasSources = usableHits(details).length > 0;
|
|
78
|
+
const hasSynthesis = boundMultilineText(details.deepseekSynthesis, MAX_SYNTHESIS_LENGTH) !== undefined;
|
|
79
|
+
if (!hasSources && !hasSynthesis) {
|
|
80
|
+
return `No search results found for "${boundedQuery}". Try rephrasing with different keywords.`;
|
|
81
|
+
}
|
|
82
|
+
const parts = [`# Web Search Results for: "${boundedQuery}"\n`, formatResultsMarkdown(details)];
|
|
83
|
+
if (hasSources) {
|
|
84
|
+
parts.push("---", "Use these search results to answer the user, and cite the relevant source URLs in your response.");
|
|
85
|
+
}
|
|
86
|
+
return parts.join("\n");
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/extensions/web-search/format.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Model-facing and expanded-TUI Markdown formatting for web_search results.\n */\n\nimport { getEngineLabel, WEB_SEARCH_DISABLED_MESSAGE } from \"./constants.ts\";\nimport {\n\tboundMultilineText,\n\tboundSingleLineText,\n\tMAX_ERROR_MESSAGE_LENGTH,\n\tMAX_OUTPUT_HITS,\n\tMAX_QUERY_LENGTH,\n\tMAX_RELATED_SEARCH_LENGTH,\n\tMAX_RELATED_SEARCHES,\n\tMAX_SNIPPET_LENGTH,\n\tMAX_SYNTHESIS_LENGTH,\n\tMAX_TITLE_LENGTH,\n\tnormalizeUrl,\n} from \"./results.ts\";\nimport type { WebSearchDetails, WebSearchHit } from \"./types.ts\";\n\ninterface FormattedHit {\n\ttitle: string;\n\turl: string;\n\tsnippet?: string;\n\tsources: WebSearchHit[\"sources\"];\n}\n\nfunction escapeMarkdownText(text: string): string {\n\treturn text\n\t\t.replace(/\\\\/g, \"\\\\\\\\\")\n\t\t.replace(/\\[/g, \"\\\\[\")\n\t\t.replace(/\\]/g, \"\\\\]\")\n\t\t.replace(/</g, \"\\\\<\")\n\t\t.replace(/>/g, \"\\\\>\");\n}\n\nfunction formatHit(hit: WebSearchHit): FormattedHit | undefined {\n\tconst url = normalizeUrl(hit.url);\n\tif (!url) return undefined;\n\tconst sources = Array.isArray(hit.sources)\n\t\t? [...new Set(hit.sources.filter((source) => source === \"MiniMax\" || source === \"DeepSeek\"))]\n\t\t: [];\n\treturn {\n\t\ttitle: escapeMarkdownText(boundSingleLineText(hit.title, MAX_TITLE_LENGTH) ?? url),\n\t\turl,\n\t\tsnippet: boundSingleLineText(hit.snippet, MAX_SNIPPET_LENGTH),\n\t\tsources,\n\t};\n}\n\nfunction usableHits(details: WebSearchDetails): FormattedHit[] {\n\treturn details.hits\n\t\t.map(formatHit)\n\t\t.filter((hit): hit is FormattedHit => hit !== undefined)\n\t\t.slice(0, MAX_OUTPUT_HITS);\n}\n\n/**\n * Sources, synthesis, and related-search sections shared by model output and\n * the expanded TUI. This function adds no model instructions.\n */\nexport function formatResultsMarkdown(details: WebSearchDetails): string {\n\tconst parts: string[] = [];\n\tconst hits = usableHits(details);\n\n\tif (hits.length > 0) {\n\t\tparts.push(`## Web Sources (${hits.length} found via ${getEngineLabel(details.engine)})\\n`);\n\n\t\thits.forEach((hit, index) => {\n\t\t\tconst sourceTag = hit.sources.length > 1 ? ` — *(found by ${hit.sources.join(\" & \")})*` : \"\";\n\t\t\tparts.push(`${index + 1}. **[${hit.title}](<${hit.url}>)**${sourceTag}`);\n\t\t\tif (hit.snippet) parts.push(` - ${escapeMarkdownText(hit.snippet)}`);\n\t\t});\n\t\tparts.push(\"\");\n\t}\n\n\tconst synthesis = boundMultilineText(details.deepseekSynthesis, MAX_SYNTHESIS_LENGTH);\n\tif (synthesis) {\n\t\tparts.push(\"## DeepSeek Search Synthesis\\n\");\n\t\tparts.push(escapeMarkdownText(synthesis));\n\t\tparts.push(\"\");\n\t}\n\n\tconst relatedSearches = details.relatedSearches\n\t\t?.map((related) => boundSingleLineText(related, MAX_RELATED_SEARCH_LENGTH))\n\t\t.filter((related): related is string => related !== undefined)\n\t\t.slice(0, MAX_RELATED_SEARCHES);\n\tif (relatedSearches && relatedSearches.length > 0) {\n\t\tparts.push(\"## Related Searches\\n\");\n\t\tparts.push(relatedSearches.map((related) => `- ${escapeMarkdownText(related)}`).join(\"\\n\"));\n\t\tparts.push(\"\");\n\t}\n\n\treturn parts.join(\"\\n\");\n}\n\n/** Format a structured result payload for the main agent. */\nexport function formatSearchOutput(query: string, details: WebSearchDetails): string {\n\tif (details.status === \"disabled\") return WEB_SEARCH_DISABLED_MESSAGE;\n\n\tconst boundedQuery = boundSingleLineText(query, MAX_QUERY_LENGTH) ?? \"\";\n\tif (details.status === \"error\") {\n\t\tconst errorMessage =\n\t\t\tboundSingleLineText(details.errorMessage, MAX_ERROR_MESSAGE_LENGTH) ?? \"Unknown search error\";\n\t\treturn `Web search failed for \"${boundedQuery}\": ${errorMessage}`;\n\t}\n\n\tconst hasSources = usableHits(details).length > 0;\n\tconst hasSynthesis = boundMultilineText(details.deepseekSynthesis, MAX_SYNTHESIS_LENGTH) !== undefined;\n\tif (!hasSources && !hasSynthesis) {\n\t\treturn `No search results found for \"${boundedQuery}\". Try rephrasing with different keywords.`;\n\t}\n\n\tconst parts = [`# Web Search Results for: \"${boundedQuery}\"\\n`, formatResultsMarkdown(details)];\n\tif (hasSources) {\n\t\tparts.push(\n\t\t\t\"---\",\n\t\t\t\"Use these search results to answer the user, and cite the relevant source URLs in your response.\",\n\t\t);\n\t}\n\treturn parts.join(\"\\n\");\n}\n"]}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { configuredEngine, resolveSearchCredentials } from "./auth.js";
|
|
5
5
|
import { getWebSearchPromptGuidelines, WEB_SEARCH_DESCRIPTION, WEB_SEARCH_LABEL, WEB_SEARCH_PROMPT_SNIPPET, WEB_SEARCH_TOOL_NAME, } from "./constants.js";
|
|
6
|
-
import { executeWebSearch } from "./
|
|
6
|
+
import { executeWebSearch } from "./execute.js";
|
|
7
7
|
import { renderWebSearchCall, renderWebSearchResult } from "./render.js";
|
|
8
8
|
import { normalizeWebSearchParams, WebSearchParamsSchema } from "./schema.js";
|
|
9
9
|
function trackQueryElapsed(context, isPartial) {
|
|
@@ -40,7 +40,7 @@ export default function webSearch(pi) {
|
|
|
40
40
|
return {
|
|
41
41
|
content: [{ type: "text", text: execution.formattedOutput }],
|
|
42
42
|
details: execution.details,
|
|
43
|
-
isError: execution.details.status
|
|
43
|
+
isError: execution.details.status === "error",
|
|
44
44
|
};
|
|
45
45
|
},
|
|
46
46
|
renderCall(args, theme) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/web-search/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EACN,4BAA4B,EAC5B,sBAAsB,EACtB,gBAAgB,EAChB,yBAAyB,EACzB,oBAAoB,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/web-search/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * web_search — Pi-native Web Search extension combining MiniMax and DeepSeek search engines.\n */\n\nimport type { ExtensionAPI, ToolRenderContext } from \"../../core/extensions/types.ts\";\nimport { configuredEngine, resolveSearchCredentials } from \"./auth.ts\";\nimport {\n\tgetWebSearchPromptGuidelines,\n\tWEB_SEARCH_DESCRIPTION,\n\tWEB_SEARCH_LABEL,\n\tWEB_SEARCH_PROMPT_SNIPPET,\n\tWEB_SEARCH_TOOL_NAME,\n} from \"./constants.ts\";\nimport { executeWebSearch } from \"./execute.ts\";\nimport { renderWebSearchCall, renderWebSearchResult } from \"./render.ts\";\nimport { normalizeWebSearchParams, WebSearchParamsSchema } from \"./schema.ts\";\nimport type { WebSearchDetails } from \"./types.ts\";\n\ninterface WebSearchRenderState {\n\tstartedAt?: number;\n\trefreshTimer?: ReturnType<typeof setTimeout>;\n}\n\nfunction trackQueryElapsed(context: ToolRenderContext<WebSearchRenderState>, isPartial: boolean): number | undefined {\n\tconst state = context.state;\n\tif (isPartial) {\n\t\tstate.startedAt ??= Date.now();\n\t\tif (state.refreshTimer === undefined) {\n\t\t\tstate.refreshTimer = setTimeout(() => {\n\t\t\t\tstate.refreshTimer = undefined;\n\t\t\t\tcontext.invalidate();\n\t\t\t}, 1000);\n\t\t\tstate.refreshTimer.unref?.();\n\t\t}\n\t\treturn Date.now() - state.startedAt;\n\t}\n\tif (state.refreshTimer !== undefined) {\n\t\tclearTimeout(state.refreshTimer);\n\t\tstate.refreshTimer = undefined;\n\t}\n\treturn undefined;\n}\n\nexport default function webSearch(pi: ExtensionAPI): void {\n\tpi.registerTool<typeof WebSearchParamsSchema, WebSearchDetails, WebSearchRenderState>({\n\t\tname: WEB_SEARCH_TOOL_NAME,\n\t\tlabel: WEB_SEARCH_LABEL,\n\t\tdescription: WEB_SEARCH_DESCRIPTION,\n\t\tpromptSnippet: WEB_SEARCH_PROMPT_SNIPPET,\n\t\tpromptGuidelines: getWebSearchPromptGuidelines(),\n\t\tparameters: WebSearchParamsSchema,\n\t\tprepareArguments: normalizeWebSearchParams,\n\n\t\tasync execute(_toolCallId, params, signal, onUpdate, ctx) {\n\t\t\tconst credentials = await resolveSearchCredentials(ctx.modelRuntime);\n\t\t\tconst execution = await executeWebSearch(params, credentials, signal, onUpdate);\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: execution.formattedOutput }],\n\t\t\t\tdetails: execution.details,\n\t\t\t\tisError: execution.details.status === \"error\",\n\t\t\t};\n\t\t},\n\n\t\trenderCall(args, theme) {\n\t\t\treturn renderWebSearchCall(args, theme);\n\t\t},\n\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst elapsedMs = trackQueryElapsed(context, options.isPartial);\n\t\t\treturn renderWebSearchResult(result, options, theme, context.isError, elapsedMs);\n\t\t},\n\t});\n\n\t// Keep the tool out of the model's tool set (and system prompt) when no search\n\t// credentials are configured. Re-evaluated on every session start (startup,\n\t// /new, /reload, resume, fork), so /login takes effect from the next session\n\t// onward; the tool stays registered for /tools and historical rendering.\n\tpi.on(\"session_start\", async (_event, ctx) => {\n\t\tconst credentials = await resolveSearchCredentials(ctx.modelRuntime);\n\t\tconst active = new Set(pi.getActiveTools());\n\t\tif (configuredEngine(credentials) === \"none\") {\n\t\t\tactive.delete(WEB_SEARCH_TOOL_NAME);\n\t\t} else {\n\t\t\tactive.add(WEB_SEARCH_TOOL_NAME);\n\t\t}\n\t\tpi.setActiveTools([...active]);\n\t});\n}\n"]}
|
|
@@ -8,8 +8,6 @@ export interface DeepSeekSearchOptions {
|
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
model?: string;
|
|
10
10
|
signal?: AbortSignal;
|
|
11
|
-
allowedDomains?: string[];
|
|
12
|
-
blockedDomains?: string[];
|
|
13
11
|
}
|
|
14
12
|
export declare function searchDeepSeek(options: DeepSeekSearchOptions): Promise<ProviderSearchResult>;
|
|
15
13
|
//# sourceMappingURL=deepseek.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepseek.d.ts","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/deepseek.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"deepseek.d.ts","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/deepseek.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAgB,MAAM,aAAa,CAAC;AAGtE,MAAM,WAAW,qBAAqB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AAmCD,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAiDlG"}
|
|
@@ -4,20 +4,37 @@
|
|
|
4
4
|
import { postJson } from "./http.js";
|
|
5
5
|
const DEFAULT_DEEPSEEK_MESSAGES_ENDPOINT = "https://api.deepseek.com/anthropic/v1/messages";
|
|
6
6
|
const DEFAULT_DEEPSEEK_SEARCH_MODEL = "claude-sonnet-search";
|
|
7
|
+
function isRecord(value) {
|
|
8
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
function stringField(record, key) {
|
|
11
|
+
const value = record[key];
|
|
12
|
+
return typeof value === "string" ? value : undefined;
|
|
13
|
+
}
|
|
14
|
+
function parseSearchHit(value) {
|
|
15
|
+
if (!isRecord(value) || value.type !== "web_search_result")
|
|
16
|
+
return undefined;
|
|
17
|
+
const url = stringField(value, "url")?.trim();
|
|
18
|
+
if (!url)
|
|
19
|
+
return undefined;
|
|
20
|
+
const title = stringField(value, "title")?.trim();
|
|
21
|
+
const pageAge = stringField(value, "page_age")?.trim();
|
|
22
|
+
return {
|
|
23
|
+
title: title || url,
|
|
24
|
+
url,
|
|
25
|
+
date: pageAge || undefined,
|
|
26
|
+
sources: ["DeepSeek"],
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function errorMessage(value) {
|
|
30
|
+
if (!isRecord(value))
|
|
31
|
+
return undefined;
|
|
32
|
+
return stringField(value, "message") || stringField(value, "type") || "Unknown error";
|
|
33
|
+
}
|
|
7
34
|
export async function searchDeepSeek(options) {
|
|
8
35
|
const endpoint = options.baseUrl || DEFAULT_DEEPSEEK_MESSAGES_ENDPOINT;
|
|
9
36
|
const model = options.model || DEFAULT_DEEPSEEK_SEARCH_MODEL;
|
|
10
|
-
const
|
|
11
|
-
type: "web_search_20250305",
|
|
12
|
-
name: "web_search",
|
|
13
|
-
};
|
|
14
|
-
if (options.allowedDomains && options.allowedDomains.length > 0) {
|
|
15
|
-
toolConfig.allowed_domains = options.allowedDomains;
|
|
16
|
-
}
|
|
17
|
-
else if (options.blockedDomains && options.blockedDomains.length > 0) {
|
|
18
|
-
toolConfig.blocked_domains = options.blockedDomains;
|
|
19
|
-
}
|
|
20
|
-
const data = await postJson(endpoint, {
|
|
37
|
+
const rawData = await postJson(endpoint, {
|
|
21
38
|
"Content-Type": "application/json",
|
|
22
39
|
"x-api-key": options.apiKey,
|
|
23
40
|
Authorization: `Bearer ${options.apiKey}`,
|
|
@@ -26,38 +43,38 @@ export async function searchDeepSeek(options) {
|
|
|
26
43
|
model,
|
|
27
44
|
max_tokens: 1024,
|
|
28
45
|
messages: [{ role: "user", content: options.query }],
|
|
29
|
-
tools: [
|
|
46
|
+
tools: [{ type: "web_search_20250305", name: "web_search" }],
|
|
30
47
|
}, options.signal, 90_000, "DeepSeek Messages search API");
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
48
|
+
const data = isRecord(rawData) ? rawData : {};
|
|
49
|
+
const upstreamError = errorMessage(data.error);
|
|
50
|
+
if (upstreamError)
|
|
51
|
+
throw new Error(`DeepSeek search error: ${upstreamError}`);
|
|
34
52
|
const hits = [];
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
53
|
+
const synthesisParts = [];
|
|
54
|
+
const content = Array.isArray(data.content) ? data.content : [];
|
|
55
|
+
for (const value of content) {
|
|
56
|
+
if (!isRecord(value))
|
|
57
|
+
continue;
|
|
58
|
+
if (value.type === "web_search_tool_result") {
|
|
59
|
+
if (!Array.isArray(value.content))
|
|
60
|
+
continue;
|
|
61
|
+
for (const item of value.content) {
|
|
62
|
+
const hit = parseSearchHit(item);
|
|
63
|
+
if (hit)
|
|
64
|
+
hits.push(hit);
|
|
48
65
|
}
|
|
66
|
+
continue;
|
|
49
67
|
}
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
}
|
|
68
|
+
if (value.type === "text") {
|
|
69
|
+
const text = stringField(value, "text")?.trim();
|
|
70
|
+
if (text)
|
|
71
|
+
synthesisParts.push(text);
|
|
55
72
|
}
|
|
56
73
|
}
|
|
57
74
|
return {
|
|
58
75
|
source: "DeepSeek",
|
|
59
76
|
hits,
|
|
60
|
-
synthesisText:
|
|
77
|
+
synthesisText: synthesisParts.length > 0 ? synthesisParts.join("\n\n") : undefined,
|
|
61
78
|
};
|
|
62
79
|
}
|
|
63
80
|
//# sourceMappingURL=deepseek.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deepseek.js","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/deepseek.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"deepseek.js","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/deepseek.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * deepseek.ts — DeepSeek Messages API search provider (claude-sonnet-search model with web_search_20250305).\n */\n\nimport type { ProviderSearchResult, WebSearchHit } from \"../types.ts\";\nimport { postJson } from \"./http.ts\";\n\nexport interface DeepSeekSearchOptions {\n\tquery: string;\n\tapiKey: string;\n\tbaseUrl?: string;\n\tmodel?: string;\n\tsignal?: AbortSignal;\n}\n\nconst DEFAULT_DEEPSEEK_MESSAGES_ENDPOINT = \"https://api.deepseek.com/anthropic/v1/messages\";\nconst DEFAULT_DEEPSEEK_SEARCH_MODEL = \"claude-sonnet-search\";\n\ntype JsonRecord = Record<string, unknown>;\n\nfunction isRecord(value: unknown): value is JsonRecord {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stringField(record: JsonRecord, key: string): string | undefined {\n\tconst value = record[key];\n\treturn typeof value === \"string\" ? value : undefined;\n}\n\nfunction parseSearchHit(value: unknown): WebSearchHit | undefined {\n\tif (!isRecord(value) || value.type !== \"web_search_result\") return undefined;\n\tconst url = stringField(value, \"url\")?.trim();\n\tif (!url) return undefined;\n\tconst title = stringField(value, \"title\")?.trim();\n\tconst pageAge = stringField(value, \"page_age\")?.trim();\n\treturn {\n\t\ttitle: title || url,\n\t\turl,\n\t\tdate: pageAge || undefined,\n\t\tsources: [\"DeepSeek\"],\n\t};\n}\n\nfunction errorMessage(value: unknown): string | undefined {\n\tif (!isRecord(value)) return undefined;\n\treturn stringField(value, \"message\") || stringField(value, \"type\") || \"Unknown error\";\n}\n\nexport async function searchDeepSeek(options: DeepSeekSearchOptions): Promise<ProviderSearchResult> {\n\tconst endpoint = options.baseUrl || DEFAULT_DEEPSEEK_MESSAGES_ENDPOINT;\n\tconst model = options.model || DEFAULT_DEEPSEEK_SEARCH_MODEL;\n\tconst rawData = await postJson<unknown>(\n\t\tendpoint,\n\t\t{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"x-api-key\": options.apiKey,\n\t\t\tAuthorization: `Bearer ${options.apiKey}`,\n\t\t\t\"anthropic-version\": \"2023-06-01\",\n\t\t},\n\t\t{\n\t\t\tmodel,\n\t\t\tmax_tokens: 1024,\n\t\t\tmessages: [{ role: \"user\", content: options.query }],\n\t\t\ttools: [{ type: \"web_search_20250305\", name: \"web_search\" }],\n\t\t},\n\t\toptions.signal,\n\t\t90_000,\n\t\t\"DeepSeek Messages search API\",\n\t);\n\tconst data = isRecord(rawData) ? rawData : {};\n\tconst upstreamError = errorMessage(data.error);\n\tif (upstreamError) throw new Error(`DeepSeek search error: ${upstreamError}`);\n\n\tconst hits: WebSearchHit[] = [];\n\tconst synthesisParts: string[] = [];\n\tconst content = Array.isArray(data.content) ? data.content : [];\n\tfor (const value of content) {\n\t\tif (!isRecord(value)) continue;\n\t\tif (value.type === \"web_search_tool_result\") {\n\t\t\tif (!Array.isArray(value.content)) continue;\n\t\t\tfor (const item of value.content) {\n\t\t\t\tconst hit = parseSearchHit(item);\n\t\t\t\tif (hit) hits.push(hit);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (value.type === \"text\") {\n\t\t\tconst text = stringField(value, \"text\")?.trim();\n\t\t\tif (text) synthesisParts.push(text);\n\t\t}\n\t}\n\n\treturn {\n\t\tsource: \"DeepSeek\",\n\t\thits,\n\t\tsynthesisText: synthesisParts.length > 0 ? synthesisParts.join(\"\\n\\n\") : undefined,\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/http.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/http.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA6DH;;GAEG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC/B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GAChB,OAAO,CAAC,CAAC,CAAC,CA8BZ"}
|