@wix/mcp 1.0.92 → 1.0.93
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/build/bin-standalone.js +38 -20
- package/build/cjs/index.cjs +257 -23
- package/build/cjs/toolkit.cjs +257 -23
- package/build/dts/code-mode/attachments.d.ts +37 -0
- package/build/dts/code-mode/attachments.js +218 -0
- package/build/dts/code-mode/index.js +36 -3
- package/build/dts/config/default-config.js +13 -6
- package/build/dts/config/param-descriptions.js +3 -3
- package/build/dts/docs/docs.js +14 -8
- package/build/dts/docs/semanticSearch.d.ts +2 -1
- package/build/dts/docs/semanticSearch.js +12 -5
- package/build/esm/index.js +257 -23
- package/build/esm/toolkit.js +257 -23
- package/package.json +2 -2
package/build/cjs/toolkit.cjs
CHANGED
|
@@ -16289,9 +16289,12 @@ var runSemanticSearch = async (toolName, toolParams, maxResults = 20, rerank = f
|
|
|
16289
16289
|
);
|
|
16290
16290
|
return data?.results;
|
|
16291
16291
|
};
|
|
16292
|
-
var runPlatformizedSemanticSearch = async (toolName, searchTerm, maxResults = 20, linesInEachResult) => {
|
|
16292
|
+
var runPlatformizedSemanticSearch = async (toolName, searchTerm, maxResults = 20, linesInEachResult, extraDocumentTypes) => {
|
|
16293
16293
|
const startTime = Date.now();
|
|
16294
|
-
|
|
16294
|
+
const documentTypes = extraDocumentTypes?.length ? [toolName, ...extraDocumentTypes] : void 0;
|
|
16295
|
+
logger.log(
|
|
16296
|
+
`[SemanticSearch/v2] Tool: ${documentTypes ? documentTypes.join("+") : toolName}, Query: "${searchTerm}"`
|
|
16297
|
+
);
|
|
16295
16298
|
const response = await fetch(
|
|
16296
16299
|
"https://www.wixapis.com/mcp-docs-search/v1/docs/search/markdown",
|
|
16297
16300
|
{
|
|
@@ -16302,7 +16305,7 @@ var runPlatformizedSemanticSearch = async (toolName, searchTerm, maxResults = 20
|
|
|
16302
16305
|
},
|
|
16303
16306
|
body: JSON.stringify({
|
|
16304
16307
|
search_term: searchTerm,
|
|
16305
|
-
document_type: toolName,
|
|
16308
|
+
...documentTypes ? { document_types: documentTypes } : { document_type: toolName },
|
|
16306
16309
|
maximum_results: maxResults,
|
|
16307
16310
|
lines_in_each_result: linesInEachResult
|
|
16308
16311
|
})
|
|
@@ -16331,14 +16334,16 @@ var runSemanticSearchAndFormat = async ({
|
|
|
16331
16334
|
maxResults = DEFAULT_MAX_RESULTS,
|
|
16332
16335
|
rerank,
|
|
16333
16336
|
linesInEachResult,
|
|
16334
|
-
usePlatformizedSearch = true
|
|
16337
|
+
usePlatformizedSearch = true,
|
|
16338
|
+
extraDocumentTypes
|
|
16335
16339
|
}) => {
|
|
16336
16340
|
if (usePlatformizedSearch) {
|
|
16337
16341
|
return runPlatformizedSemanticSearch(
|
|
16338
16342
|
toolName,
|
|
16339
16343
|
toolParams.searchTerm,
|
|
16340
16344
|
maxResults,
|
|
16341
|
-
linesInEachResult
|
|
16345
|
+
linesInEachResult,
|
|
16346
|
+
extraDocumentTypes
|
|
16342
16347
|
);
|
|
16343
16348
|
} else {
|
|
16344
16349
|
const results = await runSemanticSearch(
|
|
@@ -17883,13 +17888,14 @@ var ACCOUNT_SITE_EXECUTE_SCOPE = dedent_default`
|
|
|
17883
17888
|
unzip(input: string | Uint8Array): Promise<Array<{ path: string; bytes: Uint8Array; text(): string }>>;
|
|
17884
17889
|
};
|
|
17885
17890
|
declare const siteId: string | undefined;
|
|
17886
|
-
// Files from the ExecuteWixAPI \`files\` param
|
|
17887
|
-
//
|
|
17888
|
-
//
|
|
17891
|
+
// Files from the ExecuteWixAPI \`files\` param, followed by the resolved
|
|
17892
|
+
// \`attachments\`. Text entries have \`content\`; an entry tagged
|
|
17893
|
+
// \`=== FILE: <path> base64 ===\` — and every attachment, path = its file name —
|
|
17894
|
+
// has encoding:'base64' and base64 \`content\`.
|
|
17889
17895
|
declare const files: Array<{ path: string; content: string; encoding?: "base64" }>;
|
|
17890
17896
|
\`\`\`
|
|
17891
17897
|
|
|
17892
|
-
FILE UPLOADS:
|
|
17898
|
+
FILE UPLOADS: files never go inline in \`code\`; two params feed the \`files\` global. \`attachments\` takes files attached in the chat or created in your file sandbox, of any type and size up to 10 MB per call (a zip of a whole site, HTML, images, PDFs): pass the files themselves, all in one call, and the platform resolves each into \`{ download_url, file_id, file_name?, mime_type? }\` — the bytes are fetched for you and arrive as base64 entries named by file name. The \`files\` param takes content you have as text here: text goes raw; a small binary (icon, logo, font) rides as a \`base64\`-tagged entry — large images/video are referenced by URL (\`<img src="https://...">\`), not bundled. \`wix.multipart()\` turns the whole set into one upload body (bytes, so binary is safe):
|
|
17893
17899
|
\`\`\`javascript
|
|
17894
17900
|
// files param:
|
|
17895
17901
|
// === FILE: index.html ===
|
|
@@ -17904,6 +17910,12 @@ var ACCOUNT_SITE_EXECUTE_SCOPE = dedent_default`
|
|
|
17904
17910
|
return res.data;
|
|
17905
17911
|
}
|
|
17906
17912
|
\`\`\`
|
|
17913
|
+
A site zip passed through \`attachments\` is one base64 entry; unzip it and upload the entries:
|
|
17914
|
+
\`\`\`javascript
|
|
17915
|
+
// attachments: [site.zip] → files = [{ path: "site.zip", content: "<base64>", encoding: "base64" }]
|
|
17916
|
+
const entries = await wix.unzip(files[0].content); // [{ path, bytes, text() }]
|
|
17917
|
+
const mp = wix.multipart(entries);
|
|
17918
|
+
\`\`\`
|
|
17907
17919
|
DOWNLOAD + EDIT + RE-UPLOAD: fetch the zip as base64, \`wix.unzip()\` it, edit text via \`entry.text()\`, keep binary as bytes, and hand the entries back to \`wix.multipart()\`:
|
|
17908
17920
|
\`\`\`javascript
|
|
17909
17921
|
const r = await wix.request({ scope: "account", method: "GET", responseType: "base64", url: zipUrl });
|
|
@@ -18108,12 +18120,12 @@ function buildToolDescriptions(includeReadme, includeImageUploadGuidance = true)
|
|
|
18108
18120
|
NEVER call this tool with a missing, empty, or guessed siteId — ask first instead.
|
|
18109
18121
|
|
|
18110
18122
|
Parameters — provide image input via image and/or imageUrls, OR imageBase64:
|
|
18111
|
-
• image (array): chat file ATTACHMENTS. Each item is an object with download_url and file_id (both required), plus optional file_name and mime_type. Pass ALL attachments in one call.
|
|
18123
|
+
• image (array): chat file ATTACHMENTS — files the user attached, or files you created in your own file sandbox. Each item is an object with download_url and file_id (both required), plus optional file_name and mime_type. Pass ALL attachments in one call.
|
|
18112
18124
|
• imageUrls (array): plain public image URLs the user pasted or other tools produced (no file_id). Pass ALL URLs in one call. Can be combined with image.
|
|
18113
18125
|
• imageBase64 (string): base64-encoded image + mimeType. One image at a time. Do NOT combine with image/imageUrls.
|
|
18114
18126
|
|
|
18115
18127
|
Delivering the bytes — this is where uploads most often fail:
|
|
18116
|
-
•
|
|
18128
|
+
• Pass a file as a file, in image: the platform resolves it into download_url and file_id before it reaches this tool — this includes files you created in your sandbox. This server does not share your filesystem, so a bare path string (e.g. /mnt/..., /home/user/..., /Users/...) is not a file. Without a file to pass, use a public http(s) URL (imageUrls) or the complete base64 (imageBase64).
|
|
18117
18129
|
• imageBase64 must be the WHOLE file, not truncated. For large images prefer imageUrls, since long base64 is easily cut off and will be rejected as unreadable.
|
|
18118
18130
|
`,
|
|
18119
18131
|
SupportAndFeedback: dedent_default`
|
|
@@ -19365,7 +19377,7 @@ var paramDescriptions = {
|
|
|
19365
19377
|
},
|
|
19366
19378
|
SearchWixRESTDocumentation: {
|
|
19367
19379
|
searchTerm: `The search term to look up in the Wix REST API Documentation \u2014 a natural-language description of the endpoint, resource, or action you need across any Wix domain (Stores, eCommerce, Bookings, CRM, Members, CMS, Events, Blog, Forms, Media, site settings, etc.), e.g. "create a catalog item with inventory", "book a service", "update data collection items". Match the wording to how many entities you will act on: a plural term ("update products") surfaces the resource's bulk methods, which a singular term ("update a product") ranks lower or leaves out. Results are ranked by relevance, so describe the goal rather than guessing an exact API name.`,
|
|
19368
|
-
maxResults: "The maximum number of results to return, default
|
|
19380
|
+
maxResults: "The maximum number of results to return (1\u201317, default 17). Results mix REST API documentation with matching recipes and skills.",
|
|
19369
19381
|
reason: "One sentence describing the original user request and the task you are trying to accomplish with this search."
|
|
19370
19382
|
},
|
|
19371
19383
|
WixBusinessFlowsDocumentation: {
|
|
@@ -19386,7 +19398,7 @@ var paramDescriptions = {
|
|
|
19386
19398
|
},
|
|
19387
19399
|
SearchWixHeadlessDocumentation: {
|
|
19388
19400
|
searchTerm: "The search term to search for in the Headless Documentation",
|
|
19389
|
-
maxResults: "The maximum number of results to return, default
|
|
19401
|
+
maxResults: "The maximum number of results to return (1\u201317, default 17). Results mix Headless documentation with matching recipes and skills."
|
|
19390
19402
|
},
|
|
19391
19403
|
SearchWixVeloDocumentation: {
|
|
19392
19404
|
searchTerm: "The search term to search for in the Velo Documentation",
|
|
@@ -19414,7 +19426,7 @@ var paramDescriptions = {
|
|
|
19414
19426
|
},
|
|
19415
19427
|
UploadImageToWixSite: {
|
|
19416
19428
|
siteId: "The ID (UUID) of the Wix site to upload to. REQUIRED. If the user has not clearly specified which site, ASK them which site to upload to (or use ListWixSites to help them pick) BEFORE calling this tool. NEVER call this tool with a missing, empty, placeholder, or guessed siteId \u2014 ask first instead.",
|
|
19417
|
-
image: "Array of file ATTACHMENTS the user uploaded in the chat. Each item requires download_url and file_id, and may optionally include file_name and mime_type \u2014
|
|
19429
|
+
image: "Array of file ATTACHMENTS: files the user uploaded in the chat, or files you created in your own file sandbox. Each item requires download_url and file_id, and may optionally include file_name and mime_type \u2014 the platform resolves a file passed here into these fields automatically, so just include the files. For plain image URLs the user pasted, use imageUrls instead. ALWAYS pass ALL attachments together in a single call \u2014 NEVER call this tool once per image. Do NOT use together with imageBase64.",
|
|
19418
19430
|
imageUrls: "Array of publicly accessible image URLs (e.g. links the user pasted or URLs produced by other tools). Use this for plain URLs that are NOT chat attachments \u2014 no file_id is needed. ALWAYS pass ALL URLs together in a single call. Can be combined with image; do NOT use together with imageBase64.",
|
|
19419
19431
|
imageBase64: 'Base64-encoded image data. Use when the client can read a file and encode it as base64. May include a data URL prefix (e.g. "data:image/jpeg;base64,...") or be raw base64. Do NOT use together with image.',
|
|
19420
19432
|
mimeType: 'MIME type of the image (e.g. "image/jpeg", "image/png", "image/webp"). Required when imageBase64 does not include a data URL prefix.',
|
|
@@ -20073,7 +20085,7 @@ var addDocsTools = (server, allowedTools = [
|
|
|
20073
20085
|
const d = desc("SearchWixRESTDocumentation");
|
|
20074
20086
|
return {
|
|
20075
20087
|
searchTerm: external_exports.string().describe(d.searchTerm),
|
|
20076
|
-
maxResults: external_exports.number().describe(d.maxResults).min(1).max(
|
|
20088
|
+
maxResults: external_exports.number().describe(d.maxResults).min(1).max(17).optional().default(17),
|
|
20077
20089
|
reason: external_exports.string().describe(d.reason)
|
|
20078
20090
|
};
|
|
20079
20091
|
})(),
|
|
@@ -20088,9 +20100,12 @@ var addDocsTools = (server, allowedTools = [
|
|
|
20088
20100
|
toolParams: {
|
|
20089
20101
|
searchTerm
|
|
20090
20102
|
},
|
|
20091
|
-
maxResults: Math.max(1, Math.min(maxResults ??
|
|
20103
|
+
maxResults: Math.max(1, Math.min(maxResults ?? 17, 17)),
|
|
20092
20104
|
linesInEachResult: 30,
|
|
20093
|
-
usePlatformizedSearch
|
|
20105
|
+
usePlatformizedSearch,
|
|
20106
|
+
// Merge recipes/skills into the REST ranking — they live in a
|
|
20107
|
+
// separate corpus the REST document_type doesn't cover on its own.
|
|
20108
|
+
extraDocumentTypes: ["SKILLS"]
|
|
20094
20109
|
});
|
|
20095
20110
|
const grounding = result.includes(QUERY_CAPABILITY_MARKER) ? [
|
|
20096
20111
|
REST_SEARCH_API_GROUNDING_REMINDER,
|
|
@@ -20353,7 +20368,7 @@ var addDocsTools = (server, allowedTools = [
|
|
|
20353
20368
|
const d = desc("SearchWixHeadlessDocumentation");
|
|
20354
20369
|
return {
|
|
20355
20370
|
searchTerm: external_exports.string().describe(d.searchTerm),
|
|
20356
|
-
maxResults: external_exports.number().describe(d.maxResults).min(1).max(
|
|
20371
|
+
maxResults: external_exports.number().describe(d.maxResults).min(1).max(17).optional().default(17)
|
|
20357
20372
|
};
|
|
20358
20373
|
})(),
|
|
20359
20374
|
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
|
|
@@ -20365,8 +20380,11 @@ var addDocsTools = (server, allowedTools = [
|
|
|
20365
20380
|
toolParams: {
|
|
20366
20381
|
searchTerm
|
|
20367
20382
|
},
|
|
20368
|
-
maxResults: Math.max(1, Math.min(maxResults ??
|
|
20369
|
-
usePlatformizedSearch
|
|
20383
|
+
maxResults: Math.max(1, Math.min(maxResults ?? 17, 17)),
|
|
20384
|
+
usePlatformizedSearch,
|
|
20385
|
+
// Merge recipes/skills into the headless ranking — same separate
|
|
20386
|
+
// corpus the WIX_HEADLESS document_type doesn't cover on its own.
|
|
20387
|
+
extraDocumentTypes: ["SKILLS"]
|
|
20370
20388
|
});
|
|
20371
20389
|
return {
|
|
20372
20390
|
content: [
|
|
@@ -22286,6 +22304,189 @@ ${text.slice(0, 2e3)}`
|
|
|
22286
22304
|
);
|
|
22287
22305
|
}
|
|
22288
22306
|
|
|
22307
|
+
// src/code-mode/attachments.ts
|
|
22308
|
+
var MAX_ATTACHMENTS_BYTES = 10 * 1024 * 1024;
|
|
22309
|
+
var MAX_REDIRECTS = 4;
|
|
22310
|
+
var OAI_USERCONTENT_HOST = /^[a-z0-9-]+\.oaiusercontent\.com$/;
|
|
22311
|
+
var OAI_BLOB_ACCOUNTS = new Set(
|
|
22312
|
+
[
|
|
22313
|
+
"australiaeast",
|
|
22314
|
+
"brazilsouth",
|
|
22315
|
+
"cacentral",
|
|
22316
|
+
"centralindia",
|
|
22317
|
+
"centralus",
|
|
22318
|
+
"centralusdr",
|
|
22319
|
+
"denmarkeast",
|
|
22320
|
+
"eastus",
|
|
22321
|
+
"eastus2",
|
|
22322
|
+
"indiasocentral",
|
|
22323
|
+
"italynorth",
|
|
22324
|
+
"japaneast",
|
|
22325
|
+
"koreacentral",
|
|
22326
|
+
"northcentralus",
|
|
22327
|
+
"northeu",
|
|
22328
|
+
"nznorth",
|
|
22329
|
+
"polandcentral",
|
|
22330
|
+
"seasia",
|
|
22331
|
+
"southcentralus",
|
|
22332
|
+
"southeastus3",
|
|
22333
|
+
"ukwest",
|
|
22334
|
+
"westcentralus",
|
|
22335
|
+
"westus",
|
|
22336
|
+
"westus2",
|
|
22337
|
+
"westus3"
|
|
22338
|
+
].map((region) => `oaisdmntpr${region}.blob.core.windows.net`)
|
|
22339
|
+
);
|
|
22340
|
+
function isAllowedAttachmentHost(hostname) {
|
|
22341
|
+
const h = hostname.toLowerCase();
|
|
22342
|
+
return OAI_USERCONTENT_HOST.test(h) || OAI_BLOB_ACCOUNTS.has(h);
|
|
22343
|
+
}
|
|
22344
|
+
function checkAttachmentUrl(url) {
|
|
22345
|
+
if (url.protocol !== "https:") return "is not an https URL";
|
|
22346
|
+
if (url.port) return "uses a non-default port";
|
|
22347
|
+
if (!isAllowedAttachmentHost(url.hostname)) {
|
|
22348
|
+
return `host "${url.hostname}" is not a ChatGPT file host`;
|
|
22349
|
+
}
|
|
22350
|
+
return void 0;
|
|
22351
|
+
}
|
|
22352
|
+
var AttachmentError = class extends Error {
|
|
22353
|
+
};
|
|
22354
|
+
function attachmentPath(a, url) {
|
|
22355
|
+
let fromUrl = "";
|
|
22356
|
+
try {
|
|
22357
|
+
fromUrl = decodeURIComponent(
|
|
22358
|
+
url.pathname.split("/").filter(Boolean).pop() ?? ""
|
|
22359
|
+
);
|
|
22360
|
+
} catch {
|
|
22361
|
+
fromUrl = "";
|
|
22362
|
+
}
|
|
22363
|
+
const raw = (a.file_name?.trim() || fromUrl || a.file_id).replace(/\\/g, "/");
|
|
22364
|
+
const segments = raw.split("/").filter((s) => s && s !== "." && s !== "..");
|
|
22365
|
+
return segments.join("/") || a.file_id;
|
|
22366
|
+
}
|
|
22367
|
+
function toBase64(bytes) {
|
|
22368
|
+
let binary = "";
|
|
22369
|
+
const chunk = 32768;
|
|
22370
|
+
for (let i = 0; i < bytes.length; i += chunk) {
|
|
22371
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + chunk));
|
|
22372
|
+
}
|
|
22373
|
+
return btoa(binary);
|
|
22374
|
+
}
|
|
22375
|
+
async function fetchAllowed(start, fetchImpl, label) {
|
|
22376
|
+
let url = start;
|
|
22377
|
+
for (let hop = 0; ; hop++) {
|
|
22378
|
+
const res = await fetchImpl(url.toString(), { redirect: "manual" });
|
|
22379
|
+
const location = res.headers.get("location");
|
|
22380
|
+
const isRedirect = res.status >= 300 && res.status < 400 && location;
|
|
22381
|
+
if (!isRedirect) return res;
|
|
22382
|
+
await res.body?.cancel().catch(() => void 0);
|
|
22383
|
+
if (hop >= MAX_REDIRECTS) {
|
|
22384
|
+
throw new AttachmentError(`${label}: too many redirects.`);
|
|
22385
|
+
}
|
|
22386
|
+
let next;
|
|
22387
|
+
try {
|
|
22388
|
+
next = new URL(location, url);
|
|
22389
|
+
} catch {
|
|
22390
|
+
throw new AttachmentError(`${label}: redirect to an invalid URL.`);
|
|
22391
|
+
}
|
|
22392
|
+
const problem = checkAttachmentUrl(next);
|
|
22393
|
+
if (problem) {
|
|
22394
|
+
throw new AttachmentError(
|
|
22395
|
+
`${label}: the download redirected to a URL that ${problem}; refused.`
|
|
22396
|
+
);
|
|
22397
|
+
}
|
|
22398
|
+
url = next;
|
|
22399
|
+
}
|
|
22400
|
+
}
|
|
22401
|
+
async function readWithin(res, budget, overBudget) {
|
|
22402
|
+
const declared = Number(res.headers.get("content-length") ?? 0);
|
|
22403
|
+
if (declared > budget) throw overBudget();
|
|
22404
|
+
if (!res.body) {
|
|
22405
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
22406
|
+
if (bytes.byteLength > budget) throw overBudget();
|
|
22407
|
+
return bytes;
|
|
22408
|
+
}
|
|
22409
|
+
const reader = res.body.getReader();
|
|
22410
|
+
const chunks = [];
|
|
22411
|
+
let total = 0;
|
|
22412
|
+
for (; ; ) {
|
|
22413
|
+
const { done, value } = await reader.read();
|
|
22414
|
+
if (done) break;
|
|
22415
|
+
total += value.byteLength;
|
|
22416
|
+
if (total > budget) {
|
|
22417
|
+
await reader.cancel().catch(() => void 0);
|
|
22418
|
+
throw overBudget();
|
|
22419
|
+
}
|
|
22420
|
+
chunks.push(value);
|
|
22421
|
+
}
|
|
22422
|
+
const out = new Uint8Array(total);
|
|
22423
|
+
let offset = 0;
|
|
22424
|
+
for (const c of chunks) {
|
|
22425
|
+
out.set(c, offset);
|
|
22426
|
+
offset += c.byteLength;
|
|
22427
|
+
}
|
|
22428
|
+
return out;
|
|
22429
|
+
}
|
|
22430
|
+
async function resolveAttachments(attachments, fetchImpl = fetch) {
|
|
22431
|
+
if (!Array.isArray(attachments) || attachments.length === 0) return [];
|
|
22432
|
+
const items = [];
|
|
22433
|
+
attachments.forEach((raw, i) => {
|
|
22434
|
+
const a = typeof raw === "object" && raw;
|
|
22435
|
+
const downloadUrl = a && typeof a.download_url === "string" ? a.download_url : "";
|
|
22436
|
+
let url;
|
|
22437
|
+
try {
|
|
22438
|
+
url = /^https?:\/\//i.test(downloadUrl) ? new URL(downloadUrl) : void 0;
|
|
22439
|
+
} catch {
|
|
22440
|
+
url = void 0;
|
|
22441
|
+
}
|
|
22442
|
+
if (!a || !url) {
|
|
22443
|
+
throw new AttachmentError(
|
|
22444
|
+
`attachments[${i}] was not resolved to a download URL (got ${JSON.stringify(
|
|
22445
|
+
typeof raw === "string" ? raw : (a && a.download_url) ?? raw
|
|
22446
|
+
)}). The platform did not hydrate this attachment; retry once, and if it still arrives like this put the file in the \`files\` bundle instead (\`=== FILE: <path> base64 ===\` for binary).`
|
|
22447
|
+
);
|
|
22448
|
+
}
|
|
22449
|
+
const problem = checkAttachmentUrl(url);
|
|
22450
|
+
if (problem) {
|
|
22451
|
+
throw new AttachmentError(
|
|
22452
|
+
`attachments[${i}].download_url ${problem}. Only platform-resolved attachments are accepted here; for any other URL fetch it in \`code\` via wix.request or put the bytes in the \`files\` bundle.`
|
|
22453
|
+
);
|
|
22454
|
+
}
|
|
22455
|
+
items.push({ a, url });
|
|
22456
|
+
});
|
|
22457
|
+
let remaining = MAX_ATTACHMENTS_BYTES;
|
|
22458
|
+
const out = [];
|
|
22459
|
+
for (const [i, { a, url }] of items.entries()) {
|
|
22460
|
+
const path = attachmentPath(a, url);
|
|
22461
|
+
const label = `attachments[${i}] (${path})`;
|
|
22462
|
+
let res;
|
|
22463
|
+
try {
|
|
22464
|
+
res = await fetchAllowed(url, fetchImpl, label);
|
|
22465
|
+
} catch (e) {
|
|
22466
|
+
if (e instanceof AttachmentError) throw e;
|
|
22467
|
+
throw new AttachmentError(
|
|
22468
|
+
`${label}: download failed (${e.message}).`
|
|
22469
|
+
);
|
|
22470
|
+
}
|
|
22471
|
+
if (!res.ok) {
|
|
22472
|
+
await res.body?.cancel().catch(() => void 0);
|
|
22473
|
+
throw new AttachmentError(
|
|
22474
|
+
`${label}: download returned HTTP ${res.status}. The download_url may have expired; attach the file again.`
|
|
22475
|
+
);
|
|
22476
|
+
}
|
|
22477
|
+
const bytes = await readWithin(
|
|
22478
|
+
res,
|
|
22479
|
+
remaining,
|
|
22480
|
+
() => new AttachmentError(
|
|
22481
|
+
`${label} pushes the attachments past ${MAX_ATTACHMENTS_BYTES} bytes in total for this call; split the upload across calls.`
|
|
22482
|
+
)
|
|
22483
|
+
);
|
|
22484
|
+
remaining -= bytes.byteLength;
|
|
22485
|
+
out.push({ path, content: toBase64(bytes), encoding: "base64" });
|
|
22486
|
+
}
|
|
22487
|
+
return out;
|
|
22488
|
+
}
|
|
22489
|
+
|
|
22289
22490
|
// src/code-mode/validation.ts
|
|
22290
22491
|
var EXECUTE_FUNCTION_EXPRESSION_HINT = 'ExecuteWixAPI code must be a function expression, not a script body. Pass code like: async () => { const response = await wix.request({ scope: "site", method: "GET", url: "https://www.wixapis.com/..." }); return response.data; }. Do not write top-level const/await/return outside the function and do not invoke the function yourself.';
|
|
22291
22492
|
function validateExecuteCode(code) {
|
|
@@ -22497,7 +22698,7 @@ function addExecuteTool(server, options) {
|
|
|
22497
22698
|
} = options;
|
|
22498
22699
|
const executeUrl = `${codeModeBaseUrl}/api/code-mode/execute`;
|
|
22499
22700
|
const d = desc("ExecuteWixAPI");
|
|
22500
|
-
server.tool(
|
|
22701
|
+
const registered = server.tool(
|
|
22501
22702
|
EXECUTE_TOOL_NAME,
|
|
22502
22703
|
toolDescriptions?.[EXECUTE_TOOL_NAME] ?? defaultToolDescriptions.ExecuteWixAPI,
|
|
22503
22704
|
{
|
|
@@ -22526,6 +22727,20 @@ function addExecuteTool(server, options) {
|
|
|
22526
22727
|
'Use base64 entries for small assets (icons, logos, fonts) and for files you downloaded and are re-uploading; large images/video go in by URL (`<img src="https://...">`), not in the bundle. A file containing a line exactly like the delimiter is not supported.'
|
|
22527
22728
|
].join(" ")
|
|
22528
22729
|
),
|
|
22730
|
+
// ChatGPT file attachments (`openai/fileParams`). Item shape must match
|
|
22731
|
+
// OpenAI's file schema: download_url + file_id required, the rest optional.
|
|
22732
|
+
// Declaring it is what makes the platform hand us a download URL instead
|
|
22733
|
+
// of a sandbox path. Resolved host-side into base64 `files` entries.
|
|
22734
|
+
attachments: external_exports.array(
|
|
22735
|
+
external_exports.object({
|
|
22736
|
+
download_url: external_exports.string(),
|
|
22737
|
+
file_id: external_exports.string(),
|
|
22738
|
+
file_name: external_exports.string().optional(),
|
|
22739
|
+
mime_type: external_exports.string().optional()
|
|
22740
|
+
})
|
|
22741
|
+
).optional().describe(
|
|
22742
|
+
'Files attached in this chat, or files you created in your own file sandbox (any type: a zip of a site, HTML, images, PDFs). Pass the files themselves and the platform resolves each into { download_url, file_id, file_name?, mime_type? }; the bytes are fetched here and appended to the `files` global as { path, content, encoding: "base64" } entries (path = file_name), so `wix.multipart()` and `wix.unzip()` work on them unchanged. Prefer this over base64 in `files` whenever you have a file handle. Up to 10 MB per call.'
|
|
22743
|
+
),
|
|
22529
22744
|
// Visitor mode takes an agent-supplied token and pins the site; account/site
|
|
22530
22745
|
// mode lets the agent pick the site.
|
|
22531
22746
|
...visitor ? {
|
|
@@ -22540,7 +22755,15 @@ function addExecuteTool(server, options) {
|
|
|
22540
22755
|
},
|
|
22541
22756
|
{ readOnlyHint: false, destructiveHint: true, openWorldHint: false },
|
|
22542
22757
|
async (rawArgs, extra) => {
|
|
22543
|
-
const {
|
|
22758
|
+
const {
|
|
22759
|
+
code,
|
|
22760
|
+
reason,
|
|
22761
|
+
hasMutations,
|
|
22762
|
+
sourceDocUrls,
|
|
22763
|
+
visitorToken,
|
|
22764
|
+
files,
|
|
22765
|
+
attachments
|
|
22766
|
+
} = rawArgs;
|
|
22544
22767
|
const siteId = visitor ? visitor.siteId : rawArgs.siteId;
|
|
22545
22768
|
logger.log(
|
|
22546
22769
|
`[ExecuteWixAPI]${visitor ? " (visitor)" : ""} Executing code (${code.length} chars), siteId=${siteId ?? "none"}, hasMutations=${hasMutations}, sourceDocUrls=${JSON.stringify(sourceDocUrls)}, reason="${reason}"`
|
|
@@ -22552,6 +22775,13 @@ function addExecuteTool(server, options) {
|
|
|
22552
22775
|
);
|
|
22553
22776
|
return executeTextResult(validation.error);
|
|
22554
22777
|
}
|
|
22778
|
+
let attachmentFiles = [];
|
|
22779
|
+
try {
|
|
22780
|
+
attachmentFiles = await resolveAttachments(attachments);
|
|
22781
|
+
} catch (e) {
|
|
22782
|
+
if (e instanceof AttachmentError) return executeErrorResult(e.message);
|
|
22783
|
+
throw e;
|
|
22784
|
+
}
|
|
22555
22785
|
const accountHeaders = await authStrategy?.getAccountAuthHeaders();
|
|
22556
22786
|
const siteAuthContext = !visitor && authStrategy?.getSiteAuthContext ? await authStrategy.getSiteAuthContext() : void 0;
|
|
22557
22787
|
let siteHeaders;
|
|
@@ -22586,7 +22816,8 @@ function addExecuteTool(server, options) {
|
|
|
22586
22816
|
accountToken: visitor ? visitorToken : accountHeaders?.Authorization,
|
|
22587
22817
|
accountId: accountHeaders?.["wix-account-id"],
|
|
22588
22818
|
siteAuthContext,
|
|
22589
|
-
...files ? { files } : {}
|
|
22819
|
+
...files ? { files } : {},
|
|
22820
|
+
...attachmentFiles.length ? { attachmentFiles } : {}
|
|
22590
22821
|
},
|
|
22591
22822
|
visitor ? visitorToken : accountHeaders?.Authorization ?? siteHeaders?.Authorization,
|
|
22592
22823
|
codeModeFetch
|
|
@@ -22617,6 +22848,9 @@ function addExecuteTool(server, options) {
|
|
|
22617
22848
|
}
|
|
22618
22849
|
}
|
|
22619
22850
|
);
|
|
22851
|
+
registered?.update?.({
|
|
22852
|
+
_meta: { ...registered._meta, "openai/fileParams": ["attachments"] }
|
|
22853
|
+
});
|
|
22620
22854
|
}
|
|
22621
22855
|
|
|
22622
22856
|
// src/infra/panorama.ts
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ChatGPT file attachments for ExecuteWixAPI (`openai/fileParams`).
|
|
3
|
+
*
|
|
4
|
+
* ChatGPT resolves a file the user attached — or one the model wrote in its
|
|
5
|
+
* own sandbox — into `{ download_url, file_id, file_name?, mime_type? }` for a
|
|
6
|
+
* param the tool lists under `_meta["openai/fileParams"]`. The bytes never go
|
|
7
|
+
* through the model. We fetch each `download_url` host-side and hand the
|
|
8
|
+
* runtime ready-made base64 file entries, the same shape the `files` bundle
|
|
9
|
+
* parses into, so `files`, `wix.multipart()` and `wix.unzip()` are unchanged.
|
|
10
|
+
*
|
|
11
|
+
* This is additive: clients without the extension never populate the param
|
|
12
|
+
* and keep using the `files` bundle (text + base64 sections).
|
|
13
|
+
*/
|
|
14
|
+
export interface ExecuteAttachment {
|
|
15
|
+
download_url: string;
|
|
16
|
+
file_id: string;
|
|
17
|
+
file_name?: string;
|
|
18
|
+
mime_type?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Same shape as the runtime's BundledFile with encoding fixed to base64. */
|
|
21
|
+
export interface AttachmentFile {
|
|
22
|
+
path: string;
|
|
23
|
+
content: string;
|
|
24
|
+
encoding: 'base64';
|
|
25
|
+
}
|
|
26
|
+
export declare const MAX_ATTACHMENTS_BYTES: number;
|
|
27
|
+
export declare function isAllowedAttachmentHost(hostname: string): boolean;
|
|
28
|
+
export declare class AttachmentError extends Error {
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Fetch every attachment and return base64 file entries for the runtime.
|
|
32
|
+
* Throws AttachmentError with an agent-facing message: an unresolved item
|
|
33
|
+
* (ChatGPT passed a sandbox path or a bare id instead of a URL), a host we
|
|
34
|
+
* don't trust, a failed download, or more bytes than MAX_ATTACHMENTS_BYTES.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveAttachments(attachments: unknown, fetchImpl?: typeof fetch): Promise<AttachmentFile[]>;
|
|
37
|
+
//# sourceMappingURL=attachments.d.ts.map
|