@humain/terminal 0.2.2 → 0.3.0

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 (156) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/bundle/chunks/{chunk-NMPIM7MN.js → chunk-CBTAWCW5.js} +1 -1
  3. package/dist/bundle/chunks/{chunk-D6HHRSB5.js → chunk-S43N4JYF.js} +14 -29
  4. package/dist/bundle/chunks/{chunk-ADQYVZ6A.js → chunk-WKLAQTQ4.js} +104 -128
  5. package/dist/bundle/chunks/{compat-CN7WN6DA.js → compat-L5WILLPV.js} +1 -1
  6. package/dist/bundle/chunks/{extract-CTIFQZDJ.js → extract-2YP6VMY4.js} +3 -3
  7. package/dist/bundle/cli.js +1 -1
  8. package/dist/bundle/index.js +1 -1
  9. package/dist/bundle/rpc-entry.js +1 -1
  10. package/dist/core/tools/subagent.d.ts +2 -0
  11. package/dist/core/tools/subagent.d.ts.map +1 -1
  12. package/dist/core/tools/subagent.js +46 -16
  13. package/dist/core/tools/subagent.js.map +1 -1
  14. package/dist/humain/web-access/vendor/anysearch.d.ts.map +1 -1
  15. package/dist/humain/web-access/vendor/anysearch.js +4 -14
  16. package/dist/humain/web-access/vendor/anysearch.js.map +1 -1
  17. package/dist/humain/web-access/vendor/bocha.d.ts.map +1 -1
  18. package/dist/humain/web-access/vendor/bocha.js +3 -24
  19. package/dist/humain/web-access/vendor/bocha.js.map +1 -1
  20. package/dist/humain/web-access/vendor/brave.d.ts.map +1 -1
  21. package/dist/humain/web-access/vendor/brave.js +3 -24
  22. package/dist/humain/web-access/vendor/brave.js.map +1 -1
  23. package/dist/humain/web-access/vendor/brightdata.d.ts.map +1 -1
  24. package/dist/humain/web-access/vendor/brightdata.js +5 -34
  25. package/dist/humain/web-access/vendor/brightdata.js.map +1 -1
  26. package/dist/humain/web-access/vendor/content-find.d.ts.map +1 -1
  27. package/dist/humain/web-access/vendor/content-find.js +186 -51
  28. package/dist/humain/web-access/vendor/content-find.js.map +1 -1
  29. package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -1
  30. package/dist/humain/web-access/vendor/curator-page.js +4 -1
  31. package/dist/humain/web-access/vendor/curator-page.js.map +1 -1
  32. package/dist/humain/web-access/vendor/curator-run.d.ts.map +1 -1
  33. package/dist/humain/web-access/vendor/curator-run.js +3 -1
  34. package/dist/humain/web-access/vendor/curator-run.js.map +1 -1
  35. package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -1
  36. package/dist/humain/web-access/vendor/curator-server.js +2 -0
  37. package/dist/humain/web-access/vendor/curator-server.js.map +1 -1
  38. package/dist/humain/web-access/vendor/domain-filter-normalization.d.ts +2 -0
  39. package/dist/humain/web-access/vendor/domain-filter-normalization.d.ts.map +1 -0
  40. package/dist/humain/web-access/vendor/domain-filter-normalization.js +19 -0
  41. package/dist/humain/web-access/vendor/domain-filter-normalization.js.map +1 -0
  42. package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -1
  43. package/dist/humain/web-access/vendor/duckduckgo.js +3 -24
  44. package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -1
  45. package/dist/humain/web-access/vendor/extract.d.ts.map +1 -1
  46. package/dist/humain/web-access/vendor/extract.js +3 -1
  47. package/dist/humain/web-access/vendor/extract.js.map +1 -1
  48. package/dist/humain/web-access/vendor/firecrawl.d.ts.map +1 -1
  49. package/dist/humain/web-access/vendor/firecrawl.js +5 -32
  50. package/dist/humain/web-access/vendor/firecrawl.js.map +1 -1
  51. package/dist/humain/web-access/vendor/gemini-search.d.ts +5 -2
  52. package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -1
  53. package/dist/humain/web-access/vendor/gemini-search.js +85 -37
  54. package/dist/humain/web-access/vendor/gemini-search.js.map +1 -1
  55. package/dist/humain/web-access/vendor/index.d.ts +3 -3
  56. package/dist/humain/web-access/vendor/index.d.ts.map +1 -1
  57. package/dist/humain/web-access/vendor/index.js +135 -157
  58. package/dist/humain/web-access/vendor/index.js.map +1 -1
  59. package/dist/humain/web-access/vendor/jina-search.d.ts.map +1 -1
  60. package/dist/humain/web-access/vendor/jina-search.js +4 -14
  61. package/dist/humain/web-access/vendor/jina-search.js.map +1 -1
  62. package/dist/humain/web-access/vendor/kagi.d.ts.map +1 -1
  63. package/dist/humain/web-access/vendor/kagi.js +4 -12
  64. package/dist/humain/web-access/vendor/kagi.js.map +1 -1
  65. package/dist/humain/web-access/vendor/kimi-search.d.ts.map +1 -1
  66. package/dist/humain/web-access/vendor/kimi-search.js +5 -32
  67. package/dist/humain/web-access/vendor/kimi-search.js.map +1 -1
  68. package/dist/humain/web-access/vendor/mistral-search.d.ts.map +1 -1
  69. package/dist/humain/web-access/vendor/mistral-search.js +1 -18
  70. package/dist/humain/web-access/vendor/mistral-search.js.map +1 -1
  71. package/dist/humain/web-access/vendor/ollama.d.ts.map +1 -1
  72. package/dist/humain/web-access/vendor/ollama.js +2 -6
  73. package/dist/humain/web-access/vendor/ollama.js.map +1 -1
  74. package/dist/humain/web-access/vendor/openai-search.d.ts +3 -0
  75. package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -1
  76. package/dist/humain/web-access/vendor/openai-search.js +181 -38
  77. package/dist/humain/web-access/vendor/openai-search.js.map +1 -1
  78. package/dist/humain/web-access/vendor/opencode-session-headers.d.ts +10 -0
  79. package/dist/humain/web-access/vendor/opencode-session-headers.d.ts.map +1 -0
  80. package/dist/humain/web-access/vendor/opencode-session-headers.js +23 -0
  81. package/dist/humain/web-access/vendor/opencode-session-headers.js.map +1 -0
  82. package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -1
  83. package/dist/humain/web-access/vendor/page-query.js +10 -2
  84. package/dist/humain/web-access/vendor/page-query.js.map +1 -1
  85. package/dist/humain/web-access/vendor/parallel.d.ts.map +1 -1
  86. package/dist/humain/web-access/vendor/parallel.js +1 -18
  87. package/dist/humain/web-access/vendor/parallel.js.map +1 -1
  88. package/dist/humain/web-access/vendor/pdf-extract.d.ts +2 -0
  89. package/dist/humain/web-access/vendor/pdf-extract.d.ts.map +1 -1
  90. package/dist/humain/web-access/vendor/pdf-extract.js +1 -0
  91. package/dist/humain/web-access/vendor/pdf-extract.js.map +1 -1
  92. package/dist/humain/web-access/vendor/querit.d.ts.map +1 -1
  93. package/dist/humain/web-access/vendor/querit.js +5 -32
  94. package/dist/humain/web-access/vendor/querit.js.map +1 -1
  95. package/dist/humain/web-access/vendor/search-answer-formatting.d.ts +8 -0
  96. package/dist/humain/web-access/vendor/search-answer-formatting.d.ts.map +1 -0
  97. package/dist/humain/web-access/vendor/search-answer-formatting.js +6 -0
  98. package/dist/humain/web-access/vendor/search-answer-formatting.js.map +1 -0
  99. package/dist/humain/web-access/vendor/search-result-count-normalization.d.ts +2 -0
  100. package/dist/humain/web-access/vendor/search-result-count-normalization.d.ts.map +1 -0
  101. package/dist/humain/web-access/vendor/search-result-count-normalization.js +6 -0
  102. package/dist/humain/web-access/vendor/search-result-count-normalization.js.map +1 -0
  103. package/dist/humain/web-access/vendor/search1api.d.ts.map +1 -1
  104. package/dist/humain/web-access/vendor/search1api.js +5 -32
  105. package/dist/humain/web-access/vendor/search1api.js.map +1 -1
  106. package/dist/humain/web-access/vendor/searchinfinity.d.ts.map +1 -1
  107. package/dist/humain/web-access/vendor/searchinfinity.js +5 -32
  108. package/dist/humain/web-access/vendor/searchinfinity.js.map +1 -1
  109. package/dist/humain/web-access/vendor/searxng.d.ts.map +1 -1
  110. package/dist/humain/web-access/vendor/searxng.js +3 -24
  111. package/dist/humain/web-access/vendor/searxng.js.map +1 -1
  112. package/dist/humain/web-access/vendor/serpapi.d.ts.map +1 -1
  113. package/dist/humain/web-access/vendor/serpapi.js +5 -30
  114. package/dist/humain/web-access/vendor/serpapi.js.map +1 -1
  115. package/dist/humain/web-access/vendor/serpbase.d.ts.map +1 -1
  116. package/dist/humain/web-access/vendor/serpbase.js +3 -24
  117. package/dist/humain/web-access/vendor/serpbase.js.map +1 -1
  118. package/dist/humain/web-access/vendor/serpdive.d.ts.map +1 -1
  119. package/dist/humain/web-access/vendor/serpdive.js +3 -24
  120. package/dist/humain/web-access/vendor/serpdive.js.map +1 -1
  121. package/dist/humain/web-access/vendor/serper.d.ts.map +1 -1
  122. package/dist/humain/web-access/vendor/serper.js +5 -30
  123. package/dist/humain/web-access/vendor/serper.js.map +1 -1
  124. package/dist/humain/web-access/vendor/serply.d.ts +4 -0
  125. package/dist/humain/web-access/vendor/serply.d.ts.map +1 -0
  126. package/dist/humain/web-access/vendor/serply.js +191 -0
  127. package/dist/humain/web-access/vendor/serply.js.map +1 -0
  128. package/dist/humain/web-access/vendor/source-check.d.ts.map +1 -1
  129. package/dist/humain/web-access/vendor/source-check.js +11 -47
  130. package/dist/humain/web-access/vendor/source-check.js.map +1 -1
  131. package/dist/humain/web-access/vendor/summary-review.d.ts +1 -1
  132. package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -1
  133. package/dist/humain/web-access/vendor/summary-review.js +6 -2
  134. package/dist/humain/web-access/vendor/summary-review.js.map +1 -1
  135. package/dist/humain/web-access/vendor/tavily.d.ts.map +1 -1
  136. package/dist/humain/web-access/vendor/tavily.js +3 -24
  137. package/dist/humain/web-access/vendor/tavily.js.map +1 -1
  138. package/dist/humain/web-access/vendor/tinyfish.d.ts.map +1 -1
  139. package/dist/humain/web-access/vendor/tinyfish.js +5 -32
  140. package/dist/humain/web-access/vendor/tinyfish.js.map +1 -1
  141. package/dist/humain/web-access/vendor/utils.d.ts.map +1 -1
  142. package/dist/humain/web-access/vendor/utils.js +2 -0
  143. package/dist/humain/web-access/vendor/utils.js.map +1 -1
  144. package/dist/humain/web-access/vendor/valyu.d.ts.map +1 -1
  145. package/dist/humain/web-access/vendor/valyu.js +5 -30
  146. package/dist/humain/web-access/vendor/valyu.js.map +1 -1
  147. package/dist/humain/web-access/vendor/xai-search.d.ts.map +1 -1
  148. package/dist/humain/web-access/vendor/xai-search.js +1 -18
  149. package/dist/humain/web-access/vendor/xai-search.js.map +1 -1
  150. package/dist/humain/web-access/vendor/xcrawl.d.ts.map +1 -1
  151. package/dist/humain/web-access/vendor/xcrawl.js +5 -34
  152. package/dist/humain/web-access/vendor/xcrawl.js.map +1 -1
  153. package/npm-shrinkwrap.json +6 -6
  154. package/package.json +2 -2
  155. package/src/humain/web-access/UPSTREAM.md +33 -1
  156. package/src/humain/web-access/upstream.json +6 -5
