@osovv/vv-opencode 1.1.6 → 1.2.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.
Files changed (127) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +59 -2
  3. package/dist/commands/completion.js +1 -1
  4. package/dist/commands/completion.js.map +1 -1
  5. package/dist/commands/init.js +1 -1
  6. package/dist/commands/init.js.map +1 -1
  7. package/dist/commands/install.js +7 -2
  8. package/dist/commands/install.js.map +1 -1
  9. package/dist/commands/patch-provider.d.ts +4 -4
  10. package/dist/commands/patch-provider.js +7 -6
  11. package/dist/commands/patch-provider.js.map +1 -1
  12. package/dist/commands/plugin-list.js +1 -1
  13. package/dist/commands/plugin-list.js.map +1 -1
  14. package/dist/commands/plugin-toggle.js +1 -1
  15. package/dist/commands/plugin-toggle.js.map +1 -1
  16. package/dist/commands/preset.js +1 -0
  17. package/dist/commands/preset.js.map +1 -1
  18. package/dist/commands/role.js +1 -1
  19. package/dist/commands/role.js.map +1 -1
  20. package/dist/commands/sync.js +7 -2
  21. package/dist/commands/sync.js.map +1 -1
  22. package/dist/commands/upgrade.js +1 -1
  23. package/dist/commands/upgrade.js.map +1 -1
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.js +7 -5
  26. package/dist/index.js.map +1 -1
  27. package/dist/lib/agent-models.js +1 -1
  28. package/dist/lib/agent-models.js.map +1 -1
  29. package/dist/lib/managed-agents.js +1 -1
  30. package/dist/lib/managed-agents.js.map +1 -1
  31. package/dist/lib/managed-skills.js +1 -1
  32. package/dist/lib/managed-skills.js.map +1 -1
  33. package/dist/lib/model-roles.js +1 -1
  34. package/dist/lib/model-roles.js.map +1 -1
  35. package/dist/lib/opencode.js +22 -7
  36. package/dist/lib/opencode.js.map +1 -1
  37. package/dist/lib/orchestration.js +4 -2
  38. package/dist/lib/orchestration.js.map +1 -1
  39. package/dist/lib/plugin-toggle-config.d.ts +1 -1
  40. package/dist/lib/plugin-toggle-config.js +4 -2
  41. package/dist/lib/plugin-toggle-config.js.map +1 -1
  42. package/dist/lib/vvoc-config.d.ts +93 -0
  43. package/dist/lib/vvoc-config.js +87 -2
  44. package/dist/lib/vvoc-config.js.map +1 -1
  45. package/dist/lib/vvoc-paths.js +2 -3
  46. package/dist/lib/vvoc-paths.js.map +1 -1
  47. package/dist/lib/vvoc-preset-registry.js +1 -1
  48. package/dist/lib/vvoc-preset-registry.js.map +1 -1
  49. package/dist/plugins/guardian/index.js +44 -6
  50. package/dist/plugins/guardian/index.js.map +1 -1
  51. package/dist/plugins/hashline-edit/edit-text-normalization.js +6 -5
  52. package/dist/plugins/hashline-edit/edit-text-normalization.js.map +1 -1
  53. package/dist/plugins/hashline-edit/index.js +16 -7
  54. package/dist/plugins/hashline-edit/index.js.map +1 -1
  55. package/dist/plugins/hashline-edit/tool-description.d.ts +1 -1
  56. package/dist/plugins/hashline-edit/tool-description.js +3 -2
  57. package/dist/plugins/hashline-edit/tool-description.js.map +1 -1
  58. package/dist/plugins/secrets-redaction/config.d.ts +6 -1
  59. package/dist/plugins/secrets-redaction/config.js +30 -5
  60. package/dist/plugins/secrets-redaction/config.js.map +1 -1
  61. package/dist/plugins/secrets-redaction/deep.js +1 -1
  62. package/dist/plugins/secrets-redaction/deep.js.map +1 -1
  63. package/dist/plugins/secrets-redaction/engine.js +10 -4
  64. package/dist/plugins/secrets-redaction/engine.js.map +1 -1
  65. package/dist/plugins/secrets-redaction/index.js +14 -21
  66. package/dist/plugins/secrets-redaction/index.js.map +1 -1
  67. package/dist/plugins/secrets-redaction/patterns.js +4 -4
  68. package/dist/plugins/secrets-redaction/patterns.js.map +1 -1
  69. package/dist/plugins/secrets-redaction/restore.js +1 -1
  70. package/dist/plugins/secrets-redaction/restore.js.map +1 -1
  71. package/dist/plugins/secrets-redaction/session.js +1 -2
  72. package/dist/plugins/secrets-redaction/session.js.map +1 -1
  73. package/dist/plugins/web-tools/config.d.ts +43 -0
  74. package/dist/plugins/web-tools/config.js +134 -0
  75. package/dist/plugins/web-tools/config.js.map +1 -0
  76. package/dist/plugins/web-tools/fetch-service.d.ts +14 -0
  77. package/dist/plugins/web-tools/fetch-service.js +169 -0
  78. package/dist/plugins/web-tools/fetch-service.js.map +1 -0
  79. package/dist/plugins/web-tools/html-markdown.d.ts +13 -0
  80. package/dist/plugins/web-tools/html-markdown.js +82 -0
  81. package/dist/plugins/web-tools/html-markdown.js.map +1 -0
  82. package/dist/plugins/web-tools/http.d.ts +34 -0
  83. package/dist/plugins/web-tools/http.js +154 -0
  84. package/dist/plugins/web-tools/http.js.map +1 -0
  85. package/dist/plugins/web-tools/index.d.ts +18 -0
  86. package/dist/plugins/web-tools/index.js +93 -0
  87. package/dist/plugins/web-tools/index.js.map +1 -0
  88. package/dist/plugins/web-tools/media-loader.d.ts +26 -0
  89. package/dist/plugins/web-tools/media-loader.js +178 -0
  90. package/dist/plugins/web-tools/media-loader.js.map +1 -0
  91. package/dist/plugins/web-tools/providers/brave.d.ts +3 -0
  92. package/dist/plugins/web-tools/providers/brave.js +101 -0
  93. package/dist/plugins/web-tools/providers/brave.js.map +1 -0
  94. package/dist/plugins/web-tools/providers/exa.d.ts +28 -0
  95. package/dist/plugins/web-tools/providers/exa.js +138 -0
  96. package/dist/plugins/web-tools/providers/exa.js.map +1 -0
  97. package/dist/plugins/web-tools/providers/native-fetch.d.ts +21 -0
  98. package/dist/plugins/web-tools/providers/native-fetch.js +112 -0
  99. package/dist/plugins/web-tools/providers/native-fetch.js.map +1 -0
  100. package/dist/plugins/web-tools/providers/spider.d.ts +25 -0
  101. package/dist/plugins/web-tools/providers/spider.js +104 -0
  102. package/dist/plugins/web-tools/providers/spider.js.map +1 -0
  103. package/dist/plugins/web-tools/providers/zai.d.ts +33 -0
  104. package/dist/plugins/web-tools/providers/zai.js +181 -0
  105. package/dist/plugins/web-tools/providers/zai.js.map +1 -0
  106. package/dist/plugins/web-tools/search-service.d.ts +18 -0
  107. package/dist/plugins/web-tools/search-service.js +110 -0
  108. package/dist/plugins/web-tools/search-service.js.map +1 -0
  109. package/dist/plugins/workflow/index.js +24 -5
  110. package/dist/plugins/workflow/index.js.map +1 -1
  111. package/dist/plugins/workflow/persistence.js +1 -1
  112. package/dist/plugins/workflow/persistence.js.map +1 -1
  113. package/dist/plugins/workflow/state.d.ts +14 -0
  114. package/dist/plugins/workflow/state.js +44 -1
  115. package/dist/plugins/workflow/state.js.map +1 -1
  116. package/dist/plugins/workflow/tooling.js +1 -1
  117. package/dist/plugins/workflow/tooling.js.map +1 -1
  118. package/dist/tui/context/analyze.js +11 -3
  119. package/dist/tui/context/analyze.js.map +1 -1
  120. package/dist/tui/context/collect.js +1 -1
  121. package/dist/tui/context/collect.js.map +1 -1
  122. package/dist/tui/context/plugin.js +3 -2
  123. package/dist/tui/context/plugin.js.map +1 -1
  124. package/dist/tui.js +1 -1
  125. package/package.json +15 -8
  126. package/schemas/vvoc/v3.json +43 -1
  127. package/templates/skills/vv-execute/SKILL.md +17 -12
