@ykurilov/agent-chat-core 0.59.0 → 0.60.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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @ykurilov/agent-chat-core
2
2
 
3
+ ## 0.60.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6e8723c: Снимок страницы в ответе инструмента уходит картинкой к Together и Fireworks (раньше — строкой текста, ход зависал); профиль DeepSeek 4.1 Flash видит снимки через DeepSeek, Together, Fireworks и OpenRouter. Сценарии не называют инструменты, которых нет у модели этого хода; правила просмотра ссылок — в описании инструмента.
8
+
3
9
  ## 0.59.0
4
10
 
5
11
  ### Minor Changes
@@ -8242,6 +8242,59 @@ function sdkReasoningRequest(level) {
8242
8242
  }
8243
8243
  }
8244
8244
 
8245
+ // src/models/providers/tool-result-images.ts
8246
+ function withToolResultImages(given) {
8247
+ return (async (input, init) => {
8248
+ const fetchImplementation = given ?? globalThis.fetch;
8249
+ if (typeof init?.body !== "string" || !init.body.includes('"role":"tool"')) return fetchImplementation(input, init);
8250
+ let body;
8251
+ try {
8252
+ body = JSON.parse(init.body);
8253
+ } catch {
8254
+ return fetchImplementation(input, init);
8255
+ }
8256
+ let changed = false;
8257
+ for (const message of body.messages ?? []) {
8258
+ if (message.role !== "tool" || typeof message.content !== "string") continue;
8259
+ const parts = imageContent(message.content);
8260
+ if (!parts) continue;
8261
+ message.content = parts;
8262
+ changed = true;
8263
+ }
8264
+ return fetchImplementation(input, changed ? { ...init, body: JSON.stringify(body) } : init);
8265
+ });
8266
+ }
8267
+ function imageContent(text) {
8268
+ if (!text.startsWith("[")) return void 0;
8269
+ let value;
8270
+ try {
8271
+ value = JSON.parse(text);
8272
+ } catch {
8273
+ return void 0;
8274
+ }
8275
+ if (!Array.isArray(value)) return void 0;
8276
+ const parts = [];
8277
+ let images = 0;
8278
+ for (const part of value) {
8279
+ if (part?.type === "text" && typeof part.text === "string") {
8280
+ parts.push({ type: "text", text: part.text });
8281
+ continue;
8282
+ }
8283
+ const url = part?.type === "file" && typeof part.mediaType === "string" && part.mediaType.startsWith("image/") ? imageUrl(part.mediaType, part.data) : void 0;
8284
+ if (!url) return void 0;
8285
+ parts.push({ type: "image_url", image_url: { url } });
8286
+ images += 1;
8287
+ }
8288
+ return images > 0 ? parts : void 0;
8289
+ }
8290
+ function imageUrl(mediaType, data) {
8291
+ if (data?.type === "url" && typeof data.url === "string") return data.url;
8292
+ if (data?.type !== "data") return void 0;
8293
+ const raw = data.data;
8294
+ const base64 = typeof raw === "string" ? raw : raw && typeof raw === "object" ? Buffer.from(Object.keys(raw).sort((a, b) => Number(a) - Number(b)).map((key) => raw[key])).toString("base64") : void 0;
8295
+ return base64 === void 0 ? void 0 : `data:${mediaType === "image/jpg" ? "image/jpeg" : mediaType};base64,${base64}`;
8296
+ }
8297
+
8245
8298
  // src/models/providers/session-header.ts
8246
8299
  var SAFE_SESSION_ID = /^[A-Za-z0-9._:~-]{1,128}$/;
8247
8300
  function sessionHeaderValue(chatId) {
@@ -8267,7 +8320,7 @@ function createFireworksProvider(connectionOptions = {}) {
8267
8320
  id: "fireworks",
8268
8321
  displayName: "Fireworks",
8269
8322
  apiKeyEnv: "FIREWORKS_API_KEY",
8270
- createLanguageModel: (providerModelId, apiKey, options2) => createFireworks({ apiKey, fetch: options2?.fetch, ...connection })(providerModelId),
8323
+ createLanguageModel: (providerModelId, apiKey, options2) => createFireworks({ apiKey, fetch: withToolResultImages(options2?.fetch), ...connection })(providerModelId),
8271
8324
  reasoningRequest: (level) => sdkReasoningRequest(level),
8272
8325
  requestOptions: ({ chatId }) => ({
8273
8326
  providerOptions: {
@@ -8639,7 +8692,7 @@ function createTogetherProvider(connectionOptions = {}) {
8639
8692
  id: "together",
8640
8693
  displayName: "Together AI",
8641
8694
  apiKeyEnv: "TOGETHER_API_KEY",
8642
- createLanguageModel: (providerModelId, apiKey, options2) => createTogetherAI({ apiKey, fetch: options2?.fetch, ...connection })(providerModelId),
8695
+ createLanguageModel: (providerModelId, apiKey, options2) => createTogetherAI({ apiKey, fetch: withToolResultImages(options2?.fetch), ...connection })(providerModelId),
8643
8696
  reasoningRequest: (level) => sdkReasoningRequest(level),
8644
8697
  samplingRequest: ({ minP }) => minP === void 0 ? {} : { togetherai: { min_p: minP } },
8645
8698
  requestOptions: () => ({}),
@@ -8699,11 +8752,11 @@ var deepseek41FlashProfile = {
8699
8752
  displayName: "DeepSeek 4.1 Flash",
8700
8753
  contextWindowTokens: 1e6,
8701
8754
  acceptsImages: true,
8702
- // Together даёт модель только с текстом (каталог Together, 2026-10-11): картинка туда не уходит.
8703
- acceptsImagesByProvider: { together: false },
8704
- // Картинку в результате инструмента видит у самого DeepSeek (проверено вживую 2026-10-05) и через OpenRouter у всех
8705
- // хозяев, кроме запрещённых ниже: одни её не видят, другие отвергают запрос (замер всех хозяев модели в OpenRouter 2026-10-06, specs/research-openrouter-tool-images.md).
8706
- toolResultImageProviders: ["deepseek", "openrouter"],
8755
+ // Картинку в результате инструмента видит у самого DeepSeek (проверено вживую 2026-10-05), у Together и Fireworks
8756
+ // (вживую 2026-10-15: картинка в ответе инструмента и в сообщении человека — цвет назван верно; запись каталога
8757
+ // Together «только текст» устарела) и через OpenRouter у всех хозяев, кроме запрещённых ниже: одни её не видят,
8758
+ // другие отвергают запрос (замер всех хозяев модели в OpenRouter 2026-10-06, specs/research-openrouter-tool-images.md).
8759
+ toolResultImageProviders: ["deepseek", "together", "fireworks", "openrouter"],
8707
8760
  reasoning: { replayPastTurns: true, levels: ["off", "on"], defaultLevel: "on" },
8708
8761
  // Запрет стоит всегда, а не только при картинке: запрос одинаков в каждом ходе, кэш и выбранный хозяин не теряются.
8709
8762
  providerOptions: { openrouter: { provider: { ignore: ["deepinfra", "open-inference", "phala", "sail-research", "venice"] } } },
@@ -14116,4 +14169,4 @@ export {
14116
14169
  InvalidWidgetAnswerError,
14117
14170
  createChatService
14118
14171
  };
14119
- //# sourceMappingURL=chunk-QA5DVEXF.js.map
14172
+ //# sourceMappingURL=chunk-WQZQZCAB.js.map