llm-exe 3.0.0 → 3.0.2
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/index.d.mts +77 -27
- package/dist/index.d.ts +77 -27
- package/dist/index.js +283 -24
- package/dist/index.mjs +281 -24
- package/package.json +2 -1
- package/readme.md +1 -1
package/dist/index.js
CHANGED
|
@@ -67,10 +67,12 @@ __export(index_exports, {
|
|
|
67
67
|
createState: () => createState,
|
|
68
68
|
createStateItem: () => createStateItem,
|
|
69
69
|
defineSchema: () => defineSchema,
|
|
70
|
+
formatLlmExeErrorForLog: () => formatLlmExeErrorForLog,
|
|
70
71
|
guards: () => guards_exports,
|
|
71
72
|
isLlmExeError: () => isLlmExeError,
|
|
72
73
|
registerHelpers: () => registerHelpers,
|
|
73
74
|
registerPartials: () => registerPartials,
|
|
75
|
+
serializeLlmExeError: () => serializeLlmExeError,
|
|
74
76
|
useExecutors: () => useExecutors,
|
|
75
77
|
useLlm: () => useLlm,
|
|
76
78
|
useLlmConfiguration: () => useLlmConfiguration,
|
|
@@ -530,6 +532,48 @@ function formatErrorList(values, options) {
|
|
|
530
532
|
}
|
|
531
533
|
return parts.join(", ");
|
|
532
534
|
}
|
|
535
|
+
function formatLlmExeErrorForLog(error) {
|
|
536
|
+
if (!error || typeof error !== "object") {
|
|
537
|
+
return formatErrorValue(error);
|
|
538
|
+
}
|
|
539
|
+
const e = error;
|
|
540
|
+
const name = typeof e.name === "string" && e.name ? e.name : "Error";
|
|
541
|
+
const message = typeof e.message === "string" ? e.message : "";
|
|
542
|
+
const code = typeof e.code === "string" ? e.code : void 0;
|
|
543
|
+
const category = typeof e.category === "string" ? e.category : void 0;
|
|
544
|
+
let header;
|
|
545
|
+
if (code) {
|
|
546
|
+
header = `${name} [${code}]: ${message}`;
|
|
547
|
+
} else if (category) {
|
|
548
|
+
header = `${name} [${category}]: ${message}`;
|
|
549
|
+
} else {
|
|
550
|
+
header = `${name}: ${message}`;
|
|
551
|
+
}
|
|
552
|
+
const chain = [];
|
|
553
|
+
let current = e.cause;
|
|
554
|
+
let depth = 0;
|
|
555
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
556
|
+
while (current && depth < 5) {
|
|
557
|
+
if (typeof current === "object") {
|
|
558
|
+
if (seen.has(current)) {
|
|
559
|
+
chain.push("Caused by: [Circular]");
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
seen.add(current);
|
|
563
|
+
}
|
|
564
|
+
const c = current;
|
|
565
|
+
const cName = typeof c.name === "string" && c.name ? c.name : "Error";
|
|
566
|
+
const cMsg = typeof c.message === "string" ? c.message : String(current);
|
|
567
|
+
const cCode = typeof c.code === "string" ? c.code : void 0;
|
|
568
|
+
chain.push(
|
|
569
|
+
cCode ? `Caused by: ${cName} [${cCode}]: ${cMsg}` : `Caused by: ${cName}: ${cMsg}`
|
|
570
|
+
);
|
|
571
|
+
current = c.cause;
|
|
572
|
+
depth++;
|
|
573
|
+
}
|
|
574
|
+
return chain.length > 0 ? `${header}
|
|
575
|
+
${chain.join("\n")}` : header;
|
|
576
|
+
}
|
|
533
577
|
|
|
534
578
|
// src/errors/createLlmExeError.ts
|
|
535
579
|
var DOCS_BASE_URL = "https://llm-exe.com";
|
|
@@ -1051,7 +1095,9 @@ var BaseExecutor = class {
|
|
|
1051
1095
|
return this;
|
|
1052
1096
|
}
|
|
1053
1097
|
on(eventName, fn) {
|
|
1054
|
-
return this.setHooks({
|
|
1098
|
+
return this.setHooks({
|
|
1099
|
+
[eventName]: fn
|
|
1100
|
+
});
|
|
1055
1101
|
}
|
|
1056
1102
|
off(eventName, fn) {
|
|
1057
1103
|
return this.removeHook(eventName, fn);
|
|
@@ -1149,8 +1195,8 @@ var CoreExecutor = class extends BaseExecutor {
|
|
|
1149
1195
|
__publicField(this, "_handler");
|
|
1150
1196
|
this._handler = fn.handler.bind(null);
|
|
1151
1197
|
}
|
|
1152
|
-
async handler(_input) {
|
|
1153
|
-
return this._handler.call(null, _input);
|
|
1198
|
+
async handler(_input, _options, _context) {
|
|
1199
|
+
return this._handler.call(null, _input, _context);
|
|
1154
1200
|
}
|
|
1155
1201
|
};
|
|
1156
1202
|
|
|
@@ -3302,6 +3348,7 @@ __export(utils_exports, {
|
|
|
3302
3348
|
assert: () => assert,
|
|
3303
3349
|
asyncCallWithTimeout: () => asyncCallWithTimeout,
|
|
3304
3350
|
defineSchema: () => defineSchema,
|
|
3351
|
+
escapeTemplateString: () => escapeTemplateString,
|
|
3305
3352
|
filterObjectOnSchema: () => filterObjectOnSchema,
|
|
3306
3353
|
guessProviderFromModel: () => guessProviderFromModel,
|
|
3307
3354
|
importHelpers: () => importHelpers,
|
|
@@ -3374,6 +3421,12 @@ function importHelpers(_helpers) {
|
|
|
3374
3421
|
return helpers;
|
|
3375
3422
|
}
|
|
3376
3423
|
|
|
3424
|
+
// src/utils/modules/escapeTemplateString.ts
|
|
3425
|
+
function escapeTemplateString(input) {
|
|
3426
|
+
if (typeof input !== "string") return input;
|
|
3427
|
+
return input.replace(/\{\{/g, "\\{{");
|
|
3428
|
+
}
|
|
3429
|
+
|
|
3377
3430
|
// src/utils/modules/replaceTemplateStringAsync.ts
|
|
3378
3431
|
async function replaceTemplateStringAsync(templateString, substitutions = {}, configuration = {
|
|
3379
3432
|
helpers: [],
|
|
@@ -4039,9 +4092,53 @@ function OutputOpenAIChat(result, _config) {
|
|
|
4039
4092
|
};
|
|
4040
4093
|
}
|
|
4041
4094
|
|
|
4095
|
+
// src/llm/config/_utils/imageContent.ts
|
|
4096
|
+
function isImageUrlContentBlock(block) {
|
|
4097
|
+
if (typeof block !== "object" || block === null) {
|
|
4098
|
+
return false;
|
|
4099
|
+
}
|
|
4100
|
+
const imageUrl = block.image_url;
|
|
4101
|
+
return typeof imageUrl === "object" && imageUrl !== null && typeof imageUrl.url === "string";
|
|
4102
|
+
}
|
|
4103
|
+
var DATA_URI_PATTERN = /^data:([^;,]+);base64,(.+)$/;
|
|
4104
|
+
function parseImageUrl(url, context) {
|
|
4105
|
+
if (typeof url !== "string" || url.trim() === "") {
|
|
4106
|
+
throw new LlmExeError("Image content block has an empty url", {
|
|
4107
|
+
code: "prompt.invalid_messages",
|
|
4108
|
+
context: {
|
|
4109
|
+
...context,
|
|
4110
|
+
received: url,
|
|
4111
|
+
expected: "an https URL or a data: URI",
|
|
4112
|
+
resolution: "Set image_url.url to an https URL or a base64 data: URI (data:image/png;base64,...)."
|
|
4113
|
+
}
|
|
4114
|
+
});
|
|
4115
|
+
}
|
|
4116
|
+
if (url.startsWith("data:")) {
|
|
4117
|
+
const match = url.match(DATA_URI_PATTERN);
|
|
4118
|
+
if (!match) {
|
|
4119
|
+
throw new LlmExeError("Malformed data: URI in image content block", {
|
|
4120
|
+
code: "prompt.invalid_messages",
|
|
4121
|
+
context: {
|
|
4122
|
+
...context,
|
|
4123
|
+
received: `${url.slice(0, 48)}...`,
|
|
4124
|
+
expected: "data:<media-type>;base64,<data>",
|
|
4125
|
+
resolution: "Images must be base64-encoded with an explicit media type, e.g. data:image/png;base64,iVBOR..."
|
|
4126
|
+
}
|
|
4127
|
+
});
|
|
4128
|
+
}
|
|
4129
|
+
return { kind: "base64", mediaType: match[1], data: match[2] };
|
|
4130
|
+
}
|
|
4131
|
+
return { kind: "url", url };
|
|
4132
|
+
}
|
|
4133
|
+
|
|
4042
4134
|
// src/llm/config/openai/promptSanitizeMessageCallback.ts
|
|
4043
4135
|
function openaiPromptMessageCallback(_message) {
|
|
4044
4136
|
let message = { ..._message };
|
|
4137
|
+
if (Array.isArray(message.content)) {
|
|
4138
|
+
message.content = message.content.map(
|
|
4139
|
+
(block) => isImageUrlContentBlock(block) && block.type !== "image_url" ? { ...block, type: "image_url" } : block
|
|
4140
|
+
);
|
|
4141
|
+
}
|
|
4045
4142
|
if (message.role === "function") {
|
|
4046
4143
|
message.role = "tool";
|
|
4047
4144
|
message.tool_call_id = message.id;
|
|
@@ -4247,6 +4344,9 @@ var openai = {
|
|
|
4247
4344
|
"openai.chat.v1": openAiChatV1,
|
|
4248
4345
|
"openai.chat-mock.v1": openAiChatMockV1,
|
|
4249
4346
|
// GPT-5 family
|
|
4347
|
+
"openai.gpt-5.5": withDefaultModel(openAiChatV1, "gpt-5.5"),
|
|
4348
|
+
"openai.gpt-5.4": withDefaultModel(openAiChatV1, "gpt-5.4"),
|
|
4349
|
+
"openai.gpt-5.4-mini": withDefaultModel(openAiChatV1, "gpt-5.4-mini"),
|
|
4250
4350
|
"openai.gpt-5.2": withDefaultModel(openAiChatV1, "gpt-5.2"),
|
|
4251
4351
|
"openai.gpt-5-mini": withDefaultModel(openAiChatV1, "gpt-5-mini"),
|
|
4252
4352
|
"openai.gpt-5-nano": withDefaultModel(openAiChatV1, "gpt-5-nano"),
|
|
@@ -4268,8 +4368,46 @@ var openai = {
|
|
|
4268
4368
|
};
|
|
4269
4369
|
|
|
4270
4370
|
// src/llm/config/anthropic/promptSanitizeMessageCallback.ts
|
|
4271
|
-
function anthropicPromptMessageCallback(_message) {
|
|
4371
|
+
function anthropicPromptMessageCallback(_message, options = {}) {
|
|
4372
|
+
const { provider = "anthropic.chat", allowImageUrlSources = true } = options;
|
|
4272
4373
|
let message = { ..._message };
|
|
4374
|
+
if (Array.isArray(message.content)) {
|
|
4375
|
+
message.content = message.content.map((block) => {
|
|
4376
|
+
if (!isImageUrlContentBlock(block)) {
|
|
4377
|
+
return block;
|
|
4378
|
+
}
|
|
4379
|
+
const parsed = parseImageUrl(block.image_url.url, {
|
|
4380
|
+
operation: "anthropicPromptMessageCallback",
|
|
4381
|
+
provider
|
|
4382
|
+
});
|
|
4383
|
+
if (parsed.kind === "base64") {
|
|
4384
|
+
return {
|
|
4385
|
+
type: "image",
|
|
4386
|
+
source: {
|
|
4387
|
+
type: "base64",
|
|
4388
|
+
media_type: parsed.mediaType,
|
|
4389
|
+
data: parsed.data
|
|
4390
|
+
}
|
|
4391
|
+
};
|
|
4392
|
+
}
|
|
4393
|
+
if (!allowImageUrlSources) {
|
|
4394
|
+
throw new LlmExeError("Image URLs are not supported by this provider", {
|
|
4395
|
+
code: "prompt.invalid_messages",
|
|
4396
|
+
context: {
|
|
4397
|
+
operation: "anthropicPromptMessageCallback",
|
|
4398
|
+
provider,
|
|
4399
|
+
received: parsed.url,
|
|
4400
|
+
expected: "a base64 data: URI",
|
|
4401
|
+
resolution: "Bedrock does not fetch remote images. Base64-encode the image and pass it as a data: URI (data:image/png;base64,...)."
|
|
4402
|
+
}
|
|
4403
|
+
});
|
|
4404
|
+
}
|
|
4405
|
+
return {
|
|
4406
|
+
type: "image",
|
|
4407
|
+
source: { type: "url", url: parsed.url }
|
|
4408
|
+
};
|
|
4409
|
+
});
|
|
4410
|
+
}
|
|
4273
4411
|
if (message.role === "function") {
|
|
4274
4412
|
message.role = "user";
|
|
4275
4413
|
message.content = [
|
|
@@ -4315,10 +4453,11 @@ function mergeConsecutiveSameRole(messages) {
|
|
|
4315
4453
|
}
|
|
4316
4454
|
return merged;
|
|
4317
4455
|
}
|
|
4318
|
-
function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
|
|
4456
|
+
function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj, _options = {}) {
|
|
4457
|
+
const toAnthropicMessage = (m) => anthropicPromptMessageCallback(m, _options);
|
|
4319
4458
|
if (typeof _messages === "string") {
|
|
4320
4459
|
return [{ role: "user", content: _messages }].map(
|
|
4321
|
-
|
|
4460
|
+
toAnthropicMessage
|
|
4322
4461
|
);
|
|
4323
4462
|
}
|
|
4324
4463
|
const [first, ...messages] = [
|
|
@@ -4328,7 +4467,7 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
|
|
|
4328
4467
|
return [
|
|
4329
4468
|
{ role: "user", content: first.content },
|
|
4330
4469
|
...messages
|
|
4331
|
-
].map(
|
|
4470
|
+
].map(toAnthropicMessage);
|
|
4332
4471
|
}
|
|
4333
4472
|
if (first.role === "system" && messages.length > 0) {
|
|
4334
4473
|
_outputObj.system = first.content;
|
|
@@ -4337,7 +4476,7 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
|
|
|
4337
4476
|
return { ...m, role: "user" };
|
|
4338
4477
|
}
|
|
4339
4478
|
return m;
|
|
4340
|
-
}).map(
|
|
4479
|
+
}).map(toAnthropicMessage);
|
|
4341
4480
|
return mergeConsecutiveSameRole(result2);
|
|
4342
4481
|
}
|
|
4343
4482
|
const result = [
|
|
@@ -4348,7 +4487,7 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
|
|
|
4348
4487
|
}
|
|
4349
4488
|
return m;
|
|
4350
4489
|
})
|
|
4351
|
-
].map(
|
|
4490
|
+
].map(toAnthropicMessage);
|
|
4352
4491
|
return mergeConsecutiveSameRole(result);
|
|
4353
4492
|
}
|
|
4354
4493
|
|
|
@@ -4461,7 +4600,11 @@ var amazonAnthropicChatV1 = {
|
|
|
4461
4600
|
mapBody: {
|
|
4462
4601
|
prompt: {
|
|
4463
4602
|
key: "messages",
|
|
4464
|
-
transform: anthropicPromptSanitize
|
|
4603
|
+
transform: (v, i, o) => anthropicPromptSanitize(v, i, o, {
|
|
4604
|
+
provider: "amazon:anthropic.chat",
|
|
4605
|
+
// Bedrock's invoke API only accepts base64 image sources
|
|
4606
|
+
allowImageUrlSources: false
|
|
4607
|
+
})
|
|
4465
4608
|
},
|
|
4466
4609
|
topP: {
|
|
4467
4610
|
key: "top_p"
|
|
@@ -4517,6 +4660,21 @@ var amazonMetaChatV1 = {
|
|
|
4517
4660
|
if (typeof messages === "string") {
|
|
4518
4661
|
return messages;
|
|
4519
4662
|
} else {
|
|
4663
|
+
const hasImageContent = messages.some(
|
|
4664
|
+
(message) => Array.isArray(message?.content) && message.content.some(isImageUrlContentBlock)
|
|
4665
|
+
);
|
|
4666
|
+
if (hasImageContent) {
|
|
4667
|
+
throw new LlmExeError("Image content is not supported", {
|
|
4668
|
+
code: "prompt.invalid_messages",
|
|
4669
|
+
context: {
|
|
4670
|
+
operation: "amazonMetaChatV1.prompt.transform",
|
|
4671
|
+
provider: "amazon:meta.chat",
|
|
4672
|
+
received: "a message with image content",
|
|
4673
|
+
expected: "text-only messages",
|
|
4674
|
+
resolution: "This model accepts a flattened text prompt and cannot receive images."
|
|
4675
|
+
}
|
|
4676
|
+
});
|
|
4677
|
+
}
|
|
4520
4678
|
return replaceTemplateString(`{{>DialogueHistory key='messages'}}`, {
|
|
4521
4679
|
messages
|
|
4522
4680
|
});
|
|
@@ -4544,7 +4702,11 @@ var bedrock = {
|
|
|
4544
4702
|
|
|
4545
4703
|
// src/llm/config/anthropic/index.ts
|
|
4546
4704
|
var ANTHROPIC_VERSION = "2023-06-01";
|
|
4547
|
-
var MODELS_REJECTING_SAMPLING_PARAMS = [
|
|
4705
|
+
var MODELS_REJECTING_SAMPLING_PARAMS = [
|
|
4706
|
+
"claude-opus-4-7",
|
|
4707
|
+
"claude-opus-4-8",
|
|
4708
|
+
"claude-fable-5"
|
|
4709
|
+
];
|
|
4548
4710
|
var isClaude4x = (model) => /^claude-(opus|sonnet|haiku)-4-/.test(model);
|
|
4549
4711
|
var dropIfModelRejectsSamplingParams = (v, body) => MODELS_REJECTING_SAMPLING_PARAMS.includes(body.model) ? void 0 : v;
|
|
4550
4712
|
var topPTransform = (v, body) => {
|
|
@@ -4565,6 +4727,15 @@ var anthropicChatV1 = {
|
|
|
4565
4727
|
required: [true, "maxTokens required"],
|
|
4566
4728
|
default: 4096
|
|
4567
4729
|
},
|
|
4730
|
+
// Every key mapped in mapBody must also be declared here:
|
|
4731
|
+
// stateFromOptions picks only declared option keys, so an undeclared
|
|
4732
|
+
// key never reaches mapBody (see issue #661).
|
|
4733
|
+
temperature: {},
|
|
4734
|
+
topP: {},
|
|
4735
|
+
topK: {},
|
|
4736
|
+
stopSequences: {},
|
|
4737
|
+
metadata: {},
|
|
4738
|
+
serviceTier: {},
|
|
4568
4739
|
anthropicApiKey: {
|
|
4569
4740
|
default: getEnvironmentVariable("ANTHROPIC_API_KEY")
|
|
4570
4741
|
}
|
|
@@ -4598,9 +4769,8 @@ var anthropicChatV1 = {
|
|
|
4598
4769
|
stopSequences: {
|
|
4599
4770
|
key: "stop_sequences"
|
|
4600
4771
|
},
|
|
4601
|
-
stream:
|
|
4602
|
-
|
|
4603
|
-
},
|
|
4772
|
+
// No `stream` mapping: the request pipeline has no SSE support, so
|
|
4773
|
+
// forwarding stream=true would return an unparseable response.
|
|
4604
4774
|
metadata: {
|
|
4605
4775
|
key: "metadata"
|
|
4606
4776
|
},
|
|
@@ -4629,6 +4799,11 @@ var anthropicChatV1 = {
|
|
|
4629
4799
|
};
|
|
4630
4800
|
var anthropic = {
|
|
4631
4801
|
"anthropic.chat.v1": anthropicChatV1,
|
|
4802
|
+
// Claude Fable 5 models
|
|
4803
|
+
"anthropic.claude-fable-5": withDefaultModel(
|
|
4804
|
+
anthropicChatV1,
|
|
4805
|
+
"claude-fable-5"
|
|
4806
|
+
),
|
|
4632
4807
|
// Claude 4.8 models
|
|
4633
4808
|
"anthropic.claude-opus-4-8": withDefaultModel(
|
|
4634
4809
|
anthropicChatV1,
|
|
@@ -4662,10 +4837,9 @@ var anthropic = {
|
|
|
4662
4837
|
config: withDefaultModel(anthropicChatV1, "claude-opus-4-6"),
|
|
4663
4838
|
message: 'Shorthand "anthropic.claude-opus-4-6" is deprecated and may be removed in a future release.'
|
|
4664
4839
|
}),
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
}),
|
|
4840
|
+
// NOTE: "anthropic.claude-opus-4-1" (claude-opus-4-1-20250805) was removed —
|
|
4841
|
+
// Anthropic retires that model on Aug 5, 2026. Migrate to
|
|
4842
|
+
// anthropic.claude-opus-4-5/-6/-7/-8.
|
|
4669
4843
|
...deprecateShorthand("anthropic.claude-sonnet-4", {
|
|
4670
4844
|
config: withDefaultModel(anthropicChatV1, "claude-sonnet-4-0"),
|
|
4671
4845
|
message: 'Shorthand "anthropic.claude-sonnet-4" is deprecated and may be removed in a future release.'
|
|
@@ -4811,6 +4985,60 @@ function OutputOllamaChat(result, _config) {
|
|
|
4811
4985
|
};
|
|
4812
4986
|
}
|
|
4813
4987
|
|
|
4988
|
+
// src/llm/config/ollama/promptSanitize.ts
|
|
4989
|
+
function ollamaPromptSanitize(_messages) {
|
|
4990
|
+
if (typeof _messages === "string") {
|
|
4991
|
+
return [{ role: "user", content: _messages }];
|
|
4992
|
+
}
|
|
4993
|
+
return _messages.map((_message) => {
|
|
4994
|
+
if (!Array.isArray(_message.content)) {
|
|
4995
|
+
return _message;
|
|
4996
|
+
}
|
|
4997
|
+
const message = { ..._message };
|
|
4998
|
+
const textParts = [];
|
|
4999
|
+
const images = [];
|
|
5000
|
+
for (const block of message.content) {
|
|
5001
|
+
if (isImageUrlContentBlock(block)) {
|
|
5002
|
+
const parsed = parseImageUrl(block.image_url.url, {
|
|
5003
|
+
operation: "ollamaPromptSanitize",
|
|
5004
|
+
provider: "ollama.chat"
|
|
5005
|
+
});
|
|
5006
|
+
if (parsed.kind === "url") {
|
|
5007
|
+
throw new LlmExeError("Image URLs are not supported by ollama", {
|
|
5008
|
+
code: "prompt.invalid_messages",
|
|
5009
|
+
context: {
|
|
5010
|
+
operation: "ollamaPromptSanitize",
|
|
5011
|
+
provider: "ollama.chat",
|
|
5012
|
+
received: parsed.url,
|
|
5013
|
+
expected: "a base64 data: URI",
|
|
5014
|
+
resolution: "Ollama does not fetch remote images. Base64-encode the image and pass it as a data: URI (data:image/png;base64,...)."
|
|
5015
|
+
}
|
|
5016
|
+
});
|
|
5017
|
+
}
|
|
5018
|
+
images.push(parsed.data);
|
|
5019
|
+
} else if (typeof block?.text === "string") {
|
|
5020
|
+
textParts.push(block.text);
|
|
5021
|
+
} else {
|
|
5022
|
+
throw new LlmExeError("Unsupported content block for ollama", {
|
|
5023
|
+
code: "prompt.invalid_messages",
|
|
5024
|
+
context: {
|
|
5025
|
+
operation: "ollamaPromptSanitize",
|
|
5026
|
+
provider: "ollama.chat",
|
|
5027
|
+
received: block,
|
|
5028
|
+
expected: "text or image_url content blocks",
|
|
5029
|
+
resolution: "Ollama messages only support text and base64 images."
|
|
5030
|
+
}
|
|
5031
|
+
});
|
|
5032
|
+
}
|
|
5033
|
+
}
|
|
5034
|
+
message.content = textParts.join("\n");
|
|
5035
|
+
if (images.length > 0) {
|
|
5036
|
+
message.images = images;
|
|
5037
|
+
}
|
|
5038
|
+
return message;
|
|
5039
|
+
});
|
|
5040
|
+
}
|
|
5041
|
+
|
|
4814
5042
|
// src/llm/config/ollama/index.ts
|
|
4815
5043
|
var ollamaChatV1 = {
|
|
4816
5044
|
key: "ollama.chat.v1",
|
|
@@ -4828,12 +5056,7 @@ var ollamaChatV1 = {
|
|
|
4828
5056
|
mapBody: {
|
|
4829
5057
|
prompt: {
|
|
4830
5058
|
key: "messages",
|
|
4831
|
-
transform: (v) =>
|
|
4832
|
-
if (typeof v === "string") {
|
|
4833
|
-
return [{ role: "user", content: v }];
|
|
4834
|
-
}
|
|
4835
|
-
return v;
|
|
4836
|
-
}
|
|
5059
|
+
transform: (v) => ollamaPromptSanitize(v)
|
|
4837
5060
|
},
|
|
4838
5061
|
model: {
|
|
4839
5062
|
key: "model"
|
|
@@ -4870,6 +5093,37 @@ var ollama = {
|
|
|
4870
5093
|
};
|
|
4871
5094
|
|
|
4872
5095
|
// src/llm/config/google/promptSanitizeMessageCallback.ts
|
|
5096
|
+
var GOOGLE_SUPPORTED_FILE_URI = /^(gs:\/\/|https:\/\/generativelanguage\.googleapis\.com\/)/;
|
|
5097
|
+
function googleGeminiContentBlockToPart(block) {
|
|
5098
|
+
if (isImageUrlContentBlock(block)) {
|
|
5099
|
+
const parsed = parseImageUrl(block.image_url.url, {
|
|
5100
|
+
operation: "googleGeminiPromptMessageCallback",
|
|
5101
|
+
provider: "google.chat"
|
|
5102
|
+
});
|
|
5103
|
+
if (parsed.kind === "base64") {
|
|
5104
|
+
return {
|
|
5105
|
+
inlineData: { mimeType: parsed.mediaType, data: parsed.data }
|
|
5106
|
+
};
|
|
5107
|
+
}
|
|
5108
|
+
if (GOOGLE_SUPPORTED_FILE_URI.test(parsed.url)) {
|
|
5109
|
+
return { fileData: { fileUri: parsed.url } };
|
|
5110
|
+
}
|
|
5111
|
+
throw new LlmExeError("Gemini cannot load images from arbitrary URLs", {
|
|
5112
|
+
code: "prompt.invalid_messages",
|
|
5113
|
+
context: {
|
|
5114
|
+
operation: "googleGeminiPromptMessageCallback",
|
|
5115
|
+
provider: "google.chat",
|
|
5116
|
+
received: parsed.url,
|
|
5117
|
+
expected: "a base64 data: URI, a Files API URI, or a gs:// URI",
|
|
5118
|
+
resolution: "Pass the image as a data: URI (data:image/png;base64,...), or upload it with the Gemini Files API and pass the returned file URI."
|
|
5119
|
+
}
|
|
5120
|
+
});
|
|
5121
|
+
}
|
|
5122
|
+
if (typeof block?.text === "string") {
|
|
5123
|
+
return { text: block.text };
|
|
5124
|
+
}
|
|
5125
|
+
return block;
|
|
5126
|
+
}
|
|
4873
5127
|
function googleGeminiPromptMessageCallback(_message) {
|
|
4874
5128
|
let message = { ..._message };
|
|
4875
5129
|
const parts = [];
|
|
@@ -4883,6 +5137,9 @@ function googleGeminiPromptMessageCallback(_message) {
|
|
|
4883
5137
|
if (typeof payload.content === "string" && message.role !== "function") {
|
|
4884
5138
|
parts.push({ text: message.content });
|
|
4885
5139
|
}
|
|
5140
|
+
if (Array.isArray(payload.content) && message.role !== "function") {
|
|
5141
|
+
parts.push(...payload.content.map(googleGeminiContentBlockToPart));
|
|
5142
|
+
}
|
|
4886
5143
|
if (message.role === "function") {
|
|
4887
5144
|
role = "user";
|
|
4888
5145
|
parts.push({
|
|
@@ -7700,10 +7957,12 @@ function createStateItem(name, defaultValue) {
|
|
|
7700
7957
|
createState,
|
|
7701
7958
|
createStateItem,
|
|
7702
7959
|
defineSchema,
|
|
7960
|
+
formatLlmExeErrorForLog,
|
|
7703
7961
|
guards,
|
|
7704
7962
|
isLlmExeError,
|
|
7705
7963
|
registerHelpers,
|
|
7706
7964
|
registerPartials,
|
|
7965
|
+
serializeLlmExeError,
|
|
7707
7966
|
useExecutors,
|
|
7708
7967
|
useLlm,
|
|
7709
7968
|
useLlmConfiguration,
|