@@ -1 +1 @@
1
- {"version":3,"file":"jina-search.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/jina-search.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAuBrE,UAAU,iBAAkB,SAAQ,aAAa;IAChD,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAuLD,wBAAgB,qBAAqB,IAAI,OAAO,CAM/C;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,cAAc,CAAC,CA+D5G"}
1
+ {"version":3,"file":"jina-search.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/jina-search.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAyBrE,UAAU,iBAAkB,SAAQ,aAAa;IAChD,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AA0KD,wBAAgB,qBAAqB,IAAI,OAAO,CAM/C;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,cAAc,CAAC,CA+D5G"}
@@ -1,6 +1,8 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { activityMonitor } from "./activity.js";
3
3
  import { hasCredentialSource, redactCredential, resolveCredential } from "./credential-source.js";
4
+ import { formatSearchResultsAsAnswer } from "./search-answer-formatting.js";
5
+ import { normalizeSearchResultCount } from "./search-result-count-normalization.js";
4
6
  import { getWebSearchConfigPath } from "./utils.js";
5
7
  const JINA_SEARCH_BASE_URL = "https://s.jina.ai/";
6
8
  const CONFIG_PATH = getWebSearchConfigPath();
@@ -45,11 +47,6 @@ async function requireApiKey(signal) {
45
47
  }
46
48
  return apiKey;
47
49
  }
48
- function normalizeCount(value) {
49
- if (typeof value !== "number" || !Number.isFinite(value))
50
- return 5;
51
- return Math.max(1, Math.min(Math.floor(value), 20));
52
- }
53
50
  function normalizeDomain(value) {
54
51
  let input = value.trim().toLowerCase();
55
52
  if (input.startsWith("-"))
@@ -152,13 +149,6 @@ function mapItems(items, numResults, filters) {
152
149
  }
153
150
  return { results, content };
154
151
  }
