@ykurilov/agent-chat-core 0.60.0 → 0.61.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 +24 -0
- package/dist/{chunk-WQZQZCAB.js → chunk-XQ5FJ2VT.js} +176 -69
- package/dist/chunk-XQ5FJ2VT.js.map +1 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/storage-contract.js +1 -1
- package/dist/types/agent-run/tool-result-images-policy.d.ts +37 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/models/model-catalog.d.ts +15 -2
- package/package.json +1 -1
- package/dist/chunk-WQZQZCAB.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @ykurilov/agent-chat-core
|
|
2
2
|
|
|
3
|
+
## 0.61.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b3f42a3: Снимок страницы: не проверено — не значит «не умеет». `page_screenshot` и снимок в `person_link_view` даются любой
|
|
8
|
+
модели, которая видит картинки, кроме провайдеров из `blindToolResultImageProviders` профиля. Картинка никогда не уходит
|
|
9
|
+
модели base64-строкой. Картинку получают провайдеры с `toolResultImages: true` (встроенные помечены) и провайдеры из
|
|
10
|
+
`toolResultImageProviders` профиля; остальным ядро шлёт текст страницы. Провайдер отказал из-за картинки (код 400, 415 или 422, в тексте ошибки — про картинку) — тот же запрос сразу
|
|
11
|
+
уходит текстом; удался повтор — строка `[картинки инструментов]` в журнал, и до перезапуска службы эта пара модели и
|
|
12
|
+
провайдера получает текст. Повтор упал — пара не запоминается, дальше идёт ошибка повтора. 413 — текстом только этот
|
|
13
|
+
запрос. Переполнение контекста и прочие отказы идут дальше как есть. Ошибка внутри уже открытого потока (код 200) не
|
|
14
|
+
откатывается. Первый переход на текст один раз сбрасывает кэш модели. Firecrawl отдаёт
|
|
15
|
+
текст страницы вместе со снимком (тот же кредит).
|
|
16
|
+
|
|
17
|
+
Что сделать приложению:
|
|
18
|
+
|
|
19
|
+
- своя проверка «провайдер проверен — даём снимок» больше не нужна;
|
|
20
|
+
- запрещали снимок тем, что не вписывали провайдер в `toolResultImageProviders`, — теперь нужен
|
|
21
|
+
`blindToolResultImageProviders`, иначе снимок уйдёт;
|
|
22
|
+
- провайдер точно не видит картинку из инструмента — `blindToolResultImageProviders: ["id"]` в профиле модели;
|
|
23
|
+
- свой провайдер, передающий картинки инструментов частью `file` SDK, — `toolResultImages: true` в его описании;
|
|
24
|
+
- своя служба снимков может вернуть `page` (текст той же страницы); свой инструмент с картинкой — запасной текст
|
|
25
|
+
`toolImageFallbackText(текст)` из `@ykurilov/agent-chat-core`.
|
|
26
|
+
|
|
3
27
|
## 0.60.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
|
@@ -749,6 +749,7 @@ function withRouteModels(models, providers) {
|
|
|
749
749
|
const pricing = model.pricing && { ...model.pricing };
|
|
750
750
|
const imageProviders = model.toolResultImageProviders && [...model.toolResultImageProviders];
|
|
751
751
|
const imagesByProvider = model.acceptsImagesByProvider && { ...model.acceptsImagesByProvider };
|
|
752
|
+
const blindProviders = model.blindToolResultImageProviders && [...model.blindToolResultImageProviders];
|
|
752
753
|
for (const route of routes) {
|
|
753
754
|
const source = route.servesModelsOf;
|
|
754
755
|
if (!model.providerModelIds[source]) continue;
|
|
@@ -756,13 +757,15 @@ function withRouteModels(models, providers) {
|
|
|
756
757
|
if (pricing?.[source] && !pricing[route.id]) pricing[route.id] = pricing[source];
|
|
757
758
|
if (imageProviders?.includes(source) && !imageProviders.includes(route.id)) imageProviders.push(route.id);
|
|
758
759
|
if (imagesByProvider && source in imagesByProvider && !(route.id in imagesByProvider)) imagesByProvider[route.id] = imagesByProvider[source];
|
|
760
|
+
if (blindProviders?.includes(source) && !blindProviders.includes(route.id) && !imageProviders?.includes(route.id)) blindProviders.push(route.id);
|
|
759
761
|
}
|
|
760
762
|
return {
|
|
761
763
|
...model,
|
|
762
764
|
providerModelIds,
|
|
763
765
|
...pricing && { pricing },
|
|
764
766
|
...imageProviders && { toolResultImageProviders: imageProviders },
|
|
765
|
-
...imagesByProvider && { acceptsImagesByProvider: imagesByProvider }
|
|
767
|
+
...imagesByProvider && { acceptsImagesByProvider: imagesByProvider },
|
|
768
|
+
...blindProviders && { blindToolResultImageProviders: blindProviders }
|
|
766
769
|
};
|
|
767
770
|
});
|
|
768
771
|
}
|
|
@@ -2341,6 +2344,151 @@ function createForgedBlockGuard(formats) {
|
|
|
2341
2344
|
};
|
|
2342
2345
|
}
|
|
2343
2346
|
|
|
2347
|
+
// src/agent-run/tool-result-images-policy.ts
|
|
2348
|
+
import { wrapLanguageModel as wrapLanguageModel3 } from "ai";
|
|
2349
|
+
|
|
2350
|
+
// src/provider-errors/error-fields.ts
|
|
2351
|
+
import { APICallError, RetryError } from "ai";
|
|
2352
|
+
function underlyingError(error) {
|
|
2353
|
+
return RetryError.isInstance(error) ? error.lastError : error;
|
|
2354
|
+
}
|
|
2355
|
+
function errorStatusCode(error) {
|
|
2356
|
+
if (APICallError.isInstance(error)) return error.statusCode;
|
|
2357
|
+
if (typeof error !== "object" || error === null) return void 0;
|
|
2358
|
+
const fields = error;
|
|
2359
|
+
const nested = typeof fields.error === "object" && fields.error !== null ? fields.error.code : void 0;
|
|
2360
|
+
for (const value of [fields.statusCode, fields.status, fields.code, nested]) {
|
|
2361
|
+
const code = asStatusCode(value);
|
|
2362
|
+
if (code !== void 0) return code;
|
|
2363
|
+
}
|
|
2364
|
+
return void 0;
|
|
2365
|
+
}
|
|
2366
|
+
function asStatusCode(value) {
|
|
2367
|
+
const code = typeof value === "number" ? value : typeof value === "string" && /^\s*\d{3}\s*$/.test(value) ? Number(value) : void 0;
|
|
2368
|
+
return code !== void 0 && Number.isInteger(code) && code >= 100 && code <= 599 ? code : void 0;
|
|
2369
|
+
}
|
|
2370
|
+
function errorText(error) {
|
|
2371
|
+
if (APICallError.isInstance(error)) return [error.responseBody, error.message].filter(Boolean).join("\n");
|
|
2372
|
+
if (error instanceof Error) return error.message;
|
|
2373
|
+
if (typeof error === "string") return error;
|
|
2374
|
+
try {
|
|
2375
|
+
return JSON.stringify(error) ?? "";
|
|
2376
|
+
} catch {
|
|
2377
|
+
return "";
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
function errorHeaders(error) {
|
|
2381
|
+
return APICallError.isInstance(error) ? error.responseHeaders : void 0;
|
|
2382
|
+
}
|
|
2383
|
+
function errorName(error) {
|
|
2384
|
+
const name = typeof error === "object" && error !== null ? error.name : void 0;
|
|
2385
|
+
return typeof name === "string" && name !== "" ? name : void 0;
|
|
2386
|
+
}
|
|
2387
|
+
function requestedRetryMs(error, nowMs) {
|
|
2388
|
+
const headers = errorHeaders(error);
|
|
2389
|
+
if (!headers) return void 0;
|
|
2390
|
+
let requestedMs;
|
|
2391
|
+
const inMs = Number.parseFloat(headers["retry-after-ms"] ?? "");
|
|
2392
|
+
if (!Number.isNaN(inMs)) requestedMs = inMs;
|
|
2393
|
+
const retryAfter = headers["retry-after"];
|
|
2394
|
+
if (requestedMs === void 0 && retryAfter) {
|
|
2395
|
+
const inSeconds = Number.parseFloat(retryAfter);
|
|
2396
|
+
requestedMs = Number.isNaN(inSeconds) ? Date.parse(retryAfter) - nowMs : inSeconds * 1e3;
|
|
2397
|
+
}
|
|
2398
|
+
if (requestedMs === void 0 || Number.isNaN(requestedMs) || requestedMs < 0) return void 0;
|
|
2399
|
+
return requestedMs;
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
// src/agent-run/tool-result-images-policy.ts
|
|
2403
|
+
var FALLBACK_NAMESPACE = "agentChat";
|
|
2404
|
+
var NO_IMAGE_NOTE = "[\u041A\u0430\u0440\u0442\u0438\u043D\u043A\u0430 \u043D\u0435 \u043F\u043E\u043A\u0430\u0437\u0430\u043D\u0430: \u044D\u0442\u0430 \u043C\u043E\u0434\u0435\u043B\u044C \u0443 \u044D\u0442\u043E\u0433\u043E \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0430 \u043D\u0435 \u043F\u043E\u043B\u0443\u0447\u0430\u0435\u0442 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438 \u0438\u0437 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u0432.]";
|
|
2405
|
+
var REFUSAL_CODES = /* @__PURE__ */ new Set([400, 413, 415, 422]);
|
|
2406
|
+
var TOO_LARGE = 413;
|
|
2407
|
+
var IMAGE_REFUSAL = /image|vision|multi-?modal|content[ _-]?type|base64|unsupported content|media[ _-]?type|mime/i;
|
|
2408
|
+
var CONTEXT_OVERFLOW = /context (length|window)|maximum context|too many tokens|token limit|prompt is too long|reduce the length/i;
|
|
2409
|
+
function toolImageFallbackText(text) {
|
|
2410
|
+
return { type: "text", text, providerOptions: { [FALLBACK_NAMESPACE]: { toolImageFallback: true } } };
|
|
2411
|
+
}
|
|
2412
|
+
function modelMaySeeToolResultImages(profile, providerId) {
|
|
2413
|
+
return modelAcceptsImages(profile, providerId) && !profile.blindToolResultImageProviders?.includes(providerId);
|
|
2414
|
+
}
|
|
2415
|
+
var refusalsByCatalog = /* @__PURE__ */ new WeakMap();
|
|
2416
|
+
function refusalsOf(catalog) {
|
|
2417
|
+
let refusals = refusalsByCatalog.get(catalog);
|
|
2418
|
+
if (!refusals) {
|
|
2419
|
+
refusals = /* @__PURE__ */ new Set();
|
|
2420
|
+
refusalsByCatalog.set(catalog, refusals);
|
|
2421
|
+
}
|
|
2422
|
+
return refusals;
|
|
2423
|
+
}
|
|
2424
|
+
function withToolResultImagePolicy(model, context) {
|
|
2425
|
+
if (typeof model === "string") return model;
|
|
2426
|
+
const { profile, provider } = context;
|
|
2427
|
+
const pair = `${profile.id}@${provider.id}`;
|
|
2428
|
+
const refusals = refusalsOf(context.catalog);
|
|
2429
|
+
const carries = provider.toolResultImages === true || profile.toolResultImageProviders?.includes(provider.id) === true;
|
|
2430
|
+
const imagesAllowed = () => carries && modelMaySeeToolResultImages(profile, provider.id) && !refusals.has(pair);
|
|
2431
|
+
async function attempt(params, call) {
|
|
2432
|
+
if (!hasToolResultImages(params.prompt)) return call(params);
|
|
2433
|
+
if (!imagesAllowed()) return call({ ...params, prompt: withToolResultImages(params.prompt, false) });
|
|
2434
|
+
try {
|
|
2435
|
+
return await call({ ...params, prompt: withToolResultImages(params.prompt, true) });
|
|
2436
|
+
} catch (error) {
|
|
2437
|
+
const cause = underlyingError(error);
|
|
2438
|
+
const code = errorStatusCode(cause);
|
|
2439
|
+
if (params.abortSignal?.aborted || code === void 0 || !REFUSAL_CODES.has(code)) throw error;
|
|
2440
|
+
const text = errorText(cause);
|
|
2441
|
+
if (CONTEXT_OVERFLOW.test(text)) throw error;
|
|
2442
|
+
const aboutImage = code !== TOO_LARGE && IMAGE_REFUSAL.test(text);
|
|
2443
|
+
if (code !== TOO_LARGE && !aboutImage) throw error;
|
|
2444
|
+
const result = await call({ ...params, prompt: withToolResultImages(params.prompt, false) });
|
|
2445
|
+
if (aboutImage) refusals.add(pair);
|
|
2446
|
+
context.logError?.(
|
|
2447
|
+
aboutImage ? `[\u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u0432] ${provider.id} \u043E\u0442\u043A\u0430\u0437\u0430\u043B \u043C\u043E\u0434\u0435\u043B\u0438 ${profile.id} \u0432 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0435 \u0438\u0437 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u0430 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 (\u043A\u043E\u0434 ${code}): \u0437\u0430\u043F\u0440\u043E\u0441 \u043F\u043E\u0432\u0442\u043E\u0440\u0451\u043D \u0442\u0435\u043A\u0441\u0442\u043E\u043C \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B, \u0434\u043E \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u0441\u043B\u0443\u0436\u0431\u044B \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u0435\u043A\u0441\u0442` : `[\u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u0432] ${provider.id}: \u0437\u0430\u043F\u0440\u043E\u0441 \u043C\u043E\u0434\u0435\u043B\u0438 ${profile.id} \u0441 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u043E\u0439 \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0432\u0435\u043B\u0438\u043A (\u043A\u043E\u0434 ${code}), \u043F\u043E\u0432\u0442\u043E\u0440\u0451\u043D \u0442\u0435\u043A\u0441\u0442\u043E\u043C \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B`
|
|
2448
|
+
);
|
|
2449
|
+
return result;
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
return wrapLanguageModel3({
|
|
2453
|
+
model,
|
|
2454
|
+
middleware: {
|
|
2455
|
+
specificationVersion: "v4",
|
|
2456
|
+
wrapGenerate: ({ params, model: inner }) => attempt(params, (next) => inner.doGenerate(next)),
|
|
2457
|
+
wrapStream: ({ params, model: inner }) => attempt(params, (next) => inner.doStream(next))
|
|
2458
|
+
}
|
|
2459
|
+
});
|
|
2460
|
+
}
|
|
2461
|
+
function isImage(item) {
|
|
2462
|
+
return item.type === "file" && (item.mediaType === "image" || item.mediaType.startsWith("image/"));
|
|
2463
|
+
}
|
|
2464
|
+
function isFallback(item) {
|
|
2465
|
+
return item.type === "text" && item.providerOptions?.[FALLBACK_NAMESPACE]?.toolImageFallback === true;
|
|
2466
|
+
}
|
|
2467
|
+
function hasToolResultImages(prompt) {
|
|
2468
|
+
return prompt.some(
|
|
2469
|
+
(message) => message.role === "tool" && message.content.some((part) => part.type === "tool-result" && part.output.type === "content" && part.output.value.some((item) => isImage(item) || isFallback(item)))
|
|
2470
|
+
);
|
|
2471
|
+
}
|
|
2472
|
+
function withToolResultImages(prompt, images) {
|
|
2473
|
+
return prompt.map((message) => {
|
|
2474
|
+
if (message.role !== "tool") return message;
|
|
2475
|
+
return {
|
|
2476
|
+
...message,
|
|
2477
|
+
content: message.content.map((part) => {
|
|
2478
|
+
if (part.type !== "tool-result" || part.output.type !== "content") return part;
|
|
2479
|
+
return { ...part, output: { ...part.output, value: contentFor(part.output.value, images) } };
|
|
2480
|
+
})
|
|
2481
|
+
};
|
|
2482
|
+
});
|
|
2483
|
+
}
|
|
2484
|
+
function contentFor(value, images) {
|
|
2485
|
+
if (images) return value.filter((item) => !isFallback(item));
|
|
2486
|
+
const fallbacks = value.filter(isFallback).map((item) => ({ type: "text", text: item.text }));
|
|
2487
|
+
const kept = value.filter((item) => !isImage(item) && !isFallback(item));
|
|
2488
|
+
if (fallbacks.length > 0) return [...kept, ...fallbacks];
|
|
2489
|
+
return value.some(isImage) ? [...kept, { type: "text", text: NO_IMAGE_NOTE }] : kept;
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2344
2492
|
// src/storage/chat-storage.ts
|
|
2345
2493
|
var RELEASED_ANSWER_ALIVE_AT = (/* @__PURE__ */ new Date(0)).toISOString();
|
|
2346
2494
|
function aliveAtByLocalClock(mark) {
|
|
@@ -2849,58 +2997,6 @@ function isEmptyTokenUsage(usage) {
|
|
|
2849
2997
|
return usage.inputTokens === 0 && usage.outputTokens === 0 && usage.reasoningTokens === 0 && (usage.cacheWriteTokens ?? 0) === 0;
|
|
2850
2998
|
}
|
|
2851
2999
|
|
|
2852
|
-
// src/provider-errors/error-fields.ts
|
|
2853
|
-
import { APICallError, RetryError } from "ai";
|
|
2854
|
-
function underlyingError(error) {
|
|
2855
|
-
return RetryError.isInstance(error) ? error.lastError : error;
|
|
2856
|
-
}
|
|
2857
|
-
function errorStatusCode(error) {
|
|
2858
|
-
if (APICallError.isInstance(error)) return error.statusCode;
|
|
2859
|
-
if (typeof error !== "object" || error === null) return void 0;
|
|
2860
|
-
const fields = error;
|
|
2861
|
-
const nested = typeof fields.error === "object" && fields.error !== null ? fields.error.code : void 0;
|
|
2862
|
-
for (const value of [fields.statusCode, fields.status, fields.code, nested]) {
|
|
2863
|
-
const code = asStatusCode(value);
|
|
2864
|
-
if (code !== void 0) return code;
|
|
2865
|
-
}
|
|
2866
|
-
return void 0;
|
|
2867
|
-
}
|
|
2868
|
-
function asStatusCode(value) {
|
|
2869
|
-
const code = typeof value === "number" ? value : typeof value === "string" && /^\s*\d{3}\s*$/.test(value) ? Number(value) : void 0;
|
|
2870
|
-
return code !== void 0 && Number.isInteger(code) && code >= 100 && code <= 599 ? code : void 0;
|
|
2871
|
-
}
|
|
2872
|
-
function errorText(error) {
|
|
2873
|
-
if (APICallError.isInstance(error)) return [error.responseBody, error.message].filter(Boolean).join("\n");
|
|
2874
|
-
if (error instanceof Error) return error.message;
|
|
2875
|
-
if (typeof error === "string") return error;
|
|
2876
|
-
try {
|
|
2877
|
-
return JSON.stringify(error) ?? "";
|
|
2878
|
-
} catch {
|
|
2879
|
-
return "";
|
|
2880
|
-
}
|
|
2881
|
-
}
|
|
2882
|
-
function errorHeaders(error) {
|
|
2883
|
-
return APICallError.isInstance(error) ? error.responseHeaders : void 0;
|
|
2884
|
-
}
|
|
2885
|
-
function errorName(error) {
|
|
2886
|
-
const name = typeof error === "object" && error !== null ? error.name : void 0;
|
|
2887
|
-
return typeof name === "string" && name !== "" ? name : void 0;
|
|
2888
|
-
}
|
|
2889
|
-
function requestedRetryMs(error, nowMs) {
|
|
2890
|
-
const headers = errorHeaders(error);
|
|
2891
|
-
if (!headers) return void 0;
|
|
2892
|
-
let requestedMs;
|
|
2893
|
-
const inMs = Number.parseFloat(headers["retry-after-ms"] ?? "");
|
|
2894
|
-
if (!Number.isNaN(inMs)) requestedMs = inMs;
|
|
2895
|
-
const retryAfter = headers["retry-after"];
|
|
2896
|
-
if (requestedMs === void 0 && retryAfter) {
|
|
2897
|
-
const inSeconds = Number.parseFloat(retryAfter);
|
|
2898
|
-
requestedMs = Number.isNaN(inSeconds) ? Date.parse(retryAfter) - nowMs : inSeconds * 1e3;
|
|
2899
|
-
}
|
|
2900
|
-
if (requestedMs === void 0 || Number.isNaN(requestedMs) || requestedMs < 0) return void 0;
|
|
2901
|
-
return requestedMs;
|
|
2902
|
-
}
|
|
2903
|
-
|
|
2904
3000
|
// src/provider-errors/error-signs.ts
|
|
2905
3001
|
var signs = (patterns) => new RegExp(patterns.join("|"), "i");
|
|
2906
3002
|
var OVERFLOW_SIGNS = [
|
|
@@ -3406,7 +3502,7 @@ function usageMinusJournaled(usage, journaled) {
|
|
|
3406
3502
|
}
|
|
3407
3503
|
|
|
3408
3504
|
// src/agent-run/build-model-request.ts
|
|
3409
|
-
import { convertToModelMessages, wrapLanguageModel as
|
|
3505
|
+
import { convertToModelMessages, wrapLanguageModel as wrapLanguageModel6 } from "ai";
|
|
3410
3506
|
|
|
3411
3507
|
// src/conversation/hanging-tool-calls.ts
|
|
3412
3508
|
var PRELIMINARY_OUTPUT_MAX_LENGTH = 2e3;
|
|
@@ -3626,7 +3722,7 @@ ${chunk.delta}` } : chunk];
|
|
|
3626
3722
|
}
|
|
3627
3723
|
|
|
3628
3724
|
// src/agent-run/observe-model-calls.ts
|
|
3629
|
-
import { wrapLanguageModel as
|
|
3725
|
+
import { wrapLanguageModel as wrapLanguageModel4 } from "ai";
|
|
3630
3726
|
function observeModelCalls(model, context) {
|
|
3631
3727
|
if (typeof model === "string") return model;
|
|
3632
3728
|
const now = context.now ?? Date.now;
|
|
@@ -3636,7 +3732,7 @@ function observeModelCalls(model, context) {
|
|
|
3636
3732
|
attempts.set(params.prompt, attempt);
|
|
3637
3733
|
return attempt;
|
|
3638
3734
|
};
|
|
3639
|
-
return
|
|
3735
|
+
return wrapLanguageModel4({
|
|
3640
3736
|
model,
|
|
3641
3737
|
middleware: {
|
|
3642
3738
|
specificationVersion: "v4",
|
|
@@ -4224,7 +4320,7 @@ function withoutUndelivered(history) {
|
|
|
4224
4320
|
}
|
|
4225
4321
|
|
|
4226
4322
|
// src/agent-run/garbled-tail.ts
|
|
4227
|
-
import { wrapLanguageModel as
|
|
4323
|
+
import { wrapLanguageModel as wrapLanguageModel5 } from "ai";
|
|
4228
4324
|
var SIGN_ORDER = ["think", "role", "restart", "tool"];
|
|
4229
4325
|
var TOKEN_SOURCE = String.raw`<\/?think>|<\|[^|\n<>]{1,40}\|>|<|[^|\n<>]{1,40}|>`;
|
|
4230
4326
|
var TEMPLATE_TOKEN = new RegExp(TOKEN_SOURCE, "g");
|
|
@@ -4396,7 +4492,7 @@ function createGarbledTailGuard() {
|
|
|
4396
4492
|
/** Модель попытки под присмотром: каждый запрос — новый шаг. */
|
|
4397
4493
|
wrap(model) {
|
|
4398
4494
|
if (typeof model === "string") return model;
|
|
4399
|
-
return
|
|
4495
|
+
return wrapLanguageModel5({
|
|
4400
4496
|
model,
|
|
4401
4497
|
middleware: {
|
|
4402
4498
|
specificationVersion: "v4",
|
|
@@ -4519,7 +4615,12 @@ function withoutCodeAndQuotes(text) {
|
|
|
4519
4615
|
async function buildModelRequest(input) {
|
|
4520
4616
|
const found = findModel(input.catalog, input.modelId, input.providerId);
|
|
4521
4617
|
const { profile, provider } = found;
|
|
4522
|
-
const base = resolveLanguageModel(found, input.env, input.fetch)
|
|
4618
|
+
const base = withToolResultImagePolicy(resolveLanguageModel(found, input.env, input.fetch), {
|
|
4619
|
+
catalog: input.catalog,
|
|
4620
|
+
profile,
|
|
4621
|
+
provider,
|
|
4622
|
+
...input.logError && { logError: input.logError }
|
|
4623
|
+
});
|
|
4523
4624
|
const observed = input.observe ? observeModelCalls(base, {
|
|
4524
4625
|
...input.observe,
|
|
4525
4626
|
chatId: input.chatId,
|
|
@@ -4624,7 +4725,7 @@ function withoutLoneSurrogatesDeep(value) {
|
|
|
4624
4725
|
}
|
|
4625
4726
|
function withRequestWatch(model, provider, watch) {
|
|
4626
4727
|
if (!watch || typeof model === "string") return model;
|
|
4627
|
-
return
|
|
4728
|
+
return wrapLanguageModel6({
|
|
4628
4729
|
model,
|
|
4629
4730
|
middleware: {
|
|
4630
4731
|
specificationVersion: "v4",
|
|
@@ -4644,7 +4745,7 @@ function withRequestWatch(model, provider, watch) {
|
|
|
4644
4745
|
});
|
|
4645
4746
|
}
|
|
4646
4747
|
function withTransientRetries(model, context) {
|
|
4647
|
-
return typeof model === "string" ? model :
|
|
4748
|
+
return typeof model === "string" ? model : wrapLanguageModel6({ model, middleware: createTransientRetryMiddleware(context) });
|
|
4648
4749
|
}
|
|
4649
4750
|
function withLastMessageMark(messages, options2) {
|
|
4650
4751
|
if (!options2 || messages.length === 0) return messages;
|
|
@@ -8218,6 +8319,7 @@ function createDeepSeekProvider(connectionOptions = {}) {
|
|
|
8218
8319
|
// незнакомые поля не шлёт: `samplingRequest` нет, `sampling.minP` модели сюда не уходит.
|
|
8219
8320
|
// Кончившиеся деньги DeepSeek описывает телом ответа; код бывает не только 402.
|
|
8220
8321
|
errorHints: [{ match: /insufficient balance/i, kind: "insufficient_funds" }],
|
|
8322
|
+
toolResultImages: true,
|
|
8221
8323
|
...connectionField(connection),
|
|
8222
8324
|
...silenceField("DeepSeek", connectionOptions),
|
|
8223
8325
|
...hiddenField("DeepSeek", connectionOptions)
|
|
@@ -8243,7 +8345,7 @@ function sdkReasoningRequest(level) {
|
|
|
8243
8345
|
}
|
|
8244
8346
|
|
|
8245
8347
|
// src/models/providers/tool-result-images.ts
|
|
8246
|
-
function
|
|
8348
|
+
function withToolResultImages2(given) {
|
|
8247
8349
|
return (async (input, init) => {
|
|
8248
8350
|
const fetchImplementation = given ?? globalThis.fetch;
|
|
8249
8351
|
if (typeof init?.body !== "string" || !init.body.includes('"role":"tool"')) return fetchImplementation(input, init);
|
|
@@ -8320,7 +8422,7 @@ function createFireworksProvider(connectionOptions = {}) {
|
|
|
8320
8422
|
id: "fireworks",
|
|
8321
8423
|
displayName: "Fireworks",
|
|
8322
8424
|
apiKeyEnv: "FIREWORKS_API_KEY",
|
|
8323
|
-
createLanguageModel: (providerModelId, apiKey, options2) => createFireworks({ apiKey, fetch:
|
|
8425
|
+
createLanguageModel: (providerModelId, apiKey, options2) => createFireworks({ apiKey, fetch: withToolResultImages2(options2?.fetch), ...connection })(providerModelId),
|
|
8324
8426
|
reasoningRequest: (level) => sdkReasoningRequest(level),
|
|
8325
8427
|
requestOptions: ({ chatId }) => ({
|
|
8326
8428
|
providerOptions: {
|
|
@@ -8328,6 +8430,7 @@ function createFireworksProvider(connectionOptions = {}) {
|
|
|
8328
8430
|
},
|
|
8329
8431
|
headers: { "x-session-affinity": sessionHeaderValue(chatId) }
|
|
8330
8432
|
}),
|
|
8433
|
+
toolResultImages: true,
|
|
8331
8434
|
...connectionField(connection),
|
|
8332
8435
|
...silenceField("Fireworks", connectionOptions),
|
|
8333
8436
|
...hiddenField("Fireworks", connectionOptions)
|
|
@@ -8337,7 +8440,7 @@ var fireworksProvider = createFireworksProvider();
|
|
|
8337
8440
|
|
|
8338
8441
|
// src/models/providers/openrouter.ts
|
|
8339
8442
|
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
|
8340
|
-
import { wrapLanguageModel as
|
|
8443
|
+
import { wrapLanguageModel as wrapLanguageModel7 } from "ai";
|
|
8341
8444
|
|
|
8342
8445
|
// src/models/providers/openrouter-cache-mark-limit.ts
|
|
8343
8446
|
function openrouterCacheMarkLimit(providerModelId) {
|
|
@@ -8575,6 +8678,7 @@ function createOpenRouterProvider(options2 = {}) {
|
|
|
8575
8678
|
id,
|
|
8576
8679
|
displayName,
|
|
8577
8680
|
...id !== OPENROUTER_ID && { servesModelsOf: OPENROUTER_ID },
|
|
8681
|
+
toolResultImages: true,
|
|
8578
8682
|
...connectionField(connection),
|
|
8579
8683
|
...silenceField("OpenRouter", options2),
|
|
8580
8684
|
...hiddenField("OpenRouter", options2),
|
|
@@ -8587,7 +8691,7 @@ function createOpenRouterProvider(options2 = {}) {
|
|
|
8587
8691
|
createLanguageModel: (providerModelId, apiKey, requestOptions) => {
|
|
8588
8692
|
const markLimit = openrouterCacheMarkLimit(providerModelId);
|
|
8589
8693
|
const fetch = markLimit === void 0 ? requestOptions?.fetch : fetchWithCacheMarkLimit(requestOptions?.fetch, markLimit);
|
|
8590
|
-
return
|
|
8694
|
+
return wrapLanguageModel7({
|
|
8591
8695
|
model: createOpenRouter({ apiKey, fetch, ...connection }).chat(providerModelId, routingOptions),
|
|
8592
8696
|
middleware: [
|
|
8593
8697
|
openrouterRoutingMiddleware(routing),
|
|
@@ -8692,10 +8796,11 @@ function createTogetherProvider(connectionOptions = {}) {
|
|
|
8692
8796
|
id: "together",
|
|
8693
8797
|
displayName: "Together AI",
|
|
8694
8798
|
apiKeyEnv: "TOGETHER_API_KEY",
|
|
8695
|
-
createLanguageModel: (providerModelId, apiKey, options2) => createTogetherAI({ apiKey, fetch:
|
|
8799
|
+
createLanguageModel: (providerModelId, apiKey, options2) => createTogetherAI({ apiKey, fetch: withToolResultImages2(options2?.fetch), ...connection })(providerModelId),
|
|
8696
8800
|
reasoningRequest: (level) => sdkReasoningRequest(level),
|
|
8697
8801
|
samplingRequest: ({ minP }) => minP === void 0 ? {} : { togetherai: { min_p: minP } },
|
|
8698
8802
|
requestOptions: () => ({}),
|
|
8803
|
+
toolResultImages: true,
|
|
8699
8804
|
...connectionField(connection),
|
|
8700
8805
|
...silenceField("Together AI", connectionOptions),
|
|
8701
8806
|
...hiddenField("Together AI", connectionOptions)
|
|
@@ -10489,7 +10594,7 @@ function isPlainObject3(value) {
|
|
|
10489
10594
|
}
|
|
10490
10595
|
|
|
10491
10596
|
// src/memory/memory-after-answer.ts
|
|
10492
|
-
import { wrapLanguageModel as
|
|
10597
|
+
import { wrapLanguageModel as wrapLanguageModel8 } from "ai";
|
|
10493
10598
|
var DRAIN_WAIT_MS = 5e3;
|
|
10494
10599
|
function createMemoryAfterAnswer({ memory, storage, catalog, env, logError, turnObserver }) {
|
|
10495
10600
|
const running = /* @__PURE__ */ new Set();
|
|
@@ -10534,7 +10639,7 @@ function createMemoryAfterAnswer({ memory, storage, catalog, env, logError, turn
|
|
|
10534
10639
|
};
|
|
10535
10640
|
}
|
|
10536
10641
|
function withRetries(model, context) {
|
|
10537
|
-
return typeof model === "string" ? model :
|
|
10642
|
+
return typeof model === "string" ? model : wrapLanguageModel8({ model, middleware: createTransientRetryMiddleware(context) });
|
|
10538
10643
|
}
|
|
10539
10644
|
|
|
10540
10645
|
// src/conversation/to-agent-chat-message.ts
|
|
@@ -14070,6 +14175,8 @@ export {
|
|
|
14070
14175
|
serviceBlockName,
|
|
14071
14176
|
checkServiceBlockFormats,
|
|
14072
14177
|
cutForgedBlocks,
|
|
14178
|
+
toolImageFallbackText,
|
|
14179
|
+
modelMaySeeToolResultImages,
|
|
14073
14180
|
RELEASED_ANSWER_ALIVE_AT,
|
|
14074
14181
|
aliveAtByLocalClock,
|
|
14075
14182
|
silenceBoundaryByLocalClock,
|
|
@@ -14169,4 +14276,4 @@ export {
|
|
|
14169
14276
|
InvalidWidgetAnswerError,
|
|
14170
14277
|
createChatService
|
|
14171
14278
|
};
|
|
14172
|
-
//# sourceMappingURL=chunk-
|
|
14279
|
+
//# sourceMappingURL=chunk-XQ5FJ2VT.js.map
|