@osovv/vv-opencode 1.1.5 → 1.2.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 +33 -0
- package/README.md +72 -9
- package/dist/commands/completion.js +1 -1
- package/dist/commands/completion.js.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install.js +7 -2
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/patch-provider.d.ts +4 -4
- package/dist/commands/patch-provider.js +7 -6
- package/dist/commands/patch-provider.js.map +1 -1
- package/dist/commands/plugin-list.js +1 -1
- package/dist/commands/plugin-list.js.map +1 -1
- package/dist/commands/plugin-toggle.js +1 -1
- package/dist/commands/plugin-toggle.js.map +1 -1
- package/dist/commands/preset.js +1 -0
- package/dist/commands/preset.js.map +1 -1
- package/dist/commands/role.js +1 -1
- package/dist/commands/role.js.map +1 -1
- package/dist/commands/sync.js +7 -2
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/upgrade.js +1 -1
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-models.js +1 -1
- package/dist/lib/agent-models.js.map +1 -1
- package/dist/lib/managed-agents.js +1 -1
- package/dist/lib/managed-agents.js.map +1 -1
- package/dist/lib/managed-skills.js +1 -1
- package/dist/lib/managed-skills.js.map +1 -1
- package/dist/lib/model-roles.js +1 -1
- package/dist/lib/model-roles.js.map +1 -1
- package/dist/lib/opencode.js +22 -7
- package/dist/lib/opencode.js.map +1 -1
- package/dist/lib/orchestration.js +4 -2
- package/dist/lib/orchestration.js.map +1 -1
- package/dist/lib/plugin-toggle-config.d.ts +1 -1
- package/dist/lib/plugin-toggle-config.js +4 -2
- package/dist/lib/plugin-toggle-config.js.map +1 -1
- package/dist/lib/vvoc-config.d.ts +93 -0
- package/dist/lib/vvoc-config.js +87 -2
- package/dist/lib/vvoc-config.js.map +1 -1
- package/dist/lib/vvoc-preset-registry.js +1 -1
- package/dist/lib/vvoc-preset-registry.js.map +1 -1
- package/dist/plugins/guardian/index.js +44 -6
- package/dist/plugins/guardian/index.js.map +1 -1
- package/dist/plugins/hashline-edit/edit-text-normalization.js +6 -5
- package/dist/plugins/hashline-edit/edit-text-normalization.js.map +1 -1
- package/dist/plugins/hashline-edit/index.js +16 -7
- package/dist/plugins/hashline-edit/index.js.map +1 -1
- package/dist/plugins/hashline-edit/tool-description.d.ts +1 -1
- package/dist/plugins/hashline-edit/tool-description.js +3 -2
- package/dist/plugins/hashline-edit/tool-description.js.map +1 -1
- package/dist/plugins/secrets-redaction/config.d.ts +6 -1
- package/dist/plugins/secrets-redaction/config.js +29 -4
- package/dist/plugins/secrets-redaction/config.js.map +1 -1
- package/dist/plugins/secrets-redaction/engine.js +10 -4
- package/dist/plugins/secrets-redaction/engine.js.map +1 -1
- package/dist/plugins/secrets-redaction/index.js +14 -21
- package/dist/plugins/secrets-redaction/index.js.map +1 -1
- package/dist/plugins/secrets-redaction/patterns.js +3 -3
- package/dist/plugins/secrets-redaction/patterns.js.map +1 -1
- package/dist/plugins/secrets-redaction/session.js +0 -1
- package/dist/plugins/secrets-redaction/session.js.map +1 -1
- package/dist/plugins/web-tools/config.d.ts +43 -0
- package/dist/plugins/web-tools/config.js +134 -0
- package/dist/plugins/web-tools/config.js.map +1 -0
- package/dist/plugins/web-tools/fetch-service.d.ts +14 -0
- package/dist/plugins/web-tools/fetch-service.js +166 -0
- package/dist/plugins/web-tools/fetch-service.js.map +1 -0
- package/dist/plugins/web-tools/html-markdown.d.ts +13 -0
- package/dist/plugins/web-tools/html-markdown.js +82 -0
- package/dist/plugins/web-tools/html-markdown.js.map +1 -0
- package/dist/plugins/web-tools/http.d.ts +34 -0
- package/dist/plugins/web-tools/http.js +154 -0
- package/dist/plugins/web-tools/http.js.map +1 -0
- package/dist/plugins/web-tools/index.d.ts +18 -0
- package/dist/plugins/web-tools/index.js +93 -0
- package/dist/plugins/web-tools/index.js.map +1 -0
- package/dist/plugins/web-tools/media-loader.d.ts +26 -0
- package/dist/plugins/web-tools/media-loader.js +178 -0
- package/dist/plugins/web-tools/media-loader.js.map +1 -0
- package/dist/plugins/web-tools/providers/brave.d.ts +3 -0
- package/dist/plugins/web-tools/providers/brave.js +101 -0
- package/dist/plugins/web-tools/providers/brave.js.map +1 -0
- package/dist/plugins/web-tools/providers/exa.d.ts +28 -0
- package/dist/plugins/web-tools/providers/exa.js +138 -0
- package/dist/plugins/web-tools/providers/exa.js.map +1 -0
- package/dist/plugins/web-tools/providers/native-fetch.d.ts +21 -0
- package/dist/plugins/web-tools/providers/native-fetch.js +112 -0
- package/dist/plugins/web-tools/providers/native-fetch.js.map +1 -0
- package/dist/plugins/web-tools/providers/spider.d.ts +25 -0
- package/dist/plugins/web-tools/providers/spider.js +104 -0
- package/dist/plugins/web-tools/providers/spider.js.map +1 -0
- package/dist/plugins/web-tools/providers/zai.d.ts +33 -0
- package/dist/plugins/web-tools/providers/zai.js +181 -0
- package/dist/plugins/web-tools/providers/zai.js.map +1 -0
- package/dist/plugins/web-tools/search-service.d.ts +18 -0
- package/dist/plugins/web-tools/search-service.js +110 -0
- package/dist/plugins/web-tools/search-service.js.map +1 -0
- package/dist/plugins/workflow/index.js +24 -5
- package/dist/plugins/workflow/index.js.map +1 -1
- package/dist/plugins/workflow/persistence.js +1 -1
- package/dist/plugins/workflow/persistence.js.map +1 -1
- package/dist/plugins/workflow/state.d.ts +14 -0
- package/dist/plugins/workflow/state.js +44 -1
- package/dist/plugins/workflow/state.js.map +1 -1
- package/dist/plugins/workflow/tooling.js +1 -1
- package/dist/plugins/workflow/tooling.js.map +1 -1
- package/dist/tui/context/analyze.js +11 -3
- package/dist/tui/context/analyze.js.map +1 -1
- package/dist/tui/context/collect.js +1 -1
- package/dist/tui/context/collect.js.map +1 -1
- package/dist/tui/context/plugin.js +3 -2
- package/dist/tui/context/plugin.js.map +1 -1
- package/dist/tui.js +1 -1
- package/package.json +15 -8
- package/schemas/vvoc/v3.json +43 -1
- 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":"AAAA,8CAA8C;AAC9C,iBAAiB;AACjB,wBAAwB;AACxB,qGAAqG;AACrG,iKAAiK;AACjK,kEAAkE;AAClE,8EAA8E;AAC9E,kBAAkB;AAClB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,sEAAsE;AACtE,8DAA8D;AAC9D,yFAAyF;AACzF,0EAA0E;AAC1E,8FAA8F;AAC9F,qFAAqF;AACrF,iBAAiB;AACjB,EAAE;AACF,uBAAuB;AACvB,8FAA8F;AAC9F,qBAAqB;AAGrB,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,cAAc,EACd,YAAY,GAEb,MAAM,WAAW,CAAC;AAEnB,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,YAAY;IACZ,WAAW;IACX,WAAW;IACX,YAAY;IACZ,iBAAiB;CACT,CAAC;AAIX,sHAAsH;AACtH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,IAAI,CAAgB;IACpB,IAAI,CAAU;IAEvB,YAAY,OAAe,EAAE,IAAa;QACxC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,iBAAiB,GAA2C;IAChE,YAAY,EAAE,MAAM;IACpB,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,MAAM;IACnB,YAAY,EAAE,OAAO;IACrB,iBAAiB,EAAE,MAAM;CAC1B,CAAC;AAEF,oBAAoB;AACpB;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAiB;IAClD,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACrF,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,IACE,KAAK,CAAC,MAAM,IAAI,CAAC;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EACjB,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IACE,KAAK,CAAC,MAAM,IAAI,CAAC;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EACjB,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IACE,KAAK,CAAC,MAAM,IAAI,EAAE;QAClB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI;QAClB,KAAK,CAAC,EAAE,CAAC,KAAK,IAAI,EAClB,CAAC;QACD,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,IACE,KAAK,CAAC,MAAM,IAAI,CAAC;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;QACjB,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EACjB,CAAC;QACD,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AACD,kBAAkB;AAElB,sBAAsB;AACtB,SAAS,4BAA4B,CAAC,QAAiB;IACrD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1D,OAAO,IAAI,IAAI,SAAS,CAAC;AAC3B,CAAC;AAED,SAAS,eAAe,CAAC,GAAW,EAAE,IAA4B;IAChE,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;QAC1D,IAAI,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,CAAC;QAC/B,CAAC;QACD,OAAO,WAAW,SAAS,EAAE,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,WAAW,SAAS,EAAE,CAAC;IAChC,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CACtB,KAAiB,EACjB,mBAA4B;IAE5B,MAAM,OAAO,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,QAAQ,GAAG,4BAA4B,CAAC,mBAAmB,CAAC,CAAC;IACnE,IAAI,QAAQ,IAAK,0BAAgD,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrF,OAAO,QAAkC,CAAC;IAC5C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AACD,oBAAoB;AAEpB,2CAA2C;AAC3C,iFAAiF;AACjF,oFAAoF;AACpF,sEAAsE;AACtE,gDAAgD;AAChD,4CAA4C;AAC5C,yCAAyC;AACzC,MAAM,UAAU,wBAAwB,CACtC,KAAiB,EACjB,MAAwE;IAExE,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,uBAAuB,CAAC;IAC5D,IAAI,KAAK,CAAC,UAAU,GAAG,QAAQ,EAAE,CAAC;QAChC,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,0BAA0B,QAAQ,QAAQ,CAAC,CAAC;IAClF,CAAC;IACD,MAAM,IAAI,GAAG,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAChE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,MAAM,GACV,kBAAkB,CAAC,KAAK,CAAC;YACzB,4BAA4B,CAAC,MAAM,CAAC,mBAAmB,CAAC;YACxD,SAAS,CAAC;QACZ,MAAM,IAAI,aAAa,CACrB,2BAA2B,MAAM,EAAE,EACnC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAC1C,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrD,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,IAAI;QACJ,GAAG,EAAE,QAAQ,IAAI,WAAW,MAAM,EAAE;QACpC,QAAQ,EAAE,eAAe,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC;KAC5C,CAAC;AACJ,CAAC;AAED,sCAAsC;AACtC,sGAAsG;AACtG,6FAA6F;AAC7F,gCAAgC;AAChC,yDAAyD;AACzD,sBAAsB;AACtB,oCAAoC;AACpC,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,KAAkF,EAClF,SAAqB;IAErB,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,uBAAuB,CAAC;IAC3D,MAAM,QAAQ,GAAG,MAAM,cAAc,CACnC;QACE,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,0BAA0B;QACxD,QAAQ;QACR,KAAK,EAAE,KAAK,CAAC,KAAK;KACnB,EACD,SAAS,CACV,CAAC;IACF,OAAO,wBAAwB,CAAC,QAAQ,CAAC,KAAK,EAAE;QAC9C,GAAG,EAAE,QAAQ,CAAC,QAAQ;QACtB,mBAAmB,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,SAAS;QACtE,QAAQ;KACT,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -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":"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"}
|
|
@@ -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>;
|