@@ -0,0 +1,178 @@
1
+ // FILE: src/plugins/web-tools/media-loader.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Load supported images and PDFs as base64 file attachments for the web tools fetch path.
5
+ // SCOPE: MIME and magic-byte identification, base64 data-URL attachment construction, filename derivation, and rejection of unsupported or oversized payloads.
6
+ // DEPENDS: [src/plugins/web-tools/http.ts, @opencode-ai/plugin]
7
+ // LINKS: [M-WEB-MEDIA-LOADER, M-WEB-HTTP, M-WEB-NATIVE-FETCH, M-WEB-SPIDER]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // SUPPORTED_MEDIA_MIME_TYPES - Tuple of supported media MIME types.
14
+ // SupportedMediaMimeType - Supported media MIME type union.
15
+ // WebMediaError - Unsupported-media error carrying the detected or declared MIME type.
16
+ // sniffMediaMimeType - Detect a supported MIME type from leading bytes.
17
+ // mediaAttachmentFromBytes - Build a base64 data-URL attachment from already-fetched bytes.
18
+ // loadMediaAttachment - Fetch a URL and return it as an attachment when supported.
19
+ // END_MODULE_MAP
20
+ //
21
+ // START_CHANGE_SUMMARY
22
+ // LAST_CHANGE: [v1.0.0 - Initial direct media attachment loader for the unified web tools.]
23
+ // END_CHANGE_SUMMARY
24
+ import { DEFAULT_MEDIA_MAX_BYTES, DEFAULT_REQUEST_TIMEOUT_MS, requestBounded, WebHttpError, } from "./http.js";
25
+ export const SUPPORTED_MEDIA_MIME_TYPES = [
26
+ "image/jpeg",
27
+ "image/png",
28
+ "image/gif",
29
+ "image/webp",
30
+ "application/pdf",
31
+ ];
32
+ /** Unsupported-media failure. The message names the detected or declared MIME type and never includes the payload. */
33
+ export class WebMediaError extends Error {
34
+ code;
35
+ mime;
36
+ constructor(message, mime) {
37
+ super(message);
38
+ this.name = "WebMediaError";
39
+ this.code = "UNSUPPORTED";
40
+ this.mime = mime;
41
+ }
42
+ }
43
+ const EXTENSION_BY_MIME = {
44
+ "image/jpeg": ".jpg",
45
+ "image/png": ".png",
46
+ "image/gif": ".gif",
47
+ "image/webp": ".webp",
48
+ "application/pdf": ".pdf",
49
+ };
50
+ // START_BLOCK_SNIFF
51
+ /**
52
+ * Sniff the media MIME type from leading bytes.
53
+ * Returns undefined when the signature matches no supported format.
54
+ */
55
+ export function sniffMediaMimeType(bytes) {
56
+ if (bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
57
+ return "image/jpeg";
58
+ }
59
+ if (bytes.length >= 4 &&
60
+ bytes[0] === 0x89 &&
61
+ bytes[1] === 0x50 &&
62
+ bytes[2] === 0x4e &&
63
+ bytes[3] === 0x47) {
64
+ return "image/png";
65
+ }
66
+ if (bytes.length >= 4 &&
67
+ bytes[0] === 0x47 &&
68
+ bytes[1] === 0x49 &&
69
+ bytes[2] === 0x46 &&
70
+ bytes[3] === 0x38) {
71
+ return "image/gif";
72
+ }
73
+ if (bytes.length >= 12 &&
74
+ bytes[0] === 0x52 &&
75
+ bytes[1] === 0x49 &&
76
+ bytes[2] === 0x46 &&
77
+ bytes[3] === 0x46 &&
78
+ bytes[8] === 0x57 &&
79
+ bytes[9] === 0x45 &&
80
+ bytes[10] === 0x42 &&
81
+ bytes[11] === 0x50) {
82
+ return "image/webp";
83
+ }
84
+ if (bytes.length >= 4 &&
85
+ bytes[0] === 0x25 &&
86
+ bytes[1] === 0x50 &&
87
+ bytes[2] === 0x44 &&
88
+ bytes[3] === 0x46) {
89
+ return "application/pdf";
90
+ }
91
+ return undefined;
92
+ }
93
+ // END_BLOCK_SNIFF
94
+ // START_BLOCK_HELPERS
95
+ function normalizeDeclaredContentType(declared) {
96
+ if (!declared) {
97
+ return undefined;
98
+ }
99
+ const mime = declared.split(";")[0]?.trim().toLowerCase();
100
+ return mime || undefined;
101
+ }
102
+ function filenameFromUrl(url, mime) {
103
+ const extension = EXTENSION_BY_MIME[mime];
104
+ try {
105
+ const base = new URL(url).pathname.split("/").pop() ?? "";
106
+ if (base && base.includes(".")) {
107
+ return base;
108
+ }
109
+ if (base) {
110
+ return `${base}${extension}`;
111
+ }
112
+ return `resource${extension}`;
113
+ }
114
+ catch {
115
+ return `resource${extension}`;
116
+ }
117
+ }
118
+ function resolveMimeType(bytes, declaredContentType) {
119
+ const sniffed = sniffMediaMimeType(bytes);
120
+ if (sniffed) {
121
+ return sniffed;
122
+ }
123
+ const declared = normalizeDeclaredContentType(declaredContentType);
124
+ if (declared && SUPPORTED_MEDIA_MIME_TYPES.includes(declared)) {
125
+ return declared;
126
+ }
127
+ return undefined;
128
+ }
129
+ // END_BLOCK_HELPERS
130
+ // START_CONTRACT: mediaAttachmentFromBytes
131
+ // PURPOSE: Build a base64 data-URL file attachment from already-fetched bytes.
132
+ // INPUTS: { bytes: payload; source: url, declaredContentType, optional maxBytes }
133
+ // OUTPUTS: { ToolAttachment - type file, mime, data URL, filename }
134
+ // SIDE_EFFECTS: none; performs no network I/O
135
+ // LINKS: M-WEB-NATIVE-FETCH, M-WEB-SPIDER
136
+ // END_CONTRACT: mediaAttachmentFromBytes
137
+ export function mediaAttachmentFromBytes(bytes, source) {
138
+ const maxBytes = source.maxBytes ?? DEFAULT_MEDIA_MAX_BYTES;
139
+ if (bytes.byteLength > maxBytes) {
140
+ throw new WebHttpError("OVERSIZED", `media payload exceeded ${maxBytes} bytes`);
141
+ }
142
+ const mime = resolveMimeType(bytes, source.declaredContentType);
143
+ if (!mime) {
144
+ const detail = sniffMediaMimeType(bytes) ??
145
+ normalizeDeclaredContentType(source.declaredContentType) ??
146
+ "unknown";
147
+ throw new WebMediaError(`unsupported media type: ${detail}`, detail === "unknown" ? undefined : detail);
148
+ }
149
+ const base64 = Buffer.from(bytes).toString("base64");
150
+ return {
151
+ type: "file",
152
+ mime,
153
+ url: `data:${mime};base64,${base64}`,
154
+ filename: filenameFromUrl(source.url, mime),
155
+ };
156
+ }
157
+ // START_CONTRACT: loadMediaAttachment
158
+ // PURPOSE: Fetch a URL through the bounded transport and return it as an attachment when supported.
159
+ // INPUTS: { input: url, optional abort, timeoutMs, maxBytes; fetchImpl: injectable fetch }
160
+ // OUTPUTS: { ToolAttachment }
161
+ // SIDE_EFFECTS: performs network I/O through fetchImpl
162
+ // LINKS: M-WEB-HTTP
163
+ // END_CONTRACT: loadMediaAttachment
164
+ export async function loadMediaAttachment(input, fetchImpl) {
165
+ const maxBytes = input.maxBytes ?? DEFAULT_MEDIA_MAX_BYTES;
166
+ const response = await requestBounded({
167
+ url: input.url,
168
+ timeoutMs: input.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
169
+ maxBytes,
170
+ abort: input.abort,
171
+ }, fetchImpl);
172
+ return mediaAttachmentFromBytes(response.bytes, {
173
+ url: response.finalUrl,
174
+ declaredContentType: response.headers.get("content-type") ?? undefined,
175
+ maxBytes,
176
+ });
177
+ }
178
+ //# sourceMappingURL=media-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-loader.js","sourceRoot":"","sources":["../../../src/plugins/web-tools/media-loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type FetchLike } from "../http.js";
2
+ import { type WebSearchInput, type WebSearchResult } from "./exa.js";
3
+ export declare function searchBrave(input: WebSearchInput, fetchImpl?: FetchLike): Promise<WebSearchResult[]>;
@@ -0,0 +1,101 @@
1
+ // FILE: src/plugins/web-tools/providers/brave.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Call the Brave Web Search endpoint directly and normalize web results for the web_search tool.
5
+ // SCOPE: Brave request construction with X-Subscription-Token auth, count and freshness mapping, moderate safe search, and web result normalization.
6
+ // DEPENDS: [src/plugins/web-tools/http.ts, src/plugins/web-tools/providers/exa.ts]
7
+ // LINKS: [M-WEB-BRAVE, M-WEB-HTTP, M-WEB-SEARCH-SERVICE]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // searchBrave - Execute one Brave Web Search.
14
+ // END_MODULE_MAP
15
+ //
16
+ // START_CHANGE_SUMMARY
17
+ // LAST_CHANGE: [v1.0.0 - Initial Brave Web Search adapter.]
18
+ // END_CHANGE_SUMMARY
19
+ import { DEFAULT_TEXT_MAX_BYTES, requestBounded, } from "../http.js";
20
+ import { mapHttpErrorToProviderError, WebProviderError, } from "./exa.js";
21
+ const BRAVE_SEARCH_URL = "https://api.search.brave.com/res/v1/web/search";
22
+ const BRAVE_FRESHNESS = { day: "pd", week: "pw", month: "pm", year: "py" };
23
+ // START_BLOCK_HELPERS
24
+ function isPlainObject(value) {
25
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26
+ }
27
+ function normalizeBraveResult(item) {
28
+ if (!isPlainObject(item)) {
29
+ return undefined;
30
+ }
31
+ const url = typeof item.url === "string" ? item.url : undefined;
32
+ if (!url) {
33
+ return undefined;
34
+ }
35
+ const title = typeof item.title === "string" && item.title.length > 0 ? item.title : url;
36
+ const snippet = typeof item.description === "string" && item.description.length > 0
37
+ ? item.description
38
+ : undefined;
39
+ const publishedAt = typeof item.page_age === "string" ? item.page_age : undefined;
40
+ return {
41
+ title,
42
+ url,
43
+ ...(snippet ? { snippet } : {}),
44
+ ...(publishedAt ? { publishedAt } : {}),
45
+ };
46
+ }
47
+ function parseBraveResults(bytes) {
48
+ let parsed;
49
+ try {
50
+ parsed = JSON.parse(new TextDecoder().decode(bytes));
51
+ }
52
+ catch {
53
+ throw new WebProviderError("brave", "BAD_RESPONSE", "malformed JSON response from brave");
54
+ }
55
+ const web = isPlainObject(parsed) ? parsed.web : undefined;
56
+ const results = isPlainObject(web) && Array.isArray(web.results) ? web.results : undefined;
57
+ if (!results) {
58
+ throw new WebProviderError("brave", "BAD_RESPONSE", "unexpected brave response envelope");
59
+ }
60
+ return results
61
+ .map(normalizeBraveResult)
62
+ .filter((result) => result !== undefined);
63
+ }
64
+ // END_BLOCK_HELPERS
65
+ // START_CONTRACT: searchBrave
66
+ // PURPOSE: GET the Brave Web Search endpoint with X-Subscription-Token auth and normalize web.results.
67
+ // INPUTS: { input: WebSearchInput; fetchImpl: injectable fetch }
68
+ // OUTPUTS: { WebSearchResult[] - ranked results, empty array when none }
69
+ // SIDE_EFFECTS: performs network I/O through fetchImpl; never logs the credential
70
+ // LINKS: M-WEB-SEARCH-SERVICE
71
+ // END_CONTRACT: searchBrave
72
+ export async function searchBrave(input, fetchImpl) {
73
+ const params = new URLSearchParams();
74
+ params.set("q", input.query);
75
+ params.set("count", String(input.count));
76
+ params.set("safesearch", "moderate");
77
+ if (input.freshness) {
78
+ params.set("freshness", BRAVE_FRESHNESS[input.freshness]);
79
+ }
80
+ const url = `${BRAVE_SEARCH_URL}?${params.toString()}`;
81
+ let response;
82
+ try {
83
+ response = await requestBounded({
84
+ url,
85
+ method: "GET",
86
+ headers: {
87
+ "X-Subscription-Token": input.credential.value,
88
+ accept: "application/json",
89
+ },
90
+ timeoutMs: input.timeoutMs,
91
+ maxBytes: DEFAULT_TEXT_MAX_BYTES,
92
+ abort: input.abort,
93
+ }, fetchImpl);
94
+ }
95
+ catch (error) {
96
+ mapHttpErrorToProviderError(error, "brave");
97
+ throw error;
98
+ }
99
+ return parseBraveResults(response.bytes);
100
+ }
101
+ //# sourceMappingURL=brave.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"brave.js","sourceRoot":"","sources":["../../../../src/plugins/web-tools/providers/brave.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { WebProviderCredential } from "../config.js";
2
+ import { type FetchLike } from "../http.js";
3
+ export type WebProviderName = "exa" | "brave" | "spider" | "native" | "zai";
4
+ export type WebProviderErrorCode = "AUTH_FAILED" | "RATE_LIMITED" | "PROVIDER_ERROR" | "BAD_RESPONSE" | "MISSING_CREDENTIAL" | "UNSUPPORTED" | "CONVERSION_FAILED";
5
+ /** Provider-facing search or scrape error. Messages name the provider and never include the credential. */
6
+ export declare class WebProviderError extends Error {
7
+ readonly provider: WebProviderName;
8
+ readonly code: WebProviderErrorCode;
9
+ readonly status?: number;
10
+ constructor(provider: WebProviderName, code: WebProviderErrorCode, message: string, status?: number);
11
+ }
12
+ export type WebSearchResult = {
13
+ title: string;
14
+ url: string;
15
+ snippet?: string;
16
+ publishedAt?: string;
17
+ };
18
+ export type WebSearchInput = {
19
+ query: string;
20
+ count: number;
21
+ freshness?: "day" | "week" | "month" | "year";
22
+ credential: WebProviderCredential;
23
+ abort: AbortSignal;
24
+ timeoutMs: number;
25
+ };
26
+ /** Map a bounded-transport HTTP error to a provider error; re-throw timeout, abort, oversized, and network errors unchanged. */
27
+ export declare function mapHttpErrorToProviderError(error: unknown, provider: WebProviderName): never;
28
+ export declare function searchExa(input: WebSearchInput, fetchImpl?: FetchLike): Promise<WebSearchResult[]>;
@@ -0,0 +1,138 @@
1
+ // FILE: src/plugins/web-tools/providers/exa.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Call the official Exa Search API directly and normalize ranked results for the web_search tool.
5
+ // SCOPE: Exa request construction with x-api-key auth, count and freshness mapping, result normalization, and provider error mapping. Also owns the shared provider search types and WebProviderError used by sibling adapters.
6
+ // DEPENDS: [src/plugins/web-tools/http.ts, src/plugins/web-tools/config.ts]
7
+ // LINKS: [M-WEB-EXA, M-WEB-HTTP, M-WEB-SEARCH-SERVICE]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // WebProviderName - Provider identifiers for error attribution.
14
+ // WebProviderErrorCode - Provider-facing error codes.
15
+ // WebProviderError - Provider error carrying provider, code, and optional status.
16
+ // WebSearchResult - Normalized ranked search result.
17
+ // WebSearchInput - Provider-neutral search input.
18
+ // mapHttpErrorToProviderError - Map bounded HTTP status failures into credential-safe provider errors.
19
+ // searchExa - Execute one Exa search.
20
+ // END_MODULE_MAP
21
+ //
22
+ // START_CHANGE_SUMMARY
23
+ // LAST_CHANGE: [C-ZAI-DIRECT-WEB-PROVIDERS - Extended shared provider error attribution with the direct zai adapter.]
24
+ // LAST_CHANGE: [v1.0.0 - Initial Exa Search API adapter and shared provider search contracts.]
25
+ // END_CHANGE_SUMMARY
26
+ import { DEFAULT_TEXT_MAX_BYTES, requestBounded, WebHttpError, } from "../http.js";
27
+ /** Provider-facing search or scrape error. Messages name the provider and never include the credential. */
28
+ export class WebProviderError extends Error {
29
+ provider;
30
+ code;
31
+ status;
32
+ constructor(provider, code, message, status) {
33
+ super(message);
34
+ this.name = "WebProviderError";
35
+ this.provider = provider;
36
+ this.code = code;
37
+ this.status = status;
38
+ }
39
+ }
40
+ const EXA_SEARCH_URL = "https://api.exa.ai/search";
41
+ const FRESHNESS_DAYS = { day: 1, week: 7, month: 31, year: 365 };
42
+ // START_BLOCK_HELPERS
43
+ function isPlainObject(value) {
44
+ return typeof value === "object" && value !== null && !Array.isArray(value);
45
+ }
46
+ function freshnessToDate(freshness) {
47
+ const ms = Date.now() - FRESHNESS_DAYS[freshness] * 24 * 60 * 60 * 1000;
48
+ return new Date(ms).toISOString();
49
+ }
50
+ /** Map a bounded-transport HTTP error to a provider error; re-throw timeout, abort, oversized, and network errors unchanged. */
51
+ export function mapHttpErrorToProviderError(error, provider) {
52
+ if (error instanceof WebHttpError && error.code === "HTTP_ERROR") {
53
+ const status = error.status ?? 0;
54
+ if (status === 401 || status === 403) {
55
+ throw new WebProviderError(provider, "AUTH_FAILED", `${provider} authentication failed`, status);
56
+ }
57
+ if (status === 429) {
58
+ throw new WebProviderError(provider, "RATE_LIMITED", `${provider} rate limit exceeded`, status);
59
+ }
60
+ throw new WebProviderError(provider, "PROVIDER_ERROR", `${provider} server error HTTP ${status}`, status);
61
+ }
62
+ throw error;
63
+ }
64
+ function normalizeExaResult(item) {
65
+ if (!isPlainObject(item)) {
66
+ return undefined;
67
+ }
68
+ const url = typeof item.url === "string" ? item.url : undefined;
69
+ if (!url) {
70
+ return undefined;
71
+ }
72
+ const title = typeof item.title === "string" && item.title.length > 0 ? item.title : url;
73
+ const highlights = Array.isArray(item.highlights)
74
+ ? item.highlights.filter((entry) => typeof entry === "string")
75
+ : [];
76
+ const snippet = highlights[0];
77
+ const publishedAt = typeof item.publishedDate === "string" ? item.publishedDate : undefined;
78
+ return {
79
+ title,
80
+ url,
81
+ ...(snippet ? { snippet } : {}),
82
+ ...(publishedAt ? { publishedAt } : {}),
83
+ };
84
+ }
85
+ function parseExaResults(bytes) {
86
+ let parsed;
87
+ try {
88
+ parsed = JSON.parse(new TextDecoder().decode(bytes));
89
+ }
90
+ catch {
91
+ throw new WebProviderError("exa", "BAD_RESPONSE", "malformed JSON response from exa");
92
+ }
93
+ if (!isPlainObject(parsed) || !Array.isArray(parsed.results)) {
94
+ throw new WebProviderError("exa", "BAD_RESPONSE", "unexpected exa response envelope");
95
+ }
96
+ return parsed.results
97
+ .map(normalizeExaResult)
98
+ .filter((result) => result !== undefined);
99
+ }
100
+ // END_BLOCK_HELPERS
101
+ // START_CONTRACT: searchExa
102
+ // PURPOSE: POST https://api.exa.ai/search with x-api-key auth and normalize results.
103
+ // INPUTS: { input: WebSearchInput; fetchImpl: injectable fetch }
104
+ // OUTPUTS: { WebSearchResult[] - ranked results, empty array when none }
105
+ // SIDE_EFFECTS: performs network I/O through fetchImpl; never logs the credential
106
+ // LINKS: M-WEB-SEARCH-SERVICE
107
+ // END_CONTRACT: searchExa
108
+ export async function searchExa(input, fetchImpl) {
109
+ const body = JSON.stringify({
110
+ query: input.query,
111
+ type: "auto",
112
+ numResults: input.count,
113
+ contents: { highlights: { query: input.query, numSentences: 3 } },
114
+ ...(input.freshness ? { startPublishedDate: freshnessToDate(input.freshness) } : {}),
115
+ });
116
+ let response;
117
+ try {
118
+ response = await requestBounded({
119
+ url: EXA_SEARCH_URL,
120
+ method: "POST",
121
+ headers: {
122
+ "x-api-key": input.credential.value,
123
+ "content-type": "application/json",
124
+ accept: "application/json",
125
+ },
126
+ body,
127
+ timeoutMs: input.timeoutMs,
128
+ maxBytes: DEFAULT_TEXT_MAX_BYTES,
129
+ abort: input.abort,
130
+ }, fetchImpl);
131
+ }
132
+ catch (error) {
133
+ mapHttpErrorToProviderError(error, "exa");
134
+ throw error;
135
+ }
136
+ return parseExaResults(response.bytes);
137
+ }
138
+ //# sourceMappingURL=exa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exa.js","sourceRoot":"","sources":["../../../../src/plugins/web-tools/providers/exa.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,iBAAiB;AACjB,wBAAwB;AACxB,6GAA6G;AAC7G,kOAAkO;AAClO,8EAA8E;AAC9E,yDAAyD;AACzD,kBAAkB;AAClB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,kEAAkE;AAClE,wDAAwD;AACxD,oFAAoF;AACpF,uDAAuD;AACvD,oDAAoD;AACpD,yGAAyG;AACzG,wCAAwC;AACxC,iBAAiB;AACjB,EAAE;AACF,uBAAuB;AACvB,wHAAwH;AACxH,iGAAiG;AACjG,qBAAqB;AAGrB,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,YAAY,GAGb,MAAM,YAAY,CAAC;AAapB,2GAA2G;AAC3G,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,QAAQ,CAAkB;IAC1B,IAAI,CAAuB;IAC3B,MAAM,CAAU;IAEzB,YACE,QAAyB,EACzB,IAA0B,EAC1B,OAAe,EACf,MAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAkBD,MAAM,cAAc,GAAG,2BAA2B,CAAC;AAEnD,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAW,CAAC;AAE1E,sBAAsB;AACtB,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,eAAe,CAAC,SAAsC;IAC7D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACxE,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AACpC,CAAC;AAED,gIAAgI;AAChI,MAAM,UAAU,2BAA2B,CAAC,KAAc,EAAE,QAAyB;IACnF,IAAI,KAAK,YAAY,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACjE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACrC,MAAM,IAAI,gBAAgB,CACxB,QAAQ,EACR,aAAa,EACb,GAAG,QAAQ,wBAAwB,EACnC,MAAM,CACP,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,MAAM,IAAI,gBAAgB,CACxB,QAAQ,EACR,cAAc,EACd,GAAG,QAAQ,sBAAsB,EACjC,MAAM,CACP,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,gBAAgB,CACxB,QAAQ,EACR,gBAAgB,EAChB,GAAG,QAAQ,sBAAsB,MAAM,EAAE,EACzC,MAAM,CACP,CAAC;IACJ,CAAC;IACD,MAAM,KAAK,CAAC;AACd,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAa;IACvC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;IAChE,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC;IACzF,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;QAC/C,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC;QAC/E,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAC9B,MAAM,WAAW,GAAG,OAAO,IAAI,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5F,OAAO;QACL,KAAK;QACL,GAAG;QACH,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxC,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAAiB;IACxC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,gBAAgB,CAAC,KAAK,EAAE,cAAc,EAAE,kCAAkC,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,gBAAgB,CAAC,KAAK,EAAE,cAAc,EAAE,kCAAkC,CAAC,CAAC;IACxF,CAAC;IACD,OAAQ,MAAM,CAAC,OAAqB;SACjC,GAAG,CAAC,kBAAkB,CAAC;SACvB,MAAM,CAAC,CAAC,MAAM,EAA6B,EAAE,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;AACzE,CAAC;AACD,oBAAoB;AAEpB,4BAA4B;AAC5B,uFAAuF;AACvF,mEAAmE;AACnE,2EAA2E;AAC3E,oFAAoF;AACpF,gCAAgC;AAChC,0BAA0B;AAC1B,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,KAAqB,EACrB,SAAqB;IAErB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;QAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAE,MAAM;QACZ,UAAU,EAAE,KAAK,CAAC,KAAK;QACvB,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE;QACjE,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,eAAe,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrF,CAAC,CAAC;IAEH,IAAI,QAA6B,CAAC;IAClC,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,cAAc,CAC7B;YACE,GAAG,EAAE,cAAc;YACnB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,WAAW,EAAE,KAAK,CAAC,UAAU,CAAC,KAAK;gBACnC,cAAc,EAAE,kBAAkB;gBAClC,MAAM,EAAE,kBAAkB;aAC3B;YACD,IAAI;YACJ,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,QAAQ,EAAE,sBAAsB;YAChC,KAAK,EAAE,KAAK,CAAC,KAAK;SACnB,EACD,SAAS,CACV,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,2BAA2B,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC1C,MAAM,KAAK,CAAC;IACd,CAAC;IAED,OAAO,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { ToolAttachment } from "@opencode-ai/plugin";
2
+ import { type FetchLike } from "../http.js";
3
+ export type NativeFetchOutcome = {
4
+ kind: "text";
5
+ content: string;
6
+ contentType: string;
7
+ finalUrl: string;
8
+ status: number;
9
+ } | {
10
+ kind: "media";
11
+ attachment: ToolAttachment;
12
+ finalUrl: string;
13
+ status: number;
14
+ };
15
+ export declare function fetchNative(input: {
16
+ url: string;
17
+ format: "markdown" | "text" | "html";
18
+ abort: AbortSignal;
19
+ timeoutMs: number;
20
+ maxBytes?: number;
21
+ }, fetchImpl?: FetchLike): Promise<NativeFetchOutcome>;
@@ -0,0 +1,112 @@
1
+ // FILE: src/plugins/web-tools/providers/native-fetch.ts
2
+ // VERSION: 1.0.0
3
+ // START_MODULE_CONTRACT
4
+ // PURPOSE: Fetch HTTP and HTTPS resources directly and dispatch the body to media, HTML conversion, or plain text passthrough.
5
+ // SCOPE: Redirect following and size limits via the bounded transport, MIME and signature sniffing, local HTML conversion, and rejection of unsupported binaries.
6
+ // DEPENDS: [src/plugins/web-tools/http.ts, src/plugins/web-tools/html-markdown.ts, src/plugins/web-tools/media-loader.ts, src/plugins/web-tools/providers/exa.ts, @opencode-ai/plugin]
7
+ // LINKS: [M-WEB-NATIVE-FETCH, M-WEB-HTTP, M-WEB-HTML-MARKDOWN, M-WEB-MEDIA-LOADER]
8
+ // ROLE: RUNTIME
9
+ // MAP_MODE: EXPORTS
10
+ // END_MODULE_CONTRACT
11
+ //
12
+ // START_MODULE_MAP
13
+ // NativeFetchOutcome - Text or media outcome of a native fetch.
14
+ // fetchNative - Fetch one URL and dispatch its body by content.
15
+ // END_MODULE_MAP
16
+ //
17
+ // START_CHANGE_SUMMARY
18
+ // LAST_CHANGE: [v1.0.0 - Initial native fetch provider with local conversion.]
19
+ // END_CHANGE_SUMMARY
20
+ import { convertHtmlToMarkdown, convertHtmlToText } from "../html-markdown.js";
21
+ import { DEFAULT_MEDIA_MAX_BYTES, DEFAULT_TEXT_MAX_BYTES, requestBounded, WebHttpError, } from "../http.js";
22
+ import { mediaAttachmentFromBytes, sniffMediaMimeType, SUPPORTED_MEDIA_MIME_TYPES, } from "../media-loader.js";
23
+ import { WebProviderError } from "./exa.js";
24
+ const STRUCTURED_TEXT_TYPES = new Set([
25
+ "application/json",
26
+ "application/xml",
27
+ "text/xml",
28
+ "application/javascript",
29
+ "text/javascript",
30
+ ]);
31
+ // START_BLOCK_HELPERS
32
+ function normalizeContentType(declared) {
33
+ if (!declared) {
34
+ return undefined;
35
+ }
36
+ const mime = declared.split(";")[0]?.trim().toLowerCase();
37
+ return mime || undefined;
38
+ }
39
+ function isSupportedMediaMime(mime) {
40
+ return SUPPORTED_MEDIA_MIME_TYPES.includes(mime);
41
+ }
42
+ function isTextLike(mime) {
43
+ if (!mime) {
44
+ return true;
45
+ }
46
+ if (mime.startsWith("text/")) {
47
+ return true;
48
+ }
49
+ if (STRUCTURED_TEXT_TYPES.has(mime)) {
50
+ return true;
51
+ }
52
+ return mime.endsWith("+json") || mime.endsWith("+xml");
53
+ }
54
+ function looksLikeHtml(mime, text) {
55
+ if (mime === "text/html" || mime === "application/xhtml+xml") {
56
+ return true;
57
+ }
58
+ if (!mime || mime === "application/octet-stream") {
59
+ return /<\s*(html|body|div|p|h[1-6]|table)\b/i.test(text.slice(0, 2000));
60
+ }
61
+ return false;
62
+ }
63
+ // END_BLOCK_HELPERS
64
+ // START_CONTRACT: fetchNative
65
+ // PURPOSE: Fetch one URL through the bounded transport with redirects followed and dispatch the body by content.
66
+ // INPUTS: { input: url, format, abort, timeoutMs, optional maxBytes; fetchImpl: injectable fetch }
67
+ // OUTPUTS: { NativeFetchOutcome - text or media }
68
+ // SIDE_EFFECTS: performs network I/O through fetchImpl
69
+ // LINKS: M-WEB-FETCH-SERVICE
70
+ // END_CONTRACT: fetchNative
71
+ export async function fetchNative(input, fetchImpl) {
72
+ const downloadCap = input.maxBytes ?? DEFAULT_MEDIA_MAX_BYTES;
73
+ const response = await requestBounded({
74
+ url: input.url,
75
+ timeoutMs: input.timeoutMs,
76
+ maxBytes: downloadCap,
77
+ abort: input.abort,
78
+ }, fetchImpl);
79
+ const declared = normalizeContentType(response.headers.get("content-type") ?? undefined);
80
+ const sniffed = sniffMediaMimeType(response.bytes);
81
+ if (sniffed || (declared && isSupportedMediaMime(declared))) {
82
+ const attachment = mediaAttachmentFromBytes(response.bytes, {
83
+ url: response.finalUrl,
84
+ declaredContentType: declared,
85
+ maxBytes: downloadCap,
86
+ });
87
+ return { kind: "media", attachment, finalUrl: response.finalUrl, status: response.status };
88
+ }
89
+ if (isTextLike(declared)) {
90
+ const textCap = input.maxBytes ?? DEFAULT_TEXT_MAX_BYTES;
91
+ if (response.bytes.byteLength > textCap) {
92
+ throw new WebHttpError("OVERSIZED", `text response exceeded ${textCap} bytes`);
93
+ }
94
+ const text = new TextDecoder().decode(response.bytes);
95
+ const content = looksLikeHtml(declared, text)
96
+ ? input.format === "markdown"
97
+ ? convertHtmlToMarkdown(text)
98
+ : input.format === "text"
99
+ ? convertHtmlToText(text)
100
+ : text
101
+ : text;
102
+ return {
103
+ kind: "text",
104
+ content,
105
+ contentType: declared ?? "text/plain",
106
+ finalUrl: response.finalUrl,
107
+ status: response.status,
108
+ };
109
+ }
110
+ throw new WebProviderError("native", "UNSUPPORTED", `unsupported content type: ${declared ?? "unknown"}`);
111
+ }
112
+ //# sourceMappingURL=native-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-fetch.js","sourceRoot":"","sources":["../../../../src/plugins/web-tools/providers/native-fetch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { ToolAttachment } from "@opencode-ai/plugin";
2
+ import type { WebProviderCredential } from "../config.js";
3
+ import { type FetchLike } from "../http.js";
4
+ export type SpiderOutcome = {
5
+ kind: "text";
6
+ content: string;
7
+ metadata: {
8
+ status?: number;
9
+ durationMs?: number;
10
+ };
11
+ } | {
12
+ kind: "media";
13
+ attachment: ToolAttachment;
14
+ metadata: {
15
+ status?: number;
16
+ durationMs?: number;
17
+ };
18
+ };
19
+ export declare function scrapeSpider(input: {
20
+ url: string;
21
+ format: "markdown" | "text" | "html";
22
+ credential: WebProviderCredential;
23
+ abort: AbortSignal;
24
+ timeoutMs: number;
25
+ }, fetchImpl?: FetchLike): Promise<SpiderOutcome>;