@orangecatai/adgen-canvas 0.0.32 → 0.0.33
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/dist/dev/{chunk-VL47Q2RH.js → chunk-BSCN3CPW.js} +2 -2
- package/dist/dev/{chunk-OWDDSUUQ.js → chunk-O66HSY73.js} +3 -3
- package/dist/dev/data/{image-5Y3GORNT.js → image-ADAEIYVZ.js} +3 -3
- package/dist/dev/index.css +3 -0
- package/dist/dev/index.css.map +2 -2
- package/dist/dev/index.js +206 -95
- package/dist/dev/index.js.map +4 -4
- package/dist/dev/subset-shared.chunk.js +1 -1
- package/dist/dev/subset-worker.chunk.js +1 -1
- package/dist/prod/{chunk-452N23ZE.js → chunk-DB27YYNM.js} +1 -1
- package/dist/prod/{chunk-AQSA3HNR.js → chunk-MBLHWEZ7.js} +2 -2
- package/dist/prod/data/image-ALVZ6E6S.js +1 -0
- package/dist/prod/index.css +1 -1
- package/dist/prod/index.js +57 -57
- package/dist/prod/subset-shared.chunk.js +1 -1
- package/dist/prod/subset-worker.chunk.js +1 -1
- package/dist/types/excalidraw/components/ai-chat/imagePayload.d.ts +70 -0
- package/package.json +1 -1
- package/dist/prod/data/image-5D6ZUEOG.js +0 -1
- /package/dist/dev/{chunk-VL47Q2RH.js.map → chunk-BSCN3CPW.js.map} +0 -0
- /package/dist/dev/{chunk-OWDDSUUQ.js.map → chunk-O66HSY73.js.map} +0 -0
- /package/dist/dev/data/{image-5Y3GORNT.js.map → image-ADAEIYVZ.js.map} +0 -0
package/dist/dev/index.js
CHANGED
|
@@ -66,10 +66,10 @@ import {
|
|
|
66
66
|
serializeAsJSON,
|
|
67
67
|
serializeLibraryAsJSON,
|
|
68
68
|
strokeRectWithRotation_simple
|
|
69
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-O66HSY73.js";
|
|
70
70
|
import {
|
|
71
71
|
define_import_meta_env_default
|
|
72
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-BSCN3CPW.js";
|
|
73
73
|
import {
|
|
74
74
|
en_default
|
|
75
75
|
} from "./chunk-LIELFD5T.js";
|
|
@@ -9796,7 +9796,7 @@ var exportCanvas = async (type, elements, appState, files, {
|
|
|
9796
9796
|
let blob = canvasToBlob(tempCanvas);
|
|
9797
9797
|
if (appState.exportEmbedScene) {
|
|
9798
9798
|
blob = blob.then(
|
|
9799
|
-
(blob2) => import("./data/image-
|
|
9799
|
+
(blob2) => import("./data/image-ADAEIYVZ.js").then(
|
|
9800
9800
|
({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
|
|
9801
9801
|
blob: blob2,
|
|
9802
9802
|
metadata: serializeAsJSON(elements, appState, files, "local")
|
|
@@ -24070,6 +24070,176 @@ async function htmlToExcalidrawElements(html, frameX, frameY, frameWidth, frameH
|
|
|
24070
24070
|
}
|
|
24071
24071
|
}
|
|
24072
24072
|
|
|
24073
|
+
// components/ai-chat/imagePayload.ts
|
|
24074
|
+
var MAX_EDGE_PX = 1280;
|
|
24075
|
+
var JPEG_QUALITY = 0.78;
|
|
24076
|
+
var PASSTHROUGH_BYTES = 200 * 1024;
|
|
24077
|
+
function dataUrlWireBytes(dataUrl) {
|
|
24078
|
+
const commaIdx = dataUrl.indexOf(",");
|
|
24079
|
+
return commaIdx >= 0 ? dataUrl.length - commaIdx - 1 : dataUrl.length;
|
|
24080
|
+
}
|
|
24081
|
+
function isRasterImageDataUrl(dataUrl) {
|
|
24082
|
+
return /^data:image\/(png|jpe?g|gif|webp);base64,/i.test(dataUrl);
|
|
24083
|
+
}
|
|
24084
|
+
var DECODE_TIMEOUT_MS = 1e4;
|
|
24085
|
+
function loadImage(src) {
|
|
24086
|
+
return new Promise((resolve, reject) => {
|
|
24087
|
+
const img = new Image();
|
|
24088
|
+
const timer = setTimeout(() => {
|
|
24089
|
+
img.onload = null;
|
|
24090
|
+
img.onerror = null;
|
|
24091
|
+
reject(new Error("image decode timed out"));
|
|
24092
|
+
}, DECODE_TIMEOUT_MS);
|
|
24093
|
+
img.onload = () => {
|
|
24094
|
+
clearTimeout(timer);
|
|
24095
|
+
resolve(img);
|
|
24096
|
+
};
|
|
24097
|
+
img.onerror = () => {
|
|
24098
|
+
clearTimeout(timer);
|
|
24099
|
+
reject(new Error("image decode failed"));
|
|
24100
|
+
};
|
|
24101
|
+
img.src = src;
|
|
24102
|
+
});
|
|
24103
|
+
}
|
|
24104
|
+
async function shrinkImageDataUrl(dataUrl) {
|
|
24105
|
+
if (!isRasterImageDataUrl(dataUrl)) {
|
|
24106
|
+
return dataUrl;
|
|
24107
|
+
}
|
|
24108
|
+
if (dataUrlWireBytes(dataUrl) <= PASSTHROUGH_BYTES) {
|
|
24109
|
+
return dataUrl;
|
|
24110
|
+
}
|
|
24111
|
+
try {
|
|
24112
|
+
const img = await loadImage(dataUrl);
|
|
24113
|
+
const { width, height } = img;
|
|
24114
|
+
if (!width || !height) {
|
|
24115
|
+
return dataUrl;
|
|
24116
|
+
}
|
|
24117
|
+
const scale = Math.min(1, MAX_EDGE_PX / Math.max(width, height));
|
|
24118
|
+
const targetW = Math.max(1, Math.round(width * scale));
|
|
24119
|
+
const targetH = Math.max(1, Math.round(height * scale));
|
|
24120
|
+
const canvas = document.createElement("canvas");
|
|
24121
|
+
canvas.width = targetW;
|
|
24122
|
+
canvas.height = targetH;
|
|
24123
|
+
const ctx = canvas.getContext("2d");
|
|
24124
|
+
if (!ctx) {
|
|
24125
|
+
return dataUrl;
|
|
24126
|
+
}
|
|
24127
|
+
ctx.fillStyle = "#ffffff";
|
|
24128
|
+
ctx.fillRect(0, 0, targetW, targetH);
|
|
24129
|
+
ctx.drawImage(img, 0, 0, targetW, targetH);
|
|
24130
|
+
const shrunk = canvas.toDataURL("image/jpeg", JPEG_QUALITY);
|
|
24131
|
+
return dataUrlWireBytes(shrunk) < dataUrlWireBytes(dataUrl) ? shrunk : dataUrl;
|
|
24132
|
+
} catch {
|
|
24133
|
+
return dataUrl;
|
|
24134
|
+
}
|
|
24135
|
+
}
|
|
24136
|
+
var MAX_REQUEST_WIRE_BYTES = 3.5 * 1024 * 1024;
|
|
24137
|
+
function isImagePart(part) {
|
|
24138
|
+
return !!part && typeof part === "object" && part.type === "image_url" && typeof part.image_url?.url === "string";
|
|
24139
|
+
}
|
|
24140
|
+
function collectImageParts(messages) {
|
|
24141
|
+
const out = [];
|
|
24142
|
+
messages.forEach((m, msgIndex) => {
|
|
24143
|
+
if (!Array.isArray(m.content))
|
|
24144
|
+
return;
|
|
24145
|
+
for (const part of m.content) {
|
|
24146
|
+
if (isImagePart(part))
|
|
24147
|
+
out.push({ msgIndex, part });
|
|
24148
|
+
}
|
|
24149
|
+
});
|
|
24150
|
+
return out;
|
|
24151
|
+
}
|
|
24152
|
+
async function normalizeRequestImages(messages) {
|
|
24153
|
+
const loose = messages;
|
|
24154
|
+
const parts = collectImageParts(loose);
|
|
24155
|
+
if (parts.length === 0)
|
|
24156
|
+
return messages;
|
|
24157
|
+
const shrunk = await Promise.all(
|
|
24158
|
+
parts.map(({ part }) => shrinkImageDataUrl(part.image_url.url))
|
|
24159
|
+
);
|
|
24160
|
+
parts.forEach(({ part }, i) => {
|
|
24161
|
+
part.image_url.url = shrunk[i];
|
|
24162
|
+
});
|
|
24163
|
+
const bodySize = () => JSON.stringify(messages).length;
|
|
24164
|
+
if (bodySize() <= MAX_REQUEST_WIRE_BYTES)
|
|
24165
|
+
return messages;
|
|
24166
|
+
for (const edge of [960, 720, 512]) {
|
|
24167
|
+
const ordered = [...parts].sort(
|
|
24168
|
+
(a, b) => dataUrlWireBytes(b.part.image_url.url) - dataUrlWireBytes(a.part.image_url.url)
|
|
24169
|
+
);
|
|
24170
|
+
for (const { part } of ordered) {
|
|
24171
|
+
part.image_url.url = await reencodeAtEdge(part.image_url.url, edge);
|
|
24172
|
+
if (bodySize() <= MAX_REQUEST_WIRE_BYTES)
|
|
24173
|
+
return messages;
|
|
24174
|
+
}
|
|
24175
|
+
}
|
|
24176
|
+
const lastMsgIndex = loose.length - 1;
|
|
24177
|
+
for (const { msgIndex, part } of parts) {
|
|
24178
|
+
if (msgIndex === lastMsgIndex)
|
|
24179
|
+
continue;
|
|
24180
|
+
const owner = loose[msgIndex];
|
|
24181
|
+
if (!Array.isArray(owner.content))
|
|
24182
|
+
continue;
|
|
24183
|
+
owner.content = owner.content.filter((p) => p !== part);
|
|
24184
|
+
console.warn(
|
|
24185
|
+
"[imagePayload] dropped an image from an earlier turn to fit the request cap"
|
|
24186
|
+
);
|
|
24187
|
+
if (bodySize() <= MAX_REQUEST_WIRE_BYTES)
|
|
24188
|
+
return messages;
|
|
24189
|
+
}
|
|
24190
|
+
return messages;
|
|
24191
|
+
}
|
|
24192
|
+
async function describeChatError(response) {
|
|
24193
|
+
const raw = await response.text().catch(() => "");
|
|
24194
|
+
try {
|
|
24195
|
+
const parsed = JSON.parse(raw);
|
|
24196
|
+
if (parsed?.error?.message)
|
|
24197
|
+
return parsed.error.message;
|
|
24198
|
+
if (typeof parsed?.error === "string")
|
|
24199
|
+
return parsed.error;
|
|
24200
|
+
} catch {
|
|
24201
|
+
}
|
|
24202
|
+
if (response.status === 413) {
|
|
24203
|
+
return "This request was too large to send. Try attaching fewer images, or start a new chat to clear older ones.";
|
|
24204
|
+
}
|
|
24205
|
+
if (response.status === 429) {
|
|
24206
|
+
return "Rate limited \u2014 please wait a moment and try again.";
|
|
24207
|
+
}
|
|
24208
|
+
if (response.status === 401 || response.status === 403) {
|
|
24209
|
+
return "This request was not authorised. Please refresh and try again.";
|
|
24210
|
+
}
|
|
24211
|
+
if (response.status >= 500) {
|
|
24212
|
+
return `The AI service is temporarily unavailable (${response.status}). Please try again.`;
|
|
24213
|
+
}
|
|
24214
|
+
const detail = raw.trim().slice(0, 200);
|
|
24215
|
+
return detail ? `Request failed (${response.status}): ${detail}` : `Request failed (${response.status}).`;
|
|
24216
|
+
}
|
|
24217
|
+
async function reencodeAtEdge(dataUrl, edge) {
|
|
24218
|
+
if (!isRasterImageDataUrl(dataUrl))
|
|
24219
|
+
return dataUrl;
|
|
24220
|
+
try {
|
|
24221
|
+
const img = await loadImage(dataUrl);
|
|
24222
|
+
if (!img.width || !img.height)
|
|
24223
|
+
return dataUrl;
|
|
24224
|
+
const scale = Math.min(1, edge / Math.max(img.width, img.height));
|
|
24225
|
+
const w = Math.max(1, Math.round(img.width * scale));
|
|
24226
|
+
const h = Math.max(1, Math.round(img.height * scale));
|
|
24227
|
+
const canvas = document.createElement("canvas");
|
|
24228
|
+
canvas.width = w;
|
|
24229
|
+
canvas.height = h;
|
|
24230
|
+
const ctx = canvas.getContext("2d");
|
|
24231
|
+
if (!ctx)
|
|
24232
|
+
return dataUrl;
|
|
24233
|
+
ctx.fillStyle = "#ffffff";
|
|
24234
|
+
ctx.fillRect(0, 0, w, h);
|
|
24235
|
+
ctx.drawImage(img, 0, 0, w, h);
|
|
24236
|
+
const out = canvas.toDataURL("image/jpeg", 0.7);
|
|
24237
|
+
return dataUrlWireBytes(out) < dataUrlWireBytes(dataUrl) ? out : dataUrl;
|
|
24238
|
+
} catch {
|
|
24239
|
+
return dataUrl;
|
|
24240
|
+
}
|
|
24241
|
+
}
|
|
24242
|
+
|
|
24073
24243
|
// components/ai-chat/reviewerAgent.ts
|
|
24074
24244
|
var REVIEWER_SYSTEM_PROMPT = `You are the Brand Governance Agent \u2014 a Senior Ad Creative Director, Brand Compliance Officer, and Legal QA Auditor combined. You receive a rendered screenshot of a finished advertisement that was generated as a SINGLE AI image \u2014 the visuals AND all copy (headline, subheadline, CTA, body text, sign-off) are part of the image itself.
|
|
24075
24245
|
|
|
@@ -24350,10 +24520,10 @@ async function runReviewerAgent(opts) {
|
|
|
24350
24520
|
});
|
|
24351
24521
|
const payload = {
|
|
24352
24522
|
model: reviewerModel,
|
|
24353
|
-
messages: [
|
|
24523
|
+
messages: await normalizeRequestImages([
|
|
24354
24524
|
{ role: "system", content: REVIEWER_SYSTEM_PROMPT },
|
|
24355
24525
|
{ role: "user", content: userContent }
|
|
24356
|
-
],
|
|
24526
|
+
]),
|
|
24357
24527
|
response_format: { type: "json_object" },
|
|
24358
24528
|
stream: false,
|
|
24359
24529
|
temperature: 0.2
|
|
@@ -59321,7 +59491,7 @@ function isStreamingResponse(response) {
|
|
|
59321
59491
|
}
|
|
59322
59492
|
|
|
59323
59493
|
// components/ai-chat/agentLoop.ts
|
|
59324
|
-
function
|
|
59494
|
+
function isRasterImageDataUrl2(dataUrl) {
|
|
59325
59495
|
return /^data:image\/(png|jpe?g|gif|webp);base64,/i.test(dataUrl);
|
|
59326
59496
|
}
|
|
59327
59497
|
function dataUrlByteSize(dataUrl) {
|
|
@@ -59329,9 +59499,6 @@ function dataUrlByteSize(dataUrl) {
|
|
|
59329
59499
|
const b64 = commaIdx >= 0 ? dataUrl.slice(commaIdx + 1) : dataUrl;
|
|
59330
59500
|
return Math.floor(b64.length * 3 / 4);
|
|
59331
59501
|
}
|
|
59332
|
-
var MAX_REQUEST_IMAGE_BYTES = 8 * 1024 * 1024;
|
|
59333
|
-
var BRAND_CONTEXT_IMAGE_BUDGET = MAX_REQUEST_IMAGE_BYTES / 2;
|
|
59334
|
-
var PER_BRAND_IMAGE_BYTE_CAP = 600 * 1024;
|
|
59335
59502
|
var MAX_TOTAL_IMAGES = 18;
|
|
59336
59503
|
var SYSTEM_PROMPT = `You are an expert advertising art director embedded inside a canvas editor. You create finished advertisement creatives by generating a single complete image \u2014 visuals AND all copy baked directly into the image \u2014 using an AI image model. You do NOT assemble ads from separate text/shape layers.
|
|
59337
59504
|
|
|
@@ -59432,14 +59599,12 @@ var MAX_ITERATIONS = 15;
|
|
|
59432
59599
|
async function callOpenRouter(messages, chatUrl, signal, webSearchEnabled, chatModel, onContentChunk, tools = CANVAS_TOOLS) {
|
|
59433
59600
|
const baseModel = chatModel || "minimax/minimax-m3";
|
|
59434
59601
|
const model = webSearchEnabled ? `${baseModel}:online` : baseModel;
|
|
59435
|
-
const
|
|
59436
|
-
|
|
59437
|
-
stream: true,
|
|
59438
|
-
messages: messages.map((m) => {
|
|
59602
|
+
const wireMessages = await normalizeRequestImages(
|
|
59603
|
+
messages.map((m) => {
|
|
59439
59604
|
if (m.role === "assistant" && m.tool_calls) {
|
|
59440
59605
|
return {
|
|
59441
59606
|
role: m.role,
|
|
59442
|
-
content: m.content,
|
|
59607
|
+
content: structuredClone(m.content),
|
|
59443
59608
|
tool_calls: m.tool_calls
|
|
59444
59609
|
};
|
|
59445
59610
|
}
|
|
@@ -59450,8 +59615,13 @@ async function callOpenRouter(messages, chatUrl, signal, webSearchEnabled, chatM
|
|
|
59450
59615
|
content: m.content
|
|
59451
59616
|
};
|
|
59452
59617
|
}
|
|
59453
|
-
return { role: m.role, content: m.content };
|
|
59454
|
-
})
|
|
59618
|
+
return { role: m.role, content: structuredClone(m.content) };
|
|
59619
|
+
})
|
|
59620
|
+
);
|
|
59621
|
+
const body = {
|
|
59622
|
+
model,
|
|
59623
|
+
stream: true,
|
|
59624
|
+
messages: wireMessages,
|
|
59455
59625
|
tools,
|
|
59456
59626
|
tool_choice: "auto"
|
|
59457
59627
|
};
|
|
@@ -59477,15 +59647,7 @@ async function callOpenRouter(messages, chatUrl, signal, webSearchEnabled, chatM
|
|
|
59477
59647
|
body: JSON.stringify(body)
|
|
59478
59648
|
});
|
|
59479
59649
|
if (!response.ok) {
|
|
59480
|
-
|
|
59481
|
-
try {
|
|
59482
|
-
const err = await response.json();
|
|
59483
|
-
if (err?.error?.message) {
|
|
59484
|
-
message = err.error.message;
|
|
59485
|
-
}
|
|
59486
|
-
} catch {
|
|
59487
|
-
}
|
|
59488
|
-
throw new Error(message);
|
|
59650
|
+
throw new Error(await describeChatError(response));
|
|
59489
59651
|
}
|
|
59490
59652
|
if (isStreamingResponse(response)) {
|
|
59491
59653
|
let fullContent = "";
|
|
@@ -59621,13 +59783,13 @@ ${elementContext}`
|
|
|
59621
59783
|
toolCtx.onListBrandTemplates ? toolCtx.onListBrandTemplates(keywords) : Promise.resolve([])
|
|
59622
59784
|
]);
|
|
59623
59785
|
const top2Assets = (assetRes.status === "fulfilled" ? assetRes.value : []).filter(
|
|
59624
|
-
(a) => a.previewDataUrl &&
|
|
59786
|
+
(a) => a.previewDataUrl && isRasterImageDataUrl2(a.previewDataUrl)
|
|
59625
59787
|
).slice(0, 2);
|
|
59626
59788
|
const top2Creatives = (creativeRes.status === "fulfilled" ? creativeRes.value : []).filter(
|
|
59627
|
-
(c) => c.previewDataUrl &&
|
|
59789
|
+
(c) => c.previewDataUrl && isRasterImageDataUrl2(c.previewDataUrl)
|
|
59628
59790
|
).slice(0, 2);
|
|
59629
59791
|
const top2Templates = (templateRes.status === "fulfilled" ? templateRes.value : []).filter(
|
|
59630
|
-
(t2) => t2.thumbnailDataUrl &&
|
|
59792
|
+
(t2) => t2.thumbnailDataUrl && isRasterImageDataUrl2(t2.thumbnailDataUrl)
|
|
59631
59793
|
).slice(0, 2);
|
|
59632
59794
|
console.log(
|
|
59633
59795
|
`[agent:pre-fetch] brand assets=${top2Assets.length}/${assetRes.status === "fulfilled" ? assetRes.value.length : "err"} ad-creatives=${top2Creatives.length}/${creativeRes.status === "fulfilled" ? creativeRes.value.length : "err"} templates=${top2Templates.length}/${templateRes.status === "fulfilled" ? templateRes.value.length : "err"}`
|
|
@@ -59648,24 +59810,13 @@ ${elementContext}`
|
|
|
59648
59810
|
];
|
|
59649
59811
|
const budgetedPreviews = [];
|
|
59650
59812
|
for (const p of previews) {
|
|
59651
|
-
|
|
59652
|
-
if (size > PER_BRAND_IMAGE_BYTE_CAP) {
|
|
59813
|
+
if (brandContextImagesUsed >= MAX_TOTAL_IMAGES) {
|
|
59653
59814
|
console.warn(
|
|
59654
|
-
`[agent:pre-fetch] dropping "${p.label}" \u2014
|
|
59655
|
-
size / 1024
|
|
59656
|
-
)}KB exceeds the per-image cap (${Math.round(
|
|
59657
|
-
PER_BRAND_IMAGE_BYTE_CAP / 1024
|
|
59658
|
-
)}KB)`
|
|
59815
|
+
`[agent:pre-fetch] dropping "${p.label}" \u2014 per-request image count cap reached`
|
|
59659
59816
|
);
|
|
59660
59817
|
continue;
|
|
59661
59818
|
}
|
|
59662
|
-
|
|
59663
|
-
console.warn(
|
|
59664
|
-
`[agent:pre-fetch] dropping "${p.label}" \u2014 brand-context image budget exhausted`
|
|
59665
|
-
);
|
|
59666
|
-
continue;
|
|
59667
|
-
}
|
|
59668
|
-
brandContextBytesUsed += size;
|
|
59819
|
+
brandContextBytesUsed += dataUrlByteSize(p.dataUrl);
|
|
59669
59820
|
brandContextImagesUsed += 1;
|
|
59670
59821
|
budgetedPreviews.push(p);
|
|
59671
59822
|
}
|
|
@@ -59707,46 +59858,20 @@ Visual previews follow in the next message. Use them as context: match their sty
|
|
|
59707
59858
|
}
|
|
59708
59859
|
}
|
|
59709
59860
|
}
|
|
59710
|
-
const
|
|
59711
|
-
const currentSendImagesForBudget = fileAttachments?.filter((a) => a.type === "image" && a.dataUrl) ?? [];
|
|
59712
|
-
const currentSendImageBytes = currentSendImagesForBudget.reduce(
|
|
59713
|
-
(sum2, a) => sum2 + dataUrlByteSize(a.dataUrl),
|
|
59714
|
-
0
|
|
59715
|
-
);
|
|
59716
|
-
const currentSendImageCount = currentSendImagesForBudget.length + (frameScreenshot ? 1 : 0);
|
|
59717
|
-
const remainingBudgetBytes = MAX_REQUEST_IMAGE_BYTES - brandContextBytesUsed;
|
|
59718
|
-
const remainingBudgetImages = MAX_TOTAL_IMAGES - brandContextImagesUsed;
|
|
59719
|
-
if (currentSendImageBytes + frameScreenshotBytes > remainingBudgetBytes || currentSendImageCount > remainingBudgetImages) {
|
|
59720
|
-
const message = "This message is too large to process \u2014 try attaching fewer or smaller images.";
|
|
59721
|
-
console.warn(
|
|
59722
|
-
`[agent:budget] aborting \u2014 current-send content alone (${Math.round(
|
|
59723
|
-
(currentSendImageBytes + frameScreenshotBytes) / 1024
|
|
59724
|
-
)}KB, ${currentSendImageCount} image(s)) exceeds the remaining request budget`
|
|
59725
|
-
);
|
|
59726
|
-
onUpdate({ type: "final", message });
|
|
59727
|
-
return { reply: message, toolActions: [] };
|
|
59728
|
-
}
|
|
59729
|
-
let historicalBudgetBytes = remainingBudgetBytes - currentSendImageBytes - frameScreenshotBytes;
|
|
59730
|
-
let historicalBudgetImages = remainingBudgetImages - currentSendImageCount;
|
|
59861
|
+
const currentSendImageCount = (fileAttachments?.filter((a) => a.type === "image" && a.dataUrl).length ?? 0) + (frameScreenshot ? 1 : 0);
|
|
59731
59862
|
const droppedHistoricalMessageIndices = /* @__PURE__ */ new Set();
|
|
59863
|
+
let historicalImagesRemaining = MAX_TOTAL_IMAGES - brandContextImagesUsed - currentSendImageCount;
|
|
59732
59864
|
for (let i = userMessages.length - 1; i >= 0; i--) {
|
|
59733
59865
|
const imgs = userMessages[i].imageAttachments;
|
|
59734
59866
|
if (!imgs || imgs.length === 0) {
|
|
59735
59867
|
continue;
|
|
59736
59868
|
}
|
|
59737
|
-
|
|
59738
|
-
|
|
59739
|
-
0
|
|
59740
|
-
);
|
|
59741
|
-
if (bytes <= historicalBudgetBytes && imgs.length <= historicalBudgetImages) {
|
|
59742
|
-
historicalBudgetBytes -= bytes;
|
|
59743
|
-
historicalBudgetImages -= imgs.length;
|
|
59869
|
+
if (imgs.length <= historicalImagesRemaining) {
|
|
59870
|
+
historicalImagesRemaining -= imgs.length;
|
|
59744
59871
|
} else {
|
|
59745
59872
|
droppedHistoricalMessageIndices.add(i);
|
|
59746
59873
|
console.warn(
|
|
59747
|
-
`[agent:budget] dropping ${imgs.length} historical image(s) from an earlier turn (${
|
|
59748
|
-
bytes / 1024
|
|
59749
|
-
)}KB) \u2014 request budget exceeded`
|
|
59874
|
+
`[agent:budget] dropping ${imgs.length} historical image(s) from an earlier turn \u2014 per-request image count cap (${MAX_TOTAL_IMAGES}) reached`
|
|
59750
59875
|
);
|
|
59751
59876
|
}
|
|
59752
59877
|
}
|
|
@@ -60045,22 +60170,13 @@ Use the frameId="${imageGenData.frameId}" for all elements. Keep all elements wi
|
|
|
60045
60170
|
if (searchToolNames.has(name) && result.success && assetSearchResult.previewDataUrls?.length) {
|
|
60046
60171
|
const budgetedPreviews = [];
|
|
60047
60172
|
for (const p of assetSearchResult.previewDataUrls) {
|
|
60048
|
-
|
|
60049
|
-
if (size > PER_BRAND_IMAGE_BYTE_CAP) {
|
|
60050
|
-
console.warn(
|
|
60051
|
-
`[agent:mid-loop] dropping "${p.name}" \u2014 ${Math.round(
|
|
60052
|
-
size / 1024
|
|
60053
|
-
)}KB exceeds the per-image cap`
|
|
60054
|
-
);
|
|
60055
|
-
continue;
|
|
60056
|
-
}
|
|
60057
|
-
if (brandContextBytesUsed + size > BRAND_CONTEXT_IMAGE_BUDGET || brandContextImagesUsed >= MAX_TOTAL_IMAGES) {
|
|
60173
|
+
if (brandContextImagesUsed >= MAX_TOTAL_IMAGES) {
|
|
60058
60174
|
console.warn(
|
|
60059
|
-
`[agent:mid-loop] dropping "${p.name}" \u2014
|
|
60175
|
+
`[agent:mid-loop] dropping "${p.name}" \u2014 per-request image count cap reached`
|
|
60060
60176
|
);
|
|
60061
60177
|
continue;
|
|
60062
60178
|
}
|
|
60063
|
-
brandContextBytesUsed +=
|
|
60179
|
+
brandContextBytesUsed += dataUrlByteSize(p.dataUrl);
|
|
60064
60180
|
brandContextImagesUsed += 1;
|
|
60065
60181
|
budgetedPreviews.push(p);
|
|
60066
60182
|
}
|
|
@@ -62127,7 +62243,10 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
62127
62243
|
if (hasPdfs) {
|
|
62128
62244
|
plugins.push({ id: "file-parser", pdf: { engine: "cloudflare-ai" } });
|
|
62129
62245
|
}
|
|
62130
|
-
const body = {
|
|
62246
|
+
const body = {
|
|
62247
|
+
model,
|
|
62248
|
+
messages: await normalizeRequestImages(apiMessages)
|
|
62249
|
+
};
|
|
62131
62250
|
if (plugins.length > 0) {
|
|
62132
62251
|
body.plugins = plugins;
|
|
62133
62252
|
}
|
|
@@ -62143,15 +62262,7 @@ ${f.textContent}`).join("\n\n")}`;
|
|
|
62143
62262
|
body: JSON.stringify(body)
|
|
62144
62263
|
});
|
|
62145
62264
|
if (!response.ok) {
|
|
62146
|
-
|
|
62147
|
-
try {
|
|
62148
|
-
const err = await response.json();
|
|
62149
|
-
if (err?.error?.message) {
|
|
62150
|
-
message = err.error.message;
|
|
62151
|
-
}
|
|
62152
|
-
} catch {
|
|
62153
|
-
}
|
|
62154
|
-
throw new Error(message);
|
|
62265
|
+
throw new Error(await describeChatError(response));
|
|
62155
62266
|
}
|
|
62156
62267
|
if (opts?.onChunk && isStreamingResponse(response)) {
|
|
62157
62268
|
let fullContent = "";
|