@pentoshi/clai 0.10.5 → 0.11.1
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/README.md +32 -0
- package/dist/agent/runner.d.ts +2 -0
- package/dist/agent/runner.js +124 -21
- package/dist/agent/runner.js.map +1 -1
- package/dist/commands/providers.js +28 -0
- package/dist/commands/providers.js.map +1 -1
- package/dist/commands/search-providers.d.ts +50 -0
- package/dist/commands/search-providers.js +134 -0
- package/dist/commands/search-providers.js.map +1 -0
- package/dist/commands/update.js +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/llm/provider.js +9 -6
- package/dist/llm/provider.js.map +1 -1
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.js +7 -1
- package/dist/prompts/index.js.map +1 -1
- package/dist/safety/classifier.js +40 -0
- package/dist/safety/classifier.js.map +1 -1
- package/dist/store/config.d.ts +5 -0
- package/dist/store/config.js +7 -0
- package/dist/store/config.js.map +1 -1
- package/dist/store/keys.d.ts +65 -0
- package/dist/store/keys.js +164 -28
- package/dist/store/keys.js.map +1 -1
- package/dist/tools/http.d.ts +12 -1
- package/dist/tools/http.js +8 -43
- package/dist/tools/http.js.map +1 -1
- package/dist/tools/registry.js +52 -0
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/shell.d.ts +25 -0
- package/dist/tools/shell.js +155 -6
- package/dist/tools/shell.js.map +1 -1
- package/dist/tools/web/audit.d.ts +154 -0
- package/dist/tools/web/audit.js +147 -0
- package/dist/tools/web/audit.js.map +1 -0
- package/dist/tools/web/budget.d.ts +76 -0
- package/dist/tools/web/budget.js +187 -0
- package/dist/tools/web/budget.js.map +1 -0
- package/dist/tools/web/capture.d.ts +201 -0
- package/dist/tools/web/capture.js +380 -0
- package/dist/tools/web/capture.js.map +1 -0
- package/dist/tools/web/fetch-core.d.ts +66 -0
- package/dist/tools/web/fetch-core.js +1123 -0
- package/dist/tools/web/fetch-core.js.map +1 -0
- package/dist/tools/web/fetch.d.ts +42 -0
- package/dist/tools/web/fetch.js +115 -0
- package/dist/tools/web/fetch.js.map +1 -0
- package/dist/tools/web/providers/brave.d.ts +46 -0
- package/dist/tools/web/providers/brave.js +263 -0
- package/dist/tools/web/providers/brave.js.map +1 -0
- package/dist/tools/web/providers/duckduckgo.d.ts +47 -0
- package/dist/tools/web/providers/duckduckgo.js +248 -0
- package/dist/tools/web/providers/duckduckgo.js.map +1 -0
- package/dist/tools/web/providers/provider.d.ts +99 -0
- package/dist/tools/web/providers/provider.js +38 -0
- package/dist/tools/web/providers/provider.js.map +1 -0
- package/dist/tools/web/providers/tavily.d.ts +52 -0
- package/dist/tools/web/providers/tavily.js +285 -0
- package/dist/tools/web/providers/tavily.js.map +1 -0
- package/dist/tools/web/readable.d.ts +67 -0
- package/dist/tools/web/readable.js +248 -0
- package/dist/tools/web/readable.js.map +1 -0
- package/dist/tools/web/redact.d.ts +120 -0
- package/dist/tools/web/redact.js +155 -0
- package/dist/tools/web/redact.js.map +1 -0
- package/dist/tools/web/search.d.ts +51 -0
- package/dist/tools/web/search.js +389 -0
- package/dist/tools/web/search.js.map +1 -0
- package/dist/tools/web/ssrf-guard.d.ts +85 -0
- package/dist/tools/web/ssrf-guard.js +265 -0
- package/dist/tools/web/ssrf-guard.js.map +1 -0
- package/dist/tools/web/types.d.ts +331 -0
- package/dist/tools/web/types.js +71 -0
- package/dist/tools/web/types.js.map +1 -0
- package/dist/ui/spinner.js +87 -14
- package/dist/ui/spinner.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Header / cookie redaction and audit-log stripping for `web.fetch`.
|
|
3
|
+
*
|
|
4
|
+
* This module is the single source of truth for the
|
|
5
|
+
* {@link HeaderMap} format described in Requirement 2.21 (lower-cased keys,
|
|
6
|
+
* repeat values joined with `", "`, per-value 4096-char cap with the
|
|
7
|
+
* literal `[...truncated]` marker). It also implements the redaction rules
|
|
8
|
+
* required by 2.22 / 2.32 and the audit-log strip required by 5.11–5.13.
|
|
9
|
+
*
|
|
10
|
+
* See `.kiro/specs/web-search-and-fetch/design.md` "Redaction strategy"
|
|
11
|
+
* for the broader picture.
|
|
12
|
+
*/
|
|
13
|
+
import { type CookieInfo, type CookieSameSite, type HeaderMap } from "./types.js";
|
|
14
|
+
/**
|
|
15
|
+
* Case-insensitive set of header names whose values are considered
|
|
16
|
+
* sensitive. Stored lower-cased so callers can match them against
|
|
17
|
+
* already-normalized {@link HeaderMap} keys without re-casing.
|
|
18
|
+
*
|
|
19
|
+
* Mirrors Requirement 5.12 / design "Redaction strategy".
|
|
20
|
+
*/
|
|
21
|
+
export declare const SENSITIVE_HEADERS: ReadonlySet<string>;
|
|
22
|
+
/**
|
|
23
|
+
* Ordered list of `[name, value]` pairs, the most general header input
|
|
24
|
+
* shape. Repeats of the same name are preserved in the order observed and
|
|
25
|
+
* are joined by {@link applyToHeaders} per RFC 7230.
|
|
26
|
+
*
|
|
27
|
+
* Callers that have a Node `http.IncomingMessage.rawHeaders` array (a flat
|
|
28
|
+
* `string[]` of alternating name/value entries) can convert it with
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* const pairs: HeaderEntries = [];
|
|
32
|
+
* for (let i = 0; i < raw.length; i += 2) pairs.push([raw[i]!, raw[i + 1]!]);
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export type HeaderEntries = ReadonlyArray<readonly [string, string]>;
|
|
36
|
+
/**
|
|
37
|
+
* Reduced cookie shape produced by {@link stripForAudit}: only the
|
|
38
|
+
* non-secret public attributes named by Requirement 5.11 are kept. The
|
|
39
|
+
* cookie's `value`, `expires`, and `maxAge` fields are intentionally
|
|
40
|
+
* absent — the audit log never carries cookie values nor any field that
|
|
41
|
+
* could leak session lifetime back to a third party.
|
|
42
|
+
*/
|
|
43
|
+
export interface AuditSafeCookie {
|
|
44
|
+
name: string;
|
|
45
|
+
domain?: string;
|
|
46
|
+
path?: string;
|
|
47
|
+
httpOnly?: boolean;
|
|
48
|
+
secure?: boolean;
|
|
49
|
+
sameSite?: CookieSameSite;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Output shape of {@link stripForAudit}: a header map with every
|
|
53
|
+
* sensitive header dropped and a cookies list with every value-bearing
|
|
54
|
+
* field removed. Both fields are always present (possibly empty) so the
|
|
55
|
+
* caller can spread them into an audit payload without `undefined` checks.
|
|
56
|
+
*/
|
|
57
|
+
export interface AuditSafePayload {
|
|
58
|
+
headers: HeaderMap;
|
|
59
|
+
cookies: AuditSafeCookie[];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Normalize a set of HTTP response headers into the canonical
|
|
63
|
+
* {@link HeaderMap} format documented in Requirement 2.21.
|
|
64
|
+
*
|
|
65
|
+
* Steps applied, in order:
|
|
66
|
+
* 1. Lower-case every header name.
|
|
67
|
+
* 2. Join repeated values for the same name with `", "` (RFC 7230).
|
|
68
|
+
* 3. If `redactSensitive=true` and the lower-cased name is in
|
|
69
|
+
* {@link SENSITIVE_HEADERS}, replace the joined value with the literal
|
|
70
|
+
* {@link REDACTED_PLACEHOLDER}.
|
|
71
|
+
* 4. Otherwise, if the joined value's character length exceeds
|
|
72
|
+
* {@link MAX_HEADER_VALUE_LENGTH}, slice it to the cap and append
|
|
73
|
+
* {@link TRUNCATION_MARKER}.
|
|
74
|
+
*
|
|
75
|
+
* Accepts either a flat {@link HeaderMap} (already deduplicated by the
|
|
76
|
+
* caller) or a list of `[name, value]` pairs ({@link HeaderEntries}). The
|
|
77
|
+
* pair form preserves repeats — a `Set-Cookie` header that appears three
|
|
78
|
+
* times will produce three entries that this function joins. The flat-map
|
|
79
|
+
* form is convenient for callers that already have a `Record<string,
|
|
80
|
+
* string>`; in that case there are no repeats to join.
|
|
81
|
+
*
|
|
82
|
+
* The function is the single source of truth for the
|
|
83
|
+
* {@link HeaderMap} format. Both the user-facing fetch result and the
|
|
84
|
+
* audit-log path go through it (the audit path additionally calls
|
|
85
|
+
* {@link stripForAudit} to drop sensitive entries entirely).
|
|
86
|
+
*/
|
|
87
|
+
export declare function applyToHeaders(input: HeaderMap | HeaderEntries, redactSensitive: boolean): HeaderMap;
|
|
88
|
+
/**
|
|
89
|
+
* Apply the cookie-value redaction rule from Requirement 2.32.
|
|
90
|
+
*
|
|
91
|
+
* Returns a fresh array of fresh {@link CookieInfo} objects so the caller
|
|
92
|
+
* can mutate the result without aliasing the inputs:
|
|
93
|
+
* - When `redactSensitive=true`: every entry's `value` is replaced with
|
|
94
|
+
* the literal {@link REDACTED_PLACEHOLDER}; all other attributes
|
|
95
|
+
* (`name`, `domain`, `path`, `expires`, `maxAge`, `httpOnly`, `secure`,
|
|
96
|
+
* `sameSite`) are preserved unchanged.
|
|
97
|
+
* - When `redactSensitive=false`: every entry is shallow-copied verbatim.
|
|
98
|
+
*/
|
|
99
|
+
export declare function applyToCookies(cookies: readonly CookieInfo[], redactSensitive: boolean): CookieInfo[];
|
|
100
|
+
/**
|
|
101
|
+
* Build the audit-log-safe view of a fetch's headers and cookies.
|
|
102
|
+
*
|
|
103
|
+
* Always-on guarantees, regardless of `redactSensitive`:
|
|
104
|
+
* - Every {@link SENSITIVE_HEADERS} entry is removed from the returned
|
|
105
|
+
* header map (key and value both gone). The value never appears in any
|
|
106
|
+
* form, including as `[REDACTED]` — the audit log simply does not
|
|
107
|
+
* advertise that the header was present (Requirement 5.12).
|
|
108
|
+
* - Every cookie is reduced to the {@link AuditSafeCookie} shape:
|
|
109
|
+
* `{name, domain, path, httpOnly, secure, sameSite}`. Cookie values,
|
|
110
|
+
* `expires`, and `maxAge` are dropped (Requirements 5.11, 5.12).
|
|
111
|
+
*
|
|
112
|
+
* The remaining (non-sensitive) headers are passed through with their
|
|
113
|
+
* keys lower-cased so the caller does not need to re-normalize. Header
|
|
114
|
+
* values are not re-truncated here — they have already been processed by
|
|
115
|
+
* {@link applyToHeaders} on the way into `metadata.headers`.
|
|
116
|
+
*
|
|
117
|
+
* Both arguments are tolerant of `undefined` so the caller can hand off
|
|
118
|
+
* an optional `metadata.headers` / `metadata.cookies` directly.
|
|
119
|
+
*/
|
|
120
|
+
export declare function stripForAudit(headers: HeaderMap | undefined, cookies: readonly CookieInfo[] | undefined): AuditSafePayload;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Header / cookie redaction and audit-log stripping for `web.fetch`.
|
|
3
|
+
*
|
|
4
|
+
* This module is the single source of truth for the
|
|
5
|
+
* {@link HeaderMap} format described in Requirement 2.21 (lower-cased keys,
|
|
6
|
+
* repeat values joined with `", "`, per-value 4096-char cap with the
|
|
7
|
+
* literal `[...truncated]` marker). It also implements the redaction rules
|
|
8
|
+
* required by 2.22 / 2.32 and the audit-log strip required by 5.11–5.13.
|
|
9
|
+
*
|
|
10
|
+
* See `.kiro/specs/web-search-and-fetch/design.md` "Redaction strategy"
|
|
11
|
+
* for the broader picture.
|
|
12
|
+
*/
|
|
13
|
+
import { MAX_HEADER_VALUE_LENGTH, REDACTED_PLACEHOLDER, TRUNCATION_MARKER, } from "./types.js";
|
|
14
|
+
/**
|
|
15
|
+
* Case-insensitive set of header names whose values are considered
|
|
16
|
+
* sensitive. Stored lower-cased so callers can match them against
|
|
17
|
+
* already-normalized {@link HeaderMap} keys without re-casing.
|
|
18
|
+
*
|
|
19
|
+
* Mirrors Requirement 5.12 / design "Redaction strategy".
|
|
20
|
+
*/
|
|
21
|
+
export const SENSITIVE_HEADERS = new Set([
|
|
22
|
+
"cookie",
|
|
23
|
+
"set-cookie",
|
|
24
|
+
"authorization",
|
|
25
|
+
"proxy-authorization",
|
|
26
|
+
]);
|
|
27
|
+
/**
|
|
28
|
+
* Normalize a set of HTTP response headers into the canonical
|
|
29
|
+
* {@link HeaderMap} format documented in Requirement 2.21.
|
|
30
|
+
*
|
|
31
|
+
* Steps applied, in order:
|
|
32
|
+
* 1. Lower-case every header name.
|
|
33
|
+
* 2. Join repeated values for the same name with `", "` (RFC 7230).
|
|
34
|
+
* 3. If `redactSensitive=true` and the lower-cased name is in
|
|
35
|
+
* {@link SENSITIVE_HEADERS}, replace the joined value with the literal
|
|
36
|
+
* {@link REDACTED_PLACEHOLDER}.
|
|
37
|
+
* 4. Otherwise, if the joined value's character length exceeds
|
|
38
|
+
* {@link MAX_HEADER_VALUE_LENGTH}, slice it to the cap and append
|
|
39
|
+
* {@link TRUNCATION_MARKER}.
|
|
40
|
+
*
|
|
41
|
+
* Accepts either a flat {@link HeaderMap} (already deduplicated by the
|
|
42
|
+
* caller) or a list of `[name, value]` pairs ({@link HeaderEntries}). The
|
|
43
|
+
* pair form preserves repeats — a `Set-Cookie` header that appears three
|
|
44
|
+
* times will produce three entries that this function joins. The flat-map
|
|
45
|
+
* form is convenient for callers that already have a `Record<string,
|
|
46
|
+
* string>`; in that case there are no repeats to join.
|
|
47
|
+
*
|
|
48
|
+
* The function is the single source of truth for the
|
|
49
|
+
* {@link HeaderMap} format. Both the user-facing fetch result and the
|
|
50
|
+
* audit-log path go through it (the audit path additionally calls
|
|
51
|
+
* {@link stripForAudit} to drop sensitive entries entirely).
|
|
52
|
+
*/
|
|
53
|
+
export function applyToHeaders(input, redactSensitive) {
|
|
54
|
+
// Group repeated header names. Ordering is preserved by the Map.
|
|
55
|
+
const grouped = new Map();
|
|
56
|
+
const entries = Array.isArray(input)
|
|
57
|
+
? input
|
|
58
|
+
: Object.entries(input);
|
|
59
|
+
for (const [name, value] of entries) {
|
|
60
|
+
if (typeof name !== "string" || typeof value !== "string")
|
|
61
|
+
continue;
|
|
62
|
+
const key = name.toLowerCase();
|
|
63
|
+
const existing = grouped.get(key);
|
|
64
|
+
if (existing) {
|
|
65
|
+
existing.push(value);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
grouped.set(key, [value]);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const out = {};
|
|
72
|
+
for (const [key, values] of grouped) {
|
|
73
|
+
if (redactSensitive && SENSITIVE_HEADERS.has(key)) {
|
|
74
|
+
// The redacted placeholder is shorter than the cap and is a fixed
|
|
75
|
+
// marker; do not run it through the truncator.
|
|
76
|
+
out[key] = REDACTED_PLACEHOLDER;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const joined = values.join(", ");
|
|
80
|
+
out[key] =
|
|
81
|
+
joined.length > MAX_HEADER_VALUE_LENGTH
|
|
82
|
+
? joined.slice(0, MAX_HEADER_VALUE_LENGTH) + TRUNCATION_MARKER
|
|
83
|
+
: joined;
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Apply the cookie-value redaction rule from Requirement 2.32.
|
|
89
|
+
*
|
|
90
|
+
* Returns a fresh array of fresh {@link CookieInfo} objects so the caller
|
|
91
|
+
* can mutate the result without aliasing the inputs:
|
|
92
|
+
* - When `redactSensitive=true`: every entry's `value` is replaced with
|
|
93
|
+
* the literal {@link REDACTED_PLACEHOLDER}; all other attributes
|
|
94
|
+
* (`name`, `domain`, `path`, `expires`, `maxAge`, `httpOnly`, `secure`,
|
|
95
|
+
* `sameSite`) are preserved unchanged.
|
|
96
|
+
* - When `redactSensitive=false`: every entry is shallow-copied verbatim.
|
|
97
|
+
*/
|
|
98
|
+
export function applyToCookies(cookies, redactSensitive) {
|
|
99
|
+
if (!redactSensitive) {
|
|
100
|
+
return cookies.map((c) => ({ ...c }));
|
|
101
|
+
}
|
|
102
|
+
return cookies.map((c) => ({ ...c, value: REDACTED_PLACEHOLDER }));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Build the audit-log-safe view of a fetch's headers and cookies.
|
|
106
|
+
*
|
|
107
|
+
* Always-on guarantees, regardless of `redactSensitive`:
|
|
108
|
+
* - Every {@link SENSITIVE_HEADERS} entry is removed from the returned
|
|
109
|
+
* header map (key and value both gone). The value never appears in any
|
|
110
|
+
* form, including as `[REDACTED]` — the audit log simply does not
|
|
111
|
+
* advertise that the header was present (Requirement 5.12).
|
|
112
|
+
* - Every cookie is reduced to the {@link AuditSafeCookie} shape:
|
|
113
|
+
* `{name, domain, path, httpOnly, secure, sameSite}`. Cookie values,
|
|
114
|
+
* `expires`, and `maxAge` are dropped (Requirements 5.11, 5.12).
|
|
115
|
+
*
|
|
116
|
+
* The remaining (non-sensitive) headers are passed through with their
|
|
117
|
+
* keys lower-cased so the caller does not need to re-normalize. Header
|
|
118
|
+
* values are not re-truncated here — they have already been processed by
|
|
119
|
+
* {@link applyToHeaders} on the way into `metadata.headers`.
|
|
120
|
+
*
|
|
121
|
+
* Both arguments are tolerant of `undefined` so the caller can hand off
|
|
122
|
+
* an optional `metadata.headers` / `metadata.cookies` directly.
|
|
123
|
+
*/
|
|
124
|
+
export function stripForAudit(headers, cookies) {
|
|
125
|
+
const safeHeaders = {};
|
|
126
|
+
if (headers) {
|
|
127
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
128
|
+
if (typeof key !== "string" || typeof value !== "string")
|
|
129
|
+
continue;
|
|
130
|
+
const lower = key.toLowerCase();
|
|
131
|
+
if (SENSITIVE_HEADERS.has(lower))
|
|
132
|
+
continue;
|
|
133
|
+
safeHeaders[lower] = value;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const safeCookies = [];
|
|
137
|
+
if (cookies) {
|
|
138
|
+
for (const c of cookies) {
|
|
139
|
+
const entry = { name: c.name };
|
|
140
|
+
if (c.domain !== undefined)
|
|
141
|
+
entry.domain = c.domain;
|
|
142
|
+
if (c.path !== undefined)
|
|
143
|
+
entry.path = c.path;
|
|
144
|
+
if (c.httpOnly !== undefined)
|
|
145
|
+
entry.httpOnly = c.httpOnly;
|
|
146
|
+
if (c.secure !== undefined)
|
|
147
|
+
entry.secure = c.secure;
|
|
148
|
+
if (c.sameSite !== undefined)
|
|
149
|
+
entry.sameSite = c.sameSite;
|
|
150
|
+
safeCookies.push(entry);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return { headers: safeHeaders, cookies: safeCookies };
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../../src/tools/web/redact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `web.search` registry handler.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the active {@link SearchProviderId}, looks up the API key (if
|
|
5
|
+
* needed), dispatches a single outbound request via the registered
|
|
6
|
+
* adapter, validates each returned hit per Requirement 7.3, truncates to
|
|
7
|
+
* `maxResults`, and emits exactly one structured audit-log entry per
|
|
8
|
+
* invocation (Requirement 5.5).
|
|
9
|
+
*
|
|
10
|
+
* Error handling mirrors the design's error matrix: timeouts (1.8),
|
|
11
|
+
* missing keys (3.4), provider auth failures (6.1), rate limiting (6.2),
|
|
12
|
+
* network failures (6.3), parse failures (6.5), 5xx (6.6), and other
|
|
13
|
+
* non-2xx (1.9). Every failure surfaces as `ok=false` with a categorical
|
|
14
|
+
* `error.kind` and a human-readable message that names the active
|
|
15
|
+
* provider.
|
|
16
|
+
*
|
|
17
|
+
* Per Requirement 6.7 the handler issues exactly one outbound request
|
|
18
|
+
* attempt — there is no retry on transient failure.
|
|
19
|
+
*
|
|
20
|
+
* The provider modules register themselves into the shared
|
|
21
|
+
* {@link searchProviders} registry on import; we eagerly import them
|
|
22
|
+
* here so `web.search` can be invoked without any lazy-load surprises.
|
|
23
|
+
*/
|
|
24
|
+
import type { ToolResult } from "../../types.js";
|
|
25
|
+
import type { ToolRunOptions } from "../registry.js";
|
|
26
|
+
import { type SearchProvider } from "./providers/provider.js";
|
|
27
|
+
import "./providers/duckduckgo.js";
|
|
28
|
+
import "./providers/brave.js";
|
|
29
|
+
import "./providers/tavily.js";
|
|
30
|
+
import { type SearchProviderId, type WebSearchArgs, type WebSearchErrorKind, type WebSearchOutcome } from "./types.js";
|
|
31
|
+
/**
|
|
32
|
+
* Optional injection points for tests so the search dispatch can be
|
|
33
|
+
* exercised without invoking the real provider modules. Production
|
|
34
|
+
* callers never pass these.
|
|
35
|
+
*/
|
|
36
|
+
export interface WebSearchOptions extends ToolRunOptions {
|
|
37
|
+
/** Override the active provider lookup. */
|
|
38
|
+
provider?: SearchProviderId;
|
|
39
|
+
/** Override the registered {@link SearchProvider} for the active id. */
|
|
40
|
+
providerOverride?: SearchProvider;
|
|
41
|
+
/** Override the API-key resolver. Returns the raw key (or undefined). */
|
|
42
|
+
resolveKey?: (id: SearchProviderId) => Promise<string | undefined>;
|
|
43
|
+
/** Wall-clock timeout in milliseconds. Default: {@link SEARCH_TIMEOUT_MS}. */
|
|
44
|
+
timeoutMs?: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Run `web.search`. Always emits a single audit-log entry. Never
|
|
48
|
+
* throws — every failure mode surfaces as `ok=false`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function webSearch(args: WebSearchArgs, options?: WebSearchOptions): Promise<ToolResult>;
|
|
51
|
+
export type { WebSearchOutcome, WebSearchErrorKind };
|