155
- function buildAnswer(results) {
156
- return results
157
- .map((result) => result.snippet
158
- ? `${result.snippet}\nSource: ${result.title} (${result.url})`
159
- : `Source: ${result.title} (${result.url})`)
160
- .join("\n\n");
161
- }
162
152
  function rethrowRequestError(err, apiKey, activityId, request, callerSignal) {
163
153
  if (request.timeout.aborted && !callerSignal?.aborted) {
164
154
  activityMonitor.logComplete(activityId, 408);
@@ -186,7 +176,7 @@ export function isJinaSearchAvailable() {
186
176
  }
187
177
  export async function searchWithJina(query, options = {}) {
188
178
  const apiKey = await requireApiKey(options.signal);
189
- const numResults = normalizeCount(options.numResults);
179
+ const numResults = normalizeSearchResultCount(options.numResults);
190
180
  const { url, filters } = buildSearchRequest(query, options, numResults);
191
181
  const activityId = activityMonitor.logStart({ type: "api", query });
192
182
  const request = requestSignal(options.signal);
@@ -245,7 +235,7 @@ export async function searchWithJina(query, options = {}) {
245
235
  }
246
236
  activityMonitor.logComplete(activityId, response.status);
247
237
  const result = {
248
- answer: buildAnswer(mapped.results),
238
+ answer: formatSearchResultsAsAnswer(mapped.results),
249
239
  results: mapped.results,
250
240
  };
251
241
  if (options.includeContent && mapped.content.length > 0)
@@ -1 +1 @@
1
- {"version":3,"file":"jina-search.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/jina-search.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport type { ExtractedContent } from \"./extract.ts\";\nimport type { SearchOptions, SearchResponse } from \"./perplexity.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst JINA_SEARCH_BASE_URL = \"https://s.jina.ai/\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\n\ninterface WebSearchConfig {\n\tjinaApiKey?: unknown;\n}\n\ninterface JinaSearchItem {\n\ttitle?: unknown;\n\turl?: unknown;\n\tdescription?: unknown;\n\tcontent?: unknown;\n}\n\ninterface JinaSearchEnvelope {\n\tcode?: unknown;\n\tdata?: unknown;\n}\n\ninterface JinaSearchOptions extends SearchOptions {\n\tincludeContent?: boolean;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\n\tconst raw = readFileSync(CONFIG_PATH, \"utf8\");\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(raw);\n\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\t\tthrow new Error(\"expected a JSON object\");\n\t\t}\n\t\tcachedConfig = parsed as WebSearchConfig;\n\t\treturn cachedConfig;\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"Jina Search\",\n\t\tconfiguredValue: loadConfig().jinaApiKey,\n\t\tenvironmentValue: process.env.JINA_API_KEY,\n\t\tsignal,\n\t});\n}\n\nasync function requireApiKey(signal?: AbortSignal): Promise<string> {\n\tconst apiKey = await getApiKey(signal);\n\tif (!apiKey) {\n\t\tthrow new Error(\n\t\t\t\"Jina Search API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"jinaApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set JINA_API_KEY environment variable\\n\" +\n\t\t\t\"Get a key at https://jina.ai/api-dashboard\",\n\t\t);\n\t}\n\treturn apiKey;\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n\treturn Math.max(1, Math.min(Math.floor(value), 20));\n}\n\nfunction normalizeDomain(value: string): string | null {\n\tlet input = value.trim().toLowerCase();\n\tif (input.startsWith(\"-\")) input = input.slice(1).trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst parsed = input.includes(\"://\") ? new URL(input) : new URL(`https://${input}`);\n\t\tinput = parsed.hostname;\n\t} catch {\n\t\tinput = input.split(\"/\")[0]?.split(\":\")[0] ?? \"\";\n\t}\n\tinput = input.replace(/^\\.+|\\.+$/g, \"\");\n\treturn /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i.test(input) ? input : null;\n}\n\nfunction mapDomainFilter(domainFilter: string[] | undefined): { includes: string[]; excludes: string[] } {\n\tconst includes: string[] = [];\n\tconst excludes: string[] = [];\n\tfor (const raw of domainFilter ?? []) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? excludes : includes;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\treturn { includes, excludes };\n}\n\nfunction buildSearchRequest(query: string, options: JinaSearchOptions, numResults: number): { url: string; filters: ReturnType<typeof mapDomainFilter> } {\n\tconst filters = mapDomainFilter(options.domainFilter);\n\tconst recency = options.recencyFilter ? ` published in the past ${options.recencyFilter}` : \"\";\n\tconst exclusions = filters.excludes.map((domain) => ` -site:${domain}`).join(\"\");\n\tconst constrainedQuery = `${query.trim()}${exclusions}${recency}`.trim();\n\tconst url = new URL(encodeURIComponent(constrainedQuery), JINA_SEARCH_BASE_URL);\n\turl.searchParams.set(\"count\", String(numResults));\n\tfor (const domain of filters.includes) url.searchParams.append(\"site\", domain);\n\treturn { url: url.toString(), filters };\n}\n\nfunction requestSignal(signal?: AbortSignal): { signal: AbortSignal; timeout: AbortSignal } {\n\tconst timeout = AbortSignal.timeout(SEARCH_TIMEOUT_MS);\n\treturn {\n\t\ttimeout,\n\t\tsignal: signal ? AbortSignal.any([signal, timeout]) : timeout,\n\t};\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\nfunction parseItems(value: unknown): JinaSearchItem[] {\n\tif (Array.isArray(value)) return value as JinaSearchItem[];\n\tif (!value || typeof value !== \"object\") {\n\t\tthrow new Error(\"Jina Search API returned invalid response: expected an object or array\");\n\t}\n\tconst envelope = value as JinaSearchEnvelope;\n\tif (typeof envelope.code === \"number\" && envelope.code !== 200) {\n\t\tthrow new Error(`Jina Search API error ${envelope.code}: response envelope reported failure`);\n\t}\n\tif (!Array.isArray(envelope.data)) {\n\t\tthrow new Error(\"Jina Search API returned invalid response: expected data array\");\n\t}\n\treturn envelope.data as JinaSearchItem[];\n}\n\nfunction passesDomainFilter(url: string, filters: ReturnType<typeof mapDomainFilter>): boolean {\n\tlet hostname: string;\n\ttry {\n\t\thostname = new URL(url).hostname.toLowerCase();\n\t} catch {\n\t\treturn false;\n\t}\n\tconst matches = (domain: string): boolean => hostname === domain || hostname.endsWith(`.${domain}`);\n\tif (filters.includes.length > 0 && !filters.includes.some(matches)) return false;\n\treturn !filters.excludes.some(matches);\n}\n\nfunction mapItems(items: JinaSearchItem[], numResults: number, filters: ReturnType<typeof mapDomainFilter>): {\n\tresults: SearchResponse[\"results\"];\n\tcontent: ExtractedContent[];\n} {\n\tconst results: SearchResponse[\"results\"] = [];\n\tconst content: ExtractedContent[] = [];\n\tconst seen = new Set<string>();\n\tfor (const item of items) {\n\t\tconst url = typeof item?.url === \"string\" ? item.url.trim() : \"\";\n\t\tif (!url || seen.has(url) || !passesDomainFilter(url, filters)) continue;\n\t\tseen.add(url);\n\t\tconst title = typeof item.title === \"string\" && item.title.trim()\n\t\t\t? item.title.trim()\n\t\t\t: `Source ${results.length + 1}`;\n\t\tconst snippet = typeof item.description === \"string\"\n\t\t\t? item.description.replace(/\\s+/g, \" \").trim()\n\t\t\t: \"\";\n\t\tresults.push({ title, url, snippet });\n\t\tif (typeof item.content === \"string\" && item.content.trim()) {\n\t\t\tcontent.push({ url, title, content: item.content.trim(), error: null });\n\t\t}\n\t\tif (results.length >= numResults) break;\n\t}\n\treturn { results, content };\n}\n\nfunction buildAnswer(results: SearchResponse[\"results\"]): string {\n\treturn results\n\t\t.map((result) => result.snippet\n\t\t\t? `${result.snippet}\\nSource: ${result.title} (${result.url})`\n\t\t\t: `Source: ${result.title} (${result.url})`)\n\t\t.join(\"\\n\\n\");\n}\n\nfunction rethrowRequestError(\n\terr: unknown,\n\tapiKey: string,\n\tactivityId: string,\n\trequest: ReturnType<typeof requestSignal>,\n\tcallerSignal?: AbortSignal,\n): never {\n\tif (request.timeout.aborted && !callerSignal?.aborted) {\n\t\tactivityMonitor.logComplete(activityId, 408);\n\t\tthrow new Error(\"Jina Search API error 408: request timed out\");\n\t}\n\tconst message = errorMessage(err);\n\tconst redactedMessage = redactCredential(message, apiKey);\n\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\telse activityMonitor.logError(activityId, redactedMessage);\n\tif (redactedMessage === message) throw err;\n\tconst redactedError = new Error(redactedMessage);\n\tif (err instanceof Error) redactedError.name = err.name;\n\tthrow redactedError;\n}\n\nexport function isJinaSearchAvailable(): boolean {\n\treturn hasCredentialSource({\n\t\tprovider: \"Jina Search\",\n\t\tconfiguredValue: loadConfig().jinaApiKey,\n\t\tenvironmentValue: process.env.JINA_API_KEY,\n\t});\n}\n\nexport async function searchWithJina(query: string, options: JinaSearchOptions = {}): Promise<SearchResponse> {\n\tconst apiKey = await requireApiKey(options.signal);\n\tconst numResults = normalizeCount(options.numResults);\n\tconst { url, filters } = buildSearchRequest(query, options, numResults);\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\tconst request = requestSignal(options.signal);\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(url, {\n\t\t\theaders: {\n\t\t\t\t\"Accept\": \"application/json\",\n\t\t\t\t\"Authorization\": `Bearer ${apiKey}`,\n\t\t\t\t\"User-Agent\": \"pi-web-access\",\n\t\t\t\t\"X-Respond-With\": options.includeContent ? \"content\" : \"no-content\",\n\t\t\t\t\"X-Retain-Images\": \"none\",\n\t\t\t},\n\t\t\tsignal: request.signal,\n\t\t});\n\t} catch (err) {\n\t\trethrowRequestError(err, apiKey, activityId, request, options.signal);\n\t}\n\n\tif (!response.ok) {\n\t\tlet body: string;\n\t\ttry {\n\t\t\tbody = redactCredential(await response.text(), apiKey);\n\t\t} catch (err) {\n\t\t\trethrowRequestError(err, apiKey, activityId, request, options.signal);\n\t\t}\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`Jina Search API error ${response.status}: ${body.slice(0, 300)}`);\n\t}\n\n\tlet raw: unknown;\n\ttry {\n\t\traw = await response.json();\n\t} catch (err) {\n\t\tif (!(err instanceof SyntaxError)) {\n\t\t\trethrowRequestError(err, apiKey, activityId, request, options.signal);\n\t\t}\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(\"Jina Search API returned invalid JSON\");\n\t}\n\n\tlet mapped: ReturnType<typeof mapItems>;\n\ttry {\n\t\tmapped = mapItems(parseItems(raw), numResults, filters);\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tactivityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\tactivityMonitor.logComplete(activityId, response.status);\n\tconst result: SearchResponse = {\n\t\tanswer: buildAnswer(mapped.results),\n\t\tresults: mapped.results,\n\t};\n\tif (options.includeContent && mapped.content.length > 0) result.inlineContent = mapped.content;\n\treturn result;\n}\n"]}
1
+ {"version":3,"file":"jina-search.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/jina-search.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport type { ExtractedContent } from \"./extract.ts\";\nimport type { SearchOptions, SearchResponse } from \"./perplexity.ts\";\nimport { formatSearchResultsAsAnswer } from \"./search-answer-formatting.ts\";\nimport { normalizeSearchResultCount } from \"./search-result-count-normalization.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst JINA_SEARCH_BASE_URL = \"https://s.jina.ai/\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\n\ninterface WebSearchConfig {\n\tjinaApiKey?: unknown;\n}\n\ninterface JinaSearchItem {\n\ttitle?: unknown;\n\turl?: unknown;\n\tdescription?: unknown;\n\tcontent?: unknown;\n}\n\ninterface JinaSearchEnvelope {\n\tcode?: unknown;\n\tdata?: unknown;\n}\n\ninterface JinaSearchOptions extends SearchOptions {\n\tincludeContent?: boolean;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\n\tconst raw = readFileSync(CONFIG_PATH, \"utf8\");\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(raw);\n\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\t\tthrow new Error(\"expected a JSON object\");\n\t\t}\n\t\tcachedConfig = parsed as WebSearchConfig;\n\t\treturn cachedConfig;\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"Jina Search\",\n\t\tconfiguredValue: loadConfig().jinaApiKey,\n\t\tenvironmentValue: process.env.JINA_API_KEY,\n\t\tsignal,\n\t});\n}\n\nasync function requireApiKey(signal?: AbortSignal): Promise<string> {\n\tconst apiKey = await getApiKey(signal);\n\tif (!apiKey) {\n\t\tthrow new Error(\n\t\t\t\"Jina Search API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"jinaApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set JINA_API_KEY environment variable\\n\" +\n\t\t\t\"Get a key at https://jina.ai/api-dashboard\",\n\t\t);\n\t}\n\treturn apiKey;\n}\n\nfunction normalizeDomain(value: string): string | null {\n\tlet input = value.trim().toLowerCase();\n\tif (input.startsWith(\"-\")) input = input.slice(1).trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst parsed = input.includes(\"://\") ? new URL(input) : new URL(`https://${input}`);\n\t\tinput = parsed.hostname;\n\t} catch {\n\t\tinput = input.split(\"/\")[0]?.split(\":\")[0] ?? \"\";\n\t}\n\tinput = input.replace(/^\\.+|\\.+$/g, \"\");\n\treturn /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i.test(input) ? input : null;\n}\n\nfunction mapDomainFilter(domainFilter: string[] | undefined): { includes: string[]; excludes: string[] } {\n\tconst includes: string[] = [];\n\tconst excludes: string[] = [];\n\tfor (const raw of domainFilter ?? []) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? excludes : includes;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\treturn { includes, excludes };\n}\n\nfunction buildSearchRequest(query: string, options: JinaSearchOptions, numResults: number): { url: string; filters: ReturnType<typeof mapDomainFilter> } {\n\tconst filters = mapDomainFilter(options.domainFilter);\n\tconst recency = options.recencyFilter ? ` published in the past ${options.recencyFilter}` : \"\";\n\tconst exclusions = filters.excludes.map((domain) => ` -site:${domain}`).join(\"\");\n\tconst constrainedQuery = `${query.trim()}${exclusions}${recency}`.trim();\n\tconst url = new URL(encodeURIComponent(constrainedQuery), JINA_SEARCH_BASE_URL);\n\turl.searchParams.set(\"count\", String(numResults));\n\tfor (const domain of filters.includes) url.searchParams.append(\"site\", domain);\n\treturn { url: url.toString(), filters };\n}\n\nfunction requestSignal(signal?: AbortSignal): { signal: AbortSignal; timeout: AbortSignal } {\n\tconst timeout = AbortSignal.timeout(SEARCH_TIMEOUT_MS);\n\treturn {\n\t\ttimeout,\n\t\tsignal: signal ? AbortSignal.any([signal, timeout]) : timeout,\n\t};\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\nfunction parseItems(value: unknown): JinaSearchItem[] {\n\tif (Array.isArray(value)) return value as JinaSearchItem[];\n\tif (!value || typeof value !== \"object\") {\n\t\tthrow new Error(\"Jina Search API returned invalid response: expected an object or array\");\n\t}\n\tconst envelope = value as JinaSearchEnvelope;\n\tif (typeof envelope.code === \"number\" && envelope.code !== 200) {\n\t\tthrow new Error(`Jina Search API error ${envelope.code}: response envelope reported failure`);\n\t}\n\tif (!Array.isArray(envelope.data)) {\n\t\tthrow new Error(\"Jina Search API returned invalid response: expected data array\");\n\t}\n\treturn envelope.data as JinaSearchItem[];\n}\n\nfunction passesDomainFilter(url: string, filters: ReturnType<typeof mapDomainFilter>): boolean {\n\tlet hostname: string;\n\ttry {\n\t\thostname = new URL(url).hostname.toLowerCase();\n\t} catch {\n\t\treturn false;\n\t}\n\tconst matches = (domain: string): boolean => hostname === domain || hostname.endsWith(`.${domain}`);\n\tif (filters.includes.length > 0 && !filters.includes.some(matches)) return false;\n\treturn !filters.excludes.some(matches);\n}\n\nfunction mapItems(items: JinaSearchItem[], numResults: number, filters: ReturnType<typeof mapDomainFilter>): {\n\tresults: SearchResponse[\"results\"];\n\tcontent: ExtractedContent[];\n} {\n\tconst results: SearchResponse[\"results\"] = [];\n\tconst content: ExtractedContent[] = [];\n\tconst seen = new Set<string>();\n\tfor (const item of items) {\n\t\tconst url = typeof item?.url === \"string\" ? item.url.trim() : \"\";\n\t\tif (!url || seen.has(url) || !passesDomainFilter(url, filters)) continue;\n\t\tseen.add(url);\n\t\tconst title = typeof item.title === \"string\" && item.title.trim()\n\t\t\t? item.title.trim()\n\t\t\t: `Source ${results.length + 1}`;\n\t\tconst snippet = typeof item.description === \"string\"\n\t\t\t? item.description.replace(/\\s+/g, \" \").trim()\n\t\t\t: \"\";\n\t\tresults.push({ title, url, snippet });\n\t\tif (typeof item.content === \"string\" && item.content.trim()) {\n\t\t\tcontent.push({ url, title, content: item.content.trim(), error: null });\n\t\t}\n\t\tif (results.length >= numResults) break;\n\t}\n\treturn { results, content };\n}\n\nfunction rethrowRequestError(\n\terr: unknown,\n\tapiKey: string,\n\tactivityId: string,\n\trequest: ReturnType<typeof requestSignal>,\n\tcallerSignal?: AbortSignal,\n): never {\n\tif (request.timeout.aborted && !callerSignal?.aborted) {\n\t\tactivityMonitor.logComplete(activityId, 408);\n\t\tthrow new Error(\"Jina Search API error 408: request timed out\");\n\t}\n\tconst message = errorMessage(err);\n\tconst redactedMessage = redactCredential(message, apiKey);\n\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\telse activityMonitor.logError(activityId, redactedMessage);\n\tif (redactedMessage === message) throw err;\n\tconst redactedError = new Error(redactedMessage);\n\tif (err instanceof Error) redactedError.name = err.name;\n\tthrow redactedError;\n}\n\nexport function isJinaSearchAvailable(): boolean {\n\treturn hasCredentialSource({\n\t\tprovider: \"Jina Search\",\n\t\tconfiguredValue: loadConfig().jinaApiKey,\n\t\tenvironmentValue: process.env.JINA_API_KEY,\n\t});\n}\n\nexport async function searchWithJina(query: string, options: JinaSearchOptions = {}): Promise<SearchResponse> {\n\tconst apiKey = await requireApiKey(options.signal);\n\tconst numResults = normalizeSearchResultCount(options.numResults);\n\tconst { url, filters } = buildSearchRequest(query, options, numResults);\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\tconst request = requestSignal(options.signal);\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(url, {\n\t\t\theaders: {\n\t\t\t\t\"Accept\": \"application/json\",\n\t\t\t\t\"Authorization\": `Bearer ${apiKey}`,\n\t\t\t\t\"User-Agent\": \"pi-web-access\",\n\t\t\t\t\"X-Respond-With\": options.includeContent ? \"content\" : \"no-content\",\n\t\t\t\t\"X-Retain-Images\": \"none\",\n\t\t\t},\n\t\t\tsignal: request.signal,\n\t\t});\n\t} catch (err) {\n\t\trethrowRequestError(err, apiKey, activityId, request, options.signal);\n\t}\n\n\tif (!response.ok) {\n\t\tlet body: string;\n\t\ttry {\n\t\t\tbody = redactCredential(await response.text(), apiKey);\n\t\t} catch (err) {\n\t\t\trethrowRequestError(err, apiKey, activityId, request, options.signal);\n\t\t}\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`Jina Search API error ${response.status}: ${body.slice(0, 300)}`);\n\t}\n\n\tlet raw: unknown;\n\ttry {\n\t\traw = await response.json();\n\t} catch (err) {\n\t\tif (!(err instanceof SyntaxError)) {\n\t\t\trethrowRequestError(err, apiKey, activityId, request, options.signal);\n\t\t}\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(\"Jina Search API returned invalid JSON\");\n\t}\n\n\tlet mapped: ReturnType<typeof mapItems>;\n\ttry {\n\t\tmapped = mapItems(parseItems(raw), numResults, filters);\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tactivityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\tactivityMonitor.logComplete(activityId, response.status);\n\tconst result: SearchResponse = {\n\t\tanswer: formatSearchResultsAsAnswer(mapped.results),\n\t\tresults: mapped.results,\n\t};\n\tif (options.includeContent && mapped.content.length > 0) result.inlineContent = mapped.content;\n\treturn result;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"kagi.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/kagi.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAErE,OAAO,EAAmF,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAYxI,UAAU,iBAAkB,SAAQ,aAAa;IAChD,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,QAAQ,CAAC;IACvF,IAAI,CAAC,EAAE,UAAU,CAAC;CAClB;AA0ID,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,cAAc,CAAC,CA4C5G;AAED,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAiD3I"}
1
+ {"version":3,"file":"kagi.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/kagi.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIrE,OAAO,EAAmF,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAYxI,UAAU,iBAAkB,SAAQ,aAAa;IAChD,cAAc,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,cAAc,EAAE,WAAW,GAAG,QAAQ,CAAC;IACvF,IAAI,CAAC,EAAE,UAAU,CAAC;CAClB;AA+HD,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,cAAc,CAAC,CA4C5G;AAED,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAiD3I"}
@@ -1,5 +1,7 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { activityMonitor } from "./activity.js";
3
+ import { formatSearchResultsAsAnswer } from "./search-answer-formatting.js";
4
+ import { normalizeSearchResultCount } from "./search-result-count-normalization.js";
3
5
  import { hasCredentialSource, redactCredential, resolveCredential } from "./credential-source.js";
4
6
  import { fetchRemoteUrl, loadFetchContentDomainPolicy, loadSsrfConfig, validateRemoteUrl } from "./ssrf-protection.js";
5
7
  import { getWebSearchConfigPath } from "./utils.js";
@@ -48,11 +50,6 @@ async function requireApiKey(signal) {
48
50
  }
49
51
  return apiKey;
50
52
  }
51
- function normalizeCount(value) {
52
- if (typeof value !== "number" || !Number.isFinite(value))
53
- return 5;
54
- return Math.max(1, Math.min(Math.floor(value), 20));
55
- }
56
53
  function errorMessage(err) {
57
54
  return err instanceof Error ? err.message : String(err);
58
55
  }
@@ -140,17 +137,12 @@ function parseExtractResponse(value, requestedUrl) {
140
137
  }
141
138
  return null;
142
139
  }
143
- function buildAnswer(results) {
144
- return results.map((result) => result.snippet
145
- ? `${result.snippet}\nSource: ${result.title} (${result.url})`
146
- : `Source: ${result.title} (${result.url})`).join("\n\n");
147
- }
148
140
  export function isKagiAvailable() {
149
141
  return hasCredentialSource({ provider: "Kagi", configuredValue: loadConfig().kagiApiKey, environmentValue: process.env.KAGI_API_KEY });
150
142
  }
151
143
  export async function searchWithKagi(query, options = {}) {
152
144
  const apiKey = await requireApiKey(options.signal);
153
- const numResults = normalizeCount(options.numResults);
145
+ const numResults = normalizeSearchResultCount(options.numResults);
154
146
  const activityId = activityMonitor.logStart({ type: "api", query });
155
147
  let response;
156
148
  try {
@@ -191,7 +183,7 @@ export async function searchWithKagi(query, options = {}) {
191
183
  const parsed = parseSearchResponse(rawData);
192
184
  activityMonitor.logComplete(activityId, response.status);
193
185
  const results = parsed.results.slice(0, numResults);
194
- const mapped = { answer: buildAnswer(results), results };
186
+ const mapped = { answer: formatSearchResultsAsAnswer(results), results };
195
187
  if (options.includeContent) {
196
188
  const urls = new Set(results.map(result => result.url));
197
189
  const inlineContent = parsed.inlineContent.filter(content => urls.has(content.url));
@@ -1 +1 @@
1
- {"version":3,"file":"kagi.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/kagi.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { ExtractedContent, ExtractOptions } from \"./extract.ts\";\nimport type { SearchOptions, SearchResponse } from \"./perplexity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { fetchRemoteUrl, loadFetchContentDomainPolicy, loadSsrfConfig, validateRemoteUrl, type SsrfConfig } from \"./ssrf-protection.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst KAGI_SEARCH_URL = \"https://kagi.com/api/v1/search\";\nconst KAGI_EXTRACT_URL = \"https://kagi.com/api/v1/extract\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\n\ninterface WebSearchConfig {\n\tkagiApiKey?: unknown;\n}\n\ninterface KagiSearchOptions extends SearchOptions {\n\tincludeContent?: boolean;\n}\n\nexport interface KagiExtractOptions extends Pick<ExtractOptions, \"timeoutMs\" | \"lookup\"> {\n\tssrf?: SsrfConfig;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\tconst raw = readFileSync(CONFIG_PATH, \"utf-8\");\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);\n\t}\n\tcachedConfig = parsed as WebSearchConfig;\n\treturn cachedConfig;\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"Kagi\",\n\t\tconfiguredValue: loadConfig().kagiApiKey,\n\t\tenvironmentValue: process.env.KAGI_API_KEY,\n\t\tsignal,\n\t});\n}\n\nasync function requireApiKey(signal?: AbortSignal): Promise<string> {\n\tconst apiKey = await getApiKey(signal);\n\tif (!apiKey) {\n\t\tthrow new Error(\n\t\t\t\"Kagi API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"kagiApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set KAGI_API_KEY environment variable\\n\" +\n\t\t\t\"Create a key at https://kagi.com/settings?p=api\",\n\t\t);\n\t}\n\treturn apiKey;\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n\treturn Math.max(1, Math.min(Math.floor(value), 20));\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\nfunction invalidResponse(message: string): Error {\n\treturn new Error(`Kagi API returned invalid response: ${message}`);\n}\n\nfunction firstString(...values: unknown[]): string | null {\n\tfor (const value of values) {\n\t\tif (typeof value === \"string\" && value.trim()) return value.trim();\n\t}\n\treturn null;\n}\n\nfunction appendSearchItems(value: unknown, results: SearchResponse[\"results\"], inlineContent: ExtractedContent[]): void {\n\tif (Array.isArray(value)) {\n\t\tfor (const item of value) appendSearchItems(item, results, inlineContent);\n\t\treturn;\n\t}\n\tif (!value || typeof value !== \"object\") return;\n\tconst item = value as Record<string, unknown>;\n\tconst url = firstString(item.url, item.href, item.link);\n\tif (!url) return;\n\tconst title = firstString(item.title, item.name) ?? url;\n\tconst snippet = firstString(item.snippet, item.description, item.summary, item.content, item.markdown, item.text) ?? \"\";\n\tresults.push({ title, url, snippet });\n\tconst content = firstString(item.markdown, item.content, item.text);\n\tif (content) inlineContent.push({ url, title, content, error: null });\n}\n\nfunction parseErrors(value: unknown): string | null {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n\tconst envelope = value as Record<string, unknown>;\n\tconst rawErrors = envelope.errors ?? envelope.error;\n\tif (!Array.isArray(rawErrors)) return null;\n\tconst messages = rawErrors.map((entry) => {\n\t\tif (!entry || typeof entry !== \"object\") return String(entry);\n\t\tconst raw = entry as Record<string, unknown>;\n\t\treturn firstString(raw.message, raw.msg, raw.code) ?? JSON.stringify(raw);\n\t});\n\treturn messages.length > 0 ? messages.join(\"; \") : null;\n}\n\nfunction parseSearchResponse(value: unknown): { results: SearchResponse[\"results\"]; inlineContent: ExtractedContent[] } {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) throw invalidResponse(\"expected an object envelope\");\n\tconst message = parseErrors(value);\n\tif (message) throw invalidResponse(message);\n\tconst envelope = value as Record<string, unknown>;\n\tconst results: SearchResponse[\"results\"] = [];\n\tconst inlineContent: ExtractedContent[] = [];\n\tconst data = envelope.data;\n\tconst items = (typeof data === \"object\" && data !== null && !Array.isArray(data))\n\t\t? (data as Record<string, unknown>).search\n\t\t: data;\n\tappendSearchItems(items, results, inlineContent);\n\treturn { results, inlineContent };\n}\n\nfunction parseExtractResponse(value: unknown, requestedUrl: string): ExtractedContent | null {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) throw invalidResponse(\"expected extract object envelope\");\n\tconst message = parseErrors(value);\n\tif (message) throw invalidResponse(message);\n\tconst envelope = value as Record<string, unknown>;\n\tconst candidates = Array.isArray(envelope.data) ? envelope.data : [envelope.data ?? envelope];\n\tfor (const candidate of candidates) {\n\t\tif (!candidate || typeof candidate !== \"object\" || Array.isArray(candidate)) continue;\n\t\tconst item = candidate as Record<string, unknown>;\n\t\tconst content = firstString(item.markdown, item.content, item.text);\n\t\tif (!content) continue;\n\t\treturn {\n\t\t\turl: firstString(item.url, item.href, item.link) ?? requestedUrl,\n\t\t\ttitle: firstString(item.title, item.name) ?? requestedUrl,\n\t\t\tcontent,\n\t\t\terror: null,\n\t\t};\n\t}\n\treturn null;\n}\n\nfunction buildAnswer(results: SearchResponse[\"results\"]): string {\n\treturn results.map((result) => result.snippet\n\t\t? `${result.snippet}\\nSource: ${result.title} (${result.url})`\n\t\t: `Source: ${result.title} (${result.url})`).join(\"\\n\\n\");\n}\n\nexport function isKagiAvailable(): boolean {\n\treturn hasCredentialSource({ provider: \"Kagi\", configuredValue: loadConfig().kagiApiKey, environmentValue: process.env.KAGI_API_KEY });\n}\n\nexport async function searchWithKagi(query: string, options: KagiSearchOptions = {}): Promise<SearchResponse> {\n\tconst apiKey = await requireApiKey(options.signal);\n\tconst numResults = normalizeCount(options.numResults);\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(KAGI_SEARCH_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { Authorization: `Bearer ${apiKey}`, \"Content-Type\": \"application/json\", Accept: \"application/json\" },\n\t\t\tbody: JSON.stringify({ query, limit: numResults }),\n\t\t\tsignal: options.signal ? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal]) : AbortSignal.timeout(SEARCH_TIMEOUT_MS),\n\t\t});\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\t\telse activityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\tthrow new Error(`Kagi API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t}\n\tlet rawData: unknown;\n\ttry {\n\t\trawData = await response.json();\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`Kagi API returned invalid JSON: ${errorMessage(err)}`);\n\t}\n\tconst parsed = parseSearchResponse(rawData);\n\tactivityMonitor.logComplete(activityId, response.status);\n\tconst results = parsed.results.slice(0, numResults);\n\tconst mapped: SearchResponse = { answer: buildAnswer(results), results };\n\tif (options.includeContent) {\n\t\tconst urls = new Set(results.map(result => result.url));\n\t\tconst inlineContent = parsed.inlineContent.filter(content => urls.has(content.url));\n\t\tif (inlineContent.length > 0) mapped.inlineContent = inlineContent;\n\t}\n\treturn mapped;\n}\n\nexport function isKagiExtractAvailable(): boolean {\n\treturn isKagiAvailable();\n}\n\nexport async function extractWithKagi(url: string, signal?: AbortSignal, options: KagiExtractOptions = {}): Promise<ExtractedContent | null> {\n\tconst ssrf = options.ssrf ?? loadSsrfConfig();\n\tconst domainPolicy = loadFetchContentDomainPolicy();\n\tawait validateRemoteUrl(url, {\n\t\tallowRanges: ssrf.allowRanges,\n\t\ttrustEnvProxy: ssrf.trustEnvProxy,\n\t\tdomainPolicy,\n\t\t...(options.lookup ? { lookup: options.lookup } : {}),\n\t});\n\tconst apiKey = await requireApiKey(signal);\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query: `kagi extract: ${url}` });\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetchRemoteUrl(KAGI_EXTRACT_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { Authorization: `Bearer ${apiKey}`, \"Content-Type\": \"application/json\", Accept: \"application/json\" },\n\t\t\tbody: JSON.stringify({ pages: [{ url }] }),\n\t\t\tsignal: signal ? AbortSignal.any([AbortSignal.timeout(options.timeoutMs ?? SEARCH_TIMEOUT_MS), signal]) : AbortSignal.timeout(options.timeoutMs ?? SEARCH_TIMEOUT_MS),\n\t\t}, {\n\t\t\tallowRanges: ssrf.allowRanges,\n\t\t\ttrustEnvProxy: ssrf.trustEnvProxy,\n\t\t\tonRedirect: ({ from, to, init }) => to.origin === from.origin ? init : { ...init, headers: { \"Content-Type\": \"application/json\", Accept: \"application/json\" } },\n\t\t\t...(options.lookup ? { lookup: options.lookup } : {}),\n\t\t});\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\t\telse activityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\tthrow new Error(`Kagi Extract API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t}\n\tlet rawData: unknown;\n\ttry {\n\t\trawData = await response.json();\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`Kagi Extract API returned invalid JSON: ${errorMessage(err)}`);\n\t}\n\tconst parsed = parseExtractResponse(rawData, url);\n\tactivityMonitor.logComplete(activityId, response.status);\n\treturn parsed;\n}\n"]}
1
+ {"version":3,"file":"kagi.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/kagi.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { ExtractedContent, ExtractOptions } from \"./extract.ts\";\nimport type { SearchOptions, SearchResponse } from \"./perplexity.ts\";\nimport { formatSearchResultsAsAnswer } from \"./search-answer-formatting.ts\";\nimport { normalizeSearchResultCount } from \"./search-result-count-normalization.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { fetchRemoteUrl, loadFetchContentDomainPolicy, loadSsrfConfig, validateRemoteUrl, type SsrfConfig } from \"./ssrf-protection.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst KAGI_SEARCH_URL = \"https://kagi.com/api/v1/search\";\nconst KAGI_EXTRACT_URL = \"https://kagi.com/api/v1/extract\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\n\ninterface WebSearchConfig {\n\tkagiApiKey?: unknown;\n}\n\ninterface KagiSearchOptions extends SearchOptions {\n\tincludeContent?: boolean;\n}\n\nexport interface KagiExtractOptions extends Pick<ExtractOptions, \"timeoutMs\" | \"lookup\"> {\n\tssrf?: SsrfConfig;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\tconst raw = readFileSync(CONFIG_PATH, \"utf-8\");\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${message}`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);\n\t}\n\tcachedConfig = parsed as WebSearchConfig;\n\treturn cachedConfig;\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"Kagi\",\n\t\tconfiguredValue: loadConfig().kagiApiKey,\n\t\tenvironmentValue: process.env.KAGI_API_KEY,\n\t\tsignal,\n\t});\n}\n\nasync function requireApiKey(signal?: AbortSignal): Promise<string> {\n\tconst apiKey = await getApiKey(signal);\n\tif (!apiKey) {\n\t\tthrow new Error(\n\t\t\t\"Kagi API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"kagiApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set KAGI_API_KEY environment variable\\n\" +\n\t\t\t\"Create a key at https://kagi.com/settings?p=api\",\n\t\t);\n\t}\n\treturn apiKey;\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\nfunction invalidResponse(message: string): Error {\n\treturn new Error(`Kagi API returned invalid response: ${message}`);\n}\n\nfunction firstString(...values: unknown[]): string | null {\n\tfor (const value of values) {\n\t\tif (typeof value === \"string\" && value.trim()) return value.trim();\n\t}\n\treturn null;\n}\n\nfunction appendSearchItems(value: unknown, results: SearchResponse[\"results\"], inlineContent: ExtractedContent[]): void {\n\tif (Array.isArray(value)) {\n\t\tfor (const item of value) appendSearchItems(item, results, inlineContent);\n\t\treturn;\n\t}\n\tif (!value || typeof value !== \"object\") return;\n\tconst item = value as Record<string, unknown>;\n\tconst url = firstString(item.url, item.href, item.link);\n\tif (!url) return;\n\tconst title = firstString(item.title, item.name) ?? url;\n\tconst snippet = firstString(item.snippet, item.description, item.summary, item.content, item.markdown, item.text) ?? \"\";\n\tresults.push({ title, url, snippet });\n\tconst content = firstString(item.markdown, item.content, item.text);\n\tif (content) inlineContent.push({ url, title, content, error: null });\n}\n\nfunction parseErrors(value: unknown): string | null {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n\tconst envelope = value as Record<string, unknown>;\n\tconst rawErrors = envelope.errors ?? envelope.error;\n\tif (!Array.isArray(rawErrors)) return null;\n\tconst messages = rawErrors.map((entry) => {\n\t\tif (!entry || typeof entry !== \"object\") return String(entry);\n\t\tconst raw = entry as Record<string, unknown>;\n\t\treturn firstString(raw.message, raw.msg, raw.code) ?? JSON.stringify(raw);\n\t});\n\treturn messages.length > 0 ? messages.join(\"; \") : null;\n}\n\nfunction parseSearchResponse(value: unknown): { results: SearchResponse[\"results\"]; inlineContent: ExtractedContent[] } {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) throw invalidResponse(\"expected an object envelope\");\n\tconst message = parseErrors(value);\n\tif (message) throw invalidResponse(message);\n\tconst envelope = value as Record<string, unknown>;\n\tconst results: SearchResponse[\"results\"] = [];\n\tconst inlineContent: ExtractedContent[] = [];\n\tconst data = envelope.data;\n\tconst items = (typeof data === \"object\" && data !== null && !Array.isArray(data))\n\t\t? (data as Record<string, unknown>).search\n\t\t: data;\n\tappendSearchItems(items, results, inlineContent);\n\treturn { results, inlineContent };\n}\n\nfunction parseExtractResponse(value: unknown, requestedUrl: string): ExtractedContent | null {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) throw invalidResponse(\"expected extract object envelope\");\n\tconst message = parseErrors(value);\n\tif (message) throw invalidResponse(message);\n\tconst envelope = value as Record<string, unknown>;\n\tconst candidates = Array.isArray(envelope.data) ? envelope.data : [envelope.data ?? envelope];\n\tfor (const candidate of candidates) {\n\t\tif (!candidate || typeof candidate !== \"object\" || Array.isArray(candidate)) continue;\n\t\tconst item = candidate as Record<string, unknown>;\n\t\tconst content = firstString(item.markdown, item.content, item.text);\n\t\tif (!content) continue;\n\t\treturn {\n\t\t\turl: firstString(item.url, item.href, item.link) ?? requestedUrl,\n\t\t\ttitle: firstString(item.title, item.name) ?? requestedUrl,\n\t\t\tcontent,\n\t\t\terror: null,\n\t\t};\n\t}\n\treturn null;\n}\n\nexport function isKagiAvailable(): boolean {\n\treturn hasCredentialSource({ provider: \"Kagi\", configuredValue: loadConfig().kagiApiKey, environmentValue: process.env.KAGI_API_KEY });\n}\n\nexport async function searchWithKagi(query: string, options: KagiSearchOptions = {}): Promise<SearchResponse> {\n\tconst apiKey = await requireApiKey(options.signal);\n\tconst numResults = normalizeSearchResultCount(options.numResults);\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(KAGI_SEARCH_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { Authorization: `Bearer ${apiKey}`, \"Content-Type\": \"application/json\", Accept: \"application/json\" },\n\t\t\tbody: JSON.stringify({ query, limit: numResults }),\n\t\t\tsignal: options.signal ? AbortSignal.any([AbortSignal.timeout(SEARCH_TIMEOUT_MS), options.signal]) : AbortSignal.timeout(SEARCH_TIMEOUT_MS),\n\t\t});\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\t\telse activityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\tthrow new Error(`Kagi API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t}\n\tlet rawData: unknown;\n\ttry {\n\t\trawData = await response.json();\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`Kagi API returned invalid JSON: ${errorMessage(err)}`);\n\t}\n\tconst parsed = parseSearchResponse(rawData);\n\tactivityMonitor.logComplete(activityId, response.status);\n\tconst results = parsed.results.slice(0, numResults);\n\tconst mapped: SearchResponse = { answer: formatSearchResultsAsAnswer(results), results };\n\tif (options.includeContent) {\n\t\tconst urls = new Set(results.map(result => result.url));\n\t\tconst inlineContent = parsed.inlineContent.filter(content => urls.has(content.url));\n\t\tif (inlineContent.length > 0) mapped.inlineContent = inlineContent;\n\t}\n\treturn mapped;\n}\n\nexport function isKagiExtractAvailable(): boolean {\n\treturn isKagiAvailable();\n}\n\nexport async function extractWithKagi(url: string, signal?: AbortSignal, options: KagiExtractOptions = {}): Promise<ExtractedContent | null> {\n\tconst ssrf = options.ssrf ?? loadSsrfConfig();\n\tconst domainPolicy = loadFetchContentDomainPolicy();\n\tawait validateRemoteUrl(url, {\n\t\tallowRanges: ssrf.allowRanges,\n\t\ttrustEnvProxy: ssrf.trustEnvProxy,\n\t\tdomainPolicy,\n\t\t...(options.lookup ? { lookup: options.lookup } : {}),\n\t});\n\tconst apiKey = await requireApiKey(signal);\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query: `kagi extract: ${url}` });\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetchRemoteUrl(KAGI_EXTRACT_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: { Authorization: `Bearer ${apiKey}`, \"Content-Type\": \"application/json\", Accept: \"application/json\" },\n\t\t\tbody: JSON.stringify({ pages: [{ url }] }),\n\t\t\tsignal: signal ? AbortSignal.any([AbortSignal.timeout(options.timeoutMs ?? SEARCH_TIMEOUT_MS), signal]) : AbortSignal.timeout(options.timeoutMs ?? SEARCH_TIMEOUT_MS),\n\t\t}, {\n\t\t\tallowRanges: ssrf.allowRanges,\n\t\t\ttrustEnvProxy: ssrf.trustEnvProxy,\n\t\t\tonRedirect: ({ from, to, init }) => to.origin === from.origin ? init : { ...init, headers: { \"Content-Type\": \"application/json\", Accept: \"application/json\" } },\n\t\t\t...(options.lookup ? { lookup: options.lookup } : {}),\n\t\t});\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\t\telse activityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = redactCredential(await response.text(), apiKey);\n\t\tthrow new Error(`Kagi Extract API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t}\n\tlet rawData: unknown;\n\ttry {\n\t\trawData = await response.json();\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`Kagi Extract API returned invalid JSON: ${errorMessage(err)}`);\n\t}\n\tconst parsed = parseExtractResponse(rawData, url);\n\tactivityMonitor.logComplete(activityId, response.status);\n\treturn parsed;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"kimi-search.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/kimi-search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAGnD,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAgB,MAAM,iBAAiB,CAAC;AAgKnF,wBAAsB,qBAAqB,CAAC,GAAG,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAMpF;AAED,wBAAsB,cAAc,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,EAC3B,GAAG,CAAC,EAAE,gBAAgB,GACpB,OAAO,CAAC,cAAc,CAAC,CAyDzB"}
1
+ {"version":3,"file":"kimi-search.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/kimi-search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAgB,MAAM,iBAAiB,CAAC;AAsInF,wBAAsB,qBAAqB,CAAC,GAAG,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAMpF;AAED,wBAAsB,cAAc,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,EAC3B,GAAG,CAAC,EAAE,gBAAgB,GACpB,OAAO,CAAC,cAAc,CAAC,CAyDzB"}
@@ -1,6 +1,9 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { activityMonitor } from "./activity.js";
3
+ import { normalizeDomain } from "./domain-filter-normalization.js";
3
4
  import { redactCredential } from "./credential-source.js";
5
+ import { formatSearchResultsAsAnswer } from "./search-answer-formatting.js";
6
+ import { normalizeSearchResultCount } from "./search-result-count-normalization.js";
4
7
  const KIMI_SEARCH_URL = "https://api.kimi.com/coding/v1/search";
5
8
  const KIMI_PROVIDERS = ["kimi-coding", "kimi-code"];
6
9
  const SEARCH_TIMEOUT_MS = 30_000;
@@ -54,29 +57,6 @@ async function resolveKimiAuth(ctx) {
54
57
  throw firstError;
55
58
  return undefined;
56
59
  }
57
- function normalizeCount(value) {
58
- if (typeof value !== "number" || !Number.isFinite(value))
59
- return 5;
60
- return Math.max(1, Math.min(Math.floor(value), 20));
61
- }
62
- function normalizeDomain(value) {
63
- let input = value.trim().toLowerCase();
64
- if (!input)
65
- return null;
66
- if (input.startsWith("-"))
67
- input = input.slice(1).trim();
68
- if (!input)
69
- return null;
70
- try {
71
- const parsed = input.includes("://") ? new URL(input) : new URL(`https://${input}`);
72
- input = parsed.hostname;
73
- }
74
- catch {
75
- input = input.split("/")[0]?.split(":")[0] ?? "";
76
- }
77
- input = input.replace(/^\.+|\.+$/g, "");
78
- return /^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input) ? input : null;
79
- }
80
60
  function normalizeDomainFilters(domainFilter) {
81
61
  const filters = { allowed: [], blocked: [] };
82
62
  if (!domainFilter?.length)
@@ -130,7 +110,7 @@ function parseResults(value, options) {
130
110
  throw new Error("Kimi Code search API returned an invalid response: search_results must be an array");
131
111
  }
132
112
  const filters = normalizeDomainFilters(options.domainFilter);
133
- const numResults = normalizeCount(options.numResults);
113
+ const numResults = normalizeSearchResultCount(options.numResults);
134
114
  const results = [];
135
115
  for (const item of value.search_results) {
136
116
  if (!item || typeof item !== "object")
@@ -149,13 +129,6 @@ function parseResults(value, options) {
149
129
  }
150
130
  return results;
151
131
  }
152
- function formatAnswer(results) {
153
- return results
154
- .map((result) => result.snippet
155
- ? `${result.snippet}\nSource: ${result.title} (${result.url})`
156
- : `Source: ${result.title} (${result.url})`)
157
- .join("\n\n");
158
- }
159
132
  export async function isKimiSearchAvailable(ctx) {
160
133
  try {
161
134
  return !!(await resolveKimiAuth(ctx));
@@ -199,7 +172,7 @@ export async function searchWithKimi(query, options = {}, ctx) {
199
172
  throw new Error("Kimi Code search API returned no results");
200
173
  }
201
174
  activityMonitor.logComplete(activityId, response.status);
202
- return { answer: formatAnswer(results), results };
175
+ return { answer: formatSearchResultsAsAnswer(results), results };
203
176
  }
204
177
  catch (err) {
205
178
  const message = err instanceof Error ? err.message : String(err);
@@ -1 +1 @@
1
- {"version":3,"file":"kimi-search.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/kimi-search.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { ExtensionContext } from \"../host.ts\";\nimport { activityMonitor } from \"./activity.ts\";\nimport { redactCredential } from \"./credential-source.ts\";\nimport type { SearchOptions, SearchResponse, SearchResult } from \"./perplexity.ts\";\n\nconst KIMI_SEARCH_URL = \"https://api.kimi.com/coding/v1/search\";\nconst KIMI_PROVIDERS = [\"kimi-coding\", \"kimi-code\"] as const;\nconst SEARCH_TIMEOUT_MS = 30_000;\n\ntype ProviderHeaders = Record<string, string | null>;\n\ninterface KimiAuth {\n\tapiKey: string;\n\theaders: ProviderHeaders;\n}\n\ninterface NormalizedDomainFilters {\n\tallowed: string[];\n\tblocked: string[];\n}\n\nfunction buildRequestHeaders(auth: KimiAuth): Headers {\n\tconst headers = new Headers();\n\tfor (const [name, value] of Object.entries(auth.headers)) {\n\t\tif (value !== null) headers.set(name, value);\n\t}\n\theaders.set(\"Authorization\", `Bearer ${auth.apiKey}`);\n\theaders.set(\"Content-Type\", \"application/json\");\n\theaders.set(\"X-Msh-Tool-Call-Id\", randomUUID());\n\treturn headers;\n}\n\nfunction bearerToken(headers: ProviderHeaders): string | undefined {\n\tfor (const [name, value] of Object.entries(headers)) {\n\t\tif (name.toLowerCase() !== \"authorization\" || typeof value !== \"string\") continue;\n\t\tconst match = /^Bearer\\s+(.+)$/i.exec(value.trim());\n\t\tif (match?.[1]) return match[1];\n\t}\n\treturn undefined;\n}\n\nasync function resolveKimiAuth(ctx?: ExtensionContext): Promise<KimiAuth | undefined> {\n\tif (!ctx) return undefined;\n\n\tconst models = ctx.modelRegistry.getAll();\n\tlet firstError: unknown;\n\n\tfor (const provider of KIMI_PROVIDERS) {\n\t\tfor (const model of models) {\n\t\t\tif (model.provider !== provider) continue;\n\t\t\tlet resolved: Awaited<ReturnType<typeof ctx.modelRegistry.getApiKeyAndHeaders>>;\n\t\t\ttry {\n\t\t\t\tresolved = await ctx.modelRegistry.getApiKeyAndHeaders(model);\n\t\t\t} catch (err) {\n\t\t\t\tfirstError ??= err;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!resolved.ok) continue;\n\t\t\tconst headers = resolved.headers ?? {};\n\t\t\tconst apiKey = resolved.apiKey || bearerToken(headers);\n\t\t\tif (apiKey) return { apiKey, headers };\n\t\t}\n\t}\n\tif (firstError) throw firstError;\n\treturn undefined;\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n\treturn Math.max(1, Math.min(Math.floor(value), 20));\n}\n\nfunction normalizeDomain(value: string): string | null {\n\tlet input = value.trim().toLowerCase();\n\tif (!input) return null;\n\tif (input.startsWith(\"-\")) input = input.slice(1).trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst parsed = input.includes(\"://\") ? new URL(input) : new URL(`https://${input}`);\n\t\tinput = parsed.hostname;\n\t} catch {\n\t\tinput = input.split(\"/\")[0]?.split(\":\")[0] ?? \"\";\n\t}\n\tinput = input.replace(/^\\.+|\\.+$/g, \"\");\n\treturn /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i.test(input) ? input : null;\n}\n\nfunction normalizeDomainFilters(domainFilter: string[] | undefined): NormalizedDomainFilters {\n\tconst filters: NormalizedDomainFilters = { allowed: [], blocked: [] };\n\tif (!domainFilter?.length) return filters;\n\n\tfor (const raw of domainFilter) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? filters.blocked : filters.allowed;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\treturn filters;\n}\n\nfunction hostMatchesDomain(hostname: string, domain: string): boolean {\n\treturn hostname === domain || hostname.endsWith(`.${domain}`);\n}\n\nfunction matchesDomainFilters(url: string, filters: NormalizedDomainFilters): boolean {\n\tif (filters.allowed.length === 0 && filters.blocked.length === 0) return true;\n\n\tlet hostname = \"\";\n\ttry {\n\t\thostname = new URL(url).hostname.toLowerCase();\n\t} catch {\n\t\treturn false;\n\t}\n\tif (filters.allowed.length > 0 && !filters.allowed.some((domain) => hostMatchesDomain(hostname, domain))) {\n\t\treturn false;\n\t}\n\treturn !filters.blocked.some((domain) => hostMatchesDomain(hostname, domain));\n}\n\nfunction normalizeResultUrl(value: unknown): string | null {\n\tif (typeof value !== \"string\") return null;\n\tconst input = value.trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst url = new URL(input);\n\t\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") return null;\n\t\treturn url.href;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction parseResults(value: unknown, options: SearchOptions): SearchResult[] {\n\tif (!value || typeof value !== \"object\" || !Array.isArray((value as { search_results?: unknown }).search_results)) {\n\t\tthrow new Error(\"Kimi Code search API returned an invalid response: search_results must be an array\");\n\t}\n\n\tconst filters = normalizeDomainFilters(options.domainFilter);\n\tconst numResults = normalizeCount(options.numResults);\n\tconst results: SearchResult[] = [];\n\tfor (const item of (value as { search_results: unknown[] }).search_results) {\n\t\tif (!item || typeof item !== \"object\") continue;\n\t\tconst record = item as Record<string, unknown>;\n\t\tconst url = normalizeResultUrl(record.url);\n\t\tif (!url || !matchesDomainFilters(url, filters)) continue;\n\t\tresults.push({\n\t\t\ttitle: typeof record.title === \"string\" && record.title.trim() ? record.title : url,\n\t\t\turl,\n\t\t\tsnippet: typeof record.snippet === \"string\" ? record.snippet : \"\",\n\t\t});\n\t\tif (results.length >= numResults) break;\n\t}\n\treturn results;\n}\n\nfunction formatAnswer(results: SearchResult[]): string {\n\treturn results\n\t\t.map((result) => result.snippet\n\t\t\t? `${result.snippet}\\nSource: ${result.title} (${result.url})`\n\t\t\t: `Source: ${result.title} (${result.url})`)\n\t\t.join(\"\\n\\n\");\n}\n\nexport async function isKimiSearchAvailable(ctx?: ExtensionContext): Promise<boolean> {\n\ttry {\n\t\treturn !!(await resolveKimiAuth(ctx));\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function searchWithKimi(\n\tquery: string,\n\toptions: SearchOptions = {},\n\tctx?: ExtensionContext,\n): Promise<SearchResponse> {\n\tconst auth = await resolveKimiAuth(ctx);\n\tif (!auth) {\n\t\tthrow new Error(\"Kimi Code web search unavailable. Run /login kimi-coding to authenticate a Kimi Code Plan account.\");\n\t}\n\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\tconst timeoutSignal = AbortSignal.timeout(SEARCH_TIMEOUT_MS);\n\tconst requestSignal = options.signal\n\t\t? AbortSignal.any([timeoutSignal, options.signal])\n\t\t: timeoutSignal;\n\ttry {\n\t\tconst response = await fetch(KIMI_SEARCH_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: buildRequestHeaders(auth),\n\t\t\tbody: JSON.stringify({ text_query: query }),\n\t\t\tsignal: requestSignal,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tactivityMonitor.logError(activityId, `HTTP ${response.status}`);\n\t\t\tconst errorText = redactCredential(await response.text(), auth.apiKey);\n\t\t\tthrow new Error(`Kimi Code search API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t\t}\n\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = await response.json();\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new Error(`Kimi Code search API returned invalid JSON: ${message}`);\n\t\t}\n\t\tconst results = parseResults(parsed, options);\n\t\tif (results.length === 0) {\n\t\t\tthrow new Error(\"Kimi Code search API returned no results\");\n\t\t}\n\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\treturn { answer: formatAnswer(results), results };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tconst redactedMessage = redactCredential(message, auth.apiKey);\n\t\tif (options.signal?.aborted) {\n\t\t\tactivityMonitor.logComplete(activityId, 0);\n\t\t} else if (timeoutSignal.aborted || (err instanceof Error && err.name === \"TimeoutError\")) {\n\t\t\tactivityMonitor.logError(activityId, \"Kimi Code search API timed out\");\n\t\t\tthrow new Error(\"Kimi Code search API timed out\");\n\t\t} else if (redactedMessage.toLowerCase().includes(\"abort\")) {\n\t\t\tactivityMonitor.logComplete(activityId, 0);\n\t\t} else {\n\t\t\tactivityMonitor.logError(activityId, redactedMessage);\n\t\t}\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n}\n"]}
1
+ {"version":3,"file":"kimi-search.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/kimi-search.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { ExtensionContext } from \"../host.ts\";\nimport { activityMonitor } from \"./activity.ts\";\nimport { normalizeDomain } from \"./domain-filter-normalization.ts\";\nimport { redactCredential } from \"./credential-source.ts\";\nimport type { SearchOptions, SearchResponse, SearchResult } from \"./perplexity.ts\";\nimport { formatSearchResultsAsAnswer } from \"./search-answer-formatting.ts\";\nimport { normalizeSearchResultCount } from \"./search-result-count-normalization.ts\";\n\nconst KIMI_SEARCH_URL = \"https://api.kimi.com/coding/v1/search\";\nconst KIMI_PROVIDERS = [\"kimi-coding\", \"kimi-code\"] as const;\nconst SEARCH_TIMEOUT_MS = 30_000;\n\ntype ProviderHeaders = Record<string, string | null>;\n\ninterface KimiAuth {\n\tapiKey: string;\n\theaders: ProviderHeaders;\n}\n\ninterface NormalizedDomainFilters {\n\tallowed: string[];\n\tblocked: string[];\n}\n\nfunction buildRequestHeaders(auth: KimiAuth): Headers {\n\tconst headers = new Headers();\n\tfor (const [name, value] of Object.entries(auth.headers)) {\n\t\tif (value !== null) headers.set(name, value);\n\t}\n\theaders.set(\"Authorization\", `Bearer ${auth.apiKey}`);\n\theaders.set(\"Content-Type\", \"application/json\");\n\theaders.set(\"X-Msh-Tool-Call-Id\", randomUUID());\n\treturn headers;\n}\n\nfunction bearerToken(headers: ProviderHeaders): string | undefined {\n\tfor (const [name, value] of Object.entries(headers)) {\n\t\tif (name.toLowerCase() !== \"authorization\" || typeof value !== \"string\") continue;\n\t\tconst match = /^Bearer\\s+(.+)$/i.exec(value.trim());\n\t\tif (match?.[1]) return match[1];\n\t}\n\treturn undefined;\n}\n\nasync function resolveKimiAuth(ctx?: ExtensionContext): Promise<KimiAuth | undefined> {\n\tif (!ctx) return undefined;\n\n\tconst models = ctx.modelRegistry.getAll();\n\tlet firstError: unknown;\n\n\tfor (const provider of KIMI_PROVIDERS) {\n\t\tfor (const model of models) {\n\t\t\tif (model.provider !== provider) continue;\n\t\t\tlet resolved: Awaited<ReturnType<typeof ctx.modelRegistry.getApiKeyAndHeaders>>;\n\t\t\ttry {\n\t\t\t\tresolved = await ctx.modelRegistry.getApiKeyAndHeaders(model);\n\t\t\t} catch (err) {\n\t\t\t\tfirstError ??= err;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!resolved.ok) continue;\n\t\t\tconst headers = resolved.headers ?? {};\n\t\t\tconst apiKey = resolved.apiKey || bearerToken(headers);\n\t\t\tif (apiKey) return { apiKey, headers };\n\t\t}\n\t}\n\tif (firstError) throw firstError;\n\treturn undefined;\n}\n\nfunction normalizeDomainFilters(domainFilter: string[] | undefined): NormalizedDomainFilters {\n\tconst filters: NormalizedDomainFilters = { allowed: [], blocked: [] };\n\tif (!domainFilter?.length) return filters;\n\n\tfor (const raw of domainFilter) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? filters.blocked : filters.allowed;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\treturn filters;\n}\n\nfunction hostMatchesDomain(hostname: string, domain: string): boolean {\n\treturn hostname === domain || hostname.endsWith(`.${domain}`);\n}\n\nfunction matchesDomainFilters(url: string, filters: NormalizedDomainFilters): boolean {\n\tif (filters.allowed.length === 0 && filters.blocked.length === 0) return true;\n\n\tlet hostname = \"\";\n\ttry {\n\t\thostname = new URL(url).hostname.toLowerCase();\n\t} catch {\n\t\treturn false;\n\t}\n\tif (filters.allowed.length > 0 && !filters.allowed.some((domain) => hostMatchesDomain(hostname, domain))) {\n\t\treturn false;\n\t}\n\treturn !filters.blocked.some((domain) => hostMatchesDomain(hostname, domain));\n}\n\nfunction normalizeResultUrl(value: unknown): string | null {\n\tif (typeof value !== \"string\") return null;\n\tconst input = value.trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst url = new URL(input);\n\t\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") return null;\n\t\treturn url.href;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction parseResults(value: unknown, options: SearchOptions): SearchResult[] {\n\tif (!value || typeof value !== \"object\" || !Array.isArray((value as { search_results?: unknown }).search_results)) {\n\t\tthrow new Error(\"Kimi Code search API returned an invalid response: search_results must be an array\");\n\t}\n\n\tconst filters = normalizeDomainFilters(options.domainFilter);\n\tconst numResults = normalizeSearchResultCount(options.numResults);\n\tconst results: SearchResult[] = [];\n\tfor (const item of (value as { search_results: unknown[] }).search_results) {\n\t\tif (!item || typeof item !== \"object\") continue;\n\t\tconst record = item as Record<string, unknown>;\n\t\tconst url = normalizeResultUrl(record.url);\n\t\tif (!url || !matchesDomainFilters(url, filters)) continue;\n\t\tresults.push({\n\t\t\ttitle: typeof record.title === \"string\" && record.title.trim() ? record.title : url,\n\t\t\turl,\n\t\t\tsnippet: typeof record.snippet === \"string\" ? record.snippet : \"\",\n\t\t});\n\t\tif (results.length >= numResults) break;\n\t}\n\treturn results;\n}\n\nexport async function isKimiSearchAvailable(ctx?: ExtensionContext): Promise<boolean> {\n\ttry {\n\t\treturn !!(await resolveKimiAuth(ctx));\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function searchWithKimi(\n\tquery: string,\n\toptions: SearchOptions = {},\n\tctx?: ExtensionContext,\n): Promise<SearchResponse> {\n\tconst auth = await resolveKimiAuth(ctx);\n\tif (!auth) {\n\t\tthrow new Error(\"Kimi Code web search unavailable. Run /login kimi-coding to authenticate a Kimi Code Plan account.\");\n\t}\n\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query });\n\tconst timeoutSignal = AbortSignal.timeout(SEARCH_TIMEOUT_MS);\n\tconst requestSignal = options.signal\n\t\t? AbortSignal.any([timeoutSignal, options.signal])\n\t\t: timeoutSignal;\n\ttry {\n\t\tconst response = await fetch(KIMI_SEARCH_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: buildRequestHeaders(auth),\n\t\t\tbody: JSON.stringify({ text_query: query }),\n\t\t\tsignal: requestSignal,\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tactivityMonitor.logError(activityId, `HTTP ${response.status}`);\n\t\t\tconst errorText = redactCredential(await response.text(), auth.apiKey);\n\t\t\tthrow new Error(`Kimi Code search API error ${response.status}: ${errorText.slice(0, 300)}`);\n\t\t}\n\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = await response.json();\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthrow new Error(`Kimi Code search API returned invalid JSON: ${message}`);\n\t\t}\n\t\tconst results = parseResults(parsed, options);\n\t\tif (results.length === 0) {\n\t\t\tthrow new Error(\"Kimi Code search API returned no results\");\n\t\t}\n\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\treturn { answer: formatSearchResultsAsAnswer(results), results };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\tconst redactedMessage = redactCredential(message, auth.apiKey);\n\t\tif (options.signal?.aborted) {\n\t\t\tactivityMonitor.logComplete(activityId, 0);\n\t\t} else if (timeoutSignal.aborted || (err instanceof Error && err.name === \"TimeoutError\")) {\n\t\t\tactivityMonitor.logError(activityId, \"Kimi Code search API timed out\");\n\t\t\tthrow new Error(\"Kimi Code search API timed out\");\n\t\t} else if (redactedMessage.toLowerCase().includes(\"abort\")) {\n\t\t\tactivityMonitor.logComplete(activityId, 0);\n\t\t} else {\n\t\t\tactivityMonitor.logError(activityId, redactedMessage);\n\t\t}\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"mistral-search.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/mistral-search.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAgB,MAAM,iBAAiB,CAAC;AAiNnF,wBAAgB,kBAAkB,IAAI,OAAO,CAa5C;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,CAsD3G"}
1
+ {"version":3,"file":"mistral-search.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/mistral-search.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAgB,MAAM,iBAAiB,CAAC;AAkMnF,wBAAgB,kBAAkB,IAAI,OAAO,CAa5C;AAED,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,CAsD3G"}
@@ -1,5 +1,6 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { activityMonitor } from "./activity.js";
3
+ import { normalizeDomain } from "./domain-filter-normalization.js";
3
4
  import { hasCredentialSource, redactCredential, resolveCredential } from "./credential-source.js";
4
5
  import { getWebSearchConfigPath } from "./utils.js";
5
6
  const MISTRAL_CONVERSATIONS_URL = "https://api.mistral.ai/v1/conversations";
@@ -52,24 +53,6 @@ function normalizeCount(value) {
52
53
  return 5;
53
54
  return Math.max(1, Math.min(Math.floor(value), MAX_RESULTS));
54
55
  }
55
- function normalizeDomain(value) {
56
- let input = value.trim().toLowerCase();
57
- if (!input)
58
- return null;
59
- if (input.startsWith("-"))
60
- input = input.slice(1).trim();
61
- if (!input)
62
- return null;
63
- try {
64
- const parsed = input.includes("://") ? new URL(input) : new URL(`https://${input}`);
65
- input = parsed.hostname;
66
- }
67
- catch {
68
- input = input.split("/")[0]?.split(":")[0] ?? "";
69
- }
70
- input = input.replace(/^\.+|\.+$/g, "");
71
- return /^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/i.test(input) ? input : null;
72
- }
73
56
  function parseDomainFilters(domainFilter) {
74
57
  const filters = { include: [], exclude: [] };
75
58
  for (const raw of domainFilter ?? []) {