@astralyn/pi 0.84.13 → 0.84.15

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.
Files changed (202) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/core/agent-session.d.ts.map +1 -1
  3. package/dist/core/agent-session.js +12 -6
  4. package/dist/core/agent-session.js.map +1 -1
  5. package/dist/core/extensions/types.d.ts +4 -1
  6. package/dist/core/extensions/types.d.ts.map +1 -1
  7. package/dist/core/extensions/types.js.map +1 -1
  8. package/dist/core/tools/bash.d.ts +1 -0
  9. package/dist/core/tools/bash.d.ts.map +1 -1
  10. package/dist/core/tools/bash.js +4 -1
  11. package/dist/core/tools/bash.js.map +1 -1
  12. package/dist/core/tools/find.d.ts +2 -0
  13. package/dist/core/tools/find.d.ts.map +1 -1
  14. package/dist/core/tools/find.js +18 -15
  15. package/dist/core/tools/find.js.map +1 -1
  16. package/dist/extensions/background/actions.d.ts.map +1 -1
  17. package/dist/extensions/background/actions.js +3 -2
  18. package/dist/extensions/background/actions.js.map +1 -1
  19. package/dist/extensions/background/manager.d.ts.map +1 -1
  20. package/dist/extensions/background/manager.js +8 -9
  21. package/dist/extensions/background/manager.js.map +1 -1
  22. package/dist/extensions/background/registry.d.ts +4 -1
  23. package/dist/extensions/background/registry.d.ts.map +1 -1
  24. package/dist/extensions/background/registry.js +30 -17
  25. package/dist/extensions/background/registry.js.map +1 -1
  26. package/dist/extensions/background/task-view.d.ts +6 -0
  27. package/dist/extensions/background/task-view.d.ts.map +1 -1
  28. package/dist/extensions/background/task-view.js +11 -6
  29. package/dist/extensions/background/task-view.js.map +1 -1
  30. package/dist/extensions/deepwiki/client.d.ts.map +1 -1
  31. package/dist/extensions/deepwiki/client.js +3 -0
  32. package/dist/extensions/deepwiki/client.js.map +1 -1
  33. package/dist/extensions/deepwiki/execute.d.ts +2 -1
  34. package/dist/extensions/deepwiki/execute.d.ts.map +1 -1
  35. package/dist/extensions/deepwiki/execute.js +17 -2
  36. package/dist/extensions/deepwiki/execute.js.map +1 -1
  37. package/dist/extensions/deepwiki/http.d.ts +1 -0
  38. package/dist/extensions/deepwiki/http.d.ts.map +1 -1
  39. package/dist/extensions/deepwiki/http.js +16 -2
  40. package/dist/extensions/deepwiki/http.js.map +1 -1
  41. package/dist/extensions/deepwiki/schema.d.ts +1 -1
  42. package/dist/extensions/deepwiki/schema.d.ts.map +1 -1
  43. package/dist/extensions/deepwiki/schema.js +8 -2
  44. package/dist/extensions/deepwiki/schema.js.map +1 -1
  45. package/dist/extensions/question/dialog.d.ts.map +1 -1
  46. package/dist/extensions/question/dialog.js +80 -9
  47. package/dist/extensions/question/dialog.js.map +1 -1
  48. package/dist/extensions/question/index.d.ts.map +1 -1
  49. package/dist/extensions/question/index.js +8 -0
  50. package/dist/extensions/question/index.js.map +1 -1
  51. package/dist/extensions/question/schema.d.ts +2 -2
  52. package/dist/extensions/question/schema.d.ts.map +1 -1
  53. package/dist/extensions/question/schema.js +41 -11
  54. package/dist/extensions/question/schema.js.map +1 -1
  55. package/dist/extensions/question/types.d.ts +1 -1
  56. package/dist/extensions/question/types.d.ts.map +1 -1
  57. package/dist/extensions/question/types.js.map +1 -1
  58. package/dist/extensions/router/probe.d.ts.map +1 -1
  59. package/dist/extensions/router/probe.js +10 -29
  60. package/dist/extensions/router/probe.js.map +1 -1
  61. package/dist/extensions/router/register.d.ts.map +1 -1
  62. package/dist/extensions/router/register.js +16 -6
  63. package/dist/extensions/router/register.js.map +1 -1
  64. package/dist/extensions/router/store.d.ts.map +1 -1
  65. package/dist/extensions/router/store.js +108 -51
  66. package/dist/extensions/router/store.js.map +1 -1
  67. package/dist/extensions/router/ui.d.ts +6 -0
  68. package/dist/extensions/router/ui.d.ts.map +1 -1
  69. package/dist/extensions/router/ui.js +14 -6
  70. package/dist/extensions/router/ui.js.map +1 -1
  71. package/dist/extensions/statusline/index.d.ts.map +1 -1
  72. package/dist/extensions/statusline/index.js +40 -43
  73. package/dist/extensions/statusline/index.js.map +1 -1
  74. package/dist/extensions/subagent/activity.d.ts +7 -1
  75. package/dist/extensions/subagent/activity.d.ts.map +1 -1
  76. package/dist/extensions/subagent/activity.js +69 -6
  77. package/dist/extensions/subagent/activity.js.map +1 -1
  78. package/dist/extensions/subagent/agents-command.js +1 -1
  79. package/dist/extensions/subagent/agents-command.js.map +1 -1
  80. package/dist/extensions/subagent/agents.d.ts.map +1 -1
  81. package/dist/extensions/subagent/agents.js +0 -3
  82. package/dist/extensions/subagent/agents.js.map +1 -1
  83. package/dist/extensions/subagent/budget.d.ts.map +1 -1
  84. package/dist/extensions/subagent/budget.js +29 -2
  85. package/dist/extensions/subagent/budget.js.map +1 -1
  86. package/dist/extensions/subagent/cancellation.d.ts +4 -4
  87. package/dist/extensions/subagent/cancellation.d.ts.map +1 -1
  88. package/dist/extensions/subagent/cancellation.js +31 -13
  89. package/dist/extensions/subagent/cancellation.js.map +1 -1
  90. package/dist/extensions/subagent/constants.d.ts +1 -0
  91. package/dist/extensions/subagent/constants.d.ts.map +1 -1
  92. package/dist/extensions/subagent/constants.js +1 -0
  93. package/dist/extensions/subagent/constants.js.map +1 -1
  94. package/dist/extensions/subagent/index.d.ts.map +1 -1
  95. package/dist/extensions/subagent/index.js +1 -0
  96. package/dist/extensions/subagent/index.js.map +1 -1
  97. package/dist/extensions/subagent/render.d.ts +8 -1
  98. package/dist/extensions/subagent/render.d.ts.map +1 -1
  99. package/dist/extensions/subagent/render.js +148 -178
  100. package/dist/extensions/subagent/render.js.map +1 -1
  101. package/dist/extensions/subagent/runner.d.ts +1 -0
  102. package/dist/extensions/subagent/runner.d.ts.map +1 -1
  103. package/dist/extensions/subagent/runner.js +53 -44
  104. package/dist/extensions/subagent/runner.js.map +1 -1
  105. package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
  106. package/dist/extensions/subagent/sdk-runner.js +0 -3
  107. package/dist/extensions/subagent/sdk-runner.js.map +1 -1
  108. package/dist/extensions/subagent/settings.d.ts +1 -1
  109. package/dist/extensions/subagent/settings.d.ts.map +1 -1
  110. package/dist/extensions/subagent/settings.js +74 -25
  111. package/dist/extensions/subagent/settings.js.map +1 -1
  112. package/dist/extensions/subagent/state.d.ts +1 -0
  113. package/dist/extensions/subagent/state.d.ts.map +1 -1
  114. package/dist/extensions/subagent/state.js +46 -16
  115. package/dist/extensions/subagent/state.js.map +1 -1
  116. package/dist/extensions/subagent/types.d.ts +0 -7
  117. package/dist/extensions/subagent/types.d.ts.map +1 -1
  118. package/dist/extensions/subagent/types.js.map +1 -1
  119. package/dist/extensions/subagent/ui/agents-dialog.js +1 -1
  120. package/dist/extensions/subagent/ui/agents-dialog.js.map +1 -1
  121. package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -1
  122. package/dist/extensions/subagent/ui/model-list.js +3 -4
  123. package/dist/extensions/subagent/ui/model-list.js.map +1 -1
  124. package/dist/extensions/subagent/ui/model-picker.d.ts.map +1 -1
  125. package/dist/extensions/subagent/ui/model-picker.js +2 -1
  126. package/dist/extensions/subagent/ui/model-picker.js.map +1 -1
  127. package/dist/extensions/web-search/constants.d.ts +2 -2
  128. package/dist/extensions/web-search/constants.d.ts.map +1 -1
  129. package/dist/extensions/web-search/constants.js +4 -5
  130. package/dist/extensions/web-search/constants.js.map +1 -1
  131. package/dist/extensions/web-search/execute.d.ts +13 -0
  132. package/dist/extensions/web-search/execute.d.ts.map +1 -0
  133. package/dist/extensions/web-search/execute.js +101 -0
  134. package/dist/extensions/web-search/execute.js.map +1 -0
  135. package/dist/extensions/web-search/format.d.ts +12 -0
  136. package/dist/extensions/web-search/format.d.ts.map +1 -0
  137. package/dist/extensions/web-search/format.js +109 -0
  138. package/dist/extensions/web-search/format.js.map +1 -0
  139. package/dist/extensions/web-search/index.d.ts.map +1 -1
  140. package/dist/extensions/web-search/index.js +12 -9
  141. package/dist/extensions/web-search/index.js.map +1 -1
  142. package/dist/extensions/web-search/providers/deepseek.d.ts +0 -2
  143. package/dist/extensions/web-search/providers/deepseek.d.ts.map +1 -1
  144. package/dist/extensions/web-search/providers/deepseek.js +82 -34
  145. package/dist/extensions/web-search/providers/deepseek.js.map +1 -1
  146. package/dist/extensions/web-search/providers/http.d.ts +2 -7
  147. package/dist/extensions/web-search/providers/http.d.ts.map +1 -1
  148. package/dist/extensions/web-search/providers/http.js +30 -13
  149. package/dist/extensions/web-search/providers/http.js.map +1 -1
  150. package/dist/extensions/web-search/providers/minimax.d.ts +0 -2
  151. package/dist/extensions/web-search/providers/minimax.d.ts.map +1 -1
  152. package/dist/extensions/web-search/providers/minimax.js +43 -50
  153. package/dist/extensions/web-search/providers/minimax.js.map +1 -1
  154. package/dist/extensions/web-search/render.d.ts +1 -2
  155. package/dist/extensions/web-search/render.d.ts.map +1 -1
  156. package/dist/extensions/web-search/render.js +22 -17
  157. package/dist/extensions/web-search/render.js.map +1 -1
  158. package/dist/extensions/web-search/results.d.ts +35 -0
  159. package/dist/extensions/web-search/results.d.ts.map +1 -0
  160. package/dist/extensions/web-search/results.js +172 -0
  161. package/dist/extensions/web-search/results.js.map +1 -0
  162. package/dist/extensions/web-search/schema.d.ts +0 -2
  163. package/dist/extensions/web-search/schema.d.ts.map +1 -1
  164. package/dist/extensions/web-search/schema.js +4 -25
  165. package/dist/extensions/web-search/schema.js.map +1 -1
  166. package/dist/extensions/web-search/types.d.ts +0 -62
  167. package/dist/extensions/web-search/types.d.ts.map +1 -1
  168. package/dist/extensions/web-search/types.js.map +1 -1
  169. package/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  170. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  171. package/dist/modes/interactive/components/tool-execution.js +7 -0
  172. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  173. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  174. package/dist/modes/interactive/components/tool-group.js +10 -0
  175. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  176. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  177. package/dist/modes/interactive/interactive-mode.js +3 -40
  178. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  179. package/dist/modes/interactive/theme/theme.d.ts +0 -4
  180. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  181. package/dist/modes/interactive/theme/theme.js +16 -23
  182. package/dist/modes/interactive/theme/theme.js.map +1 -1
  183. package/dist/utils/http-response.d.ts +10 -0
  184. package/dist/utils/http-response.d.ts.map +1 -0
  185. package/dist/utils/http-response.js +68 -0
  186. package/dist/utils/http-response.js.map +1 -0
  187. package/docs/bundled/extensions/background.md +2 -1
  188. package/docs/bundled/extensions/deepwiki.md +7 -5
  189. package/docs/bundled/extensions/question.md +6 -4
  190. package/docs/bundled/extensions/router.md +1 -1
  191. package/docs/bundled/extensions/statusline.md +1 -0
  192. package/docs/bundled/extensions/subagent.md +29 -39
  193. package/docs/bundled/extensions/web-search.md +8 -12
  194. package/docs/development.md +7 -2
  195. package/docs/docs.json +4 -0
  196. package/docs/extensions.md +2 -2
  197. package/npm-shrinkwrap.json +2 -2
  198. package/package.json +1 -1
  199. package/dist/extensions/web-search/fusion.d.ts +0 -36
  200. package/dist/extensions/web-search/fusion.d.ts.map +0 -1
  201. package/dist/extensions/web-search/fusion.js +0 -272
  202. package/dist/extensions/web-search/fusion.js.map +0 -1
