@mini-z/dsh-search-providers 0.2.1 → 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.
- package/CHANGELOG.md +26 -0
- package/README.md +27 -14
- package/cordis.patch.yml +7 -1
- package/dsh/index.js +37 -76
- package/dsh/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0
|
|
4
|
+
|
|
5
|
+
### Breaking changes
|
|
6
|
+
|
|
7
|
+
- Replace the standalone `read_page` tool with the native `web_fetch` provider via `ctx.web.registerFetchProvider`. The bundle now selects `search-providers` for both search and fetch; default direct HTTP fetching is no longer selected.
|
|
8
|
+
- Remove the page-reading focus `query` parameter entirely, including the internal `FetchRequest` field and TinyFish fetch `purpose` mapping. Search keywords and search routing are unchanged.
|
|
9
|
+
- Return native `{ url, statusCode, body, truncated }` results. Summary, extracted Markdown, links, uncertainty, and operational warnings are rendered inside `body.content`, rather than separate top-level fields.
|
|
10
|
+
|
|
11
|
+
### Improvements
|
|
12
|
+
|
|
13
|
+
- Preserve capability-aware TinyFish → Exa → Firecrawl fetch fallback, cooldown, authentication disablement, and cancellation.
|
|
14
|
+
- Set native `web_fetch` timeout to 200 seconds to preserve the former aggregate page-reading deadline.
|
|
15
|
+
- Report truncation when extracted content exceeds 20,000 characters or outgoing links exceed 20.
|
|
16
|
+
- Explicitly report unknown origin HTTP status as `statusCode: 0`, retain the requested URL, and include a warning instead of fabricating HTTP success or a final redirect URL.
|
|
17
|
+
|
|
18
|
+
### Upgrade notes
|
|
19
|
+
|
|
20
|
+
- Replace `read_page(...)` calls with `web_fetch({ url })`; remove page-reading focus arguments. Consumers of structured results should read `body.content`.
|
|
21
|
+
- Existing JSON provider configuration does not need changes. Update the plugin in the DSH profile and restart DSH.
|
|
22
|
+
- Fetch URLs now go to third-party extraction services through the native tool; do not submit private or sensitive URLs. This backend is not intended for HTTP status or redirect diagnostics.
|
|
23
|
+
|
|
24
|
+
### Verification
|
|
25
|
+
|
|
26
|
+
- 131 automated tests pass, including native fetch routing, capability availability, cancellation, fallback, truncation, and removed focus-parameter regressions.
|
|
27
|
+
- Type checking, production build, and an offline smoke test using the installed DSH native fetch seam/tool renderer pass.
|
|
28
|
+
|
|
3
29
|
## 0.2.1
|
|
4
30
|
|
|
5
31
|
- Fix Codex credential loading for account stores with `credentials[]` and `activeAccountId`; preserve existing credential formats and never modify or refresh credentials.
|
package/README.md
CHANGED
|
@@ -3,22 +3,24 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@mini-z/dsh-search-providers)
|
|
4
4
|
[](./package.json)
|
|
5
5
|
|
|
6
|
-
A modular [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/dsh) plugin that provides `web_search` and `
|
|
6
|
+
A modular [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/dsh) plugin that provides `web_search` and `web_fetch` through multiple search services with capability-aware fallback and cooldown handling.
|
|
7
7
|
|
|
8
8
|
**Codex is the default `web_search` provider.** If its static credential is unavailable, or a request fails, the plugin proceeds through the configured fallback chain.
|
|
9
9
|
|
|
10
|
-
## Latest update — 0.
|
|
10
|
+
## Latest update — 0.3.0
|
|
11
11
|
|
|
12
|
-
- **
|
|
13
|
-
-
|
|
14
|
-
-
|
|
12
|
+
- **Breaking: native `web_fetch` takeover.** The plugin now supplies both native web tool backends and no longer registers `read_page`.
|
|
13
|
+
- **Remove page-reading focus parameters completely.** Use `web_fetch({ url })`; there is no fetch `query` parameter or TinyFish fetch `purpose` forwarding. Search keywords are unchanged.
|
|
14
|
+
- Extracted evidence is returned in native `body.content`, with explicit truncation and unknown origin status (`statusCode: 0`) reporting.
|
|
15
|
+
- Preserve TinyFish → Exa → Firecrawl fetch fallback, cooldown, cancellation, and a 200-second aggregate deadline.
|
|
16
|
+
- Existing JSON configuration and Codex credential formats remain supported. Update the plugin and restart DSH. See [migration details](#native-web_fetch-migration) and [the changelog](./CHANGELOG.md).
|
|
15
17
|
|
|
16
18
|
**Upgrading from 0.1.x?** Move provider settings from `.env` or inline Cordis configuration into `~/.dsh/search-providers.json`. Official endpoints are built in, and fallback attempts now have a 55-second outer timeout. See [configuration migration](#migration-from-inline-cordis-and-environment-settings).
|
|
17
19
|
|
|
18
20
|
## Features
|
|
19
21
|
|
|
20
22
|
- Replaces the native `web_search` provider through the DSH web seam.
|
|
21
|
-
-
|
|
23
|
+
- Replaces the native `web_fetch` provider for clean page extraction; no separate `read_page` tool is registered.
|
|
22
24
|
- Uses Codex-first search routing by default.
|
|
23
25
|
- Filters fallback candidates by capability, so search-only providers are never used for page fetching.
|
|
24
26
|
- Temporarily cools failing provider capabilities instead of repeatedly calling them.
|
|
@@ -29,7 +31,7 @@ A modular [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/dsh) plugin th
|
|
|
29
31
|
|
|
30
32
|
## Provider support and default routing
|
|
31
33
|
|
|
32
|
-
| Provider | `web_search` | `
|
|
34
|
+
| Provider | `web_search` | `web_fetch` | Credential |
|
|
33
35
|
|----------|:------------:|:-----------:|------------|
|
|
34
36
|
| Codex | ✅ | ❌ | Static credential JSON referenced by `providers.codex.credentialFile` |
|
|
35
37
|
| TinyFish | ✅ | ✅ | `providers.tinyfish.apiKey` in JSON |
|
|
@@ -46,13 +48,24 @@ Default `web_search` order:
|
|
|
46
48
|
4. Exa
|
|
47
49
|
5. Firecrawl
|
|
48
50
|
|
|
49
|
-
Default `
|
|
51
|
+
Default `web_fetch` order:
|
|
50
52
|
|
|
51
53
|
1. TinyFish
|
|
52
54
|
2. Exa
|
|
53
55
|
3. Firecrawl
|
|
54
56
|
|
|
55
|
-
Codex and Tavily are skipped automatically for `
|
|
57
|
+
Codex and Tavily are skipped automatically for `web_fetch` because they do not implement page fetching. Providers without usable credentials are skipped without being marked as failed.
|
|
58
|
+
|
|
59
|
+
## Native web_fetch migration
|
|
60
|
+
|
|
61
|
+
The bundle selects `search-providers` for both `web.searchProvider` and `web.fetchProvider`. DSH continues to own the native tool schemas, system guidance, and result cards; the plugin supplies the backends. It no longer registers `read_page`.
|
|
62
|
+
|
|
63
|
+
- Call `web_fetch({ url })`. Page reading accepts no focus question: the former `query` field has been removed from both the tool interface and internal fetch request type, including TinyFish's fetch `purpose` mapping. Search query parameters are unchanged.
|
|
64
|
+
- Results use the native `{ url, statusCode, body: { kind: 'text', content }, truncated }` shape. Summary, extracted Markdown, links, uncertainty, and fallback warnings are rendered inside `body.content`, not separate top-level fields.
|
|
65
|
+
- Extraction providers do not expose the origin HTTP status or final redirect URL. The adapter returns `statusCode: 0` (unknown, **not** HTTP success), retains the requested URL, and includes an explicit warning. Do not use this backend for HTTP status/redirect diagnostics.
|
|
66
|
+
- Content is capped at 20,000 characters and outgoing links at 20; either cap sets `truncated: true`. Native DSH presentation may apply an additional display cap.
|
|
67
|
+
- The default fetch route is TinyFish → Exa → Firecrawl. There is no automatic fallback to DSH's direct HTTP provider. URLs are sent to third-party extraction services, unlike local HTTP retrieval; do not pass private or sensitive URLs.
|
|
68
|
+
- Existing JSON provider settings need no changes. Install the rebuilt plugin into the profile and restart DSH; editing a separate source checkout does not update an installed npm copy.
|
|
56
69
|
|
|
57
70
|
## Installation
|
|
58
71
|
|
|
@@ -172,9 +185,9 @@ The plugin rechecks provider state before every attempt instead of relying on a
|
|
|
172
185
|
| Network error or timeout | Current capability cooled for 30 seconds |
|
|
173
186
|
| Other request failure | Current capability cooled for 10 seconds |
|
|
174
187
|
|
|
175
|
-
Transient state is capability-scoped: a search failure does not cool `
|
|
188
|
+
Transient state is capability-scoped: a search failure does not cool `web_fetch`, and a fetch failure does not cool `web_search`. Authentication disablement is provider-wide.
|
|
176
189
|
|
|
177
|
-
The first eligible provider uses its configured request timeout. Each subsequent fallback attempt has an additional 55-second outer limit, which also stops providers that ignore `AbortSignal`. The
|
|
190
|
+
The first eligible provider uses its configured request timeout. Each subsequent fallback attempt has an additional 55-second outer limit, which also stops providers that ignore `AbortSignal`. The bundle sets the native `web_fetch` tool's `fetchTimeoutMs` to 200 seconds to preserve the former page-reading aggregate deadline. These request deadlines are separate from the cooldown durations in the table above.
|
|
178
191
|
|
|
179
192
|
Caller cancellation is different from failure: it propagates immediately, preserves the original abort reason, does not continue fallback, and does not alter provider state.
|
|
180
193
|
|
|
@@ -197,7 +210,7 @@ The parser also accepts `credential` and `tokens` wrappers, `access` as an alter
|
|
|
197
210
|
|
|
198
211
|
Account-store files such as `.openai-codex-auth.json` are also supported: the parser reads `access` and `accountId` from the `credentials` array entry matching `activeAccountId`. Without an active selector, only a single-entry array is accepted; ambiguous or missing matches are not guessed. The store is read-only, and the original formats remain supported.
|
|
199
212
|
|
|
200
|
-
Restrict the credential file to the owning user. Codex does not implement `
|
|
213
|
+
Restrict the credential file to the owning user. Codex does not implement `web_fetch`, and its standalone endpoint does not apply this plugin's recency, domain, location, language, or maximum-result filters.
|
|
201
214
|
|
|
202
215
|
## Usage
|
|
203
216
|
|
|
@@ -219,7 +232,7 @@ Read a specific page with:
|
|
|
219
232
|
Read this page: https://example.com/article
|
|
220
233
|
```
|
|
221
234
|
|
|
222
|
-
`
|
|
235
|
+
`web_fetch` returns the native fetch result, with summary, extracted content, outgoing links, uncertainty, and operational warnings rendered in `body.content`.
|
|
223
236
|
|
|
224
237
|
## Demo mode
|
|
225
238
|
|
|
@@ -250,7 +263,7 @@ Main components:
|
|
|
250
263
|
- `src/providers/cooldown.ts` — authentication disablement and capability cooldown state.
|
|
251
264
|
- `src/providers/*.ts` — provider implementations.
|
|
252
265
|
- `src/tools/web-search.ts` — DSH web seam adapter and search fallback.
|
|
253
|
-
- `src/tools/read-page.ts` — `
|
|
266
|
+
- `src/tools/read-page.ts` — `web_fetch` registration and fetch fallback.
|
|
254
267
|
- `src/index.ts` — plugin entry point and default provider order.
|
|
255
268
|
|
|
256
269
|
To add a provider, implement `SearchProvider`, register it in `src/index.ts`, and add its configuration resolution.
|
package/cordis.patch.yml
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
# dsh bundle patch: mount the search-providers plugin and route the web seam
|
|
2
|
-
# search
|
|
2
|
+
# search and fetch capabilities through it, replacing both default providers.
|
|
3
3
|
- id: web
|
|
4
4
|
config:
|
|
5
5
|
searchProvider: search-providers
|
|
6
|
+
fetchProvider: search-providers
|
|
7
|
+
|
|
8
|
+
# Preserve the former read_page aggregate deadline for multi-provider fallback.
|
|
9
|
+
- id: tool-web
|
|
10
|
+
config:
|
|
11
|
+
fetchTimeoutMs: 200000
|
|
6
12
|
|
|
7
13
|
- insert:
|
|
8
14
|
- id: search-providers
|
package/dsh/index.js
CHANGED
|
@@ -333,9 +333,6 @@ class TinyfishProvider {
|
|
|
333
333
|
urls: [request.url],
|
|
334
334
|
format: request.format ?? "markdown"
|
|
335
335
|
};
|
|
336
|
-
if (request.query) {
|
|
337
|
-
body.purpose = request.query;
|
|
338
|
-
}
|
|
339
336
|
if (typeof request.ttl === "number") {
|
|
340
337
|
body.ttl = request.ttl;
|
|
341
338
|
}
|
|
@@ -908,33 +905,6 @@ This is canned content for the URL "${request.url}".`,
|
|
|
908
905
|
};
|
|
909
906
|
}
|
|
910
907
|
}
|
|
911
|
-
const fetchSchema = {
|
|
912
|
-
type: "object",
|
|
913
|
-
properties: {
|
|
914
|
-
summary: { type: "string" },
|
|
915
|
-
content: { type: "string" },
|
|
916
|
-
links: {
|
|
917
|
-
type: "array",
|
|
918
|
-
items: {
|
|
919
|
-
type: "object",
|
|
920
|
-
properties: {
|
|
921
|
-
text: { type: "string" },
|
|
922
|
-
url: { type: "string" }
|
|
923
|
-
},
|
|
924
|
-
required: ["text", "url"]
|
|
925
|
-
}
|
|
926
|
-
},
|
|
927
|
-
uncertainty: {
|
|
928
|
-
type: "array",
|
|
929
|
-
items: { type: "string" }
|
|
930
|
-
},
|
|
931
|
-
warnings: {
|
|
932
|
-
type: "array",
|
|
933
|
-
items: { type: "string" }
|
|
934
|
-
}
|
|
935
|
-
},
|
|
936
|
-
required: ["summary", "content", "uncertainty"]
|
|
937
|
-
};
|
|
938
908
|
const FALLBACK_ATTEMPT_TIMEOUT_MS = 55e3;
|
|
939
909
|
function resolveCandidateIds(registry, fallbackChain) {
|
|
940
910
|
let activeId;
|
|
@@ -1006,55 +976,46 @@ function raceWithSignal(operation, signal) {
|
|
|
1006
976
|
function throwIfAborted(signal) {
|
|
1007
977
|
if (signal?.aborted) throw signal.reason;
|
|
1008
978
|
}
|
|
1009
|
-
const READ_PAGE_TIMEOUT_MS = 18e4;
|
|
1010
979
|
const RENDER_CONTENT_CAP = 2e4;
|
|
1011
980
|
const RENDER_LINK_CAP = 20;
|
|
1012
|
-
function
|
|
1013
|
-
if (typeof ctx.
|
|
1014
|
-
console.error("[search-providers] ctx.
|
|
981
|
+
function registerWebFetchProvider(ctx, registry, cooldown, fallbackChain) {
|
|
982
|
+
if (typeof ctx.web?.registerFetchProvider !== "function") {
|
|
983
|
+
console.error("[search-providers] ctx.web.registerFetchProvider is not available; web_fetch provider skipped");
|
|
1015
984
|
return;
|
|
1016
985
|
}
|
|
1017
|
-
ctx.
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
url: {
|
|
1024
|
-
type: "string",
|
|
1025
|
-
description: "The http(s) URL to read"
|
|
1026
|
-
},
|
|
1027
|
-
query: {
|
|
1028
|
-
type: "string",
|
|
1029
|
-
description: 'Optional question to focus the reading on (e.g. "what are the rate limits")'
|
|
1030
|
-
}
|
|
1031
|
-
},
|
|
1032
|
-
required: ["url"]
|
|
1033
|
-
},
|
|
1034
|
-
output: {
|
|
1035
|
-
schema: fetchSchema,
|
|
1036
|
-
render: (_args, value) => [
|
|
1037
|
-
{ type: "text", text: renderFetchEvidence(value) }
|
|
1038
|
-
]
|
|
986
|
+
ctx.web.registerFetchProvider({
|
|
987
|
+
id: "search-providers",
|
|
988
|
+
available: () => {
|
|
989
|
+
const candidates = resolveFetchCandidateIds(registry, fallbackChain);
|
|
990
|
+
const { ready } = cooldown.filter(candidates, "fetch");
|
|
991
|
+
return ready.some((id) => registry.get(id)?.available());
|
|
1039
992
|
},
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
throw new Error('read_page needs an http(s) "url".');
|
|
993
|
+
async fetch(args, signal) {
|
|
994
|
+
throwIfAborted(signal);
|
|
995
|
+
try {
|
|
996
|
+
if (typeof args?.url !== "string" || !/^https?:\/\//i.test(args.url.trim())) {
|
|
997
|
+
throw new Error("Invalid URL");
|
|
998
|
+
}
|
|
999
|
+
const url = new URL(args.url.trim());
|
|
1000
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") throw new Error("Invalid protocol");
|
|
1001
|
+
} catch {
|
|
1002
|
+
throw new Error('web_fetch needs an http(s) "url".');
|
|
1051
1003
|
}
|
|
1052
|
-
const request = {
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1004
|
+
const request = { url: args.url.trim(), format: "markdown" };
|
|
1005
|
+
const result = await fetchWithFallback(registry, cooldown, fallbackChain, request, signal);
|
|
1006
|
+
const evidence = {
|
|
1007
|
+
...result,
|
|
1008
|
+
warnings: [
|
|
1009
|
+
"Origin HTTP status and final redirect URL are unavailable from this extraction provider; statusCode 0 means unknown and url is the requested URL.",
|
|
1010
|
+
...result.warnings ?? []
|
|
1011
|
+
]
|
|
1012
|
+
};
|
|
1013
|
+
return {
|
|
1014
|
+
url: request.url,
|
|
1015
|
+
statusCode: 0,
|
|
1016
|
+
body: { kind: "text", content: renderFetchEvidence(evidence) },
|
|
1017
|
+
truncated: result.content.trim().length > RENDER_CONTENT_CAP || (result.links?.length ?? 0) > RENDER_LINK_CAP
|
|
1056
1018
|
};
|
|
1057
|
-
return fetchWithFallback(registry, cooldown, fallbackChain, request, exec.signal);
|
|
1058
1019
|
}
|
|
1059
1020
|
});
|
|
1060
1021
|
}
|
|
@@ -1130,8 +1091,8 @@ function renderFetchEvidence(value) {
|
|
|
1130
1091
|
if (links.length > 0) {
|
|
1131
1092
|
lines.push("", "Links:");
|
|
1132
1093
|
for (const link of links) {
|
|
1133
|
-
const text =
|
|
1134
|
-
const url =
|
|
1094
|
+
const text = link.text ?? "";
|
|
1095
|
+
const url = link.url ?? "";
|
|
1135
1096
|
lines.push(`- ${text} — ${url}`);
|
|
1136
1097
|
}
|
|
1137
1098
|
}
|
|
@@ -1257,7 +1218,7 @@ function renderContent(result, attempted, cooling, disabled) {
|
|
|
1257
1218
|
return lines.filter(Boolean).join("\n");
|
|
1258
1219
|
}
|
|
1259
1220
|
const name = "search-providers";
|
|
1260
|
-
const inject = ["
|
|
1221
|
+
const inject = ["web"];
|
|
1261
1222
|
const DEFAULT_PROVIDER_ORDER = ["codex", "tinyfish", "tavily", "exa", "firecrawl"];
|
|
1262
1223
|
function apply(ctx, rawConfig = {}) {
|
|
1263
1224
|
const config = loadPluginConfig(rawConfig);
|
|
@@ -1282,7 +1243,7 @@ function apply(ctx, rawConfig = {}) {
|
|
|
1282
1243
|
}
|
|
1283
1244
|
const fallbackChain = config.fallbackChain ?? DEFAULT_PROVIDER_ORDER;
|
|
1284
1245
|
registerWebSearchProvider(ctx, registry, cooldown, fallbackChain);
|
|
1285
|
-
|
|
1246
|
+
registerWebFetchProvider(ctx, registry, cooldown, fallbackChain);
|
|
1286
1247
|
console.log(`[search-providers] loaded with active provider: ${registry.getActive().id}, fallback after active: [${fallbackChain.join(", ")}]`);
|
|
1287
1248
|
}
|
|
1288
1249
|
export {
|
package/dsh/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/config.ts","../src/providers/utils.ts","../src/providers/cooldown.ts","../src/providers/registry.ts","../src/providers/tinyfish.ts","../src/providers/tavily.ts","../src/providers/exa.ts","../src/providers/firecrawl.ts","../src/providers/codex.ts","../src/providers/demo.ts","../src/schemas/fetch-schema.ts","../src/tools/fallback-utils.ts","../src/tools/read-page.ts","../src/tools/web-search.ts","../src/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\n\nexport interface ProviderConfigEntry {\n apiKey?: string;\n credentialFile?: string;\n timeoutMs?: number;\n options?: Record<string, unknown>;\n}\n\n/** Cordis only selects the file; provider settings live in that file. */\nexport interface PluginConfig {\n configFile?: string;\n}\n\nexport interface SearchProvidersConfig {\n /** Active provider id. */\n provider?: string;\n providers?: Record<string, ProviderConfigEntry>;\n /** An empty array disables fallback. */\n fallbackChain?: string[];\n}\n\nexport interface ResolvedProviderConfig {\n apiKey?: string;\n credentialFile?: string;\n timeoutMs: number;\n options: Record<string, unknown>;\n}\n\nconst DEFAULT_TIMEOUT_MS = 55_000;\n\nexport function loadPluginConfig(pluginConfig: PluginConfig = {}): SearchProvidersConfig {\n if (!isRecord(pluginConfig) || Object.keys(pluginConfig).some((key) => key !== 'configFile')) {\n throw new Error('search-providers: Cordis config only accepts configFile. Move provider, providers and fallbackChain to search-providers.json.');\n }\n if (pluginConfig.configFile !== undefined && !isNonEmptyString(pluginConfig.configFile)) {\n throw new Error('search-providers: configFile must be a non-empty string.');\n }\n\n const explicit = pluginConfig.configFile !== undefined;\n const filename = resolveConfigPath(pluginConfig.configFile ?? join(homedir(), '.dsh', 'search-providers.json'));\n let text: string;\n try {\n text = readFileSync(filename, 'utf8');\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (!explicit && code === 'ENOENT') {\n console.warn(\n '[search-providers] Config file not found: ' + filename + '. Create it to configure providers; environment variables are not used.',\n );\n return {};\n }\n throw new Error('search-providers: Cannot read config file ' + filename + ' (' + (code ?? 'read error') + ').');\n }\n\n let value: unknown;\n try {\n // Accept a UTF-8 BOM, including files written by Windows editors.\n value = JSON.parse(text.charCodeAt(0) === 0xfeff ? text.slice(1) : text);\n } catch {\n // JSON parser messages can contain secrets from the source; do not forward them.\n throw new Error('search-providers: Invalid JSON in ' + filename + '.');\n }\n validateConfig(value, filename);\n for (const entry of Object.values(value.providers ?? {})) {\n if (entry.credentialFile !== undefined) {\n entry.credentialFile = resolveConfigPath(entry.credentialFile, dirname(filename));\n }\n }\n return value;\n}\n\nexport function resolveProviderConfig(\n pluginConfig: SearchProvidersConfig,\n providerId: string,\n): ResolvedProviderConfig {\n const pc = pluginConfig.providers?.[providerId] ?? {};\n return {\n apiKey: pc.apiKey,\n credentialFile: pc.credentialFile,\n timeoutMs: pc.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n options: pc.options ?? {},\n };\n}\n\nfunction resolveConfigPath(filename: string, base = process.cwd()): string {\n const path = filename.trim();\n if (path === '~') return homedir();\n if (path.startsWith('~/') || path.startsWith('~\\\\')) {\n return resolve(homedir(), path.slice(2));\n }\n return resolve(base, path);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim() !== '';\n}\n\nfunction validateConfig(value: unknown, filename: string): asserts value is SearchProvidersConfig {\n function invalid(field: string): never {\n throw new Error('search-providers: Invalid config in ' + filename + ': ' + field + '.');\n }\n if (!isRecord(value)) invalid('expected a JSON object');\n // No values are interpolated into validation errors (they may be credentials).\n if (Object.keys(value).some((key) => !['provider', 'providers', 'fallbackChain'].includes(key))) {\n invalid('unknown top-level field; use provider, providers or fallbackChain');\n }\n if (value.provider !== undefined && !isNonEmptyString(value.provider)) {\n invalid('provider must be a non-empty string');\n }\n if (value.fallbackChain !== undefined &&\n (!Array.isArray(value.fallbackChain) || !value.fallbackChain.every(isNonEmptyString))) {\n invalid('fallbackChain must be an array of non-empty strings');\n }\n if (value.providers === undefined) return;\n if (!isRecord(value.providers)) invalid('providers must be an object');\n for (const entry of Object.values(value.providers)) {\n if (!isRecord(entry)) invalid('each provider must be an object');\n if (Object.keys(entry).some((key) => !['apiKey', 'credentialFile', 'timeoutMs', 'options'].includes(key))) {\n invalid('unknown provider field; use apiKey, credentialFile, timeoutMs or options (official service URLs are built in)');\n }\n if (entry.apiKey !== undefined && typeof entry.apiKey !== 'string') invalid('apiKey must be a string');\n if (entry.credentialFile !== undefined && !isNonEmptyString(entry.credentialFile)) {\n invalid('credentialFile must be a non-empty string');\n }\n if (entry.timeoutMs !== undefined &&\n (typeof entry.timeoutMs !== 'number' || !Number.isSafeInteger(entry.timeoutMs) || entry.timeoutMs <= 0 || entry.timeoutMs > 2_147_483_647)) {\n invalid('timeoutMs must be a positive integer no greater than 2147483647');\n }\n if (entry.options !== undefined) {\n if (!isRecord(entry.options)) invalid('options must be an object');\n if (Object.hasOwn(entry.options, 'fetchBaseUrl')) {\n invalid('remove options.fetchBaseUrl; official service URLs are built in');\n }\n }\n }\n}\n","export class ProviderAuthenticationError extends Error {\n readonly kind = 'provider-auth' as const;\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = 'ProviderAuthenticationError';\n }\n}\n\nexport class ProviderHttpError extends Error {\n readonly kind = 'provider-http' as const;\n\n constructor(\n message: string,\n readonly status: number,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.name = 'ProviderHttpError';\n }\n}\n\nexport async function fetchWithTimeout(\n url: string,\n init: RequestInit,\n timeoutMs: number,\n): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(\n () => controller.abort(new Error(`request timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n try {\n const signal = init.signal\n ? combineSignals(init.signal, controller.signal)\n : controller.signal;\n return await fetch(url, { ...init, signal });\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport function combineSignals(a: AbortSignal, b: AbortSignal): AbortSignal {\n return AbortSignal.any([a, b]);\n}\n\nexport async function throwOnError(response: Response, label: string): Promise<void> {\n if (response.ok) return;\n const text = await response.text().catch(() => '');\n let detail = text.slice(0, 500);\n if (response.status === 401) {\n detail = 'Invalid or missing API key';\n } else if (response.status === 429) {\n detail = 'Rate limit exceeded';\n } else if (response.status === 432) {\n detail = 'Usage limit exceeded';\n }\n const message = `${label} returned ${response.status}: ${detail}`;\n if (response.status === 401) {\n throw new ProviderAuthenticationError(message);\n }\n throw new ProviderHttpError(message, response.status);\n}\n","import { ProviderAuthenticationError, ProviderHttpError } from './utils.js';\n\nexport type ProviderCapability = 'search' | 'fetch';\n\nexport interface CooldownEntry {\n until: number;\n reason: string;\n}\n\nexport class CooldownController {\n private disabled = new Map<string, CooldownEntry>();\n private cooling = new Map<string, CooldownEntry>();\n\n /** Record one capability failure. Confirmed authentication failures are provider-global. */\n record(providerId: string, capability: ProviderCapability, error: unknown): boolean {\n if (error instanceof ProviderAuthenticationError) {\n this.disabled.set(providerId, {\n until: Number.POSITIVE_INFINITY,\n reason: 'invalid credentials',\n });\n return true;\n }\n\n this.cooling.set(this.capabilityKey(providerId, capability), {\n until: Date.now() + this.cooldownDuration(error),\n reason: this.classifyError(error),\n });\n return true;\n }\n\n /** Check whether one provider capability is temporarily cooling. */\n isCooling(providerId: string, capability: ProviderCapability): boolean {\n return this.getEntry(this.cooling, this.capabilityKey(providerId, capability)) !== undefined;\n }\n\n /** Check whether confirmed authentication failure disabled the provider until restart. */\n isDisabled(providerId: string): boolean {\n return this.getEntry(this.disabled, providerId) !== undefined;\n }\n\n /** Get the current failure reason, if any. */\n getReason(providerId: string, capability: ProviderCapability): string | undefined {\n return this.getEntry(this.disabled, providerId)?.reason\n ?? this.getEntry(this.cooling, this.capabilityKey(providerId, capability))?.reason;\n }\n\n /** Build candidates while separating global disablement from capability cooldown. */\n filter(\n chain: string[],\n capability: ProviderCapability,\n ): { ready: string[]; cooling: string[]; disabled: string[] } {\n const ready: string[] = [];\n const cooling: string[] = [];\n const disabled: string[] = [];\n for (const id of chain) {\n if (this.isDisabled(id)) {\n disabled.push(id);\n } else if (this.isCooling(id, capability)) {\n cooling.push(id);\n } else {\n ready.push(id);\n }\n }\n return { ready, cooling, disabled };\n }\n\n private capabilityKey(providerId: string, capability: ProviderCapability): string {\n return `${providerId}:${capability}`;\n }\n\n private getEntry(map: Map<string, CooldownEntry>, key: string): CooldownEntry | undefined {\n const entry = map.get(key);\n if (!entry) return undefined;\n if (Date.now() >= entry.until) {\n map.delete(key);\n return undefined;\n }\n return entry;\n }\n\n private classifyError(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n if (this.isRateLimitError(error, message)) return 'rate limit or quota exceeded';\n if (/timeout|timed out/i.test(message)) return 'timeout';\n if (/network|ENOTFOUND|ECONNREFUSED|fetch failed/i.test(message)) return 'network error';\n return 'request failed';\n }\n\n private cooldownDuration(error: unknown): number {\n const message = error instanceof Error ? error.message : String(error);\n // Rate limits / quotas: cool for 5 minutes.\n if (this.isRateLimitError(error, message)) return 5 * 60 * 1000;\n // Timeouts / network errors: cool for 30 seconds.\n if (/timeout|timed out|network|ENOTFOUND|ECONNREFUSED|fetch failed/i.test(message)) {\n return 30 * 1000;\n }\n // Generic failures: cool for 10 seconds.\n return 10 * 1000;\n }\n\n private isRateLimitError(error: unknown, message: string): boolean {\n return (\n (error instanceof ProviderHttpError && (error.status === 429 || error.status === 432))\n || /429|432|rate.?limit|quota|usage limit|out of credits|monthly quota/i.test(message)\n );\n }\n}\n","import type { SearchProvider } from './types.js';\n\nexport class ProviderRegistry {\n private providers = new Map<string, SearchProvider>();\n private activeId: string | undefined;\n\n register(provider: SearchProvider): void {\n if (this.providers.has(provider.id)) {\n console.warn(`[search-providers] provider '${provider.id}' already registered; overwriting`);\n }\n this.providers.set(provider.id, provider);\n if (this.activeId === undefined) {\n this.activeId = provider.id;\n }\n }\n\n setActive(id: string): void {\n if (!this.providers.has(id)) {\n throw new Error(`Provider '${id}' is not registered`);\n }\n this.activeId = id;\n }\n\n getActive(): SearchProvider {\n if (this.activeId === undefined) {\n throw new Error('No search provider registered');\n }\n const provider = this.providers.get(this.activeId);\n if (!provider) {\n throw new Error(`Active provider '${this.activeId}' disappeared`);\n }\n return provider;\n }\n\n get(id: string): SearchProvider | undefined {\n return this.providers.get(id);\n }\n\n list(): string[] {\n return Array.from(this.providers.keys());\n }\n}\n","import type { ResolvedProviderConfig } from '../config.js';\nimport type {\n FetchRequest,\n FetchResult,\n SearchProvider,\n SearchRequest,\n SearchResult,\n} from './types.js';\nimport { fetchWithTimeout, throwOnError } from './utils.js';\n\ninterface TinyfishSearchResponse {\n query: string;\n results: Array<{\n position: number;\n site_name?: string;\n title: string;\n snippet: string;\n url: string;\n }>;\n total_results: number;\n page: number;\n}\n\ninterface TinyfishFetchResponse {\n results: Array<{\n url: string;\n final_url?: string;\n title?: string;\n description?: string;\n language?: string;\n format?: string;\n text: string;\n }>;\n errors: Array<{ url: string; error: string }>;\n}\n\nexport class TinyfishProvider implements SearchProvider {\n readonly id = 'tinyfish';\n readonly name = 'TinyFish';\n readonly description = 'TinyFish Search & Fetch (free tier, live web results)';\n readonly searchable = true;\n readonly fetchable = true;\n\n private readonly apiKey?: string;\n private readonly searchBaseUrl = 'https://api.search.tinyfish.ai';\n private readonly fetchBaseUrl = 'https://api.fetch.tinyfish.ai';\n private readonly timeoutMs: number;\n\n constructor(config: ResolvedProviderConfig) {\n this.apiKey = config.apiKey;\n this.timeoutMs = config.timeoutMs;\n }\n\n available(): boolean {\n return typeof this.apiKey === 'string' && this.apiKey !== '';\n }\n\n async search(request: SearchRequest, signal?: AbortSignal): Promise<SearchResult> {\n this.ensureKey();\n\n const url = new URL(this.searchBaseUrl);\n url.searchParams.set('query', request.query);\n if (request.maxResults && request.maxResults > 0) {\n url.searchParams.set('max_results', String(Math.floor(request.maxResults)));\n }\n if (typeof request.recencyDays === 'number' && request.recencyDays > 0) {\n url.searchParams.set('recency_minutes', String(Math.floor(request.recencyDays * 24 * 60)));\n }\n if (request.purpose) {\n url.searchParams.set('purpose', request.purpose);\n }\n if (request.location) {\n url.searchParams.set('location', request.location);\n }\n if (request.language) {\n url.searchParams.set('language', request.language);\n }\n if (request.domainType) {\n url.searchParams.set('domain_type', request.domainType);\n }\n if (request.includeDomains && request.includeDomains.length > 0) {\n url.searchParams.set('include_domains', request.includeDomains.join(','));\n }\n if (request.excludeDomains && request.excludeDomains.length > 0) {\n url.searchParams.set('exclude_domains', request.excludeDomains.join(','));\n }\n\n const response = await fetchWithTimeout(url.toString(), {\n method: 'GET',\n headers: {\n 'X-API-Key': this.apiKey!,\n Accept: 'application/json',\n },\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'TinyFish Search');\n\n const body = (await response.json()) as TinyfishSearchResponse;\n const items = (body.results ?? []).map((r) => ({\n title: r.title,\n url: r.url,\n snippet: r.snippet,\n source: r.site_name,\n }));\n\n return {\n status: 'ok',\n source: this.name,\n summary: items.length > 0\n ? `Found ${body.total_results ?? items.length} result(s) for \"${request.query}\"`\n : `No results found for \"${request.query}\"`,\n items,\n uncertainty: items.length === 0 ? ['No search results returned'] : [],\n };\n }\n\n async fetch(request: FetchRequest, signal?: AbortSignal): Promise<FetchResult> {\n this.ensureKey();\n\n const body: Record<string, unknown> = {\n urls: [request.url],\n format: request.format ?? 'markdown',\n };\n if (request.query) {\n body.purpose = request.query;\n }\n if (typeof request.ttl === 'number') {\n body.ttl = request.ttl;\n }\n\n const response = await fetchWithTimeout(this.fetchBaseUrl, {\n method: 'POST',\n headers: {\n 'X-API-Key': this.apiKey!,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'TinyFish Fetch');\n\n const data = (await response.json()) as TinyfishFetchResponse;\n const page = data.results?.[0];\n const error = data.errors?.[0];\n\n if (!page && error) {\n throw new Error(`TinyFish Fetch failed for ${error.url}: ${error.error}`);\n }\n if (!page) {\n throw new Error('TinyFish Fetch returned no content');\n }\n\n return {\n summary: page.title ?? page.description ?? 'Fetched page content',\n content: page.text ?? '',\n uncertainty: [],\n warnings: [],\n };\n }\n\n private ensureKey(): void {\n if (!this.apiKey) {\n throw new Error(\n 'TinyFish API key is missing. Configure providers.tinyfish.apiKey in the search-providers JSON config file.',\n );\n }\n }\n}","import type { ResolvedProviderConfig } from '../config.js';\nimport type { SearchProvider, SearchRequest, SearchResult } from './types.js';\nimport { fetchWithTimeout, throwOnError } from './utils.js';\n\ninterface TavilySearchResponse {\n query: string;\n results: Array<{\n title: string;\n url: string;\n content?: string;\n raw_content?: string;\n score?: number;\n }>;\n}\n\nexport class TavilyProvider implements SearchProvider {\n readonly id = 'tavily';\n readonly name = 'Tavily';\n readonly description = 'Tavily web search';\n readonly searchable = true;\n readonly fetchable = false;\n\n private readonly apiKey?: string;\n private readonly baseUrl = 'https://api.tavily.com';\n private readonly timeoutMs: number;\n\n constructor(config: ResolvedProviderConfig) {\n this.apiKey = config.apiKey;\n this.timeoutMs = config.timeoutMs;\n }\n\n available(): boolean {\n return typeof this.apiKey === 'string' && this.apiKey !== '';\n }\n\n async search(request: SearchRequest, signal?: AbortSignal): Promise<SearchResult> {\n this.ensureKey();\n\n const body: Record<string, unknown> = {\n query: request.query,\n search_depth: 'basic',\n max_results: request.maxResults ?? 5,\n };\n if (request.includeDomains && request.includeDomains.length > 0) {\n body.include_domains = request.includeDomains;\n }\n if (request.excludeDomains && request.excludeDomains.length > 0) {\n body.exclude_domains = request.excludeDomains;\n }\n\n const response = await fetchWithTimeout(`${this.baseUrl}/search`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'Tavily Search');\n\n const data = (await response.json()) as TavilySearchResponse;\n const items = (data.results ?? []).map((r) => ({\n title: r.title,\n url: r.url,\n snippet: r.content ?? r.raw_content ?? '',\n }));\n\n return {\n status: 'ok',\n source: this.name,\n summary: items.length > 0\n ? `Found ${items.length} result(s) for \"${request.query}\"`\n : `No results found for \"${request.query}\"`,\n items,\n uncertainty: items.length === 0 ? ['No search results returned'] : [],\n };\n }\n\n private ensureKey(): void {\n if (!this.apiKey) {\n throw new Error('Tavily API key is missing. Configure providers.tavily.apiKey in the search-providers JSON config file.');\n }\n }\n}","import type { ResolvedProviderConfig } from '../config.js';\nimport type { FetchRequest, FetchResult, SearchProvider, SearchRequest, SearchResult } from './types.js';\nimport { fetchWithTimeout, throwOnError } from './utils.js';\n\ninterface ExaSearchResponse {\n results: Array<{\n title?: string;\n url: string;\n publishedDate?: string;\n author?: string;\n text?: string;\n score?: number;\n }>;\n}\n\ninterface ExaContentsResponse {\n results: Array<{\n url: string;\n text?: string;\n title?: string;\n }>;\n}\n\nexport class ExaProvider implements SearchProvider {\n readonly id = 'exa';\n readonly name = 'Exa';\n readonly description = 'Exa neural web search and contents fetch';\n readonly searchable = true;\n readonly fetchable = true;\n\n private readonly apiKey?: string;\n private readonly baseUrl = 'https://api.exa.ai';\n private readonly timeoutMs: number;\n\n constructor(config: ResolvedProviderConfig) {\n this.apiKey = config.apiKey;\n this.timeoutMs = config.timeoutMs;\n }\n\n available(): boolean {\n return typeof this.apiKey === 'string' && this.apiKey !== '';\n }\n\n async search(request: SearchRequest, signal?: AbortSignal): Promise<SearchResult> {\n this.ensureKey();\n\n const body: Record<string, unknown> = {\n query: request.query,\n num_results: request.maxResults ?? 5,\n type: 'auto',\n };\n if (request.includeDomains && request.includeDomains.length > 0) {\n body.include_domains = request.includeDomains;\n }\n if (request.excludeDomains && request.excludeDomains.length > 0) {\n body.exclude_domains = request.excludeDomains;\n }\n\n const response = await fetchWithTimeout(`${this.baseUrl}/search`, {\n method: 'POST',\n headers: {\n 'x-api-key': this.apiKey!,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'Exa Search');\n\n const data = (await response.json()) as ExaSearchResponse;\n const items = (data.results ?? []).map((r) => ({\n title: r.title ?? r.url,\n url: r.url,\n snippet: r.text ?? '',\n publishedAt: r.publishedDate,\n }));\n\n return {\n status: 'ok',\n source: this.name,\n summary: items.length > 0\n ? `Found ${items.length} result(s) for \"${request.query}\"`\n : `No results found for \"${request.query}\"`,\n items,\n uncertainty: items.length === 0 ? ['No search results returned'] : [],\n };\n }\n\n async fetch(request: FetchRequest, signal?: AbortSignal): Promise<FetchResult> {\n this.ensureKey();\n\n const body = {\n urls: [request.url],\n text: true,\n };\n\n const response = await fetchWithTimeout(`${this.baseUrl}/contents`, {\n method: 'POST',\n headers: {\n 'x-api-key': this.apiKey!,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'Exa Contents');\n\n const data = (await response.json()) as ExaContentsResponse;\n const page = data.results?.[0];\n if (!page) {\n throw new Error('Exa Contents returned no content');\n }\n\n return {\n summary: page.title ?? 'Fetched page content',\n content: page.text ?? '',\n uncertainty: [],\n warnings: [],\n };\n }\n\n private ensureKey(): void {\n if (!this.apiKey) {\n throw new Error('Exa API key is missing. Configure providers.exa.apiKey in the search-providers JSON config file.');\n }\n }\n}","import type { ResolvedProviderConfig } from '../config.js';\nimport type { FetchRequest, FetchResult, SearchProvider, SearchRequest, SearchResult } from './types.js';\nimport { fetchWithTimeout, throwOnError } from './utils.js';\n\ninterface FirecrawlSearchResponse {\n success: boolean;\n data: {\n web: Array<{\n title?: string;\n url: string;\n description?: string;\n markdown?: string;\n }>;\n };\n}\n\ninterface FirecrawlScrapeResponse {\n success: boolean;\n data: {\n markdown?: string;\n metadata?: {\n title?: string;\n sourceURL?: string;\n };\n };\n}\n\nexport class FirecrawlProvider implements SearchProvider {\n readonly id = 'firecrawl';\n readonly name = 'Firecrawl';\n readonly description = 'Firecrawl web search and page scrape';\n readonly searchable = true;\n readonly fetchable = true;\n\n private readonly apiKey?: string;\n private readonly baseUrl = 'https://api.firecrawl.dev';\n private readonly timeoutMs: number;\n\n constructor(config: ResolvedProviderConfig) {\n this.apiKey = config.apiKey;\n this.timeoutMs = config.timeoutMs;\n }\n\n available(): boolean {\n return typeof this.apiKey === 'string' && this.apiKey !== '';\n }\n\n async search(request: SearchRequest, signal?: AbortSignal): Promise<SearchResult> {\n this.ensureKey();\n\n const body: Record<string, unknown> = {\n query: request.query,\n limit: request.maxResults ?? 5,\n sources: ['web'],\n };\n if (request.includeDomains && request.includeDomains.length > 0) {\n body.includeDomains = request.includeDomains;\n }\n if (request.excludeDomains && request.excludeDomains.length > 0) {\n body.excludeDomains = request.excludeDomains;\n }\n\n const response = await fetchWithTimeout(`${this.baseUrl}/v2/search`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'Firecrawl Search');\n\n const data = (await response.json()) as FirecrawlSearchResponse;\n if (data.success === false) {\n throw new Error('Firecrawl Search returned success: false');\n }\n\n const rawItems = data.data?.web ?? [];\n const items = rawItems.map((r) => ({\n title: r.title ?? r.url,\n url: r.url,\n snippet: r.description ?? r.markdown ?? '',\n }));\n\n return {\n status: 'ok',\n source: this.name,\n summary: items.length > 0\n ? `Found ${items.length} result(s) for \"${request.query}\"`\n : `No results found for \"${request.query}\"`,\n items,\n uncertainty: items.length === 0 ? ['No search results returned'] : [],\n };\n }\n\n async fetch(request: FetchRequest, signal?: AbortSignal): Promise<FetchResult> {\n this.ensureKey();\n\n const body = {\n url: request.url,\n formats: ['markdown'],\n };\n\n const response = await fetchWithTimeout(`${this.baseUrl}/v2/scrape`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'Firecrawl Scrape');\n\n const data = (await response.json()) as FirecrawlScrapeResponse;\n if (data.success === false) {\n throw new Error('Firecrawl Scrape returned success: false');\n }\n\n return {\n summary: data.data?.metadata?.title ?? 'Fetched page content',\n content: data.data?.markdown ?? '',\n uncertainty: [],\n warnings: [],\n };\n }\n\n private ensureKey(): void {\n if (!this.apiKey) {\n throw new Error('Firecrawl API key is missing. Configure providers.firecrawl.apiKey in the search-providers JSON config file.');\n }\n }\n}","// Codex search protocol behavior is based on dsh-codex-connect (Apache-2.0).\n// This provider only consumes an existing static credential; it never logs in,\n// refreshes tokens, or writes credential data.\nimport { randomUUID } from 'node:crypto';\nimport { readFileSync, statSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport type { ResolvedProviderConfig } from '../config.js';\nimport type { SearchProvider, SearchRequest, SearchResult } from './types.js';\nimport { ProviderAuthenticationError } from './utils.js';\n\nconst CODEX_SEARCH_URL = 'https://chatgpt.com/backend-api/codex/alpha/search';\nconst MAX_CREDENTIAL_BYTES = 128 * 1024;\nconst MAX_SUCCESS_RESPONSE_BYTES = 4 * 1024 * 1024;\nconst MAX_ERROR_RESPONSE_BYTES = 64 * 1024;\n\ninterface StaticCodexCredential {\n accessToken: string;\n accountId: string;\n}\n\ninterface CodexSearchRequestBody {\n id: string;\n model: string;\n input: Array<{\n type: 'message';\n role: 'user';\n content: Array<{ type: 'input_text'; text: string }>;\n }>;\n commands: { search_query: Array<{ q: string }> };\n settings: {\n search_context_size: 'medium';\n allowed_callers: ['direct'];\n external_web_access: false;\n };\n max_output_tokens: number;\n}\n\nexport class CodexProvider implements SearchProvider {\n readonly id = 'codex';\n readonly name = 'OpenAI Codex';\n readonly description = 'ChatGPT Codex standalone web search';\n readonly searchable = true;\n readonly fetchable = false;\n\n private readonly credentialFile?: string;\n private readonly timeoutMs: number;\n\n constructor(config: ResolvedProviderConfig) {\n const filename = readNonEmptyString(config.credentialFile);\n this.credentialFile = filename === undefined ? undefined : resolve(filename);\n this.timeoutMs = Number.isFinite(config.timeoutMs) && config.timeoutMs > 0\n ? config.timeoutMs\n : 55_000;\n }\n\n available(): boolean {\n return this.credentialFile !== undefined\n && loadStaticCredential(this.credentialFile) !== undefined;\n }\n\n async search(request: SearchRequest, signal?: AbortSignal): Promise<SearchResult> {\n throwIfAborted(signal);\n\n const credential = this.credentialFile === undefined\n ? undefined\n : loadStaticCredential(this.credentialFile);\n if (!credential) {\n throw new Error('OpenAI Codex credential file is not configured, missing or invalid');\n }\n\n const body: CodexSearchRequestBody = {\n id: randomUUID(),\n model: 'gpt-5.6-sol',\n input: [{\n type: 'message',\n role: 'user',\n content: [{ type: 'input_text', text: request.query }],\n }],\n commands: { search_query: [{ q: request.query }] },\n settings: {\n search_context_size: 'medium',\n allowed_callers: ['direct'],\n external_web_access: false,\n },\n max_output_tokens: 10_000,\n };\n\n const requestTimeout = AbortSignal.timeout(this.timeoutMs);\n const requestSignal = signal ? AbortSignal.any([signal, requestTimeout]) : requestTimeout;\n let response: Response;\n try {\n response = await fetch(CODEX_SEARCH_URL, {\n method: 'POST',\n redirect: 'error',\n headers: {\n Authorization: `Bearer ${credential.accessToken}`,\n 'chatgpt-account-id': credential.accountId,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n originator: 'deepseek-harness',\n },\n body: JSON.stringify(body),\n signal: requestSignal,\n });\n } catch (error) {\n throwIfAborted(signal);\n if (requestTimeout.aborted) {\n throw new Error(`OpenAI Codex search timed out after ${this.timeoutMs}ms`, { cause: error });\n }\n throw new Error('OpenAI Codex search request failed', { cause: error });\n }\n\n let payload: unknown;\n try {\n payload = await readBoundedJson(\n response,\n response.ok ? MAX_SUCCESS_RESPONSE_BYTES : MAX_ERROR_RESPONSE_BYTES,\n requestSignal,\n );\n } catch (error) {\n throwIfAborted(signal);\n if (requestTimeout.aborted) {\n throw new Error(`OpenAI Codex search timed out after ${this.timeoutMs}ms`, { cause: error });\n }\n if (error instanceof ResponseTooLargeError) throw error;\n throw new Error(`OpenAI Codex returned invalid JSON (HTTP ${response.status})`, { cause: error });\n }\n\n if (!response.ok) {\n const detail = providerMessage(payload);\n const suffix = detail ? `: ${detail}` : '';\n if (response.status === 401 || response.status === 403) {\n throw new ProviderAuthenticationError(\n `OpenAI Codex credential is invalid or expired (HTTP ${response.status})${suffix}`,\n );\n }\n throw new Error(`OpenAI Codex search failed (HTTP ${response.status})${suffix}`);\n }\n\n return mapCodexSearchResponse(payload);\n }\n}\n\nfunction loadStaticCredential(filename: string): StaticCodexCredential | undefined {\n try {\n const stats = statSync(filename);\n if (!stats.isFile() || stats.size <= 0 || stats.size > MAX_CREDENTIAL_BYTES) return undefined;\n const value: unknown = JSON.parse(readFileSync(filename, 'utf8'));\n return parseStaticCredential(value);\n } catch {\n return undefined;\n }\n}\n\nfunction mapCodexSearchResponse(value: unknown): SearchResult {\n if (!isRecord(value) || typeof value.output !== 'string') {\n throw new Error('OpenAI Codex returned a search response without string output');\n }\n if (value.results !== undefined && !Array.isArray(value.results)) {\n throw new Error('OpenAI Codex returned a search response with non-array results');\n }\n\n const items: SearchResult['items'] = [];\n const seen = new Set<string>();\n for (const item of value.results ?? []) {\n if (!isRecord(item) || item.type !== 'text_result') continue;\n const url = citeableUrl(item.url);\n if (!url || seen.has(url)) continue;\n seen.add(url);\n items.push({\n title: readNonEmptyString(item.title) ?? url,\n url,\n snippet: readNonEmptyString(item.snippet) ?? '',\n });\n }\n\n const summary = value.output;\n return {\n status: summary.length > 0 ? 'ok' : 'degraded',\n source: 'OpenAI Codex',\n summary: summary || `Codex returned ${items.length} source(s) without summary text`,\n items,\n uncertainty: summary.length > 0 ? [] : ['Codex returned no summary text'],\n };\n}\n\nfunction parseStaticCredential(value: unknown): StaticCodexCredential | undefined {\n if (!isRecord(value)) return undefined;\n\n // Account stores keep tokens in credentials[], selected by activeAccountId.\n const stored = Array.isArray(value.credentials) ? value.credentials : [];\n const activeAccountId = readNonEmptyString(value.activeAccountId);\n const selected = activeAccountId\n ? stored.filter((entry) => isRecord(entry)\n && (readNonEmptyString(entry.account_id) ?? readNonEmptyString(entry.accountId)) === activeAccountId)\n : value.activeAccountId === undefined ? stored : [];\n const storedCredential = selected.length === 1 && isRecord(selected[0]) ? selected[0] : undefined;\n\n const candidates = [\n value,\n isRecord(value.credential) ? value.credential : undefined,\n isRecord(value.tokens) ? value.tokens : undefined,\n storedCredential,\n ];\n\n for (const candidate of candidates) {\n if (!candidate) continue;\n const accessToken = readNonEmptyString(candidate.access_token)\n ?? readNonEmptyString(candidate.access);\n if (!accessToken) continue;\n\n const accountId = readNonEmptyString(candidate.account_id)\n ?? readNonEmptyString(candidate.accountId)\n ?? accountIdFromToken(accessToken);\n if (!accountId) continue;\n\n return { accessToken, accountId };\n }\n\n return undefined;\n}\n\nfunction decodeJwtPayload(accessToken: string): Record<string, unknown> | undefined {\n try {\n const parts = accessToken.split('.');\n if (parts.length !== 3 || !parts[1]) return undefined;\n const payload: unknown = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf8'));\n return isRecord(payload) ? payload : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction accountIdFromToken(accessToken: string): string | undefined {\n const auth = decodeJwtPayload(accessToken)?.['https://api.openai.com/auth'];\n return isRecord(auth) ? readNonEmptyString(auth.chatgpt_account_id) : undefined;\n}\n\nclass ResponseTooLargeError extends Error {\n constructor(limit: number) {\n super(`OpenAI Codex search response exceeded ${limit} bytes`);\n this.name = 'ResponseTooLargeError';\n }\n}\n\nasync function readBoundedJson(\n response: Response,\n maxBytes: number,\n signal: AbortSignal,\n): Promise<unknown> {\n const declaredLength = Number(response.headers.get('content-length'));\n if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {\n await response.body?.cancel().catch(() => {});\n throw new ResponseTooLargeError(maxBytes);\n }\n if (!response.body) throw new SyntaxError('empty response body');\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n try {\n while (true) {\n const { done, value } = await abortable(reader.read(), signal);\n if (done) break;\n if (!value) continue;\n total += value.byteLength;\n if (total > maxBytes) throw new ResponseTooLargeError(maxBytes);\n chunks.push(value);\n }\n } catch (error) {\n await reader.cancel().catch(() => {});\n throw error;\n } finally {\n reader.releaseLock();\n }\n\n return JSON.parse(Buffer.concat(chunks, total).toString('utf8')) as unknown;\n}\n\nfunction abortable<T>(operation: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) return Promise.reject(abortedError(signal));\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(abortedError(signal));\n signal.addEventListener('abort', onAbort, { once: true });\n operation.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) throw abortedError(signal);\n}\n\nfunction abortedError(signal: AbortSignal): Error {\n return new Error('OpenAI Codex search aborted', { cause: signal.reason });\n}\n\nfunction providerMessage(value: unknown): string | undefined {\n if (!isRecord(value)) return undefined;\n const raw = typeof value.error === 'string'\n ? value.error\n : isRecord(value.error) && typeof value.error.message === 'string'\n ? value.error.message\n : typeof value.message === 'string'\n ? value.message\n : undefined;\n return raw\n ?.replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/gu, '[REDACTED]')\n .slice(0, 1_000);\n}\n\nfunction citeableUrl(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n try {\n const url = new URL(value);\n return url.protocol === 'http:' || url.protocol === 'https:' ? value : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readNonEmptyString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined;\n}\n\n","import type { ResolvedProviderConfig } from '../config.js';\nimport type { FetchRequest, FetchResult, SearchProvider, SearchRequest, SearchResult } from './types.js';\n\nexport class DemoProvider implements SearchProvider {\n readonly id = 'demo';\n readonly name = 'Demo Provider';\n readonly description = 'Returns canned results for integration testing without calling any external API.';\n readonly searchable = true;\n readonly fetchable = true;\n\n constructor(_config: ResolvedProviderConfig) {}\n\n available(): boolean {\n return true;\n }\n\n async search(request: SearchRequest): Promise<SearchResult> {\n return {\n status: 'ok',\n source: this.name,\n summary: `Demo search results for \"${request.query}\"`,\n items: [\n {\n title: 'Demo Result 1',\n url: 'https://example.com/demo1',\n snippet: 'This is a demo search result used to verify the DSH plugin wiring.',\n },\n {\n title: 'Demo Result 2',\n url: 'https://example.com/demo2',\n snippet: 'Another canned result so citation cards have something to render.',\n },\n ],\n uncertainty: ['Demo mode: results are not from a real search engine.'],\n };\n }\n\n async fetch(request: FetchRequest): Promise<FetchResult> {\n return {\n summary: `Demo fetch of ${request.url}`,\n content: `# Demo Page\\n\\nThis is canned content for the URL \"${request.url}\".`,\n links: [\n { text: 'Example', url: 'https://example.com' },\n ],\n uncertainty: ['Demo mode: content is not from a real web page.'],\n warnings: [],\n };\n }\n}","export const fetchSchema = {\n type: 'object' as const,\n properties: {\n summary: { type: 'string' as const },\n content: { type: 'string' as const },\n links: {\n type: 'array' as const,\n items: {\n type: 'object' as const,\n properties: {\n text: { type: 'string' as const },\n url: { type: 'string' as const }\n },\n required: ['text', 'url'] as const\n }\n },\n uncertainty: {\n type: 'array' as const,\n items: { type: 'string' as const }\n },\n warnings: {\n type: 'array' as const,\n items: { type: 'string' as const }\n }\n },\n required: ['summary', 'content', 'uncertainty'] as const\n};\n","import type { ProviderRegistry } from '../providers/registry.js';\n\nexport const FALLBACK_ATTEMPT_TIMEOUT_MS = 55_000;\n\nexport interface AttemptContext {\n signal: AbortSignal;\n timedOut(): boolean;\n dispose(): void;\n}\n\nexport function resolveCandidateIds(\n registry: ProviderRegistry,\n fallbackChain?: string[],\n): string[] {\n let activeId: string | undefined;\n try {\n activeId = registry.getActive().id;\n } catch {\n // An empty registry has no active provider.\n }\n\n const configured = fallbackChain === undefined ? registry.list() : fallbackChain;\n const seen = new Set<string>();\n const candidates: string[] = [];\n for (const id of activeId ? [activeId, ...configured] : configured) {\n if (seen.has(id)) continue;\n seen.add(id);\n candidates.push(id);\n }\n return candidates;\n}\n\nexport function createAttemptContext(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): AttemptContext {\n const controller = new AbortController();\n let didTimeOut = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let onParentAbort: (() => void) | undefined;\n\n if (parent?.aborted) {\n controller.abort(parent.reason);\n } else {\n if (parent) {\n onParentAbort = () => controller.abort(parent.reason);\n parent.addEventListener('abort', onParentAbort, { once: true });\n }\n timer = setTimeout(() => {\n didTimeOut = true;\n controller.abort(new Error(`fallback attempt timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n }\n\n return {\n signal: controller.signal,\n timedOut: () => didTimeOut,\n dispose() {\n if (timer !== undefined) clearTimeout(timer);\n if (parent && onParentAbort) parent.removeEventListener('abort', onParentAbort);\n },\n };\n}\n\nexport function raceWithSignal<T>(operation: Promise<T>, signal: AbortSignal | undefined): Promise<T> {\n if (!signal) return operation;\n if (signal.aborted) {\n operation.catch(() => {});\n return Promise.reject(signal.reason);\n }\n\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener('abort', onAbort);\n reject(signal.reason);\n };\n signal.addEventListener('abort', onAbort, { once: true });\n operation.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n\nexport function throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw signal.reason;\n}\n","import type { CooldownController } from '../providers/cooldown.js';\nimport type { ProviderRegistry } from '../providers/registry.js';\nimport type { FetchRequest, FetchResult } from '../providers/types.js';\nimport { ProviderAuthenticationError } from '../providers/utils.js';\nimport { fetchSchema } from '../schemas/fetch-schema.js';\nimport {\n createAttemptContext,\n FALLBACK_ATTEMPT_TIMEOUT_MS,\n raceWithSignal,\n resolveCandidateIds,\n throwIfAborted,\n} from './fallback-utils.js';\n\nconst READ_PAGE_TIMEOUT_MS = 180_000;\nconst RENDER_CONTENT_CAP = 20_000;\nconst RENDER_LINK_CAP = 20;\n\nexport function registerReadPageTool(\n ctx: any,\n registry: ProviderRegistry,\n cooldown: CooldownController,\n fallbackChain?: string[],\n): void {\n if (typeof ctx.tools?.register !== 'function') {\n console.error('[search-providers] ctx.tools.register is not available; read_page tool skipped');\n return;\n }\n\n ctx.tools.register({\n name: 'read_page',\n description:\n 'Read one web page through the configured search provider. Use when a message references a specific http(s) URL whose content matters: docs, an article, a changelog, a thread. Returns structured evidence with a summary, the extracted content, outgoing links, uncertainty, and operational warnings. Pass \"query\" to focus the reading on one question.',\n parameters: {\n type: 'object',\n properties: {\n url: {\n type: 'string',\n description: 'The http(s) URL to read',\n },\n query: {\n type: 'string',\n description: 'Optional question to focus the reading on (e.g. \"what are the rate limits\")',\n },\n },\n required: ['url'],\n },\n output: {\n schema: fetchSchema,\n render: (_args: unknown, value: Record<string, unknown>) => [\n { type: 'text', text: renderFetchEvidence(value) },\n ],\n },\n timeoutMs: READ_PAGE_TIMEOUT_MS + 20_000,\n isConcurrencySafe: () => true,\n presentCall: (args: { url: string; query?: string }) => ({\n card: 'generic',\n title: 'read_page',\n kind: 'fetch',\n rawInput: args,\n }),\n async execute(args: { url: string; query?: string }, exec: { signal?: AbortSignal }) {\n if (typeof args?.url !== 'string' || !/^https?:\\/\\//i.test(args.url.trim())) {\n throw new Error('read_page needs an http(s) \"url\".');\n }\n\n const request: FetchRequest = {\n url: args.url.trim(),\n query: args.query,\n format: 'markdown',\n };\n\n return fetchWithFallback(registry, cooldown, fallbackChain, request, exec.signal);\n },\n });\n}\n\nfunction resolveFetchCandidateIds(\n registry: ProviderRegistry,\n fallbackChain: string[] | undefined,\n): string[] {\n return resolveCandidateIds(registry, fallbackChain).filter((id) => {\n const provider = registry.get(id);\n return provider !== undefined\n && provider.fetchable !== false\n && typeof provider.fetch === 'function';\n });\n}\n\nasync function fetchWithFallback(\n registry: ProviderRegistry,\n cooldown: CooldownController,\n fallbackChain: string[] | undefined,\n request: FetchRequest,\n signal: AbortSignal | undefined,\n): Promise<FetchResult> {\n throwIfAborted(signal);\n const candidates = resolveFetchCandidateIds(registry, fallbackChain);\n const attempted: string[] = [];\n const attemptedIds = new Set<string>();\n let lastError: Error | undefined;\n\n while (true) {\n throwIfAborted(signal);\n const { ready } = cooldown.filter(candidates, 'fetch');\n const id = ready.find((candidateId) => {\n if (attemptedIds.has(candidateId)) return false;\n const provider = registry.get(candidateId);\n return provider?.available()\n && provider.fetchable !== false\n && typeof provider.fetch === 'function';\n });\n if (id === undefined) break;\n\n const provider = registry.get(id)!;\n attemptedIds.add(id);\n const attempt = attempted.length === 0\n ? undefined\n : createAttemptContext(signal, FALLBACK_ATTEMPT_TIMEOUT_MS);\n\n try {\n const attemptSignal = attempt?.signal ?? signal;\n const result = await raceWithSignal(provider.fetch!(request, attemptSignal), attemptSignal);\n throwIfAborted(signal);\n if (attempt?.timedOut()) throw attempt.signal.reason;\n const { cooling, disabled } = cooldown.filter(candidates, 'fetch');\n if (attempted.length > 0) {\n result.warnings = result.warnings ?? [];\n result.warnings.push(`Fallback used after ${attempted.join(', ')} failed`);\n }\n if (cooling.length > 0) {\n result.warnings = result.warnings ?? [];\n result.warnings.push(`Cooling providers skipped: ${cooling.join(', ')}`);\n }\n if (disabled.length > 0) {\n result.warnings = result.warnings ?? [];\n result.warnings.push(`Providers disabled until restart: ${disabled.join(', ')}`);\n }\n return result;\n } catch (error) {\n throwIfAborted(signal);\n const caught = error instanceof Error ? error : new Error(String(error));\n lastError = caught instanceof ProviderAuthenticationError\n ? caught\n : attempt?.timedOut()\n ? new Error(`fallback attempt timed out after ${FALLBACK_ATTEMPT_TIMEOUT_MS}ms`, { cause: caught })\n : caught;\n attempted.push(id);\n console.warn(`[search-providers] provider '${id}' fetch failed, trying next: ${lastError.message}`);\n cooldown.record(id, 'fetch', lastError);\n } finally {\n attempt?.dispose();\n }\n }\n\n const { cooling, disabled } = cooldown.filter(candidates, 'fetch');\n const coolingIds = cooling.length > 0 ? ` [cooling: ${cooling.join(', ')}]` : '';\n const disabledIds = disabled.length > 0 ? ` [disabled until restart: ${disabled.join(', ')}]` : '';\n throw new Error(\n `No fetch provider succeeded${attempted.length > 0 ? ` (tried: ${attempted.join(', ')})` : ''}${coolingIds}${disabledIds}. ${lastError?.message ?? 'No provider available.'}`,\n { cause: lastError },\n );\n}\n\nfunction renderFetchEvidence(value: Record<string, unknown>): string {\n const lines: string[] = [String(value.summary ?? '')];\n const content = String((value.content as string) ?? '').trim();\n if (content) {\n lines.push('', 'Content:', content.length > RENDER_CONTENT_CAP ? `${content.slice(0, RENDER_CONTENT_CAP)}…` : content);\n }\n const links = Array.isArray(value.links) ? value.links.slice(0, RENDER_LINK_CAP) : [];\n if (links.length > 0) {\n lines.push('', 'Links:');\n for (const link of links) {\n const text = typeof link === 'object' && link !== null ? String((link as Record<string, unknown>).text ?? '') : '';\n const url = typeof link === 'object' && link !== null ? String((link as Record<string, unknown>).url ?? '') : '';\n lines.push(`- ${text} — ${url}`);\n }\n }\n const uncertainty = Array.isArray(value.uncertainty) ? value.uncertainty : [];\n if (uncertainty.length > 0) {\n lines.push('', `Uncertain: ${uncertainty.join('; ')}`);\n }\n const warnings = Array.isArray(value.warnings) ? value.warnings : [];\n if (warnings.length > 0) {\n lines.push('', `Warnings: ${warnings.join('; ')}`);\n }\n return lines.filter(Boolean).join('\\n');\n}\n","import type { CooldownController } from '../providers/cooldown.js';\nimport type { ProviderRegistry } from '../providers/registry.js';\nimport type { SearchRequest, SearchResult } from '../providers/types.js';\nimport { ProviderAuthenticationError } from '../providers/utils.js';\nimport {\n createAttemptContext,\n FALLBACK_ATTEMPT_TIMEOUT_MS,\n raceWithSignal,\n resolveCandidateIds,\n throwIfAborted,\n} from './fallback-utils.js';\n\ninterface WebSeamSearchRequest {\n query: string;\n maxResults?: number;\n recencyDays?: number;\n purpose?: string;\n location?: string;\n language?: string;\n}\n\nexport function registerWebSearchProvider(\n ctx: any,\n registry: ProviderRegistry,\n cooldown: CooldownController,\n fallbackChain?: string[],\n): void {\n if (typeof ctx.web?.registerSearchProvider !== 'function') {\n console.error('[search-providers] ctx.web.registerSearchProvider is not available; web_search provider skipped');\n return;\n }\n\n ctx.web.registerSearchProvider({\n id: 'search-providers',\n available: () => anyProviderAvailable(registry, cooldown, fallbackChain),\n async search(request: WebSeamSearchRequest, signal: AbortSignal | undefined) {\n const searchRequest: SearchRequest = {\n query: request.query,\n maxResults: request.maxResults,\n recencyDays: request.recencyDays,\n purpose: request.purpose,\n location: request.location,\n language: request.language,\n };\n\n const { result, attempted, cooling, disabled } = await searchWithFallback(\n registry,\n cooldown,\n fallbackChain,\n searchRequest,\n signal,\n );\n\n return {\n content: renderContent(result, attempted, cooling, disabled),\n sources: result.items.map((item) => ({\n url: item.url,\n ...(item.title ? { title: item.title } : {}),\n ...(item.snippet ? { snippet: item.snippet } : {}),\n ...(item.publishedAt ? { publishedAt: item.publishedAt } : {}),\n })),\n truncated: false,\n };\n },\n });\n}\n\nfunction resolveSearchCandidateIds(\n registry: ProviderRegistry,\n fallbackChain: string[] | undefined,\n): string[] {\n return resolveCandidateIds(registry, fallbackChain).filter((id) => {\n const provider = registry.get(id);\n return provider !== undefined && provider.searchable !== false;\n });\n}\n\nfunction anyProviderAvailable(\n registry: ProviderRegistry,\n cooldown: CooldownController,\n fallbackChain: string[] | undefined,\n): boolean {\n const candidates = resolveSearchCandidateIds(registry, fallbackChain);\n const { ready } = cooldown.filter(candidates, 'search');\n return ready.some((id) => {\n const provider = registry.get(id);\n return provider?.available() && provider.searchable !== false;\n });\n}\n\ninterface FallbackOutcome {\n result: SearchResult;\n attempted: string[];\n cooling: string[];\n disabled: string[];\n}\n\nasync function searchWithFallback(\n registry: ProviderRegistry,\n cooldown: CooldownController,\n fallbackChain: string[] | undefined,\n request: SearchRequest,\n signal: AbortSignal | undefined,\n): Promise<FallbackOutcome> {\n throwIfAborted(signal);\n const candidates = resolveSearchCandidateIds(registry, fallbackChain);\n const attempted: string[] = [];\n const attemptedIds = new Set<string>();\n let lastError: Error | undefined;\n\n while (true) {\n throwIfAborted(signal);\n const { ready } = cooldown.filter(candidates, 'search');\n const id = ready.find((candidateId) => {\n if (attemptedIds.has(candidateId)) return false;\n const provider = registry.get(candidateId);\n return provider?.available() && provider.searchable !== false;\n });\n if (id === undefined) break;\n\n const provider = registry.get(id)!;\n attemptedIds.add(id);\n const attempt = attempted.length === 0\n ? undefined\n : createAttemptContext(signal, FALLBACK_ATTEMPT_TIMEOUT_MS);\n\n try {\n const attemptSignal = attempt?.signal ?? signal;\n const result = await raceWithSignal(provider.search(request, attemptSignal), attemptSignal);\n throwIfAborted(signal);\n if (attempt?.timedOut()) throw attempt.signal.reason;\n const { cooling, disabled } = cooldown.filter(candidates, 'search');\n return { result, attempted, cooling, disabled };\n } catch (error) {\n throwIfAborted(signal);\n const caught = error instanceof Error ? error : new Error(String(error));\n lastError = caught instanceof ProviderAuthenticationError\n ? caught\n : attempt?.timedOut()\n ? new Error(`fallback attempt timed out after ${FALLBACK_ATTEMPT_TIMEOUT_MS}ms`, { cause: caught })\n : caught;\n attempted.push(id);\n console.warn(`[search-providers] provider '${id}' search failed, trying next: ${lastError.message}`);\n cooldown.record(id, 'search', lastError);\n } finally {\n attempt?.dispose();\n }\n }\n\n const { cooling, disabled } = cooldown.filter(candidates, 'search');\n const coolingIds = cooling.length > 0 ? ` [cooling: ${cooling.join(', ')}]` : '';\n const disabledIds = disabled.length > 0 ? ` [disabled until restart: ${disabled.join(', ')}]` : '';\n throw new Error(\n `No search provider succeeded${attempted.length > 0 ? ` (tried: ${attempted.join(', ')})` : ''}${coolingIds}${disabledIds}. ${lastError?.message ?? 'No provider available.'}`,\n { cause: lastError },\n );\n}\n\nfunction renderContent(\n result: SearchResult,\n attempted: string[],\n cooling: string[],\n disabled: string[],\n): string {\n const lines = [`[Search provider: ${result.source}]`, result.summary];\n if (attempted.length > 0) {\n lines.push(`[Fallback used after ${attempted.join(', ')} failed]`);\n }\n if (cooling.length > 0) {\n lines.push(`[Cooling: ${cooling.join(', ')}]`);\n }\n if (disabled.length > 0) {\n lines.push(`[Disabled until restart: ${disabled.join(', ')}]`);\n }\n if (result.uncertainty.length > 0) {\n lines.push(`Uncertain: ${result.uncertainty.join('; ')}`);\n }\n return lines.filter(Boolean).join('\\n');\n}\n","import { loadPluginConfig, resolveProviderConfig } from './config.js';\nimport { CooldownController } from './providers/cooldown.js';\nimport { ProviderRegistry } from './providers/registry.js';\nimport { TinyfishProvider } from './providers/tinyfish.js';\nimport { TavilyProvider } from './providers/tavily.js';\nimport { ExaProvider } from './providers/exa.js';\nimport { FirecrawlProvider } from './providers/firecrawl.js';\nimport { CodexProvider } from './providers/codex.js';\nimport { DemoProvider } from './providers/demo.js';\nimport type { PluginConfig } from './config.js';\nimport { registerReadPageTool } from './tools/read-page.js';\nimport { registerWebSearchProvider } from './tools/web-search.js';\n\nexport const name = 'search-providers';\nexport const inject = ['tools', 'web'];\n\nconst DEFAULT_PROVIDER_ORDER = ['codex', 'tinyfish', 'tavily', 'exa', 'firecrawl'];\n\nexport function apply(ctx: any, rawConfig: PluginConfig = {}): void {\n const config = loadPluginConfig(rawConfig);\n const registry = new ProviderRegistry();\n const cooldown = new CooldownController();\n const demoMode = config.provider === 'demo';\n\n // Register providers in priority order.\n registry.register(new CodexProvider(resolveProviderConfig(config, 'codex')));\n registry.register(new TinyfishProvider(resolveProviderConfig(config, 'tinyfish')));\n registry.register(new TavilyProvider(resolveProviderConfig(config, 'tavily')));\n registry.register(new ExaProvider(resolveProviderConfig(config, 'exa')));\n registry.register(new FirecrawlProvider(resolveProviderConfig(config, 'firecrawl')));\n\n if (demoMode) {\n registry.register(new DemoProvider(resolveProviderConfig(config, 'tinyfish')));\n }\n\n // Determine active provider.\n const activeProvider = config.provider;\n if (activeProvider) {\n try {\n registry.setActive(activeProvider);\n } catch (error) {\n console.warn(`[search-providers] configured provider '${activeProvider}' is not registered; falling back to '${registry.list()[0]}'`);\n }\n }\n\n // The active provider is always tried first. An explicit empty chain disables fallback.\n const fallbackChain = config.fallbackChain ?? DEFAULT_PROVIDER_ORDER;\n\n // Register tools.\n registerWebSearchProvider(ctx, registry, cooldown, fallbackChain);\n registerReadPageTool(ctx, registry, cooldown, fallbackChain);\n\n console.log(`[search-providers] loaded with active provider: ${registry.getActive().id}, fallback after active: [${fallbackChain.join(', ')}]`);\n}"],"names":["isRecord","throwIfAborted","resolve","provider","cooling","disabled"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/config.ts","../src/providers/utils.ts","../src/providers/cooldown.ts","../src/providers/registry.ts","../src/providers/tinyfish.ts","../src/providers/tavily.ts","../src/providers/exa.ts","../src/providers/firecrawl.ts","../src/providers/codex.ts","../src/providers/demo.ts","../src/tools/fallback-utils.ts","../src/tools/read-page.ts","../src/tools/web-search.ts","../src/index.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { dirname, join, resolve } from 'node:path';\n\nexport interface ProviderConfigEntry {\n apiKey?: string;\n credentialFile?: string;\n timeoutMs?: number;\n options?: Record<string, unknown>;\n}\n\n/** Cordis only selects the file; provider settings live in that file. */\nexport interface PluginConfig {\n configFile?: string;\n}\n\nexport interface SearchProvidersConfig {\n /** Active provider id. */\n provider?: string;\n providers?: Record<string, ProviderConfigEntry>;\n /** An empty array disables fallback. */\n fallbackChain?: string[];\n}\n\nexport interface ResolvedProviderConfig {\n apiKey?: string;\n credentialFile?: string;\n timeoutMs: number;\n options: Record<string, unknown>;\n}\n\nconst DEFAULT_TIMEOUT_MS = 55_000;\n\nexport function loadPluginConfig(pluginConfig: PluginConfig = {}): SearchProvidersConfig {\n if (!isRecord(pluginConfig) || Object.keys(pluginConfig).some((key) => key !== 'configFile')) {\n throw new Error('search-providers: Cordis config only accepts configFile. Move provider, providers and fallbackChain to search-providers.json.');\n }\n if (pluginConfig.configFile !== undefined && !isNonEmptyString(pluginConfig.configFile)) {\n throw new Error('search-providers: configFile must be a non-empty string.');\n }\n\n const explicit = pluginConfig.configFile !== undefined;\n const filename = resolveConfigPath(pluginConfig.configFile ?? join(homedir(), '.dsh', 'search-providers.json'));\n let text: string;\n try {\n text = readFileSync(filename, 'utf8');\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (!explicit && code === 'ENOENT') {\n console.warn(\n '[search-providers] Config file not found: ' + filename + '. Create it to configure providers; environment variables are not used.',\n );\n return {};\n }\n throw new Error('search-providers: Cannot read config file ' + filename + ' (' + (code ?? 'read error') + ').');\n }\n\n let value: unknown;\n try {\n // Accept a UTF-8 BOM, including files written by Windows editors.\n value = JSON.parse(text.charCodeAt(0) === 0xfeff ? text.slice(1) : text);\n } catch {\n // JSON parser messages can contain secrets from the source; do not forward them.\n throw new Error('search-providers: Invalid JSON in ' + filename + '.');\n }\n validateConfig(value, filename);\n for (const entry of Object.values(value.providers ?? {})) {\n if (entry.credentialFile !== undefined) {\n entry.credentialFile = resolveConfigPath(entry.credentialFile, dirname(filename));\n }\n }\n return value;\n}\n\nexport function resolveProviderConfig(\n pluginConfig: SearchProvidersConfig,\n providerId: string,\n): ResolvedProviderConfig {\n const pc = pluginConfig.providers?.[providerId] ?? {};\n return {\n apiKey: pc.apiKey,\n credentialFile: pc.credentialFile,\n timeoutMs: pc.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n options: pc.options ?? {},\n };\n}\n\nfunction resolveConfigPath(filename: string, base = process.cwd()): string {\n const path = filename.trim();\n if (path === '~') return homedir();\n if (path.startsWith('~/') || path.startsWith('~\\\\')) {\n return resolve(homedir(), path.slice(2));\n }\n return resolve(base, path);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim() !== '';\n}\n\nfunction validateConfig(value: unknown, filename: string): asserts value is SearchProvidersConfig {\n function invalid(field: string): never {\n throw new Error('search-providers: Invalid config in ' + filename + ': ' + field + '.');\n }\n if (!isRecord(value)) invalid('expected a JSON object');\n // No values are interpolated into validation errors (they may be credentials).\n if (Object.keys(value).some((key) => !['provider', 'providers', 'fallbackChain'].includes(key))) {\n invalid('unknown top-level field; use provider, providers or fallbackChain');\n }\n if (value.provider !== undefined && !isNonEmptyString(value.provider)) {\n invalid('provider must be a non-empty string');\n }\n if (value.fallbackChain !== undefined &&\n (!Array.isArray(value.fallbackChain) || !value.fallbackChain.every(isNonEmptyString))) {\n invalid('fallbackChain must be an array of non-empty strings');\n }\n if (value.providers === undefined) return;\n if (!isRecord(value.providers)) invalid('providers must be an object');\n for (const entry of Object.values(value.providers)) {\n if (!isRecord(entry)) invalid('each provider must be an object');\n if (Object.keys(entry).some((key) => !['apiKey', 'credentialFile', 'timeoutMs', 'options'].includes(key))) {\n invalid('unknown provider field; use apiKey, credentialFile, timeoutMs or options (official service URLs are built in)');\n }\n if (entry.apiKey !== undefined && typeof entry.apiKey !== 'string') invalid('apiKey must be a string');\n if (entry.credentialFile !== undefined && !isNonEmptyString(entry.credentialFile)) {\n invalid('credentialFile must be a non-empty string');\n }\n if (entry.timeoutMs !== undefined &&\n (typeof entry.timeoutMs !== 'number' || !Number.isSafeInteger(entry.timeoutMs) || entry.timeoutMs <= 0 || entry.timeoutMs > 2_147_483_647)) {\n invalid('timeoutMs must be a positive integer no greater than 2147483647');\n }\n if (entry.options !== undefined) {\n if (!isRecord(entry.options)) invalid('options must be an object');\n if (Object.hasOwn(entry.options, 'fetchBaseUrl')) {\n invalid('remove options.fetchBaseUrl; official service URLs are built in');\n }\n }\n }\n}\n","export class ProviderAuthenticationError extends Error {\n readonly kind = 'provider-auth' as const;\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = 'ProviderAuthenticationError';\n }\n}\n\nexport class ProviderHttpError extends Error {\n readonly kind = 'provider-http' as const;\n\n constructor(\n message: string,\n readonly status: number,\n options?: ErrorOptions,\n ) {\n super(message, options);\n this.name = 'ProviderHttpError';\n }\n}\n\nexport async function fetchWithTimeout(\n url: string,\n init: RequestInit,\n timeoutMs: number,\n): Promise<Response> {\n const controller = new AbortController();\n const timer = setTimeout(\n () => controller.abort(new Error(`request timed out after ${timeoutMs}ms`)),\n timeoutMs,\n );\n try {\n const signal = init.signal\n ? combineSignals(init.signal, controller.signal)\n : controller.signal;\n return await fetch(url, { ...init, signal });\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport function combineSignals(a: AbortSignal, b: AbortSignal): AbortSignal {\n return AbortSignal.any([a, b]);\n}\n\nexport async function throwOnError(response: Response, label: string): Promise<void> {\n if (response.ok) return;\n const text = await response.text().catch(() => '');\n let detail = text.slice(0, 500);\n if (response.status === 401) {\n detail = 'Invalid or missing API key';\n } else if (response.status === 429) {\n detail = 'Rate limit exceeded';\n } else if (response.status === 432) {\n detail = 'Usage limit exceeded';\n }\n const message = `${label} returned ${response.status}: ${detail}`;\n if (response.status === 401) {\n throw new ProviderAuthenticationError(message);\n }\n throw new ProviderHttpError(message, response.status);\n}\n","import { ProviderAuthenticationError, ProviderHttpError } from './utils.js';\n\nexport type ProviderCapability = 'search' | 'fetch';\n\nexport interface CooldownEntry {\n until: number;\n reason: string;\n}\n\nexport class CooldownController {\n private disabled = new Map<string, CooldownEntry>();\n private cooling = new Map<string, CooldownEntry>();\n\n /** Record one capability failure. Confirmed authentication failures are provider-global. */\n record(providerId: string, capability: ProviderCapability, error: unknown): boolean {\n if (error instanceof ProviderAuthenticationError) {\n this.disabled.set(providerId, {\n until: Number.POSITIVE_INFINITY,\n reason: 'invalid credentials',\n });\n return true;\n }\n\n this.cooling.set(this.capabilityKey(providerId, capability), {\n until: Date.now() + this.cooldownDuration(error),\n reason: this.classifyError(error),\n });\n return true;\n }\n\n /** Check whether one provider capability is temporarily cooling. */\n isCooling(providerId: string, capability: ProviderCapability): boolean {\n return this.getEntry(this.cooling, this.capabilityKey(providerId, capability)) !== undefined;\n }\n\n /** Check whether confirmed authentication failure disabled the provider until restart. */\n isDisabled(providerId: string): boolean {\n return this.getEntry(this.disabled, providerId) !== undefined;\n }\n\n /** Get the current failure reason, if any. */\n getReason(providerId: string, capability: ProviderCapability): string | undefined {\n return this.getEntry(this.disabled, providerId)?.reason\n ?? this.getEntry(this.cooling, this.capabilityKey(providerId, capability))?.reason;\n }\n\n /** Build candidates while separating global disablement from capability cooldown. */\n filter(\n chain: string[],\n capability: ProviderCapability,\n ): { ready: string[]; cooling: string[]; disabled: string[] } {\n const ready: string[] = [];\n const cooling: string[] = [];\n const disabled: string[] = [];\n for (const id of chain) {\n if (this.isDisabled(id)) {\n disabled.push(id);\n } else if (this.isCooling(id, capability)) {\n cooling.push(id);\n } else {\n ready.push(id);\n }\n }\n return { ready, cooling, disabled };\n }\n\n private capabilityKey(providerId: string, capability: ProviderCapability): string {\n return `${providerId}:${capability}`;\n }\n\n private getEntry(map: Map<string, CooldownEntry>, key: string): CooldownEntry | undefined {\n const entry = map.get(key);\n if (!entry) return undefined;\n if (Date.now() >= entry.until) {\n map.delete(key);\n return undefined;\n }\n return entry;\n }\n\n private classifyError(error: unknown): string {\n const message = error instanceof Error ? error.message : String(error);\n if (this.isRateLimitError(error, message)) return 'rate limit or quota exceeded';\n if (/timeout|timed out/i.test(message)) return 'timeout';\n if (/network|ENOTFOUND|ECONNREFUSED|fetch failed/i.test(message)) return 'network error';\n return 'request failed';\n }\n\n private cooldownDuration(error: unknown): number {\n const message = error instanceof Error ? error.message : String(error);\n // Rate limits / quotas: cool for 5 minutes.\n if (this.isRateLimitError(error, message)) return 5 * 60 * 1000;\n // Timeouts / network errors: cool for 30 seconds.\n if (/timeout|timed out|network|ENOTFOUND|ECONNREFUSED|fetch failed/i.test(message)) {\n return 30 * 1000;\n }\n // Generic failures: cool for 10 seconds.\n return 10 * 1000;\n }\n\n private isRateLimitError(error: unknown, message: string): boolean {\n return (\n (error instanceof ProviderHttpError && (error.status === 429 || error.status === 432))\n || /429|432|rate.?limit|quota|usage limit|out of credits|monthly quota/i.test(message)\n );\n }\n}\n","import type { SearchProvider } from './types.js';\n\nexport class ProviderRegistry {\n private providers = new Map<string, SearchProvider>();\n private activeId: string | undefined;\n\n register(provider: SearchProvider): void {\n if (this.providers.has(provider.id)) {\n console.warn(`[search-providers] provider '${provider.id}' already registered; overwriting`);\n }\n this.providers.set(provider.id, provider);\n if (this.activeId === undefined) {\n this.activeId = provider.id;\n }\n }\n\n setActive(id: string): void {\n if (!this.providers.has(id)) {\n throw new Error(`Provider '${id}' is not registered`);\n }\n this.activeId = id;\n }\n\n getActive(): SearchProvider {\n if (this.activeId === undefined) {\n throw new Error('No search provider registered');\n }\n const provider = this.providers.get(this.activeId);\n if (!provider) {\n throw new Error(`Active provider '${this.activeId}' disappeared`);\n }\n return provider;\n }\n\n get(id: string): SearchProvider | undefined {\n return this.providers.get(id);\n }\n\n list(): string[] {\n return Array.from(this.providers.keys());\n }\n}\n","import type { ResolvedProviderConfig } from '../config.js';\nimport type {\n FetchRequest,\n FetchResult,\n SearchProvider,\n SearchRequest,\n SearchResult,\n} from './types.js';\nimport { fetchWithTimeout, throwOnError } from './utils.js';\n\ninterface TinyfishSearchResponse {\n query: string;\n results: Array<{\n position: number;\n site_name?: string;\n title: string;\n snippet: string;\n url: string;\n }>;\n total_results: number;\n page: number;\n}\n\ninterface TinyfishFetchResponse {\n results: Array<{\n url: string;\n final_url?: string;\n title?: string;\n description?: string;\n language?: string;\n format?: string;\n text: string;\n }>;\n errors: Array<{ url: string; error: string }>;\n}\n\nexport class TinyfishProvider implements SearchProvider {\n readonly id = 'tinyfish';\n readonly name = 'TinyFish';\n readonly description = 'TinyFish Search & Fetch (free tier, live web results)';\n readonly searchable = true;\n readonly fetchable = true;\n\n private readonly apiKey?: string;\n private readonly searchBaseUrl = 'https://api.search.tinyfish.ai';\n private readonly fetchBaseUrl = 'https://api.fetch.tinyfish.ai';\n private readonly timeoutMs: number;\n\n constructor(config: ResolvedProviderConfig) {\n this.apiKey = config.apiKey;\n this.timeoutMs = config.timeoutMs;\n }\n\n available(): boolean {\n return typeof this.apiKey === 'string' && this.apiKey !== '';\n }\n\n async search(request: SearchRequest, signal?: AbortSignal): Promise<SearchResult> {\n this.ensureKey();\n\n const url = new URL(this.searchBaseUrl);\n url.searchParams.set('query', request.query);\n if (request.maxResults && request.maxResults > 0) {\n url.searchParams.set('max_results', String(Math.floor(request.maxResults)));\n }\n if (typeof request.recencyDays === 'number' && request.recencyDays > 0) {\n url.searchParams.set('recency_minutes', String(Math.floor(request.recencyDays * 24 * 60)));\n }\n if (request.purpose) {\n url.searchParams.set('purpose', request.purpose);\n }\n if (request.location) {\n url.searchParams.set('location', request.location);\n }\n if (request.language) {\n url.searchParams.set('language', request.language);\n }\n if (request.domainType) {\n url.searchParams.set('domain_type', request.domainType);\n }\n if (request.includeDomains && request.includeDomains.length > 0) {\n url.searchParams.set('include_domains', request.includeDomains.join(','));\n }\n if (request.excludeDomains && request.excludeDomains.length > 0) {\n url.searchParams.set('exclude_domains', request.excludeDomains.join(','));\n }\n\n const response = await fetchWithTimeout(url.toString(), {\n method: 'GET',\n headers: {\n 'X-API-Key': this.apiKey!,\n Accept: 'application/json',\n },\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'TinyFish Search');\n\n const body = (await response.json()) as TinyfishSearchResponse;\n const items = (body.results ?? []).map((r) => ({\n title: r.title,\n url: r.url,\n snippet: r.snippet,\n source: r.site_name,\n }));\n\n return {\n status: 'ok',\n source: this.name,\n summary: items.length > 0\n ? `Found ${body.total_results ?? items.length} result(s) for \"${request.query}\"`\n : `No results found for \"${request.query}\"`,\n items,\n uncertainty: items.length === 0 ? ['No search results returned'] : [],\n };\n }\n\n async fetch(request: FetchRequest, signal?: AbortSignal): Promise<FetchResult> {\n this.ensureKey();\n\n const body: Record<string, unknown> = {\n urls: [request.url],\n format: request.format ?? 'markdown',\n };\n if (typeof request.ttl === 'number') {\n body.ttl = request.ttl;\n }\n\n const response = await fetchWithTimeout(this.fetchBaseUrl, {\n method: 'POST',\n headers: {\n 'X-API-Key': this.apiKey!,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'TinyFish Fetch');\n\n const data = (await response.json()) as TinyfishFetchResponse;\n const page = data.results?.[0];\n const error = data.errors?.[0];\n\n if (!page && error) {\n throw new Error(`TinyFish Fetch failed for ${error.url}: ${error.error}`);\n }\n if (!page) {\n throw new Error('TinyFish Fetch returned no content');\n }\n\n return {\n summary: page.title ?? page.description ?? 'Fetched page content',\n content: page.text ?? '',\n uncertainty: [],\n warnings: [],\n };\n }\n\n private ensureKey(): void {\n if (!this.apiKey) {\n throw new Error(\n 'TinyFish API key is missing. Configure providers.tinyfish.apiKey in the search-providers JSON config file.',\n );\n }\n }\n}","import type { ResolvedProviderConfig } from '../config.js';\nimport type { SearchProvider, SearchRequest, SearchResult } from './types.js';\nimport { fetchWithTimeout, throwOnError } from './utils.js';\n\ninterface TavilySearchResponse {\n query: string;\n results: Array<{\n title: string;\n url: string;\n content?: string;\n raw_content?: string;\n score?: number;\n }>;\n}\n\nexport class TavilyProvider implements SearchProvider {\n readonly id = 'tavily';\n readonly name = 'Tavily';\n readonly description = 'Tavily web search';\n readonly searchable = true;\n readonly fetchable = false;\n\n private readonly apiKey?: string;\n private readonly baseUrl = 'https://api.tavily.com';\n private readonly timeoutMs: number;\n\n constructor(config: ResolvedProviderConfig) {\n this.apiKey = config.apiKey;\n this.timeoutMs = config.timeoutMs;\n }\n\n available(): boolean {\n return typeof this.apiKey === 'string' && this.apiKey !== '';\n }\n\n async search(request: SearchRequest, signal?: AbortSignal): Promise<SearchResult> {\n this.ensureKey();\n\n const body: Record<string, unknown> = {\n query: request.query,\n search_depth: 'basic',\n max_results: request.maxResults ?? 5,\n };\n if (request.includeDomains && request.includeDomains.length > 0) {\n body.include_domains = request.includeDomains;\n }\n if (request.excludeDomains && request.excludeDomains.length > 0) {\n body.exclude_domains = request.excludeDomains;\n }\n\n const response = await fetchWithTimeout(`${this.baseUrl}/search`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'Tavily Search');\n\n const data = (await response.json()) as TavilySearchResponse;\n const items = (data.results ?? []).map((r) => ({\n title: r.title,\n url: r.url,\n snippet: r.content ?? r.raw_content ?? '',\n }));\n\n return {\n status: 'ok',\n source: this.name,\n summary: items.length > 0\n ? `Found ${items.length} result(s) for \"${request.query}\"`\n : `No results found for \"${request.query}\"`,\n items,\n uncertainty: items.length === 0 ? ['No search results returned'] : [],\n };\n }\n\n private ensureKey(): void {\n if (!this.apiKey) {\n throw new Error('Tavily API key is missing. Configure providers.tavily.apiKey in the search-providers JSON config file.');\n }\n }\n}","import type { ResolvedProviderConfig } from '../config.js';\nimport type { FetchRequest, FetchResult, SearchProvider, SearchRequest, SearchResult } from './types.js';\nimport { fetchWithTimeout, throwOnError } from './utils.js';\n\ninterface ExaSearchResponse {\n results: Array<{\n title?: string;\n url: string;\n publishedDate?: string;\n author?: string;\n text?: string;\n score?: number;\n }>;\n}\n\ninterface ExaContentsResponse {\n results: Array<{\n url: string;\n text?: string;\n title?: string;\n }>;\n}\n\nexport class ExaProvider implements SearchProvider {\n readonly id = 'exa';\n readonly name = 'Exa';\n readonly description = 'Exa neural web search and contents fetch';\n readonly searchable = true;\n readonly fetchable = true;\n\n private readonly apiKey?: string;\n private readonly baseUrl = 'https://api.exa.ai';\n private readonly timeoutMs: number;\n\n constructor(config: ResolvedProviderConfig) {\n this.apiKey = config.apiKey;\n this.timeoutMs = config.timeoutMs;\n }\n\n available(): boolean {\n return typeof this.apiKey === 'string' && this.apiKey !== '';\n }\n\n async search(request: SearchRequest, signal?: AbortSignal): Promise<SearchResult> {\n this.ensureKey();\n\n const body: Record<string, unknown> = {\n query: request.query,\n num_results: request.maxResults ?? 5,\n type: 'auto',\n };\n if (request.includeDomains && request.includeDomains.length > 0) {\n body.include_domains = request.includeDomains;\n }\n if (request.excludeDomains && request.excludeDomains.length > 0) {\n body.exclude_domains = request.excludeDomains;\n }\n\n const response = await fetchWithTimeout(`${this.baseUrl}/search`, {\n method: 'POST',\n headers: {\n 'x-api-key': this.apiKey!,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'Exa Search');\n\n const data = (await response.json()) as ExaSearchResponse;\n const items = (data.results ?? []).map((r) => ({\n title: r.title ?? r.url,\n url: r.url,\n snippet: r.text ?? '',\n publishedAt: r.publishedDate,\n }));\n\n return {\n status: 'ok',\n source: this.name,\n summary: items.length > 0\n ? `Found ${items.length} result(s) for \"${request.query}\"`\n : `No results found for \"${request.query}\"`,\n items,\n uncertainty: items.length === 0 ? ['No search results returned'] : [],\n };\n }\n\n async fetch(request: FetchRequest, signal?: AbortSignal): Promise<FetchResult> {\n this.ensureKey();\n\n const body = {\n urls: [request.url],\n text: true,\n };\n\n const response = await fetchWithTimeout(`${this.baseUrl}/contents`, {\n method: 'POST',\n headers: {\n 'x-api-key': this.apiKey!,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'Exa Contents');\n\n const data = (await response.json()) as ExaContentsResponse;\n const page = data.results?.[0];\n if (!page) {\n throw new Error('Exa Contents returned no content');\n }\n\n return {\n summary: page.title ?? 'Fetched page content',\n content: page.text ?? '',\n uncertainty: [],\n warnings: [],\n };\n }\n\n private ensureKey(): void {\n if (!this.apiKey) {\n throw new Error('Exa API key is missing. Configure providers.exa.apiKey in the search-providers JSON config file.');\n }\n }\n}","import type { ResolvedProviderConfig } from '../config.js';\nimport type { FetchRequest, FetchResult, SearchProvider, SearchRequest, SearchResult } from './types.js';\nimport { fetchWithTimeout, throwOnError } from './utils.js';\n\ninterface FirecrawlSearchResponse {\n success: boolean;\n data: {\n web: Array<{\n title?: string;\n url: string;\n description?: string;\n markdown?: string;\n }>;\n };\n}\n\ninterface FirecrawlScrapeResponse {\n success: boolean;\n data: {\n markdown?: string;\n metadata?: {\n title?: string;\n sourceURL?: string;\n };\n };\n}\n\nexport class FirecrawlProvider implements SearchProvider {\n readonly id = 'firecrawl';\n readonly name = 'Firecrawl';\n readonly description = 'Firecrawl web search and page scrape';\n readonly searchable = true;\n readonly fetchable = true;\n\n private readonly apiKey?: string;\n private readonly baseUrl = 'https://api.firecrawl.dev';\n private readonly timeoutMs: number;\n\n constructor(config: ResolvedProviderConfig) {\n this.apiKey = config.apiKey;\n this.timeoutMs = config.timeoutMs;\n }\n\n available(): boolean {\n return typeof this.apiKey === 'string' && this.apiKey !== '';\n }\n\n async search(request: SearchRequest, signal?: AbortSignal): Promise<SearchResult> {\n this.ensureKey();\n\n const body: Record<string, unknown> = {\n query: request.query,\n limit: request.maxResults ?? 5,\n sources: ['web'],\n };\n if (request.includeDomains && request.includeDomains.length > 0) {\n body.includeDomains = request.includeDomains;\n }\n if (request.excludeDomains && request.excludeDomains.length > 0) {\n body.excludeDomains = request.excludeDomains;\n }\n\n const response = await fetchWithTimeout(`${this.baseUrl}/v2/search`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'Firecrawl Search');\n\n const data = (await response.json()) as FirecrawlSearchResponse;\n if (data.success === false) {\n throw new Error('Firecrawl Search returned success: false');\n }\n\n const rawItems = data.data?.web ?? [];\n const items = rawItems.map((r) => ({\n title: r.title ?? r.url,\n url: r.url,\n snippet: r.description ?? r.markdown ?? '',\n }));\n\n return {\n status: 'ok',\n source: this.name,\n summary: items.length > 0\n ? `Found ${items.length} result(s) for \"${request.query}\"`\n : `No results found for \"${request.query}\"`,\n items,\n uncertainty: items.length === 0 ? ['No search results returned'] : [],\n };\n }\n\n async fetch(request: FetchRequest, signal?: AbortSignal): Promise<FetchResult> {\n this.ensureKey();\n\n const body = {\n url: request.url,\n formats: ['markdown'],\n };\n\n const response = await fetchWithTimeout(`${this.baseUrl}/v2/scrape`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n signal,\n }, this.timeoutMs);\n\n await throwOnError(response, 'Firecrawl Scrape');\n\n const data = (await response.json()) as FirecrawlScrapeResponse;\n if (data.success === false) {\n throw new Error('Firecrawl Scrape returned success: false');\n }\n\n return {\n summary: data.data?.metadata?.title ?? 'Fetched page content',\n content: data.data?.markdown ?? '',\n uncertainty: [],\n warnings: [],\n };\n }\n\n private ensureKey(): void {\n if (!this.apiKey) {\n throw new Error('Firecrawl API key is missing. Configure providers.firecrawl.apiKey in the search-providers JSON config file.');\n }\n }\n}","// Codex search protocol behavior is based on dsh-codex-connect (Apache-2.0).\n// This provider only consumes an existing static credential; it never logs in,\n// refreshes tokens, or writes credential data.\nimport { randomUUID } from 'node:crypto';\nimport { readFileSync, statSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport type { ResolvedProviderConfig } from '../config.js';\nimport type { SearchProvider, SearchRequest, SearchResult } from './types.js';\nimport { ProviderAuthenticationError } from './utils.js';\n\nconst CODEX_SEARCH_URL = 'https://chatgpt.com/backend-api/codex/alpha/search';\nconst MAX_CREDENTIAL_BYTES = 128 * 1024;\nconst MAX_SUCCESS_RESPONSE_BYTES = 4 * 1024 * 1024;\nconst MAX_ERROR_RESPONSE_BYTES = 64 * 1024;\n\ninterface StaticCodexCredential {\n accessToken: string;\n accountId: string;\n}\n\ninterface CodexSearchRequestBody {\n id: string;\n model: string;\n input: Array<{\n type: 'message';\n role: 'user';\n content: Array<{ type: 'input_text'; text: string }>;\n }>;\n commands: { search_query: Array<{ q: string }> };\n settings: {\n search_context_size: 'medium';\n allowed_callers: ['direct'];\n external_web_access: false;\n };\n max_output_tokens: number;\n}\n\nexport class CodexProvider implements SearchProvider {\n readonly id = 'codex';\n readonly name = 'OpenAI Codex';\n readonly description = 'ChatGPT Codex standalone web search';\n readonly searchable = true;\n readonly fetchable = false;\n\n private readonly credentialFile?: string;\n private readonly timeoutMs: number;\n\n constructor(config: ResolvedProviderConfig) {\n const filename = readNonEmptyString(config.credentialFile);\n this.credentialFile = filename === undefined ? undefined : resolve(filename);\n this.timeoutMs = Number.isFinite(config.timeoutMs) && config.timeoutMs > 0\n ? config.timeoutMs\n : 55_000;\n }\n\n available(): boolean {\n return this.credentialFile !== undefined\n && loadStaticCredential(this.credentialFile) !== undefined;\n }\n\n async search(request: SearchRequest, signal?: AbortSignal): Promise<SearchResult> {\n throwIfAborted(signal);\n\n const credential = this.credentialFile === undefined\n ? undefined\n : loadStaticCredential(this.credentialFile);\n if (!credential) {\n throw new Error('OpenAI Codex credential file is not configured, missing or invalid');\n }\n\n const body: CodexSearchRequestBody = {\n id: randomUUID(),\n model: 'gpt-5.6-sol',\n input: [{\n type: 'message',\n role: 'user',\n content: [{ type: 'input_text', text: request.query }],\n }],\n commands: { search_query: [{ q: request.query }] },\n settings: {\n search_context_size: 'medium',\n allowed_callers: ['direct'],\n external_web_access: false,\n },\n max_output_tokens: 10_000,\n };\n\n const requestTimeout = AbortSignal.timeout(this.timeoutMs);\n const requestSignal = signal ? AbortSignal.any([signal, requestTimeout]) : requestTimeout;\n let response: Response;\n try {\n response = await fetch(CODEX_SEARCH_URL, {\n method: 'POST',\n redirect: 'error',\n headers: {\n Authorization: `Bearer ${credential.accessToken}`,\n 'chatgpt-account-id': credential.accountId,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n originator: 'deepseek-harness',\n },\n body: JSON.stringify(body),\n signal: requestSignal,\n });\n } catch (error) {\n throwIfAborted(signal);\n if (requestTimeout.aborted) {\n throw new Error(`OpenAI Codex search timed out after ${this.timeoutMs}ms`, { cause: error });\n }\n throw new Error('OpenAI Codex search request failed', { cause: error });\n }\n\n let payload: unknown;\n try {\n payload = await readBoundedJson(\n response,\n response.ok ? MAX_SUCCESS_RESPONSE_BYTES : MAX_ERROR_RESPONSE_BYTES,\n requestSignal,\n );\n } catch (error) {\n throwIfAborted(signal);\n if (requestTimeout.aborted) {\n throw new Error(`OpenAI Codex search timed out after ${this.timeoutMs}ms`, { cause: error });\n }\n if (error instanceof ResponseTooLargeError) throw error;\n throw new Error(`OpenAI Codex returned invalid JSON (HTTP ${response.status})`, { cause: error });\n }\n\n if (!response.ok) {\n const detail = providerMessage(payload);\n const suffix = detail ? `: ${detail}` : '';\n if (response.status === 401 || response.status === 403) {\n throw new ProviderAuthenticationError(\n `OpenAI Codex credential is invalid or expired (HTTP ${response.status})${suffix}`,\n );\n }\n throw new Error(`OpenAI Codex search failed (HTTP ${response.status})${suffix}`);\n }\n\n return mapCodexSearchResponse(payload);\n }\n}\n\nfunction loadStaticCredential(filename: string): StaticCodexCredential | undefined {\n try {\n const stats = statSync(filename);\n if (!stats.isFile() || stats.size <= 0 || stats.size > MAX_CREDENTIAL_BYTES) return undefined;\n const value: unknown = JSON.parse(readFileSync(filename, 'utf8'));\n return parseStaticCredential(value);\n } catch {\n return undefined;\n }\n}\n\nfunction mapCodexSearchResponse(value: unknown): SearchResult {\n if (!isRecord(value) || typeof value.output !== 'string') {\n throw new Error('OpenAI Codex returned a search response without string output');\n }\n if (value.results !== undefined && !Array.isArray(value.results)) {\n throw new Error('OpenAI Codex returned a search response with non-array results');\n }\n\n const items: SearchResult['items'] = [];\n const seen = new Set<string>();\n for (const item of value.results ?? []) {\n if (!isRecord(item) || item.type !== 'text_result') continue;\n const url = citeableUrl(item.url);\n if (!url || seen.has(url)) continue;\n seen.add(url);\n items.push({\n title: readNonEmptyString(item.title) ?? url,\n url,\n snippet: readNonEmptyString(item.snippet) ?? '',\n });\n }\n\n const summary = value.output;\n return {\n status: summary.length > 0 ? 'ok' : 'degraded',\n source: 'OpenAI Codex',\n summary: summary || `Codex returned ${items.length} source(s) without summary text`,\n items,\n uncertainty: summary.length > 0 ? [] : ['Codex returned no summary text'],\n };\n}\n\nfunction parseStaticCredential(value: unknown): StaticCodexCredential | undefined {\n if (!isRecord(value)) return undefined;\n\n // Account stores keep tokens in credentials[], selected by activeAccountId.\n const stored = Array.isArray(value.credentials) ? value.credentials : [];\n const activeAccountId = readNonEmptyString(value.activeAccountId);\n const selected = activeAccountId\n ? stored.filter((entry) => isRecord(entry)\n && (readNonEmptyString(entry.account_id) ?? readNonEmptyString(entry.accountId)) === activeAccountId)\n : value.activeAccountId === undefined ? stored : [];\n const storedCredential = selected.length === 1 && isRecord(selected[0]) ? selected[0] : undefined;\n\n const candidates = [\n value,\n isRecord(value.credential) ? value.credential : undefined,\n isRecord(value.tokens) ? value.tokens : undefined,\n storedCredential,\n ];\n\n for (const candidate of candidates) {\n if (!candidate) continue;\n const accessToken = readNonEmptyString(candidate.access_token)\n ?? readNonEmptyString(candidate.access);\n if (!accessToken) continue;\n\n const accountId = readNonEmptyString(candidate.account_id)\n ?? readNonEmptyString(candidate.accountId)\n ?? accountIdFromToken(accessToken);\n if (!accountId) continue;\n\n return { accessToken, accountId };\n }\n\n return undefined;\n}\n\nfunction decodeJwtPayload(accessToken: string): Record<string, unknown> | undefined {\n try {\n const parts = accessToken.split('.');\n if (parts.length !== 3 || !parts[1]) return undefined;\n const payload: unknown = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf8'));\n return isRecord(payload) ? payload : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction accountIdFromToken(accessToken: string): string | undefined {\n const auth = decodeJwtPayload(accessToken)?.['https://api.openai.com/auth'];\n return isRecord(auth) ? readNonEmptyString(auth.chatgpt_account_id) : undefined;\n}\n\nclass ResponseTooLargeError extends Error {\n constructor(limit: number) {\n super(`OpenAI Codex search response exceeded ${limit} bytes`);\n this.name = 'ResponseTooLargeError';\n }\n}\n\nasync function readBoundedJson(\n response: Response,\n maxBytes: number,\n signal: AbortSignal,\n): Promise<unknown> {\n const declaredLength = Number(response.headers.get('content-length'));\n if (Number.isFinite(declaredLength) && declaredLength > maxBytes) {\n await response.body?.cancel().catch(() => {});\n throw new ResponseTooLargeError(maxBytes);\n }\n if (!response.body) throw new SyntaxError('empty response body');\n\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n try {\n while (true) {\n const { done, value } = await abortable(reader.read(), signal);\n if (done) break;\n if (!value) continue;\n total += value.byteLength;\n if (total > maxBytes) throw new ResponseTooLargeError(maxBytes);\n chunks.push(value);\n }\n } catch (error) {\n await reader.cancel().catch(() => {});\n throw error;\n } finally {\n reader.releaseLock();\n }\n\n return JSON.parse(Buffer.concat(chunks, total).toString('utf8')) as unknown;\n}\n\nfunction abortable<T>(operation: Promise<T>, signal: AbortSignal): Promise<T> {\n if (signal.aborted) return Promise.reject(abortedError(signal));\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(abortedError(signal));\n signal.addEventListener('abort', onAbort, { once: true });\n operation.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) throw abortedError(signal);\n}\n\nfunction abortedError(signal: AbortSignal): Error {\n return new Error('OpenAI Codex search aborted', { cause: signal.reason });\n}\n\nfunction providerMessage(value: unknown): string | undefined {\n if (!isRecord(value)) return undefined;\n const raw = typeof value.error === 'string'\n ? value.error\n : isRecord(value.error) && typeof value.error.message === 'string'\n ? value.error.message\n : typeof value.message === 'string'\n ? value.message\n : undefined;\n return raw\n ?.replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\b/gu, '[REDACTED]')\n .slice(0, 1_000);\n}\n\nfunction citeableUrl(value: unknown): string | undefined {\n if (typeof value !== 'string') return undefined;\n try {\n const url = new URL(value);\n return url.protocol === 'http:' || url.protocol === 'https:' ? value : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readNonEmptyString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined;\n}\n\n","import type { ResolvedProviderConfig } from '../config.js';\nimport type { FetchRequest, FetchResult, SearchProvider, SearchRequest, SearchResult } from './types.js';\n\nexport class DemoProvider implements SearchProvider {\n readonly id = 'demo';\n readonly name = 'Demo Provider';\n readonly description = 'Returns canned results for integration testing without calling any external API.';\n readonly searchable = true;\n readonly fetchable = true;\n\n constructor(_config: ResolvedProviderConfig) {}\n\n available(): boolean {\n return true;\n }\n\n async search(request: SearchRequest): Promise<SearchResult> {\n return {\n status: 'ok',\n source: this.name,\n summary: `Demo search results for \"${request.query}\"`,\n items: [\n {\n title: 'Demo Result 1',\n url: 'https://example.com/demo1',\n snippet: 'This is a demo search result used to verify the DSH plugin wiring.',\n },\n {\n title: 'Demo Result 2',\n url: 'https://example.com/demo2',\n snippet: 'Another canned result so citation cards have something to render.',\n },\n ],\n uncertainty: ['Demo mode: results are not from a real search engine.'],\n };\n }\n\n async fetch(request: FetchRequest): Promise<FetchResult> {\n return {\n summary: `Demo fetch of ${request.url}`,\n content: `# Demo Page\\n\\nThis is canned content for the URL \"${request.url}\".`,\n links: [\n { text: 'Example', url: 'https://example.com' },\n ],\n uncertainty: ['Demo mode: content is not from a real web page.'],\n warnings: [],\n };\n }\n}","import type { ProviderRegistry } from '../providers/registry.js';\n\nexport const FALLBACK_ATTEMPT_TIMEOUT_MS = 55_000;\n\nexport interface AttemptContext {\n signal: AbortSignal;\n timedOut(): boolean;\n dispose(): void;\n}\n\nexport function resolveCandidateIds(\n registry: ProviderRegistry,\n fallbackChain?: string[],\n): string[] {\n let activeId: string | undefined;\n try {\n activeId = registry.getActive().id;\n } catch {\n // An empty registry has no active provider.\n }\n\n const configured = fallbackChain === undefined ? registry.list() : fallbackChain;\n const seen = new Set<string>();\n const candidates: string[] = [];\n for (const id of activeId ? [activeId, ...configured] : configured) {\n if (seen.has(id)) continue;\n seen.add(id);\n candidates.push(id);\n }\n return candidates;\n}\n\nexport function createAttemptContext(\n parent: AbortSignal | undefined,\n timeoutMs: number,\n): AttemptContext {\n const controller = new AbortController();\n let didTimeOut = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let onParentAbort: (() => void) | undefined;\n\n if (parent?.aborted) {\n controller.abort(parent.reason);\n } else {\n if (parent) {\n onParentAbort = () => controller.abort(parent.reason);\n parent.addEventListener('abort', onParentAbort, { once: true });\n }\n timer = setTimeout(() => {\n didTimeOut = true;\n controller.abort(new Error(`fallback attempt timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n }\n\n return {\n signal: controller.signal,\n timedOut: () => didTimeOut,\n dispose() {\n if (timer !== undefined) clearTimeout(timer);\n if (parent && onParentAbort) parent.removeEventListener('abort', onParentAbort);\n },\n };\n}\n\nexport function raceWithSignal<T>(operation: Promise<T>, signal: AbortSignal | undefined): Promise<T> {\n if (!signal) return operation;\n if (signal.aborted) {\n operation.catch(() => {});\n return Promise.reject(signal.reason);\n }\n\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener('abort', onAbort);\n reject(signal.reason);\n };\n signal.addEventListener('abort', onAbort, { once: true });\n operation.then(\n (value) => {\n signal.removeEventListener('abort', onAbort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener('abort', onAbort);\n reject(error);\n },\n );\n });\n}\n\nexport function throwIfAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw signal.reason;\n}\n","import type { CooldownController } from '../providers/cooldown.js';\nimport type { ProviderRegistry } from '../providers/registry.js';\nimport type { FetchRequest, FetchResult } from '../providers/types.js';\nimport { ProviderAuthenticationError } from '../providers/utils.js';\nimport {\n createAttemptContext,\n FALLBACK_ATTEMPT_TIMEOUT_MS,\n raceWithSignal,\n resolveCandidateIds,\n throwIfAborted,\n} from './fallback-utils.js';\n\nconst RENDER_CONTENT_CAP = 20_000;\nconst RENDER_LINK_CAP = 20;\n\n/** Native web_fetch input deliberately supports only a URL. */\ninterface WebSeamFetchRequest {\n url: string;\n}\n\nexport function registerWebFetchProvider(\n ctx: any,\n registry: ProviderRegistry,\n cooldown: CooldownController,\n fallbackChain?: string[],\n): void {\n if (typeof ctx.web?.registerFetchProvider !== 'function') {\n console.error('[search-providers] ctx.web.registerFetchProvider is not available; web_fetch provider skipped');\n return;\n }\n\n ctx.web.registerFetchProvider({\n id: 'search-providers',\n available: () => {\n const candidates = resolveFetchCandidateIds(registry, fallbackChain);\n const { ready } = cooldown.filter(candidates, 'fetch');\n return ready.some((id) => registry.get(id)?.available());\n },\n async fetch(args: WebSeamFetchRequest, signal?: AbortSignal) {\n throwIfAborted(signal);\n try {\n if (typeof args?.url !== 'string' || !/^https?:\\/\\//i.test(args.url.trim())) {\n throw new Error('Invalid URL');\n }\n const url = new URL(args.url.trim());\n if (url.protocol !== 'http:' && url.protocol !== 'https:') throw new Error('Invalid protocol');\n } catch {\n throw new Error('web_fetch needs an http(s) \"url\".');\n }\n\n const request: FetchRequest = { url: args.url.trim(), format: 'markdown' };\n const result = await fetchWithFallback(registry, cooldown, fallbackChain, request, signal);\n // Extraction APIs do not expose the origin HTTP status or final redirect URL.\n // Use an explicit unknown sentinel, never invent HTTP 200 for extracted content.\n const evidence: FetchResult = {\n ...result,\n warnings: [\n 'Origin HTTP status and final redirect URL are unavailable from this extraction provider; statusCode 0 means unknown and url is the requested URL.',\n ...(result.warnings ?? []),\n ],\n };\n return {\n url: request.url,\n statusCode: 0,\n body: { kind: 'text' as const, content: renderFetchEvidence(evidence) },\n truncated: result.content.trim().length > RENDER_CONTENT_CAP\n || (result.links?.length ?? 0) > RENDER_LINK_CAP,\n };\n },\n });\n}\n\nfunction resolveFetchCandidateIds(\n registry: ProviderRegistry,\n fallbackChain: string[] | undefined,\n): string[] {\n return resolveCandidateIds(registry, fallbackChain).filter((id) => {\n const provider = registry.get(id);\n return provider !== undefined\n && provider.fetchable !== false\n && typeof provider.fetch === 'function';\n });\n}\n\nasync function fetchWithFallback(\n registry: ProviderRegistry,\n cooldown: CooldownController,\n fallbackChain: string[] | undefined,\n request: FetchRequest,\n signal: AbortSignal | undefined,\n): Promise<FetchResult> {\n throwIfAborted(signal);\n const candidates = resolveFetchCandidateIds(registry, fallbackChain);\n const attempted: string[] = [];\n const attemptedIds = new Set<string>();\n let lastError: Error | undefined;\n\n while (true) {\n throwIfAborted(signal);\n const { ready } = cooldown.filter(candidates, 'fetch');\n const id = ready.find((candidateId) => {\n if (attemptedIds.has(candidateId)) return false;\n const provider = registry.get(candidateId);\n return provider?.available()\n && provider.fetchable !== false\n && typeof provider.fetch === 'function';\n });\n if (id === undefined) break;\n\n const provider = registry.get(id)!;\n attemptedIds.add(id);\n const attempt = attempted.length === 0\n ? undefined\n : createAttemptContext(signal, FALLBACK_ATTEMPT_TIMEOUT_MS);\n\n try {\n const attemptSignal = attempt?.signal ?? signal;\n const result = await raceWithSignal(provider.fetch!(request, attemptSignal), attemptSignal);\n throwIfAborted(signal);\n if (attempt?.timedOut()) throw attempt.signal.reason;\n const { cooling, disabled } = cooldown.filter(candidates, 'fetch');\n if (attempted.length > 0) {\n result.warnings = result.warnings ?? [];\n result.warnings.push(`Fallback used after ${attempted.join(', ')} failed`);\n }\n if (cooling.length > 0) {\n result.warnings = result.warnings ?? [];\n result.warnings.push(`Cooling providers skipped: ${cooling.join(', ')}`);\n }\n if (disabled.length > 0) {\n result.warnings = result.warnings ?? [];\n result.warnings.push(`Providers disabled until restart: ${disabled.join(', ')}`);\n }\n return result;\n } catch (error) {\n throwIfAborted(signal);\n const caught = error instanceof Error ? error : new Error(String(error));\n lastError = caught instanceof ProviderAuthenticationError\n ? caught\n : attempt?.timedOut()\n ? new Error(`fallback attempt timed out after ${FALLBACK_ATTEMPT_TIMEOUT_MS}ms`, { cause: caught })\n : caught;\n attempted.push(id);\n console.warn(`[search-providers] provider '${id}' fetch failed, trying next: ${lastError.message}`);\n cooldown.record(id, 'fetch', lastError);\n } finally {\n attempt?.dispose();\n }\n }\n\n const { cooling, disabled } = cooldown.filter(candidates, 'fetch');\n const coolingIds = cooling.length > 0 ? ` [cooling: ${cooling.join(', ')}]` : '';\n const disabledIds = disabled.length > 0 ? ` [disabled until restart: ${disabled.join(', ')}]` : '';\n throw new Error(\n `No fetch provider succeeded${attempted.length > 0 ? ` (tried: ${attempted.join(', ')})` : ''}${coolingIds}${disabledIds}. ${lastError?.message ?? 'No provider available.'}`,\n { cause: lastError },\n );\n}\n\nfunction renderFetchEvidence(value: FetchResult): string {\n const lines: string[] = [String(value.summary ?? '')];\n const content = String((value.content as string) ?? '').trim();\n if (content) {\n lines.push('', 'Content:', content.length > RENDER_CONTENT_CAP ? `${content.slice(0, RENDER_CONTENT_CAP)}…` : content);\n }\n const links = Array.isArray(value.links) ? value.links.slice(0, RENDER_LINK_CAP) : [];\n if (links.length > 0) {\n lines.push('', 'Links:');\n for (const link of links) {\n const text = link.text ?? '';\n const url = link.url ?? '';\n lines.push(`- ${text} — ${url}`);\n }\n }\n const uncertainty = Array.isArray(value.uncertainty) ? value.uncertainty : [];\n if (uncertainty.length > 0) {\n lines.push('', `Uncertain: ${uncertainty.join('; ')}`);\n }\n const warnings = Array.isArray(value.warnings) ? value.warnings : [];\n if (warnings.length > 0) {\n lines.push('', `Warnings: ${warnings.join('; ')}`);\n }\n return lines.filter(Boolean).join('\\n');\n}\n","import type { CooldownController } from '../providers/cooldown.js';\nimport type { ProviderRegistry } from '../providers/registry.js';\nimport type { SearchRequest, SearchResult } from '../providers/types.js';\nimport { ProviderAuthenticationError } from '../providers/utils.js';\nimport {\n createAttemptContext,\n FALLBACK_ATTEMPT_TIMEOUT_MS,\n raceWithSignal,\n resolveCandidateIds,\n throwIfAborted,\n} from './fallback-utils.js';\n\ninterface WebSeamSearchRequest {\n query: string;\n maxResults?: number;\n recencyDays?: number;\n purpose?: string;\n location?: string;\n language?: string;\n}\n\nexport function registerWebSearchProvider(\n ctx: any,\n registry: ProviderRegistry,\n cooldown: CooldownController,\n fallbackChain?: string[],\n): void {\n if (typeof ctx.web?.registerSearchProvider !== 'function') {\n console.error('[search-providers] ctx.web.registerSearchProvider is not available; web_search provider skipped');\n return;\n }\n\n ctx.web.registerSearchProvider({\n id: 'search-providers',\n available: () => anyProviderAvailable(registry, cooldown, fallbackChain),\n async search(request: WebSeamSearchRequest, signal: AbortSignal | undefined) {\n const searchRequest: SearchRequest = {\n query: request.query,\n maxResults: request.maxResults,\n recencyDays: request.recencyDays,\n purpose: request.purpose,\n location: request.location,\n language: request.language,\n };\n\n const { result, attempted, cooling, disabled } = await searchWithFallback(\n registry,\n cooldown,\n fallbackChain,\n searchRequest,\n signal,\n );\n\n return {\n content: renderContent(result, attempted, cooling, disabled),\n sources: result.items.map((item) => ({\n url: item.url,\n ...(item.title ? { title: item.title } : {}),\n ...(item.snippet ? { snippet: item.snippet } : {}),\n ...(item.publishedAt ? { publishedAt: item.publishedAt } : {}),\n })),\n truncated: false,\n };\n },\n });\n}\n\nfunction resolveSearchCandidateIds(\n registry: ProviderRegistry,\n fallbackChain: string[] | undefined,\n): string[] {\n return resolveCandidateIds(registry, fallbackChain).filter((id) => {\n const provider = registry.get(id);\n return provider !== undefined && provider.searchable !== false;\n });\n}\n\nfunction anyProviderAvailable(\n registry: ProviderRegistry,\n cooldown: CooldownController,\n fallbackChain: string[] | undefined,\n): boolean {\n const candidates = resolveSearchCandidateIds(registry, fallbackChain);\n const { ready } = cooldown.filter(candidates, 'search');\n return ready.some((id) => {\n const provider = registry.get(id);\n return provider?.available() && provider.searchable !== false;\n });\n}\n\ninterface FallbackOutcome {\n result: SearchResult;\n attempted: string[];\n cooling: string[];\n disabled: string[];\n}\n\nasync function searchWithFallback(\n registry: ProviderRegistry,\n cooldown: CooldownController,\n fallbackChain: string[] | undefined,\n request: SearchRequest,\n signal: AbortSignal | undefined,\n): Promise<FallbackOutcome> {\n throwIfAborted(signal);\n const candidates = resolveSearchCandidateIds(registry, fallbackChain);\n const attempted: string[] = [];\n const attemptedIds = new Set<string>();\n let lastError: Error | undefined;\n\n while (true) {\n throwIfAborted(signal);\n const { ready } = cooldown.filter(candidates, 'search');\n const id = ready.find((candidateId) => {\n if (attemptedIds.has(candidateId)) return false;\n const provider = registry.get(candidateId);\n return provider?.available() && provider.searchable !== false;\n });\n if (id === undefined) break;\n\n const provider = registry.get(id)!;\n attemptedIds.add(id);\n const attempt = attempted.length === 0\n ? undefined\n : createAttemptContext(signal, FALLBACK_ATTEMPT_TIMEOUT_MS);\n\n try {\n const attemptSignal = attempt?.signal ?? signal;\n const result = await raceWithSignal(provider.search(request, attemptSignal), attemptSignal);\n throwIfAborted(signal);\n if (attempt?.timedOut()) throw attempt.signal.reason;\n const { cooling, disabled } = cooldown.filter(candidates, 'search');\n return { result, attempted, cooling, disabled };\n } catch (error) {\n throwIfAborted(signal);\n const caught = error instanceof Error ? error : new Error(String(error));\n lastError = caught instanceof ProviderAuthenticationError\n ? caught\n : attempt?.timedOut()\n ? new Error(`fallback attempt timed out after ${FALLBACK_ATTEMPT_TIMEOUT_MS}ms`, { cause: caught })\n : caught;\n attempted.push(id);\n console.warn(`[search-providers] provider '${id}' search failed, trying next: ${lastError.message}`);\n cooldown.record(id, 'search', lastError);\n } finally {\n attempt?.dispose();\n }\n }\n\n const { cooling, disabled } = cooldown.filter(candidates, 'search');\n const coolingIds = cooling.length > 0 ? ` [cooling: ${cooling.join(', ')}]` : '';\n const disabledIds = disabled.length > 0 ? ` [disabled until restart: ${disabled.join(', ')}]` : '';\n throw new Error(\n `No search provider succeeded${attempted.length > 0 ? ` (tried: ${attempted.join(', ')})` : ''}${coolingIds}${disabledIds}. ${lastError?.message ?? 'No provider available.'}`,\n { cause: lastError },\n );\n}\n\nfunction renderContent(\n result: SearchResult,\n attempted: string[],\n cooling: string[],\n disabled: string[],\n): string {\n const lines = [`[Search provider: ${result.source}]`, result.summary];\n if (attempted.length > 0) {\n lines.push(`[Fallback used after ${attempted.join(', ')} failed]`);\n }\n if (cooling.length > 0) {\n lines.push(`[Cooling: ${cooling.join(', ')}]`);\n }\n if (disabled.length > 0) {\n lines.push(`[Disabled until restart: ${disabled.join(', ')}]`);\n }\n if (result.uncertainty.length > 0) {\n lines.push(`Uncertain: ${result.uncertainty.join('; ')}`);\n }\n return lines.filter(Boolean).join('\\n');\n}\n","import { loadPluginConfig, resolveProviderConfig } from './config.js';\nimport { CooldownController } from './providers/cooldown.js';\nimport { ProviderRegistry } from './providers/registry.js';\nimport { TinyfishProvider } from './providers/tinyfish.js';\nimport { TavilyProvider } from './providers/tavily.js';\nimport { ExaProvider } from './providers/exa.js';\nimport { FirecrawlProvider } from './providers/firecrawl.js';\nimport { CodexProvider } from './providers/codex.js';\nimport { DemoProvider } from './providers/demo.js';\nimport type { PluginConfig } from './config.js';\nimport { registerWebFetchProvider } from './tools/read-page.js';\nimport { registerWebSearchProvider } from './tools/web-search.js';\n\nexport const name = 'search-providers';\nexport const inject = ['web'];\n\nconst DEFAULT_PROVIDER_ORDER = ['codex', 'tinyfish', 'tavily', 'exa', 'firecrawl'];\n\nexport function apply(ctx: any, rawConfig: PluginConfig = {}): void {\n const config = loadPluginConfig(rawConfig);\n const registry = new ProviderRegistry();\n const cooldown = new CooldownController();\n const demoMode = config.provider === 'demo';\n\n // Register providers in priority order.\n registry.register(new CodexProvider(resolveProviderConfig(config, 'codex')));\n registry.register(new TinyfishProvider(resolveProviderConfig(config, 'tinyfish')));\n registry.register(new TavilyProvider(resolveProviderConfig(config, 'tavily')));\n registry.register(new ExaProvider(resolveProviderConfig(config, 'exa')));\n registry.register(new FirecrawlProvider(resolveProviderConfig(config, 'firecrawl')));\n\n if (demoMode) {\n registry.register(new DemoProvider(resolveProviderConfig(config, 'tinyfish')));\n }\n\n // Determine active provider.\n const activeProvider = config.provider;\n if (activeProvider) {\n try {\n registry.setActive(activeProvider);\n } catch (error) {\n console.warn(`[search-providers] configured provider '${activeProvider}' is not registered; falling back to '${registry.list()[0]}'`);\n }\n }\n\n // The active provider is always tried first. An explicit empty chain disables fallback.\n const fallbackChain = config.fallbackChain ?? DEFAULT_PROVIDER_ORDER;\n\n // Register native web capability providers.\n registerWebSearchProvider(ctx, registry, cooldown, fallbackChain);\n registerWebFetchProvider(ctx, registry, cooldown, fallbackChain);\n\n console.log(`[search-providers] loaded with active provider: ${registry.getActive().id}, fallback after active: [${fallbackChain.join(', ')}]`);\n}"],"names":["isRecord","throwIfAborted","resolve","provider","cooling","disabled"],"mappings":"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"}
|
package/package.json
CHANGED