llm-exe 3.0.0-beta.1 → 3.0.0-beta.3
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 +44 -21
- package/dist/index.d.ts +44 -21
- package/dist/index.js +299 -78
- package/dist/index.mjs +299 -78
- package/package.json +1 -1
- package/readme.md +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1200,9 +1200,12 @@ var BOOLEAN_VALUES = ["true", "false", "yes", "no", "y", "n", "1", "0"];
|
|
|
1200
1200
|
var TRUTHY_VALUES = /* @__PURE__ */ new Set(["true", "yes", "y", "1"]);
|
|
1201
1201
|
var FALSY_VALUES = /* @__PURE__ */ new Set(["false", "no", "n", "0"]);
|
|
1202
1202
|
var MAX_ERROR_INPUT_EXCERPT_LENGTH = 500;
|
|
1203
|
+
var BOOLEAN_TOKEN_PATTERN = /(?<![\p{L}\p{N}])(?:true|false|yes|no|y|n|1|0)(?![\p{L}\p{N}])/giu;
|
|
1203
1204
|
var BooleanParser = class extends BaseParser {
|
|
1204
|
-
constructor() {
|
|
1205
|
+
constructor(options) {
|
|
1205
1206
|
super("boolean");
|
|
1207
|
+
__publicField(this, "match");
|
|
1208
|
+
this.match = options?.match ?? "exact";
|
|
1206
1209
|
}
|
|
1207
1210
|
getInputErrorContext(text) {
|
|
1208
1211
|
const context = {
|
|
@@ -1250,6 +1253,36 @@ var BooleanParser = class extends BaseParser {
|
|
|
1250
1253
|
if (FALSY_VALUES.has(clean)) {
|
|
1251
1254
|
return false;
|
|
1252
1255
|
}
|
|
1256
|
+
if (this.match === "extract") {
|
|
1257
|
+
const matches = Array.from(
|
|
1258
|
+
text.toLowerCase().matchAll(BOOLEAN_TOKEN_PATTERN)
|
|
1259
|
+
).map((match) => match[0]);
|
|
1260
|
+
const values = Array.from(
|
|
1261
|
+
new Set(
|
|
1262
|
+
matches.map((match) => {
|
|
1263
|
+
if (TRUTHY_VALUES.has(match)) return true;
|
|
1264
|
+
return false;
|
|
1265
|
+
})
|
|
1266
|
+
)
|
|
1267
|
+
);
|
|
1268
|
+
if (values.length === 1) {
|
|
1269
|
+
return values[0];
|
|
1270
|
+
}
|
|
1271
|
+
if (values.length > 1) {
|
|
1272
|
+
throw new LlmExeError(`Multiple boolean values found in input.`, {
|
|
1273
|
+
code: "parser.parse_failed",
|
|
1274
|
+
context: {
|
|
1275
|
+
operation: "BooleanParser.parse",
|
|
1276
|
+
parser: "boolean",
|
|
1277
|
+
reason: "ambiguous_boolean",
|
|
1278
|
+
expected: "one boolean value",
|
|
1279
|
+
match: this.match,
|
|
1280
|
+
matchCount: values.length,
|
|
1281
|
+
...this.getInputErrorContext(text)
|
|
1282
|
+
}
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1253
1286
|
throw new LlmExeError(`No boolean value found in input.`, {
|
|
1254
1287
|
code: "parser.parse_failed",
|
|
1255
1288
|
context: {
|
|
@@ -1257,6 +1290,7 @@ var BooleanParser = class extends BaseParser {
|
|
|
1257
1290
|
parser: "boolean",
|
|
1258
1291
|
reason: "unrecognized_boolean",
|
|
1259
1292
|
expected: BOOLEAN_VALUES,
|
|
1293
|
+
match: this.match,
|
|
1260
1294
|
...this.getInputErrorContext(text)
|
|
1261
1295
|
}
|
|
1262
1296
|
});
|
|
@@ -1281,7 +1315,7 @@ function toNumber(value) {
|
|
|
1281
1315
|
|
|
1282
1316
|
// src/parser/parsers/NumberParser.ts
|
|
1283
1317
|
var NUMERIC_TOKEN_PATTERN = /(^|[^\w.,])([+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?)(?![\w,])/g;
|
|
1284
|
-
var
|
|
1318
|
+
var EXACT_NUMERIC_PATTERN = /^[+-]?(?:(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?$/;
|
|
1285
1319
|
var NumberParser = class extends BaseParser {
|
|
1286
1320
|
constructor(options) {
|
|
1287
1321
|
super("number");
|
|
@@ -1316,16 +1350,16 @@ var NumberParser = class extends BaseParser {
|
|
|
1316
1350
|
}
|
|
1317
1351
|
});
|
|
1318
1352
|
}
|
|
1319
|
-
if (this.match === "
|
|
1353
|
+
if (this.match === "exact") {
|
|
1320
1354
|
const trimmed = text.trim();
|
|
1321
|
-
if (!
|
|
1322
|
-
throw new LlmExeError(`Input is not
|
|
1355
|
+
if (!EXACT_NUMERIC_PATTERN.test(trimmed)) {
|
|
1356
|
+
throw new LlmExeError(`Input is not an exact numeric value.`, {
|
|
1323
1357
|
code: "parser.parse_failed",
|
|
1324
1358
|
context: {
|
|
1325
1359
|
operation: "NumberParser.parse",
|
|
1326
1360
|
parser: "number",
|
|
1327
1361
|
reason: "no_numeric_value",
|
|
1328
|
-
expected: "
|
|
1362
|
+
expected: "exact number",
|
|
1329
1363
|
match: this.match,
|
|
1330
1364
|
inputLength: text.length
|
|
1331
1365
|
}
|
|
@@ -1592,9 +1626,11 @@ function isPlainObject2(value) {
|
|
|
1592
1626
|
const proto = Object.getPrototypeOf(value);
|
|
1593
1627
|
return proto === Object.prototype || proto === null;
|
|
1594
1628
|
}
|
|
1595
|
-
function
|
|
1629
|
+
function normalizeExactResponseJsonText(input) {
|
|
1596
1630
|
const trimmed = input.trim();
|
|
1597
|
-
const fenceMatch = trimmed.match(
|
|
1631
|
+
const fenceMatch = trimmed.match(
|
|
1632
|
+
/^```([a-zA-Z]*)[^\S\r\n]*\r?\n([\s\S]*)```$/
|
|
1633
|
+
);
|
|
1598
1634
|
if (!fenceMatch) {
|
|
1599
1635
|
return trimmed;
|
|
1600
1636
|
}
|
|
@@ -1604,19 +1640,82 @@ function normalizeWholeResponseJsonText(input) {
|
|
|
1604
1640
|
}
|
|
1605
1641
|
return body.trim();
|
|
1606
1642
|
}
|
|
1643
|
+
function findBalancedJsonEnd(input, start) {
|
|
1644
|
+
const first = input[start];
|
|
1645
|
+
const stack = first === "{" ? ["}"] : first === "[" ? ["]"] : [];
|
|
1646
|
+
let inString = false;
|
|
1647
|
+
let escaping = false;
|
|
1648
|
+
for (let index = start + 1; index < input.length; index += 1) {
|
|
1649
|
+
const char = input[index];
|
|
1650
|
+
if (inString) {
|
|
1651
|
+
if (escaping) {
|
|
1652
|
+
escaping = false;
|
|
1653
|
+
} else if (char === "\\") {
|
|
1654
|
+
escaping = true;
|
|
1655
|
+
} else if (char === '"') {
|
|
1656
|
+
inString = false;
|
|
1657
|
+
}
|
|
1658
|
+
continue;
|
|
1659
|
+
}
|
|
1660
|
+
if (char === '"') {
|
|
1661
|
+
inString = true;
|
|
1662
|
+
continue;
|
|
1663
|
+
}
|
|
1664
|
+
if (char === "{" || char === "[") {
|
|
1665
|
+
stack.push(char === "{" ? "}" : "]");
|
|
1666
|
+
continue;
|
|
1667
|
+
}
|
|
1668
|
+
if (char !== "}" && char !== "]") {
|
|
1669
|
+
continue;
|
|
1670
|
+
}
|
|
1671
|
+
if (stack[stack.length - 1] !== char) {
|
|
1672
|
+
return void 0;
|
|
1673
|
+
}
|
|
1674
|
+
stack.pop();
|
|
1675
|
+
if (stack.length === 0) {
|
|
1676
|
+
return index;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
return void 0;
|
|
1680
|
+
}
|
|
1681
|
+
function extractJsonCandidates(input) {
|
|
1682
|
+
const candidates = [];
|
|
1683
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
1684
|
+
const char = input[index];
|
|
1685
|
+
if (char !== "{" && char !== "[") {
|
|
1686
|
+
continue;
|
|
1687
|
+
}
|
|
1688
|
+
const end = findBalancedJsonEnd(input, index);
|
|
1689
|
+
if (end === void 0) {
|
|
1690
|
+
continue;
|
|
1691
|
+
}
|
|
1692
|
+
const candidate = input.slice(index, end + 1);
|
|
1693
|
+
try {
|
|
1694
|
+
candidates.push({
|
|
1695
|
+
parsed: JSON.parse(candidate)
|
|
1696
|
+
});
|
|
1697
|
+
index = end;
|
|
1698
|
+
} catch {
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
return candidates;
|
|
1702
|
+
}
|
|
1607
1703
|
var JsonParser = class extends BaseParserWithJson {
|
|
1608
1704
|
constructor(options = {}) {
|
|
1609
1705
|
super("json", options);
|
|
1610
1706
|
__publicField(this, "shouldValidateSchema");
|
|
1707
|
+
__publicField(this, "match");
|
|
1708
|
+
this.match = options.match ?? "exact";
|
|
1611
1709
|
this.shouldValidateSchema = !!options.schema && options.validateSchema !== false;
|
|
1612
1710
|
}
|
|
1613
1711
|
/**
|
|
1614
1712
|
* v3 parser contract:
|
|
1615
1713
|
* Category: strict
|
|
1616
|
-
* Mode:
|
|
1714
|
+
* Mode: exact
|
|
1617
1715
|
*
|
|
1618
|
-
* Parses strict JSON object/array output
|
|
1619
|
-
*
|
|
1716
|
+
* Parses strict JSON object/array output by default. Pass match: "extract"
|
|
1717
|
+
* to extract one JSON object or array from surrounding text. Invalid JSON,
|
|
1718
|
+
* empty input, JSON primitives, and non-plain runtime objects throw typed parser errors.
|
|
1620
1719
|
* Schema validation is on by default when a schema is provided unless
|
|
1621
1720
|
* validateSchema: false is explicitly set.
|
|
1622
1721
|
*
|
|
@@ -1639,19 +1738,52 @@ var JsonParser = class extends BaseParserWithJson {
|
|
|
1639
1738
|
});
|
|
1640
1739
|
}
|
|
1641
1740
|
try {
|
|
1642
|
-
parsed = JSON.parse(
|
|
1741
|
+
parsed = JSON.parse(normalizeExactResponseJsonText(text));
|
|
1643
1742
|
} catch (cause) {
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1743
|
+
if (this.match === "extract") {
|
|
1744
|
+
const candidates = extractJsonCandidates(text);
|
|
1745
|
+
if (candidates.length === 1) {
|
|
1746
|
+
parsed = candidates[0].parsed;
|
|
1747
|
+
} else if (candidates.length > 1) {
|
|
1748
|
+
throw new LlmExeError(`Multiple JSON values found in input.`, {
|
|
1749
|
+
code: "parser.parse_failed",
|
|
1750
|
+
context: {
|
|
1751
|
+
operation: "JsonParser.parse",
|
|
1752
|
+
parser: "json",
|
|
1753
|
+
reason: "ambiguous_json_match",
|
|
1754
|
+
expected: "one JSON object or array",
|
|
1755
|
+
match: this.match,
|
|
1756
|
+
inputLength,
|
|
1757
|
+
matchCount: candidates.length
|
|
1758
|
+
}
|
|
1759
|
+
});
|
|
1760
|
+
} else {
|
|
1761
|
+
throw new LlmExeError(`No JSON value found in input.`, {
|
|
1762
|
+
code: "parser.parse_failed",
|
|
1763
|
+
context: {
|
|
1764
|
+
operation: "JsonParser.parse",
|
|
1765
|
+
parser: "json",
|
|
1766
|
+
reason: "no_json_value",
|
|
1767
|
+
expected: "JSON object or array",
|
|
1768
|
+
match: this.match,
|
|
1769
|
+
inputLength
|
|
1770
|
+
},
|
|
1771
|
+
cause
|
|
1772
|
+
});
|
|
1773
|
+
}
|
|
1774
|
+
} else {
|
|
1775
|
+
throw new LlmExeError(`Invalid JSON input.`, {
|
|
1776
|
+
code: "parser.parse_failed",
|
|
1777
|
+
context: {
|
|
1778
|
+
operation: "JsonParser.parse",
|
|
1779
|
+
parser: "json",
|
|
1780
|
+
reason: "invalid_json",
|
|
1781
|
+
expected: "JSON object or array",
|
|
1782
|
+
inputLength
|
|
1783
|
+
},
|
|
1784
|
+
cause
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1655
1787
|
}
|
|
1656
1788
|
} else if (Array.isArray(text) || isPlainObject2(text)) {
|
|
1657
1789
|
parsed = text;
|
|
@@ -2922,7 +3054,7 @@ var StringExtractParser = class extends BaseParser {
|
|
|
2922
3054
|
* Mode: configured value extraction
|
|
2923
3055
|
*
|
|
2924
3056
|
* Returns the single configured enum value found in input. Matching is
|
|
2925
|
-
* word-bounded by default; pass match: "
|
|
3057
|
+
* word-bounded by default; pass match: "exact" to require exact input or
|
|
2926
3058
|
* match: "substring" for legacy contains() behavior. Case-insensitive by
|
|
2927
3059
|
* default.
|
|
2928
3060
|
*
|
|
@@ -3004,8 +3136,8 @@ var StringExtractParser = class extends BaseParser {
|
|
|
3004
3136
|
}
|
|
3005
3137
|
findMatches(text) {
|
|
3006
3138
|
switch (this.match) {
|
|
3007
|
-
case "
|
|
3008
|
-
return this.
|
|
3139
|
+
case "exact":
|
|
3140
|
+
return this.matchExact(text);
|
|
3009
3141
|
case "substring":
|
|
3010
3142
|
return this.matchSubstring(text);
|
|
3011
3143
|
case "word":
|
|
@@ -3013,7 +3145,7 @@ var StringExtractParser = class extends BaseParser {
|
|
|
3013
3145
|
return this.matchWord(text);
|
|
3014
3146
|
}
|
|
3015
3147
|
}
|
|
3016
|
-
|
|
3148
|
+
matchExact(text) {
|
|
3017
3149
|
const candidate = this.ignoreCase ? text.trim().toLowerCase() : text.trim();
|
|
3018
3150
|
return this.enum.filter((option) => {
|
|
3019
3151
|
if (option === "") return false;
|
|
@@ -3063,36 +3195,33 @@ function createParser(...args) {
|
|
|
3063
3195
|
case "replaceStringTemplate":
|
|
3064
3196
|
return new ReplaceStringTemplateParser();
|
|
3065
3197
|
case "boolean":
|
|
3066
|
-
return new BooleanParser();
|
|
3198
|
+
return new BooleanParser(options);
|
|
3067
3199
|
case "number":
|
|
3068
3200
|
return new NumberParser(options);
|
|
3069
3201
|
case "string":
|
|
3070
3202
|
return new StringParser();
|
|
3071
3203
|
default:
|
|
3072
|
-
throw new LlmExeError(
|
|
3073
|
-
|
|
3074
|
-
{
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
],
|
|
3092
|
-
resolution: "Use a registered parser type, or define a custom parser."
|
|
3093
|
-
}
|
|
3204
|
+
throw new LlmExeError(`Invalid parser type: "${type}"`, {
|
|
3205
|
+
code: "parser.invalid_type",
|
|
3206
|
+
context: {
|
|
3207
|
+
operation: "createParser",
|
|
3208
|
+
parser: type,
|
|
3209
|
+
availableParsers: [
|
|
3210
|
+
"json",
|
|
3211
|
+
"string",
|
|
3212
|
+
"boolean",
|
|
3213
|
+
"number",
|
|
3214
|
+
"stringExtract",
|
|
3215
|
+
"listToArray",
|
|
3216
|
+
"listToJson",
|
|
3217
|
+
"listToKeyValue",
|
|
3218
|
+
"replaceStringTemplate",
|
|
3219
|
+
"markdownCodeBlock",
|
|
3220
|
+
"markdownCodeBlocks"
|
|
3221
|
+
],
|
|
3222
|
+
resolution: "Use a registered parser type, or define a custom parser."
|
|
3094
3223
|
}
|
|
3095
|
-
);
|
|
3224
|
+
});
|
|
3096
3225
|
}
|
|
3097
3226
|
}
|
|
3098
3227
|
function createCustomParser(name, parserFn) {
|
|
@@ -4157,6 +4286,20 @@ function anthropicPromptSanitize(_messages, _inputBodyObj, _outputObj) {
|
|
|
4157
4286
|
return mergeConsecutiveSameRole(result);
|
|
4158
4287
|
}
|
|
4159
4288
|
|
|
4289
|
+
// src/llm/output/_utils/getBedrockTokenCounts.ts
|
|
4290
|
+
function getBedrockTokenCounts(headers) {
|
|
4291
|
+
if (!headers) return void 0;
|
|
4292
|
+
const input = parseInt(headers["x-amzn-bedrock-input-token-count"], 10);
|
|
4293
|
+
const output = parseInt(headers["x-amzn-bedrock-output-token-count"], 10);
|
|
4294
|
+
if (!Number.isFinite(input) && !Number.isFinite(output)) {
|
|
4295
|
+
return void 0;
|
|
4296
|
+
}
|
|
4297
|
+
return {
|
|
4298
|
+
input_tokens: Number.isFinite(input) ? input : 0,
|
|
4299
|
+
output_tokens: Number.isFinite(output) ? output : 0
|
|
4300
|
+
};
|
|
4301
|
+
}
|
|
4302
|
+
|
|
4160
4303
|
// src/llm/output/claude.ts
|
|
4161
4304
|
function formatResult2(response) {
|
|
4162
4305
|
const content = response?.content || [];
|
|
@@ -4179,15 +4322,18 @@ function formatResult2(response) {
|
|
|
4179
4322
|
}
|
|
4180
4323
|
return out;
|
|
4181
4324
|
}
|
|
4182
|
-
function OutputAnthropicClaude3Chat(result, _config) {
|
|
4325
|
+
function OutputAnthropicClaude3Chat(result, _config, headers) {
|
|
4183
4326
|
const id = result.id;
|
|
4184
4327
|
const name = result.model || _config?.options.model?.default || "anthropic.unknown";
|
|
4185
4328
|
const stopReason = result.stop_reason;
|
|
4186
4329
|
const content = formatResult2(result);
|
|
4330
|
+
const headerUsage = getBedrockTokenCounts(headers);
|
|
4331
|
+
const input_tokens = result?.usage?.input_tokens ?? headerUsage?.input_tokens ?? 0;
|
|
4332
|
+
const output_tokens = result?.usage?.output_tokens ?? headerUsage?.output_tokens ?? 0;
|
|
4187
4333
|
const usage = {
|
|
4188
|
-
input_tokens
|
|
4189
|
-
output_tokens
|
|
4190
|
-
total_tokens:
|
|
4334
|
+
input_tokens,
|
|
4335
|
+
output_tokens,
|
|
4336
|
+
total_tokens: input_tokens + output_tokens
|
|
4191
4337
|
};
|
|
4192
4338
|
return {
|
|
4193
4339
|
id,
|
|
@@ -4200,7 +4346,7 @@ function OutputAnthropicClaude3Chat(result, _config) {
|
|
|
4200
4346
|
}
|
|
4201
4347
|
|
|
4202
4348
|
// src/llm/output/llama.ts
|
|
4203
|
-
function OutputMetaLlama3Chat(result, _config) {
|
|
4349
|
+
function OutputMetaLlama3Chat(result, _config, headers) {
|
|
4204
4350
|
const id = uuidv4();
|
|
4205
4351
|
const name = _config?.options?.model?.default || "meta";
|
|
4206
4352
|
const created = (/* @__PURE__ */ new Date()).getTime();
|
|
@@ -4208,10 +4354,13 @@ function OutputMetaLlama3Chat(result, _config) {
|
|
|
4208
4354
|
const content = [
|
|
4209
4355
|
{ type: "text", text: result.generation }
|
|
4210
4356
|
];
|
|
4357
|
+
const headerUsage = getBedrockTokenCounts(headers);
|
|
4358
|
+
const output_tokens = result?.generation_token_count ?? headerUsage?.output_tokens ?? 0;
|
|
4359
|
+
const input_tokens = result?.prompt_token_count ?? headerUsage?.input_tokens ?? 0;
|
|
4211
4360
|
const usage = {
|
|
4212
|
-
output_tokens
|
|
4213
|
-
input_tokens
|
|
4214
|
-
total_tokens:
|
|
4361
|
+
output_tokens,
|
|
4362
|
+
input_tokens,
|
|
4363
|
+
total_tokens: output_tokens + input_tokens
|
|
4215
4364
|
};
|
|
4216
4365
|
return {
|
|
4217
4366
|
id,
|
|
@@ -4329,7 +4478,7 @@ var bedrock = {
|
|
|
4329
4478
|
|
|
4330
4479
|
// src/llm/config/anthropic/index.ts
|
|
4331
4480
|
var ANTHROPIC_VERSION = "2023-06-01";
|
|
4332
|
-
var MODELS_REJECTING_SAMPLING_PARAMS = ["claude-opus-4-7"];
|
|
4481
|
+
var MODELS_REJECTING_SAMPLING_PARAMS = ["claude-opus-4-7", "claude-opus-4-8"];
|
|
4333
4482
|
var isClaude4x = (model) => /^claude-(opus|sonnet|haiku)-4-/.test(model);
|
|
4334
4483
|
var dropIfModelRejectsSamplingParams = (v, body) => MODELS_REJECTING_SAMPLING_PARAMS.includes(body.model) ? void 0 : v;
|
|
4335
4484
|
var topPTransform = (v, body) => {
|
|
@@ -4414,6 +4563,11 @@ var anthropicChatV1 = {
|
|
|
4414
4563
|
};
|
|
4415
4564
|
var anthropic = {
|
|
4416
4565
|
"anthropic.chat.v1": anthropicChatV1,
|
|
4566
|
+
// Claude 4.8 models
|
|
4567
|
+
"anthropic.claude-opus-4-8": withDefaultModel(
|
|
4568
|
+
anthropicChatV1,
|
|
4569
|
+
"claude-opus-4-8"
|
|
4570
|
+
),
|
|
4417
4571
|
// Claude 4.7 models
|
|
4418
4572
|
"anthropic.claude-opus-4-7": withDefaultModel(
|
|
4419
4573
|
anthropicChatV1,
|
|
@@ -4597,7 +4751,11 @@ var ollamaChatV1 = {
|
|
|
4597
4751
|
provider: "ollama.chat",
|
|
4598
4752
|
endpoint: `${getEnvironmentVariable("OLLAMA_ENDPOINT") || `http://localhost:11434`}/api/chat`,
|
|
4599
4753
|
options: {
|
|
4600
|
-
prompt: {}
|
|
4754
|
+
prompt: {},
|
|
4755
|
+
temperature: {},
|
|
4756
|
+
topP: {},
|
|
4757
|
+
maxTokens: {},
|
|
4758
|
+
stopSequences: {}
|
|
4601
4759
|
},
|
|
4602
4760
|
method: "POST",
|
|
4603
4761
|
headers: `{"Content-Type": "application/json" }`,
|
|
@@ -4613,6 +4771,18 @@ var ollamaChatV1 = {
|
|
|
4613
4771
|
},
|
|
4614
4772
|
model: {
|
|
4615
4773
|
key: "model"
|
|
4774
|
+
},
|
|
4775
|
+
temperature: {
|
|
4776
|
+
key: "options.temperature"
|
|
4777
|
+
},
|
|
4778
|
+
topP: {
|
|
4779
|
+
key: "options.top_p"
|
|
4780
|
+
},
|
|
4781
|
+
maxTokens: {
|
|
4782
|
+
key: "options.num_predict"
|
|
4783
|
+
},
|
|
4784
|
+
stopSequences: {
|
|
4785
|
+
key: "options.stop"
|
|
4616
4786
|
}
|
|
4617
4787
|
},
|
|
4618
4788
|
transformResponse: OutputOllamaChat
|
|
@@ -4808,7 +4978,10 @@ var googleGeminiChatV1 = {
|
|
|
4808
4978
|
options: {
|
|
4809
4979
|
effort: {},
|
|
4810
4980
|
prompt: {},
|
|
4811
|
-
|
|
4981
|
+
temperature: {},
|
|
4982
|
+
topP: {},
|
|
4983
|
+
maxTokens: {},
|
|
4984
|
+
stopSequences: {},
|
|
4812
4985
|
geminiApiKey: {
|
|
4813
4986
|
default: getEnvironmentVariable("GEMINI_API_KEY")
|
|
4814
4987
|
}
|
|
@@ -4820,6 +4993,18 @@ var googleGeminiChatV1 = {
|
|
|
4820
4993
|
key: "contents",
|
|
4821
4994
|
transform: googleGeminiPromptSanitize
|
|
4822
4995
|
},
|
|
4996
|
+
temperature: {
|
|
4997
|
+
key: "generationConfig.temperature"
|
|
4998
|
+
},
|
|
4999
|
+
topP: {
|
|
5000
|
+
key: "generationConfig.topP"
|
|
5001
|
+
},
|
|
5002
|
+
maxTokens: {
|
|
5003
|
+
key: "generationConfig.maxOutputTokens"
|
|
5004
|
+
},
|
|
5005
|
+
stopSequences: {
|
|
5006
|
+
key: "generationConfig.stopSequences"
|
|
5007
|
+
},
|
|
4823
5008
|
effort: {
|
|
4824
5009
|
key: "config.thinkingConfig.thinkingBudget",
|
|
4825
5010
|
transform: (v, _s) => {
|
|
@@ -4961,6 +5146,13 @@ function isValidUrl(input) {
|
|
|
4961
5146
|
}
|
|
4962
5147
|
|
|
4963
5148
|
// src/utils/modules/request.ts
|
|
5149
|
+
function headersToRecord(headers) {
|
|
5150
|
+
const record = {};
|
|
5151
|
+
headers.forEach((value, key) => {
|
|
5152
|
+
record[key.toLowerCase()] = value;
|
|
5153
|
+
});
|
|
5154
|
+
return record;
|
|
5155
|
+
}
|
|
4964
5156
|
async function apiRequest(url, options) {
|
|
4965
5157
|
const finalOptions = {
|
|
4966
5158
|
...options
|
|
@@ -5046,13 +5238,16 @@ async function apiRequest(url, options) {
|
|
|
5046
5238
|
});
|
|
5047
5239
|
}
|
|
5048
5240
|
const contentType = response.headers.get("content-type");
|
|
5241
|
+
const headers = headersToRecord(response.headers);
|
|
5049
5242
|
if (contentType?.includes("application/json")) {
|
|
5050
|
-
const
|
|
5051
|
-
return
|
|
5052
|
-
} else {
|
|
5053
|
-
const responseData = await response.text();
|
|
5054
|
-
return responseData;
|
|
5243
|
+
const responseData2 = await response.json();
|
|
5244
|
+
return { data: responseData2, headers };
|
|
5055
5245
|
}
|
|
5246
|
+
const responseData = await response.text();
|
|
5247
|
+
return {
|
|
5248
|
+
data: responseData,
|
|
5249
|
+
headers
|
|
5250
|
+
};
|
|
5056
5251
|
}
|
|
5057
5252
|
|
|
5058
5253
|
// src/utils/modules/convertDotNotation.ts
|
|
@@ -5424,7 +5619,7 @@ async function useLlm_call(state, messages, _options) {
|
|
|
5424
5619
|
}
|
|
5425
5620
|
]
|
|
5426
5621
|
};
|
|
5427
|
-
return BaseLlmOutput(transformResponse(mockResponse, config));
|
|
5622
|
+
return BaseLlmOutput(transformResponse(mockResponse, config, {}));
|
|
5428
5623
|
}
|
|
5429
5624
|
try {
|
|
5430
5625
|
const response = await apiRequest(url, {
|
|
@@ -5432,7 +5627,9 @@ async function useLlm_call(state, messages, _options) {
|
|
|
5432
5627
|
body,
|
|
5433
5628
|
headers
|
|
5434
5629
|
});
|
|
5435
|
-
return BaseLlmOutput(
|
|
5630
|
+
return BaseLlmOutput(
|
|
5631
|
+
transformResponse(response.data, config, response.headers)
|
|
5632
|
+
);
|
|
5436
5633
|
} catch (e) {
|
|
5437
5634
|
if (!isLlmExeError(e, "request.http_error")) throw e;
|
|
5438
5635
|
const ctx = e.context ?? {};
|
|
@@ -5613,7 +5810,9 @@ var embeddingConfigs = {
|
|
|
5613
5810
|
"openai.embedding.v1": {
|
|
5614
5811
|
key: "openai.embedding.v1",
|
|
5615
5812
|
provider: "openai.embedding",
|
|
5616
|
-
|
|
5813
|
+
// Templated host: `baseUrl` defaults to OpenAI. Override to point at any
|
|
5814
|
+
// OpenAI-compatible embeddings server (Baseten, vLLM, TEI, Together, etc.).
|
|
5815
|
+
endpoint: `{{baseUrl}}/embeddings`,
|
|
5617
5816
|
method: "POST",
|
|
5618
5817
|
headers: `{"Authorization":"Bearer {{openAiApiKey}}", "Content-Type": "application/json" }`,
|
|
5619
5818
|
options: {
|
|
@@ -5624,6 +5823,9 @@ var embeddingConfigs = {
|
|
|
5624
5823
|
encodingFormat: {},
|
|
5625
5824
|
openAiApiKey: {
|
|
5626
5825
|
default: getEnvironmentVariable("OPENAI_API_KEY")
|
|
5826
|
+
},
|
|
5827
|
+
baseUrl: {
|
|
5828
|
+
default: "https://api.openai.com/v1"
|
|
5627
5829
|
}
|
|
5628
5830
|
},
|
|
5629
5831
|
mapBody: {
|
|
@@ -5810,15 +6012,34 @@ function AmazonTitanEmbedding(result, config) {
|
|
|
5810
6012
|
}
|
|
5811
6013
|
|
|
5812
6014
|
// src/embedding/output/CohereBedrockEmbedding.ts
|
|
5813
|
-
function
|
|
6015
|
+
function resolveEmbeddings(embeddings, model) {
|
|
6016
|
+
if (Array.isArray(embeddings)) {
|
|
6017
|
+
return embeddings;
|
|
6018
|
+
}
|
|
6019
|
+
if (embeddings && typeof embeddings === "object") {
|
|
6020
|
+
if (Array.isArray(embeddings.float)) {
|
|
6021
|
+
return embeddings.float;
|
|
6022
|
+
}
|
|
6023
|
+
throw new Error(
|
|
6024
|
+
`Unexpected embeddings in Cohere Bedrock response (model: "${model}"). Expected float embeddings, received object with keys: [${Object.keys(embeddings).join(", ")}]`
|
|
6025
|
+
);
|
|
6026
|
+
}
|
|
6027
|
+
throw new Error(
|
|
6028
|
+
`Unexpected embeddings shape in Cohere Bedrock response (model: "${model}"). Expected an array (Embed v3) or an object with float embeddings (Embed v4), received: ${embeddings === null ? "null" : typeof embeddings}`
|
|
6029
|
+
);
|
|
6030
|
+
}
|
|
6031
|
+
function CohereBedrockEmbedding(result, config, headers) {
|
|
6032
|
+
const headerUsage = getBedrockTokenCounts(headers);
|
|
5814
6033
|
const __result = deepClone(result);
|
|
5815
6034
|
const model = config.model || "cohere.unknown";
|
|
5816
6035
|
const created = (/* @__PURE__ */ new Date()).getTime();
|
|
5817
|
-
const embedding =
|
|
6036
|
+
const embedding = resolveEmbeddings(__result.embeddings, model);
|
|
6037
|
+
const input_tokens = headerUsage?.input_tokens ?? 0;
|
|
6038
|
+
const output_tokens = headerUsage?.output_tokens ?? 0;
|
|
5818
6039
|
const usage = {
|
|
5819
|
-
output_tokens
|
|
5820
|
-
input_tokens
|
|
5821
|
-
total_tokens:
|
|
6040
|
+
output_tokens,
|
|
6041
|
+
input_tokens,
|
|
6042
|
+
total_tokens: input_tokens + output_tokens
|
|
5822
6043
|
};
|
|
5823
6044
|
return BaseEmbeddingOutput({
|
|
5824
6045
|
id: __result.id,
|
|
@@ -5850,14 +6071,14 @@ function OpenAiEmbedding(result, config) {
|
|
|
5850
6071
|
}
|
|
5851
6072
|
|
|
5852
6073
|
// src/embedding/output/getEmbeddingOutputParser.ts
|
|
5853
|
-
function getEmbeddingOutputParser(config, response) {
|
|
6074
|
+
function getEmbeddingOutputParser(config, response, headers) {
|
|
5854
6075
|
switch (config.key) {
|
|
5855
6076
|
case "openai.embedding.v1":
|
|
5856
6077
|
return OpenAiEmbedding(response, config);
|
|
5857
6078
|
case "amazon.embedding.v1":
|
|
5858
6079
|
return AmazonTitanEmbedding(response, config);
|
|
5859
6080
|
case "amazon:cohere.embedding.v1":
|
|
5860
|
-
return CohereBedrockEmbedding(response, config);
|
|
6081
|
+
return CohereBedrockEmbedding(response, config, headers);
|
|
5861
6082
|
default:
|
|
5862
6083
|
throw new LlmExeError("Unsupported provider", {
|
|
5863
6084
|
code: "embedding.invalid_response_shape",
|
|
@@ -5894,7 +6115,7 @@ async function createEmbedding_call(state, _input, _options) {
|
|
|
5894
6115
|
body,
|
|
5895
6116
|
headers
|
|
5896
6117
|
});
|
|
5897
|
-
return getEmbeddingOutputParser(state, request);
|
|
6118
|
+
return getEmbeddingOutputParser(state, request.data, request.headers);
|
|
5898
6119
|
} catch (e) {
|
|
5899
6120
|
if (!isLlmExeError(e, "request.http_error")) throw e;
|
|
5900
6121
|
const ctx = e.context ?? {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "llm-exe",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.3",
|
|
4
4
|
"description": "Simplify building LLM-powered apps with easy-to-use base components, supporting text and chat-based prompts with handlebars template engine, output parsers, and flexible function calling capabilities.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
package/readme.md
CHANGED
|
@@ -9,7 +9,7 @@ A package that provides simplified base components to make building and maintain
|
|
|
9
9
|
- Write functions powered by LLM's with easy to use building blocks.
|
|
10
10
|
- Pure Javascript and Typescript. Allows you to pass and infer types.
|
|
11
11
|
- Supercharge your prompts by using handlebars within prompt template.
|
|
12
|
-
- Support for text-based
|
|
12
|
+
- Support for text-based and chat-based prompts. (ChatGPT, Claude, Grok, Gemini, Bedrock, Ollama, etc)
|
|
13
13
|
- Call LLM's from different providers without changing your code. (OpenAi/Anthropic/xAI/Google/AWS Bedrock/Ollama/Deepseek)
|
|
14
14
|
- Allow LLM's to call functions (or call other LLM executors).
|
|
15
15
|
- Not very opinionated. You have control on how you use it.
|
|
@@ -85,7 +85,7 @@ Welcome back!
|
|
|
85
85
|
```ts
|
|
86
86
|
createParser("string"); // pass-through, returns string
|
|
87
87
|
createParser("json", { schema }); // JSON with optional schema validation
|
|
88
|
-
createParser("boolean"); //
|
|
88
|
+
createParser("boolean"); // parses a boolean token
|
|
89
89
|
createParser("number"); // extracts number from response
|
|
90
90
|
createParser("stringExtract", { enum: ["yes", "no"] }); // match one of the enum values
|
|
91
91
|
createParser("listToArray"); // newline-separated list → string[]
|