@@ -1,23 +1,69 @@
1
1
  /**
2
2
  * deepseek.ts — DeepSeek Messages API search provider (claude-sonnet-search model with web_search_20250305).
3
3
  */
4
+ import { MAX_PROVIDER_HIT_SCAN } from "../results.js";
4
5
  import { postJson } from "./http.js";
5
6
  const DEFAULT_DEEPSEEK_MESSAGES_ENDPOINT = "https://api.deepseek.com/anthropic/v1/messages";
6
7
  const DEFAULT_DEEPSEEK_SEARCH_MODEL = "claude-sonnet-search";
7
- export async function searchDeepSeek(options) {
8
- const endpoint = options.baseUrl || DEFAULT_DEEPSEEK_MESSAGES_ENDPOINT;
9
- const model = options.model || DEFAULT_DEEPSEEK_SEARCH_MODEL;
10
- const toolConfig = {
11
- type: "web_search_20250305",
12
- name: "web_search",
8
+ function isRecord(value) {
9
+ return typeof value === "object" && value !== null && !Array.isArray(value);
10
+ }
11
+ function stringField(record, key) {
12
+ const value = record[key];
13
+ return typeof value === "string" ? value : undefined;
14
+ }
15
+ function parseSearchHit(value) {
16
+ if (!isRecord(value) || value.type !== "web_search_result")
17
+ return undefined;
18
+ const url = stringField(value, "url")?.trim();
19
+ if (!url)
20
+ return undefined;
21
+ const title = stringField(value, "title")?.trim();
22
+ const pageAge = stringField(value, "page_age")?.trim();
23
+ return {
24
+ title: title || url,
25
+ url,
26
+ date: pageAge || undefined,
27
+ sources: ["DeepSeek"],
13
28
  };
14
- if (options.allowedDomains && options.allowedDomains.length > 0) {
15
- toolConfig.allowed_domains = options.allowedDomains;
29
+ }
30
+ function errorMessage(value) {
31
+ if (!isRecord(value))
32
+ return undefined;
33
+ return stringField(value, "message") || stringField(value, "type") || "Unknown error";
34
+ }
35
+ function searchToolErrorMessage(value) {
36
+ return (stringField(value, "message")?.trim() ||
37
+ stringField(value, "error_code")?.trim() ||
38
+ stringField(value, "type")?.trim() ||
39
+ "Unknown search tool error");
40
+ }
41
+ function parseSearchToolContent(value) {
42
+ if (Array.isArray(value)) {
43
+ const hits = [];
44
+ for (const item of value) {
45
+ const hit = parseSearchHit(item);
46
+ if (!hit)
47
+ throw new Error("DeepSeek returned malformed web_search_tool_result content");
48
+ if (hits.length < MAX_PROVIDER_HIT_SCAN)
49
+ hits.push(hit);
50
+ }
51
+ return hits;
16
52
  }
17
- else if (options.blockedDomains && options.blockedDomains.length > 0) {
18
- toolConfig.blocked_domains = options.blockedDomains;
53
+ if (isRecord(value)) {
54
+ if (value.type === "web_search_tool_result_error" ||
55
+ value.error_code !== undefined ||
56
+ value.message !== undefined) {
57
+ throw new Error(`DeepSeek web search failed: ${searchToolErrorMessage(value)}`);
58
+ }
59
+ throw new Error("DeepSeek returned malformed web_search_tool_result content");
19
60
  }
20
- const data = await postJson(endpoint, {
61
+ throw new Error("DeepSeek returned malformed web_search_tool_result content");
62
+ }
63
+ export async function searchDeepSeek(options) {
64
+ const endpoint = options.baseUrl || DEFAULT_DEEPSEEK_MESSAGES_ENDPOINT;
65
+ const model = options.model || DEFAULT_DEEPSEEK_SEARCH_MODEL;
66
+ const rawData = await postJson(endpoint, {
21
67
  "Content-Type": "application/json",
22
68
  "x-api-key": options.apiKey,
23
69
  Authorization: `Bearer ${options.apiKey}`,
@@ -26,38 +72,40 @@ export async function searchDeepSeek(options) {
26
72
  model,
27
73
  max_tokens: 1024,
28
74
  messages: [{ role: "user", content: options.query }],
29
- tools: [toolConfig],
75
+ tools: [{ type: "web_search_20250305", name: "web_search" }],
30
76
  }, options.signal, 90_000, "DeepSeek Messages search API");
31
- if (data.error) {
32
- throw new Error(`DeepSeek search error: ${data.error.message || data.error.type || "Unknown error"}`);
33
- }
77
+ const data = isRecord(rawData) ? rawData : {};
78
+ const upstreamError = errorMessage(data.error);
79
+ if (upstreamError)
80
+ throw new Error(`DeepSeek search error: ${upstreamError}`);
34
81
  const hits = [];
35
- let synthesisText = "";
36
- for (const block of data.content || []) {
37
- if (block.type === "web_search_tool_result") {
38
- const toolResultBlock = block;
39
- for (const item of toolResultBlock.content || []) {
40
- if (item.url && typeof item.url === "string") {
41
- hits.push({
42
- title: item.title?.trim() || item.url.trim(),
43
- url: item.url.trim(),
44
- date: item.page_age || undefined,
45
- sources: ["DeepSeek"],
46
- });
47
- }
82
+ const synthesisParts = [];
83
+ let sawStructuredResult = false;
84
+ const content = Array.isArray(data.content) ? data.content : [];
85
+ for (const value of content) {
86
+ if (!isRecord(value))
87
+ continue;
88
+ if (value.type === "web_search_tool_result") {
89
+ sawStructuredResult = true;
90
+ for (const hit of parseSearchToolContent(value.content)) {
91
+ if (hits.length < MAX_PROVIDER_HIT_SCAN)
92
+ hits.push(hit);
48
93
  }
94
+ continue;
49
95
  }
50
- else if (block.type === "text") {
51
- const textBlock = block;
52
- if (textBlock.text) {
53
- synthesisText += (synthesisText ? "\n\n" : "") + textBlock.text.trim();
54
- }
96
+ if (value.type === "text") {
97
+ const text = stringField(value, "text")?.trim();
98
+ if (text)
99
+ synthesisParts.push(text);
55
100
  }
56
101
  }
102
+ if (!sawStructuredResult) {
103
+ throw new Error("DeepSeek returned no web_search_tool_result block");
104
+ }
57
105
  return {
58
106
  source: "DeepSeek",
59
107
  hits,
60
- synthesisText: synthesisText || undefined,
108
+ synthesisText: synthesisParts.length > 0 ? synthesisParts.join("\n\n") : undefined,
61
109
  };
62
110
  }
63
111
  //# sourceMappingURL=deepseek.js.map
@@ -1 +1 @@
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 { DeepSeekMessagesResponse, 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\tallowedDomains?: string[];\n\tblockedDomains?: string[];\n}\n\nconst DEFAULT_DEEPSEEK_MESSAGES_ENDPOINT = \"https://api.deepseek.com/anthropic/v1/messages\";\nconst DEFAULT_DEEPSEEK_SEARCH_MODEL = \"claude-sonnet-search\";\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\n\tconst toolConfig: Record<string, unknown> = {\n\t\ttype: \"web_search_20250305\",\n\t\tname: \"web_search\",\n\t};\n\n\tif (options.allowedDomains && options.allowedDomains.length > 0) {\n\t\ttoolConfig.allowed_domains = options.allowedDomains;\n\t} else if (options.blockedDomains && options.blockedDomains.length > 0) {\n\t\ttoolConfig.blocked_domains = options.blockedDomains;\n\t}\n\n\tconst data = await postJson<DeepSeekMessagesResponse>(\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: [toolConfig],\n\t\t},\n\t\toptions.signal,\n\t\t90_000,\n\t\t\"DeepSeek Messages search API\",\n\t);\n\n\tif (data.error) {\n\t\tthrow new Error(`DeepSeek search error: ${data.error.message || data.error.type || \"Unknown error\"}`);\n\t}\n\n\tconst hits: WebSearchHit[] = [];\n\tlet synthesisText = \"\";\n\n\tfor (const block of data.content || []) {\n\t\tif (block.type === \"web_search_tool_result\") {\n\t\t\tconst toolResultBlock = block as {\n\t\t\t\tcontent?: { type?: string; title?: string; url?: string; page_age?: string }[];\n\t\t\t};\n\t\t\tfor (const item of toolResultBlock.content || []) {\n\t\t\t\tif (item.url && typeof item.url === \"string\") {\n\t\t\t\t\thits.push({\n\t\t\t\t\t\ttitle: item.title?.trim() || item.url.trim(),\n\t\t\t\t\t\turl: item.url.trim(),\n\t\t\t\t\t\tdate: item.page_age || undefined,\n\t\t\t\t\t\tsources: [\"DeepSeek\"],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (block.type === \"text\") {\n\t\t\tconst textBlock = block as { text?: string };\n\t\t\tif (textBlock.text) {\n\t\t\t\tsynthesisText += (synthesisText ? \"\\n\\n\" : \"\") + textBlock.text.trim();\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tsource: \"DeepSeek\",\n\t\thits,\n\t\tsynthesisText: synthesisText || undefined,\n\t};\n}\n"]}
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 { MAX_PROVIDER_HIT_SCAN } from \"../results.ts\";\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\nfunction searchToolErrorMessage(value: JsonRecord): string {\n\treturn (\n\t\tstringField(value, \"message\")?.trim() ||\n\t\tstringField(value, \"error_code\")?.trim() ||\n\t\tstringField(value, \"type\")?.trim() ||\n\t\t\"Unknown search tool error\"\n\t);\n}\n\nfunction parseSearchToolContent(value: unknown): WebSearchHit[] {\n\tif (Array.isArray(value)) {\n\t\tconst hits: WebSearchHit[] = [];\n\t\tfor (const item of value) {\n\t\t\tconst hit = parseSearchHit(item);\n\t\t\tif (!hit) throw new Error(\"DeepSeek returned malformed web_search_tool_result content\");\n\t\t\tif (hits.length < MAX_PROVIDER_HIT_SCAN) hits.push(hit);\n\t\t}\n\t\treturn hits;\n\t}\n\tif (isRecord(value)) {\n\t\tif (\n\t\t\tvalue.type === \"web_search_tool_result_error\" ||\n\t\t\tvalue.error_code !== undefined ||\n\t\t\tvalue.message !== undefined\n\t\t) {\n\t\t\tthrow new Error(`DeepSeek web search failed: ${searchToolErrorMessage(value)}`);\n\t\t}\n\t\tthrow new Error(\"DeepSeek returned malformed web_search_tool_result content\");\n\t}\n\tthrow new Error(\"DeepSeek returned malformed web_search_tool_result content\");\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\tlet sawStructuredResult = false;\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\tsawStructuredResult = true;\n\t\t\tfor (const hit of parseSearchToolContent(value.content)) {\n\t\t\t\tif (hits.length < MAX_PROVIDER_HIT_SCAN) 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\tif (!sawStructuredResult) {\n\t\tthrow new Error(\"DeepSeek returned no web_search_tool_result block\");\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,9 +1,4 @@
1
- /**
2
- * http.ts — Shared JSON POST plumbing for search providers: caller signal plus
3
- * per-request timeout, bounded upstream error bodies, clear parse errors.
4
- */
5
- /**
6
- * POST a JSON body and return the parsed response.
7
- */
1
+ /** JSON POST plumbing for search providers. */
2
+ /** POST a JSON body and return the parsed response. */
8
3
  export declare function postJson<T>(url: string, headers: Record<string, string>, body: unknown, signal: AbortSignal | undefined, timeoutMs: number, errorLabel: string): Promise<T>;
9
4
  //# sourceMappingURL=http.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/http.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH;;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,CAkBZ"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/http.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAU/C,uDAAuD;AACvD,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,CAiCZ"}
@@ -1,25 +1,42 @@
1
- /**
2
- * http.ts — Shared JSON POST plumbing for search providers: caller signal plus
3
- * per-request timeout, bounded upstream error bodies, clear parse errors.
4
- */
1
+ /** JSON POST plumbing for search providers. */
2
+ import { readResponseTextBounded } from "../../../utils/http-response.js";
3
+ /** Successful response bodies are model-facing; keep them bounded. */
4
+ const MAX_RESPONSE_BODY_BYTES = 2 * 1024 * 1024;
5
5
  /** Error bodies are surfaced to the model; keep them bounded. */
6
- const MAX_ERROR_BODY_LENGTH = 200;
7
- /**
8
- * POST a JSON body and return the parsed response.
9
- */
6
+ const MAX_ERROR_BODY_BYTES = 200;
7
+ /** POST a JSON body and return the parsed response. */
10
8
  export async function postJson(url, headers, body, signal, timeoutMs, errorLabel) {
9
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
10
+ const requestSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
11
11
  const response = await fetch(url, {
12
12
  method: "POST",
13
13
  headers,
14
14
  body: JSON.stringify(body),
15
- signal: signal ? AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]) : AbortSignal.timeout(timeoutMs),
15
+ signal: requestSignal,
16
16
  });
17
17
  if (!response.ok) {
18
- const errorText = await response.text().catch(() => "");
19
- throw new Error(`${errorLabel} returned HTTP ${response.status} ${response.statusText}: ${errorText.slice(0, MAX_ERROR_BODY_LENGTH)}`);
18
+ let errorText = "";
19
+ try {
20
+ errorText = await readResponseTextBounded(response, {
21
+ maxBytes: MAX_ERROR_BODY_BYTES,
22
+ signal: requestSignal,
23
+ });
24
+ }
25
+ catch {
26
+ requestSignal.throwIfAborted();
27
+ }
28
+ throw new Error(`${errorLabel} returned HTTP ${response.status} ${response.statusText}: ${errorText}`);
20
29
  }
21
- return (await response.json().catch(() => {
30
+ const responseText = await readResponseTextBounded(response, {
31
+ maxBytes: MAX_RESPONSE_BODY_BYTES,
32
+ overflowMessage: `${errorLabel} response exceeded ${MAX_RESPONSE_BODY_BYTES} bytes`,
33
+ signal: requestSignal,
34
+ });
35
+ try {
36
+ return JSON.parse(responseText);
37
+ }
38
+ catch {
22
39
  throw new Error(`${errorLabel} returned invalid JSON`);
23
- }));
40
+ }
24
41
  }
25
42
  //# sourceMappingURL=http.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/http.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,iEAAiE;AACjE,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC7B,GAAW,EACX,OAA+B,EAC/B,IAAa,EACb,MAA+B,EAC/B,SAAiB,EACjB,UAAkB;IAElB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QACjC,MAAM,EAAE,MAAM;QACd,OAAO;QACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC;KAC3G,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACxD,MAAM,IAAI,KAAK,CACd,GAAG,UAAU,kBAAkB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC,EAAE,CACrH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;QACxC,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,wBAAwB,CAAC,CAAC;IACxD,CAAC,CAAC,CAAM,CAAC;AACV,CAAC","sourcesContent":["/**\n * http.ts — Shared JSON POST plumbing for search providers: caller signal plus\n * per-request timeout, bounded upstream error bodies, clear parse errors.\n */\n\n/** Error bodies are surfaced to the model; keep them bounded. */\nconst MAX_ERROR_BODY_LENGTH = 200;\n\n/**\n * POST a JSON body and return the parsed response.\n */\nexport async function postJson<T>(\n\turl: string,\n\theaders: Record<string, string>,\n\tbody: unknown,\n\tsignal: AbortSignal | undefined,\n\ttimeoutMs: number,\n\terrorLabel: string,\n): Promise<T> {\n\tconst response = await fetch(url, {\n\t\tmethod: \"POST\",\n\t\theaders,\n\t\tbody: JSON.stringify(body),\n\t\tsignal: signal ? AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]) : AbortSignal.timeout(timeoutMs),\n\t});\n\n\tif (!response.ok) {\n\t\tconst errorText = await response.text().catch(() => \"\");\n\t\tthrow new Error(\n\t\t\t`${errorLabel} returned HTTP ${response.status} ${response.statusText}: ${errorText.slice(0, MAX_ERROR_BODY_LENGTH)}`,\n\t\t);\n\t}\n\n\treturn (await response.json().catch(() => {\n\t\tthrow new Error(`${errorLabel} returned invalid JSON`);\n\t})) as T;\n}\n"]}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/http.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAE/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAE1E,sEAAsE;AACtE,MAAM,uBAAuB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhD,iEAAiE;AACjE,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC,uDAAuD;AACvD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC7B,GAAW,EACX,OAA+B,EAC/B,IAAa,EACb,MAA+B,EAC/B,SAAiB,EACjB,UAAkB;IAElB,MAAM,aAAa,GAAG,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;IACxF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QACjC,MAAM,EAAE,MAAM;QACd,OAAO;QACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAC1B,MAAM,EAAE,aAAa;KACrB,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,IAAI,SAAS,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC;YACJ,SAAS,GAAG,MAAM,uBAAuB,CAAC,QAAQ,EAAE;gBACnD,QAAQ,EAAE,oBAAoB;gBAC9B,MAAM,EAAE,aAAa;aACrB,CAAC,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACR,aAAa,CAAC,cAAc,EAAE,CAAC;QAChC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,kBAAkB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC,CAAC;IACxG,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,uBAAuB,CAAC,QAAQ,EAAE;QAC5D,QAAQ,EAAE,uBAAuB;QACjC,eAAe,EAAE,GAAG,UAAU,sBAAsB,uBAAuB,QAAQ;QACnF,MAAM,EAAE,aAAa;KACrB,CAAC,CAAC;IACH,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAM,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,wBAAwB,CAAC,CAAC;IACxD,CAAC;AACF,CAAC","sourcesContent":["/** JSON POST plumbing for search providers. */\n\nimport { readResponseTextBounded } from \"../../../utils/http-response.ts\";\n\n/** Successful response bodies are model-facing; keep them bounded. */\nconst MAX_RESPONSE_BODY_BYTES = 2 * 1024 * 1024;\n\n/** Error bodies are surfaced to the model; keep them bounded. */\nconst MAX_ERROR_BODY_BYTES = 200;\n\n/** POST a JSON body and return the parsed response. */\nexport async function postJson<T>(\n\turl: string,\n\theaders: Record<string, string>,\n\tbody: unknown,\n\tsignal: AbortSignal | undefined,\n\ttimeoutMs: number,\n\terrorLabel: string,\n): Promise<T> {\n\tconst timeoutSignal = AbortSignal.timeout(timeoutMs);\n\tconst requestSignal = signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;\n\tconst response = await fetch(url, {\n\t\tmethod: \"POST\",\n\t\theaders,\n\t\tbody: JSON.stringify(body),\n\t\tsignal: requestSignal,\n\t});\n\n\tif (!response.ok) {\n\t\tlet errorText = \"\";\n\t\ttry {\n\t\t\terrorText = await readResponseTextBounded(response, {\n\t\t\t\tmaxBytes: MAX_ERROR_BODY_BYTES,\n\t\t\t\tsignal: requestSignal,\n\t\t\t});\n\t\t} catch {\n\t\t\trequestSignal.throwIfAborted();\n\t\t}\n\t\tthrow new Error(`${errorLabel} returned HTTP ${response.status} ${response.statusText}: ${errorText}`);\n\t}\n\n\tconst responseText = await readResponseTextBounded(response, {\n\t\tmaxBytes: MAX_RESPONSE_BODY_BYTES,\n\t\toverflowMessage: `${errorLabel} response exceeded ${MAX_RESPONSE_BODY_BYTES} bytes`,\n\t\tsignal: requestSignal,\n\t});\n\ttry {\n\t\treturn JSON.parse(responseText) as T;\n\t} catch {\n\t\tthrow new Error(`${errorLabel} returned invalid JSON`);\n\t}\n}\n"]}
@@ -7,8 +7,6 @@ export interface MiniMaxSearchOptions {
7
7
  apiKey: string;
8
8
  apiHost?: string;
9
9
  signal?: AbortSignal;
10
- allowedDomains?: string[];
11
- blockedDomains?: string[];
12
10
  }
13
11
  export declare function searchMiniMax(options: MiniMaxSearchOptions): Promise<ProviderSearchResult>;
14
12
  //# sourceMappingURL=minimax.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"minimax.d.ts","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/minimax.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAyB,oBAAoB,EAAgB,MAAM,aAAa,CAAC;AAG7F,MAAM,WAAW,oBAAoB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AA+BD,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA+ChG"}
1
+ {"version":3,"file":"minimax.d.ts","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/minimax.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,oBAAoB,EAAgB,MAAM,aAAa,CAAC;AAGtE,MAAM,WAAW,oBAAoB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;CACrB;AA0BD,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA4ChG"}
@@ -1,69 +1,62 @@
1
1
  /**
2
2
  * minimax.ts — MiniMax Coding Plan Search REST API provider.
3
3
  */
4
+ import { MAX_PROVIDER_HIT_SCAN, MAX_PROVIDER_RELATED_SCAN, MAX_RELATED_SEARCHES } from "../results.js";
4
5
  import { postJson } from "./http.js";
5
- function buildSearchQuery(query, allowedDomains, blockedDomains) {
6
- let q = query.trim();
7
- if (allowedDomains && allowedDomains.length > 0) {
8
- const siteFilter = allowedDomains.map((d) => `site:${d.trim()}`).join(" OR ");
9
- q = `${q} (${siteFilter})`;
10
- }
11
- else if (blockedDomains && blockedDomains.length > 0) {
12
- const blockFilter = blockedDomains.map((d) => `-site:${d.trim()}`).join(" ");
13
- q = `${q} ${blockFilter}`;
14
- }
15
- return q;
6
+ function isRecord(value) {
7
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16
8
  }
17
- function matchesDomainFilters(url, allowedDomains, blockedDomains) {
18
- try {
19
- const parsed = new URL(url);
20
- const hostname = parsed.hostname.toLowerCase();
21
- if (allowedDomains && allowedDomains.length > 0) {
22
- return allowedDomains.some((d) => hostname === d.toLowerCase() || hostname.endsWith(`.${d.toLowerCase()}`));
23
- }
24
- if (blockedDomains && blockedDomains.length > 0) {
25
- return !blockedDomains.some((d) => hostname === d.toLowerCase() || hostname.endsWith(`.${d.toLowerCase()}`));
26
- }
27
- return true;
28
- }
29
- catch {
30
- return true;
31
- }
9
+ function stringField(record, key) {
10
+ const value = record[key];
11
+ return typeof value === "string" ? value : undefined;
12
+ }
13
+ function parseSearchHit(value) {
14
+ if (!isRecord(value))
15
+ return undefined;
16
+ const url = stringField(value, "link")?.trim();
17
+ if (!url)
18
+ return undefined;
19
+ return {
20
+ title: stringField(value, "title")?.trim() || url,
21
+ url,
22
+ snippet: stringField(value, "snippet")?.trim() || undefined,
23
+ date: stringField(value, "date")?.trim() || undefined,
24
+ sources: ["MiniMax"],
25
+ };
32
26
  }
33
27
  export async function searchMiniMax(options) {
34
28
  const host = options.apiHost?.replace(/\/+$/, "") || "https://api.minimaxi.com";
35
- const effectiveQuery = buildSearchQuery(options.query, options.allowedDomains, options.blockedDomains);
36
- const data = await postJson(`${host}/v1/coding_plan/search`, {
29
+ const rawData = await postJson(`${host}/v1/coding_plan/search`, {
37
30
  "Content-Type": "application/json",
38
31
  Authorization: `Bearer ${options.apiKey}`,
39
- }, { q: effectiveQuery }, options.signal, 60_000, "MiniMax search API");
40
- if (data.base_resp && data.base_resp.status_code !== 0) {
41
- throw new Error(`MiniMax search failed: [${data.base_resp.status_code}] ${data.base_resp.status_msg}`);
32
+ }, { q: options.query.trim() }, options.signal, 60_000, "MiniMax search API");
33
+ const data = isRecord(rawData) ? rawData : {};
34
+ const baseResponse = isRecord(data.base_resp) ? data.base_resp : undefined;
35
+ const statusCode = baseResponse?.status_code;
36
+ if (baseResponse && typeof statusCode === "number" && statusCode !== 0) {
37
+ throw new Error(`MiniMax search failed: [${statusCode}] ${stringField(baseResponse, "status_msg") ?? "Unknown error"}`);
42
38
  }
43
- const rawHits = data.organic || [];
44
39
  const hits = [];
45
- for (const item of rawHits) {
46
- if (!item.link || !item.link.trim())
47
- continue;
48
- const cleanLink = item.link.trim();
49
- if (!matchesDomainFilters(cleanLink, options.allowedDomains, options.blockedDomains)) {
50
- continue;
51
- }
52
- hits.push({
53
- title: item.title?.trim() || cleanLink,
54
- url: cleanLink,
55
- snippet: item.snippet?.trim() || undefined,
56
- date: item.date?.trim() || undefined,
57
- sources: ["MiniMax"],
58
- });
40
+ const organic = Array.isArray(data.organic) ? data.organic : [];
41
+ const hitScanLimit = Math.min(organic.length, MAX_PROVIDER_HIT_SCAN);
42
+ for (let index = 0; index < hitScanLimit; index++) {
43
+ const hit = parseSearchHit(organic[index]);
44
+ if (hit)
45
+ hits.push(hit);
46
+ }
47
+ const relatedSearches = [];
48
+ const related = Array.isArray(data.related_searches) ? data.related_searches : [];
49
+ const relatedScanLimit = Math.min(related.length, MAX_PROVIDER_RELATED_SCAN);
50
+ for (let index = 0; index < relatedScanLimit && relatedSearches.length < MAX_RELATED_SEARCHES; index++) {
51
+ const value = related[index];
52
+ const query = isRecord(value) ? stringField(value, "query")?.trim() : undefined;
53
+ if (query)
54
+ relatedSearches.push(query);
59
55
  }
60
- const relatedSearches = data.related_searches
61
- ?.map((r) => r.query?.trim())
62
- .filter((q) => Boolean(q && q.length > 0));
63
56
  return {
64
57
  source: "MiniMax",
65
58
  hits,
66
- relatedSearches: relatedSearches && relatedSearches.length > 0 ? relatedSearches : undefined,
59
+ relatedSearches: relatedSearches.length > 0 ? relatedSearches : undefined,
67
60
  };
68
61
  }
69
62
  //# sourceMappingURL=minimax.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"minimax.js","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/minimax.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * minimax.ts — MiniMax Coding Plan Search REST API provider.\n */\n\nimport type { MiniMaxSearchResponse, ProviderSearchResult, WebSearchHit } from \"../types.ts\";\nimport { postJson } from \"./http.ts\";\n\nexport interface MiniMaxSearchOptions {\n\tquery: string;\n\tapiKey: string;\n\tapiHost?: string;\n\tsignal?: AbortSignal;\n\tallowedDomains?: string[];\n\tblockedDomains?: string[];\n}\n\nfunction buildSearchQuery(query: string, allowedDomains?: string[], blockedDomains?: string[]): string {\n\tlet q = query.trim();\n\tif (allowedDomains && allowedDomains.length > 0) {\n\t\tconst siteFilter = allowedDomains.map((d) => `site:${d.trim()}`).join(\" OR \");\n\t\tq = `${q} (${siteFilter})`;\n\t} else if (blockedDomains && blockedDomains.length > 0) {\n\t\tconst blockFilter = blockedDomains.map((d) => `-site:${d.trim()}`).join(\" \");\n\t\tq = `${q} ${blockFilter}`;\n\t}\n\treturn q;\n}\n\nfunction matchesDomainFilters(url: string, allowedDomains?: string[], blockedDomains?: string[]): boolean {\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\tconst hostname = parsed.hostname.toLowerCase();\n\n\t\tif (allowedDomains && allowedDomains.length > 0) {\n\t\t\treturn allowedDomains.some((d) => hostname === d.toLowerCase() || hostname.endsWith(`.${d.toLowerCase()}`));\n\t\t}\n\t\tif (blockedDomains && blockedDomains.length > 0) {\n\t\t\treturn !blockedDomains.some((d) => hostname === d.toLowerCase() || hostname.endsWith(`.${d.toLowerCase()}`));\n\t\t}\n\t\treturn true;\n\t} catch {\n\t\treturn true;\n\t}\n}\n\nexport async function searchMiniMax(options: MiniMaxSearchOptions): Promise<ProviderSearchResult> {\n\tconst host = options.apiHost?.replace(/\\/+$/, \"\") || \"https://api.minimaxi.com\";\n\tconst effectiveQuery = buildSearchQuery(options.query, options.allowedDomains, options.blockedDomains);\n\n\tconst data = await postJson<MiniMaxSearchResponse>(\n\t\t`${host}/v1/coding_plan/search`,\n\t\t{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAuthorization: `Bearer ${options.apiKey}`,\n\t\t},\n\t\t{ q: effectiveQuery },\n\t\toptions.signal,\n\t\t60_000,\n\t\t\"MiniMax search API\",\n\t);\n\n\tif (data.base_resp && data.base_resp.status_code !== 0) {\n\t\tthrow new Error(`MiniMax search failed: [${data.base_resp.status_code}] ${data.base_resp.status_msg}`);\n\t}\n\n\tconst rawHits = data.organic || [];\n\tconst hits: WebSearchHit[] = [];\n\n\tfor (const item of rawHits) {\n\t\tif (!item.link || !item.link.trim()) continue;\n\t\tconst cleanLink = item.link.trim();\n\t\tif (!matchesDomainFilters(cleanLink, options.allowedDomains, options.blockedDomains)) {\n\t\t\tcontinue;\n\t\t}\n\t\thits.push({\n\t\t\ttitle: item.title?.trim() || cleanLink,\n\t\t\turl: cleanLink,\n\t\t\tsnippet: item.snippet?.trim() || undefined,\n\t\t\tdate: item.date?.trim() || undefined,\n\t\t\tsources: [\"MiniMax\"],\n\t\t});\n\t}\n\n\tconst relatedSearches = data.related_searches\n\t\t?.map((r) => r.query?.trim())\n\t\t.filter((q): q is string => Boolean(q && q.length > 0));\n\n\treturn {\n\t\tsource: \"MiniMax\",\n\t\thits,\n\t\trelatedSearches: relatedSearches && relatedSearches.length > 0 ? relatedSearches : undefined,\n\t};\n}\n"]}
1
+ {"version":3,"file":"minimax.js","sourceRoot":"","sources":["../../../../src/extensions/web-search/providers/minimax.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * minimax.ts — MiniMax Coding Plan Search REST API provider.\n */\n\nimport { MAX_PROVIDER_HIT_SCAN, MAX_PROVIDER_RELATED_SCAN, MAX_RELATED_SEARCHES } from \"../results.ts\";\nimport type { ProviderSearchResult, WebSearchHit } from \"../types.ts\";\nimport { postJson } from \"./http.ts\";\n\nexport interface MiniMaxSearchOptions {\n\tquery: string;\n\tapiKey: string;\n\tapiHost?: string;\n\tsignal?: AbortSignal;\n}\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)) return undefined;\n\tconst url = stringField(value, \"link\")?.trim();\n\tif (!url) return undefined;\n\treturn {\n\t\ttitle: stringField(value, \"title\")?.trim() || url,\n\t\turl,\n\t\tsnippet: stringField(value, \"snippet\")?.trim() || undefined,\n\t\tdate: stringField(value, \"date\")?.trim() || undefined,\n\t\tsources: [\"MiniMax\"],\n\t};\n}\n\nexport async function searchMiniMax(options: MiniMaxSearchOptions): Promise<ProviderSearchResult> {\n\tconst host = options.apiHost?.replace(/\\/+$/, \"\") || \"https://api.minimaxi.com\";\n\tconst rawData = await postJson<unknown>(\n\t\t`${host}/v1/coding_plan/search`,\n\t\t{\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\tAuthorization: `Bearer ${options.apiKey}`,\n\t\t},\n\t\t{ q: options.query.trim() },\n\t\toptions.signal,\n\t\t60_000,\n\t\t\"MiniMax search API\",\n\t);\n\tconst data = isRecord(rawData) ? rawData : {};\n\tconst baseResponse = isRecord(data.base_resp) ? data.base_resp : undefined;\n\tconst statusCode = baseResponse?.status_code;\n\tif (baseResponse && typeof statusCode === \"number\" && statusCode !== 0) {\n\t\tthrow new Error(\n\t\t\t`MiniMax search failed: [${statusCode}] ${stringField(baseResponse, \"status_msg\") ?? \"Unknown error\"}`,\n\t\t);\n\t}\n\n\tconst hits: WebSearchHit[] = [];\n\tconst organic = Array.isArray(data.organic) ? data.organic : [];\n\tconst hitScanLimit = Math.min(organic.length, MAX_PROVIDER_HIT_SCAN);\n\tfor (let index = 0; index < hitScanLimit; index++) {\n\t\tconst hit = parseSearchHit(organic[index]);\n\t\tif (hit) hits.push(hit);\n\t}\n\n\tconst relatedSearches: string[] = [];\n\tconst related = Array.isArray(data.related_searches) ? data.related_searches : [];\n\tconst relatedScanLimit = Math.min(related.length, MAX_PROVIDER_RELATED_SCAN);\n\tfor (let index = 0; index < relatedScanLimit && relatedSearches.length < MAX_RELATED_SEARCHES; index++) {\n\t\tconst value = related[index];\n\t\tconst query = isRecord(value) ? stringField(value, \"query\")?.trim() : undefined;\n\t\tif (query) relatedSearches.push(query);\n\t}\n\n\treturn {\n\t\tsource: \"MiniMax\",\n\t\thits,\n\t\trelatedSearches: relatedSearches.length > 0 ? relatedSearches : undefined,\n\t};\n}\n"]}
@@ -4,8 +4,7 @@
4
4
  import { type Component } from "@earendil-works/pi-tui";
5
5
  import type { AgentToolResult, ToolRenderResultOptions } from "../../core/extensions/types.ts";
6
6
  import { type Theme } from "../../modes/interactive/theme/theme.ts";
7
- import type { WebSearchParams } from "./schema.ts";
8
7
  import type { WebSearchDetails } from "./types.ts";
9
- export declare function renderWebSearchCall(args: WebSearchParams, theme: Theme): Component;
8
+ export declare function renderWebSearchCall(args: unknown, theme: Theme): Component;
10
9
  export declare function renderWebSearchResult(result: AgentToolResult<WebSearchDetails>, options: ToolRenderResultOptions, theme: Theme, isError: boolean, elapsedMs?: number): Component;
11
10
  //# sourceMappingURL=render.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/extensions/web-search/render.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAqC,MAAM,wBAAwB,CAAC;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAE/F,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAGtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAgB,MAAM,YAAY,CAAC;AAsCjE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,CAYlF;AASD,wBAAgB,qBAAqB,CACpC,MAAM,EAAE,eAAe,CAAC,gBAAgB,CAAC,EACzC,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,SAAS,CAAC,EAAE,MAAM,GAChB,SAAS,CA6DX"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/extensions/web-search/render.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAqC,MAAM,wBAAwB,CAAC;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAE/F,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAItF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA4CnD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG,SAAS,CAO1E;AASD,wBAAgB,qBAAqB,CACpC,MAAM,EAAE,eAAe,CAAC,gBAAgB,CAAC,EACzC,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,SAAS,CAAC,EAAE,MAAM,GAChB,SAAS,CA8DX"}
@@ -5,7 +5,8 @@ import { Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
5
5
  import { keyHint } from "../../modes/interactive/components/keybinding-hints.js";
6
6
  import { getMarkdownTheme } from "../../modes/interactive/theme/theme.js";
7
7
  import { getEngineLabel, WEB_SEARCH_LABEL } from "./constants.js";
8
- import { formatResultsMarkdown } from "./fusion.js";
8
+ import { formatResultsMarkdown } from "./format.js";
9
+ import { MAX_HISTORICAL_HIT_SCAN } from "./results.js";
9
10
  /** Matches the bash/deepwiki progress display: sub-2s calls stay quiet. */
10
11
  const ELAPSED_DISPLAY_THRESHOLD_MS = 2000;
11
12
  function singleLine(text) {
@@ -24,11 +25,20 @@ function firstText(result) {
24
25
  return "";
25
26
  }
26
27
  /** " · github.com, react.dev, +3" from the first-seen unique hit domains. */
27
- function domainSummary(hits) {
28
+ function domainSummary(value) {
29
+ if (!Array.isArray(value))
30
+ return "";
28
31
  const seen = new Set();
29
- for (const hit of hits) {
32
+ const scanLimit = Math.min(value.length, MAX_HISTORICAL_HIT_SCAN);
33
+ for (let index = 0; index < scanLimit; index++) {
34
+ const hit = value[index];
35
+ if (!hit || typeof hit !== "object")
36
+ continue;
37
+ const url = hit.url;
38
+ if (typeof url !== "string")
39
+ continue;
30
40
  try {
31
- const host = new URL(hit.url).hostname.replace(/^www\./, "");
41
+ const host = new URL(url).hostname.replace(/^www\./, "");
32
42
  if (host)
33
43
  seen.add(host);
34
44
  }
@@ -44,14 +54,8 @@ function domainSummary(hits) {
44
54
  }
45
55
  export function renderWebSearchCall(args, theme) {
46
56
  let line = theme.fg("toolTitle", theme.bold(`${WEB_SEARCH_LABEL} `));
47
- const query = singleLine(args.query || "");
57
+ const query = singleLine(args && typeof args === "object" && !Array.isArray(args) ? args.query : "");
48
58
  line += theme.fg("accent", `"${truncateText(query, 60)}"`);
49
- if (args.allowed_domains && args.allowed_domains.length > 0) {
50
- line += ` ${theme.fg("muted", `[sites: ${args.allowed_domains.join(", ")}]`)}`;
51
- }
52
- else if (args.blocked_domains && args.blocked_domains.length > 0) {
53
- line += ` ${theme.fg("muted", `[-sites: ${args.blocked_domains.join(", ")}]`)}`;
54
- }
55
59
  return new Text(line, 0, 0);
56
60
  }
57
61
  function markdownBlock(text) {
@@ -73,15 +77,15 @@ export function renderWebSearchResult(result, options, theme, isError, elapsedMs
73
77
  }
74
78
  const text = firstText(result);
75
79
  const errorMessage = details?.errorMessage;
76
- if (isError || details?.status === "error") {
77
- const line = truncateText(errorMessage ?? (singleLine(text) || "Search request failed"), 160);
78
- return new Text(theme.fg("error", `failed · ${line}`), 0, 0);
79
- }
80
80
  if (details?.status === "disabled") {
81
81
  // Only reachable when the tool was force-enabled without credentials, or in
82
82
  // historical sessions: the session_start hook keeps it hidden otherwise.
83
83
  return new Text(theme.fg("warning", "disabled · no MiniMax/DeepSeek key — /login minimax-cn or export MINIMAX_API_KEY / DEEPSEEK_API_KEY"), 0, 0);
84
84
  }
85
+ if (isError || details?.status === "error") {
86
+ const line = truncateText(errorMessage ?? (singleLine(text) || "Search request failed"), 160);
87
+ return new Text(theme.fg("error", `failed · ${line}`), 0, 0);
88
+ }
85
89
  if (!options.expanded) {
86
90
  const hint = `${theme.fg("muted", " (")}${keyHint("app.tools.expand", "to expand")}${theme.fg("muted", ")")}`;
87
91
  if (!details) {
@@ -89,12 +93,13 @@ export function renderWebSearchResult(result, options, theme, isError, elapsedMs
89
93
  const line = truncateText(singleLine(text), 100) || "done";
90
94
  return new Text(`${theme.fg("toolOutput", line)}${hint}`, 0, 0);
91
95
  }
92
- const hitCount = details.totalHits ?? details.hits.length;
96
+ const historicalHits = Array.isArray(details.hits) ? details.hits : [];
97
+ const hitCount = details.totalHits ?? historicalHits.length;
93
98
  const engine = getEngineLabel(details.engine);
94
99
  const engineLabel = engine ? ` via ${engine}` : "";
95
100
  const duration = details.durationMs ? ` · ${(details.durationMs / 1000).toFixed(1)}s` : "";
96
101
  const countText = hitCount === 1 ? "1 result" : hitCount === 0 ? "no results" : `${hitCount} results`;
97
- const summary = theme.fg("toolOutput", truncateText(`${countText}${engineLabel}${duration}${domainSummary(details.hits)}`, 100));
102
+ const summary = theme.fg("toolOutput", truncateText(`${countText}${engineLabel}${duration}${domainSummary(historicalHits)}`, 100));
98
103
  return new Text(`${summary}${hint}`, 0, 0);
99
104
  }
100
105
  // Expanded: structured sections from details, without the model-facing agent