@axlsdk/axl 0.20.1 → 0.21.1
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/README.md +7 -0
- package/dist/index.cjs +340 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -50
- package/dist/index.d.ts +64 -50
- package/dist/index.js +340 -12
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -71,6 +71,13 @@ Presets: `openrouter`, `azure`, `xai`, `deepseek`, `mistral`, `groq`, `bedrock`,
|
|
|
71
71
|
|
|
72
72
|
Each provider also accepts an opt-in `rateLimit` (`{ maxConcurrent?, minIntervalMs?, acquireTimeoutMs? }`) for proactive client-side pacing on top of the automatic 429/503/529 backoff — useful when a large fan-out (e.g. an eval) shares one API key. It caps in-flight request concurrency (not token throughput) for that provider's chat calls. See [Providers → Rate limiting](../../docs/providers.md#rate-limiting-opt-in).
|
|
73
73
|
|
|
74
|
+
Built-in providers require HTTPS for remote endpoints and never follow redirects.
|
|
75
|
+
Literal loopback HTTP remains automatic for local inference; Docker service names,
|
|
76
|
+
private-network URLs, and other remote HTTP endpoints require the provider-local
|
|
77
|
+
`dangerouslyAllowInsecureHttp: true` acknowledgement. Keep Axl and proprietary
|
|
78
|
+
system prompts on your trusted backend—see
|
|
79
|
+
[Prompt confidentiality](../../docs/security.md#prompt-confidentiality-and-the-trusted-backend).
|
|
80
|
+
|
|
74
81
|
State store options: `'memory'` (default), `'sqlite'` (requires `better-sqlite3`), or a `RedisStore` instance for multi-process deployments. See [State Stores](#state-stores).
|
|
75
82
|
|
|
76
83
|
### Tools, Agents, and Workflows
|
package/dist/index.cjs
CHANGED
|
@@ -380,6 +380,221 @@ var ValidationError = class extends AxlError {
|
|
|
380
380
|
|
|
381
381
|
// src/tool.ts
|
|
382
382
|
var DEFAULT_MAX_STRING_LENGTH = 1e4;
|
|
383
|
+
var MAX_MODEL_ARGUMENT_ISSUES = 8;
|
|
384
|
+
var MAX_MODEL_ARGUMENT_MESSAGE_LENGTH = 2e3;
|
|
385
|
+
var MAX_MODEL_ARGUMENT_LINE_LENGTH = 220;
|
|
386
|
+
var MAX_MODEL_ARGUMENT_PATH_LENGTH = 160;
|
|
387
|
+
var MAX_UNION_DEPTH = 3;
|
|
388
|
+
var MAX_UNION_BRANCHES = 4;
|
|
389
|
+
var MAX_LITERAL_ALTERNATIVES = 10;
|
|
390
|
+
var SAFE_SCHEMA_TYPES = /* @__PURE__ */ new Set([
|
|
391
|
+
"string",
|
|
392
|
+
"number",
|
|
393
|
+
"boolean",
|
|
394
|
+
"null",
|
|
395
|
+
"array",
|
|
396
|
+
"object",
|
|
397
|
+
"integer"
|
|
398
|
+
]);
|
|
399
|
+
var SAFE_STRING_FORMATS = /* @__PURE__ */ new Set([
|
|
400
|
+
"email",
|
|
401
|
+
"url",
|
|
402
|
+
"emoji",
|
|
403
|
+
"uuid",
|
|
404
|
+
"guid",
|
|
405
|
+
"nanoid",
|
|
406
|
+
"cuid",
|
|
407
|
+
"cuid2",
|
|
408
|
+
"ulid",
|
|
409
|
+
"xid",
|
|
410
|
+
"ksuid",
|
|
411
|
+
"datetime",
|
|
412
|
+
"date",
|
|
413
|
+
"time",
|
|
414
|
+
"duration",
|
|
415
|
+
"ipv4",
|
|
416
|
+
"ipv6",
|
|
417
|
+
"cidrv4",
|
|
418
|
+
"cidrv6",
|
|
419
|
+
"base64",
|
|
420
|
+
"base64url",
|
|
421
|
+
"json_string",
|
|
422
|
+
"e164",
|
|
423
|
+
"lowercase",
|
|
424
|
+
"uppercase",
|
|
425
|
+
"jwt"
|
|
426
|
+
]);
|
|
427
|
+
function truncateModelFeedback(value, maximum) {
|
|
428
|
+
return value.length <= maximum ? value : `${value.slice(0, Math.max(0, maximum - 1))}\u2026`;
|
|
429
|
+
}
|
|
430
|
+
var DISPLAY_CONTROL_CHARACTERS = /[\u061C\u200B-\u200F\u202A-\u202E\u2066-\u2069\u2028\u2029]/g;
|
|
431
|
+
function isJsonSchema(value) {
|
|
432
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
433
|
+
}
|
|
434
|
+
function escapeDisplayControls(value) {
|
|
435
|
+
return value.replace(
|
|
436
|
+
DISPLAY_CONTROL_CHARACTERS,
|
|
437
|
+
(character) => `\\u${character.codePointAt(0).toString(16).padStart(4, "0")}`
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
function quoteModelText(value) {
|
|
441
|
+
return escapeDisplayControls(JSON.stringify(value));
|
|
442
|
+
}
|
|
443
|
+
function schemaNumber(value) {
|
|
444
|
+
return typeof value === "number" && Number.isFinite(value) ? String(value) : void 0;
|
|
445
|
+
}
|
|
446
|
+
function schemaLiteral(value) {
|
|
447
|
+
if (typeof value === "string") {
|
|
448
|
+
const rendered = quoteModelText(value);
|
|
449
|
+
return rendered.length <= 120 ? rendered : '"<literal omitted>"';
|
|
450
|
+
}
|
|
451
|
+
if (typeof value === "number") return Number.isFinite(value) ? String(value) : void 0;
|
|
452
|
+
if (typeof value === "boolean") return String(value);
|
|
453
|
+
if (value === null) return "null";
|
|
454
|
+
return void 0;
|
|
455
|
+
}
|
|
456
|
+
function schemaType(schema) {
|
|
457
|
+
const type = schema.type;
|
|
458
|
+
return typeof type === "string" && SAFE_SCHEMA_TYPES.has(type) ? type : void 0;
|
|
459
|
+
}
|
|
460
|
+
function compositionBranches(schema) {
|
|
461
|
+
const branches = [];
|
|
462
|
+
for (const key of ["anyOf", "oneOf", "allOf"]) {
|
|
463
|
+
const value = schema[key];
|
|
464
|
+
if (!Array.isArray(value)) continue;
|
|
465
|
+
for (const branch of value.slice(0, MAX_UNION_BRANCHES)) {
|
|
466
|
+
if (isJsonSchema(branch)) branches.push(branch);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return branches;
|
|
470
|
+
}
|
|
471
|
+
function unionBranches(schema) {
|
|
472
|
+
const branches = [];
|
|
473
|
+
for (const key of ["anyOf", "oneOf"]) {
|
|
474
|
+
const value = schema[key];
|
|
475
|
+
if (!Array.isArray(value)) continue;
|
|
476
|
+
for (const branch of value.slice(0, MAX_UNION_BRANCHES)) {
|
|
477
|
+
if (isJsonSchema(branch)) branches.push(branch);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return branches;
|
|
481
|
+
}
|
|
482
|
+
function resolvePathSegment(schema, segment, depth = 0) {
|
|
483
|
+
if (depth >= MAX_UNION_DEPTH) return void 0;
|
|
484
|
+
if (typeof segment === "string") {
|
|
485
|
+
const properties = schema.properties;
|
|
486
|
+
if (isJsonSchema(properties) && Object.hasOwn(properties, segment)) {
|
|
487
|
+
const child = properties[segment];
|
|
488
|
+
if (isJsonSchema(child)) return { node: child, renderedSegment: segment };
|
|
489
|
+
}
|
|
490
|
+
if (isJsonSchema(schema.additionalProperties)) {
|
|
491
|
+
return { node: schema.additionalProperties, renderedSegment: "<key>" };
|
|
492
|
+
}
|
|
493
|
+
} else if (typeof segment === "number" && Number.isSafeInteger(segment) && segment >= 0) {
|
|
494
|
+
const prefixItems = schema.prefixItems;
|
|
495
|
+
if (Array.isArray(prefixItems) && isJsonSchema(prefixItems[segment])) {
|
|
496
|
+
return { node: prefixItems[segment], renderedSegment: String(segment) };
|
|
497
|
+
}
|
|
498
|
+
if (isJsonSchema(schema.items)) {
|
|
499
|
+
return { node: schema.items, renderedSegment: "<index>" };
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
for (const branch of compositionBranches(schema)) {
|
|
503
|
+
const resolved = resolvePathSegment(branch, segment, depth + 1);
|
|
504
|
+
if (resolved !== void 0) return resolved;
|
|
505
|
+
}
|
|
506
|
+
return void 0;
|
|
507
|
+
}
|
|
508
|
+
function resolveSchemaPath(providerVisibleSchema, issuePath) {
|
|
509
|
+
if (!isJsonSchema(providerVisibleSchema)) return void 0;
|
|
510
|
+
let node = providerVisibleSchema;
|
|
511
|
+
const segments = [];
|
|
512
|
+
for (const segment of issuePath) {
|
|
513
|
+
const resolved = resolvePathSegment(node, segment);
|
|
514
|
+
if (resolved === void 0) {
|
|
515
|
+
segments.push("<path omitted>");
|
|
516
|
+
return { node, segments };
|
|
517
|
+
}
|
|
518
|
+
node = resolved.node;
|
|
519
|
+
segments.push(resolved.renderedSegment);
|
|
520
|
+
}
|
|
521
|
+
return { node, segments };
|
|
522
|
+
}
|
|
523
|
+
function jsonPointerPath(segments) {
|
|
524
|
+
if (segments.length === 0) return "<root>";
|
|
525
|
+
const pointer = `/${segments.map((segment) => segment.replaceAll("~", "~0").replaceAll("/", "~1")).join("/")}`;
|
|
526
|
+
const rendered = quoteModelText(pointer);
|
|
527
|
+
return rendered.length <= MAX_MODEL_ARGUMENT_PATH_LENGTH ? rendered : '"<path omitted>"';
|
|
528
|
+
}
|
|
529
|
+
function schemaAlternatives(schema, depth = 0) {
|
|
530
|
+
if (depth >= MAX_UNION_DEPTH) return [];
|
|
531
|
+
const constant = "const" in schema ? schemaLiteral(schema.const) : void 0;
|
|
532
|
+
if (constant !== void 0) return [constant];
|
|
533
|
+
if (Array.isArray(schema.enum)) {
|
|
534
|
+
const values = schema.enum.slice(0, MAX_LITERAL_ALTERNATIVES).map(schemaLiteral);
|
|
535
|
+
if (values.every((value) => value !== void 0)) return values;
|
|
536
|
+
}
|
|
537
|
+
const type = schemaType(schema);
|
|
538
|
+
if (type !== void 0) return [type];
|
|
539
|
+
const alternatives = unionBranches(schema).flatMap(
|
|
540
|
+
(branch) => schemaAlternatives(branch, depth + 1)
|
|
541
|
+
);
|
|
542
|
+
return alternatives.slice(0, MAX_LITERAL_ALTERNATIVES);
|
|
543
|
+
}
|
|
544
|
+
function schemaEnumExpectation(schema) {
|
|
545
|
+
if ("const" in schema) {
|
|
546
|
+
const constant = schemaLiteral(schema.const);
|
|
547
|
+
return constant === void 0 ? void 0 : `expected ${constant}`;
|
|
548
|
+
}
|
|
549
|
+
if (!Array.isArray(schema.enum)) return void 0;
|
|
550
|
+
const values = schema.enum.slice(0, MAX_LITERAL_ALTERNATIVES).map(schemaLiteral);
|
|
551
|
+
if (values.some((value) => value === void 0)) return void 0;
|
|
552
|
+
const rendered = values;
|
|
553
|
+
if (rendered.length === 0) return void 0;
|
|
554
|
+
const omission = schema.enum.length > rendered.length ? ", \u2026" : "";
|
|
555
|
+
return `expected ${rendered.length === 1 ? rendered[0] : `one of ${rendered.join(", ")}`}${omission}`;
|
|
556
|
+
}
|
|
557
|
+
function schemaTypeExpectation(schema) {
|
|
558
|
+
const type = schemaType(schema);
|
|
559
|
+
if (type !== void 0) return `expected ${type}`;
|
|
560
|
+
const alternatives = schemaAlternatives(schema);
|
|
561
|
+
return alternatives.length === 0 ? void 0 : `expected one of: ${alternatives.join(", ")}`;
|
|
562
|
+
}
|
|
563
|
+
function schemaSizeExpectation(schema, direction) {
|
|
564
|
+
const type = schemaType(schema);
|
|
565
|
+
const keyword = direction === "small" ? type === "string" ? "minLength" : type === "array" ? "minItems" : "minimum" : type === "string" ? "maxLength" : type === "array" ? "maxItems" : "maximum";
|
|
566
|
+
const value = schemaNumber(schema[keyword]);
|
|
567
|
+
if (value === void 0) return void 0;
|
|
568
|
+
const label = type === "string" ? "string length" : type === "array" ? "array length" : type;
|
|
569
|
+
if (label === void 0) return void 0;
|
|
570
|
+
return `expected ${label} ${direction === "small" ? "at least" : "at most"} ${value}`;
|
|
571
|
+
}
|
|
572
|
+
function schemaExpectation(schema, issueCode) {
|
|
573
|
+
switch (issueCode) {
|
|
574
|
+
case "invalid_type":
|
|
575
|
+
return schemaTypeExpectation(schema) ?? "failed structural validation";
|
|
576
|
+
case "invalid_value":
|
|
577
|
+
return schemaEnumExpectation(schema) ?? schemaTypeExpectation(schema) ?? "failed structural validation";
|
|
578
|
+
case "too_small":
|
|
579
|
+
return schemaSizeExpectation(schema, "small") ?? schemaTypeExpectation(schema) ?? "failed structural validation";
|
|
580
|
+
case "too_big":
|
|
581
|
+
return schemaSizeExpectation(schema, "big") ?? schemaTypeExpectation(schema) ?? "failed structural validation";
|
|
582
|
+
case "not_multiple_of": {
|
|
583
|
+
const multipleOf = schemaNumber(schema.multipleOf);
|
|
584
|
+
return multipleOf === void 0 ? schemaTypeExpectation(schema) ?? "failed structural validation" : `expected a multiple of ${multipleOf}`;
|
|
585
|
+
}
|
|
586
|
+
case "invalid_format": {
|
|
587
|
+
const format = schema.format;
|
|
588
|
+
return typeof format === "string" && SAFE_STRING_FORMATS.has(format) ? `expected valid ${format} format` : schemaTypeExpectation(schema) ?? "failed structural validation";
|
|
589
|
+
}
|
|
590
|
+
case "invalid_union":
|
|
591
|
+
return schemaTypeExpectation(schema) ?? "failed structural validation";
|
|
592
|
+
default: {
|
|
593
|
+
const typeExpectation = schemaTypeExpectation(schema);
|
|
594
|
+
return typeExpectation === void 0 ? "failed structural validation" : `failed structural validation; ${typeExpectation}`;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
383
598
|
var ToolStringLengthError = class extends Error {
|
|
384
599
|
constructor(path, actual, maximum) {
|
|
385
600
|
const renderedPath = path.reduce(
|
|
@@ -395,6 +610,42 @@ var ToolStringLengthError = class extends Error {
|
|
|
395
610
|
this.name = "ToolStringLengthError";
|
|
396
611
|
}
|
|
397
612
|
};
|
|
613
|
+
function toolArgumentModelMessage(error, providerVisibleSchema) {
|
|
614
|
+
try {
|
|
615
|
+
let lines;
|
|
616
|
+
let omitted = false;
|
|
617
|
+
if (error instanceof import_zod.ZodError) {
|
|
618
|
+
if (error.issues.length === 0) return void 0;
|
|
619
|
+
lines = [];
|
|
620
|
+
for (const issue of error.issues.slice(0, MAX_MODEL_ARGUMENT_ISSUES)) {
|
|
621
|
+
const resolved = resolveSchemaPath(providerVisibleSchema, issue.path);
|
|
622
|
+
if (resolved === void 0) return void 0;
|
|
623
|
+
const path = jsonPointerPath(resolved.segments);
|
|
624
|
+
const expectation = schemaExpectation(resolved.node, issue.code);
|
|
625
|
+
lines.push(
|
|
626
|
+
truncateModelFeedback(`- ${path}: ${expectation}`, MAX_MODEL_ARGUMENT_LINE_LENGTH)
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
omitted = error.issues.length > lines.length;
|
|
630
|
+
} else if (error instanceof ToolStringLengthError) {
|
|
631
|
+
const resolved = resolveSchemaPath(providerVisibleSchema, error.path);
|
|
632
|
+
const maximum = schemaNumber(error.maximum);
|
|
633
|
+
if (resolved === void 0 || maximum === void 0) return void 0;
|
|
634
|
+
const path = jsonPointerPath(resolved.segments);
|
|
635
|
+
lines = [`- ${path}: maximum string length is ${maximum}`];
|
|
636
|
+
} else {
|
|
637
|
+
return void 0;
|
|
638
|
+
}
|
|
639
|
+
const header = "Error: Invalid tool arguments:";
|
|
640
|
+
const footer = "Correct the arguments and try again.";
|
|
641
|
+
const omission = omitted ? "Additional validation issues were omitted." : void 0;
|
|
642
|
+
const parts = [header, ...lines, ...omission ? [omission] : [], footer];
|
|
643
|
+
const message = parts.join("\n");
|
|
644
|
+
return message.length <= MAX_MODEL_ARGUMENT_MESSAGE_LENGTH ? message : void 0;
|
|
645
|
+
} catch {
|
|
646
|
+
return void 0;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
398
649
|
function validateStringLengths(value, maxLen, path = []) {
|
|
399
650
|
if (typeof value === "string") {
|
|
400
651
|
if (value.length > maxLen) {
|
|
@@ -705,7 +956,7 @@ async function fetchWithRetry(input, init, opts) {
|
|
|
705
956
|
for (let attempt = 0; ; attempt++) {
|
|
706
957
|
let res;
|
|
707
958
|
try {
|
|
708
|
-
res = await fetch(input, init);
|
|
959
|
+
res = await fetch(input, { ...init, redirect: "manual" });
|
|
709
960
|
} catch (err) {
|
|
710
961
|
if (isAbortError2(err, init?.signal ?? void 0)) throw err;
|
|
711
962
|
if (attempt >= maxRetries) {
|
|
@@ -911,6 +1162,38 @@ function isBuiltinTablePricingEligible(profile, context) {
|
|
|
911
1162
|
return typeof effectiveTier === "string" && policy.supportedServiceTiers.includes(effectiveTier);
|
|
912
1163
|
}
|
|
913
1164
|
|
|
1165
|
+
// src/http-transport.ts
|
|
1166
|
+
function assertSafeProviderBaseUrl(baseUrl, surface, dangerouslyAllowInsecureHttp = false) {
|
|
1167
|
+
assertSafeHttpEndpoint(baseUrl, surface, dangerouslyAllowInsecureHttp, "prompts and credentials");
|
|
1168
|
+
}
|
|
1169
|
+
function assertSafeHttpEndpoint(endpoint, surface, dangerouslyAllowInsecureHttp = false, exposedData = "sensitive data") {
|
|
1170
|
+
let url;
|
|
1171
|
+
try {
|
|
1172
|
+
url = new URL(endpoint);
|
|
1173
|
+
} catch {
|
|
1174
|
+
throw unsafeTransportError(surface, "a valid absolute HTTP(S) URL", exposedData);
|
|
1175
|
+
}
|
|
1176
|
+
if (url.protocol === "https:") return;
|
|
1177
|
+
if (url.protocol !== "http:") {
|
|
1178
|
+
throw unsafeTransportError(surface, "an HTTPS URL", exposedData);
|
|
1179
|
+
}
|
|
1180
|
+
if (dangerouslyAllowInsecureHttp || isLiteralLoopbackHost(url.hostname)) return;
|
|
1181
|
+
throw unsafeTransportError(
|
|
1182
|
+
surface,
|
|
1183
|
+
"an HTTPS URL, or set dangerouslyAllowInsecureHttp: true only for a deliberately insecure endpoint",
|
|
1184
|
+
exposedData
|
|
1185
|
+
);
|
|
1186
|
+
}
|
|
1187
|
+
function isLiteralLoopbackHost(hostname) {
|
|
1188
|
+
return hostname === "localhost" || hostname === "localhost." || /^127(?:\.\d{1,3}){3}$/.test(hostname) || hostname === "[::1]";
|
|
1189
|
+
}
|
|
1190
|
+
function unsafeTransportError(surface, remediation, exposedData) {
|
|
1191
|
+
return new AxlError(
|
|
1192
|
+
"UNSAFE_TRANSPORT",
|
|
1193
|
+
`${surface} requires ${remediation}. Remote HTTP can expose ${exposedData} in transit.`
|
|
1194
|
+
);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
914
1197
|
// src/providers/openai-compatible.ts
|
|
915
1198
|
function resolvePerModel(value, model, fallback) {
|
|
916
1199
|
if (value === void 0) return fallback;
|
|
@@ -1054,6 +1337,11 @@ var OpenAICompatibleProvider = class {
|
|
|
1054
1337
|
const envBase = p.envBaseUrl ? process.env[p.envBaseUrl] : void 0;
|
|
1055
1338
|
const explicitBase = options.baseUrl ?? envBase;
|
|
1056
1339
|
this.baseUrl = (explicitBase ?? p.defaultBaseUrl).replace(/\/$/, "");
|
|
1340
|
+
assertSafeProviderBaseUrl(
|
|
1341
|
+
this.baseUrl,
|
|
1342
|
+
`${p.label ?? p.name} provider`,
|
|
1343
|
+
options.dangerouslyAllowInsecureHttp
|
|
1344
|
+
);
|
|
1057
1345
|
this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
|
|
1058
1346
|
const label = p.label ?? p.name;
|
|
1059
1347
|
if (p.requireExplicitBaseUrl && explicitBase === void 0) {
|
|
@@ -1954,6 +2242,11 @@ var OpenAIResponsesProvider = class {
|
|
|
1954
2242
|
constructor(options = {}) {
|
|
1955
2243
|
this.apiKeySource = options.apiKey ?? process.env.OPENAI_API_KEY ?? "";
|
|
1956
2244
|
this.baseUrl = (options.baseUrl ?? process.env.OPENAI_BASE_URL ?? "https://api.openai.com/v1").replace(/\/$/, "");
|
|
2245
|
+
assertSafeProviderBaseUrl(
|
|
2246
|
+
this.baseUrl,
|
|
2247
|
+
"OpenAI Responses provider",
|
|
2248
|
+
options.dangerouslyAllowInsecureHttp
|
|
2249
|
+
);
|
|
1957
2250
|
this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
|
|
1958
2251
|
if (typeof this.apiKeySource === "string" && !this.apiKeySource) {
|
|
1959
2252
|
throw new Error("OpenAI API key is required. Set OPENAI_API_KEY or pass apiKey in options.");
|
|
@@ -2709,6 +3002,11 @@ var AnthropicProvider = class {
|
|
|
2709
3002
|
constructor(options = {}) {
|
|
2710
3003
|
this.apiKeySource = options.apiKey ?? process.env.ANTHROPIC_API_KEY ?? "";
|
|
2711
3004
|
this.baseUrl = (options.baseUrl ?? "https://api.anthropic.com/v1").replace(/\/$/, "");
|
|
3005
|
+
assertSafeProviderBaseUrl(
|
|
3006
|
+
this.baseUrl,
|
|
3007
|
+
"Anthropic provider",
|
|
3008
|
+
options.dangerouslyAllowInsecureHttp
|
|
3009
|
+
);
|
|
2712
3010
|
this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
|
|
2713
3011
|
if (typeof this.apiKeySource === "string" && !this.apiKeySource) {
|
|
2714
3012
|
throw new Error(
|
|
@@ -3399,6 +3697,11 @@ var GeminiProvider = class {
|
|
|
3399
3697
|
/\/$/,
|
|
3400
3698
|
""
|
|
3401
3699
|
);
|
|
3700
|
+
assertSafeProviderBaseUrl(
|
|
3701
|
+
this.baseUrl,
|
|
3702
|
+
"Google provider",
|
|
3703
|
+
options.dangerouslyAllowInsecureHttp
|
|
3704
|
+
);
|
|
3402
3705
|
this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
|
|
3403
3706
|
if (typeof this.apiKeySource === "string" && !this.apiKeySource) {
|
|
3404
3707
|
throw new Error("Google API key is required. Set GOOGLE_API_KEY or pass apiKey in options.");
|
|
@@ -4286,6 +4589,7 @@ var builtinFactories = {
|
|
|
4286
4589
|
return new OpenAIProvider({
|
|
4287
4590
|
apiKey: opts.apiKey,
|
|
4288
4591
|
baseUrl: opts.baseUrl,
|
|
4592
|
+
dangerouslyAllowInsecureHttp: opts.dangerouslyAllowInsecureHttp,
|
|
4289
4593
|
rateLimit: opts.rateLimit
|
|
4290
4594
|
});
|
|
4291
4595
|
},
|
|
@@ -4298,6 +4602,7 @@ var builtinFactories = {
|
|
|
4298
4602
|
return new OpenAIResponsesProvider({
|
|
4299
4603
|
apiKey: opts.apiKey,
|
|
4300
4604
|
baseUrl: opts.baseUrl,
|
|
4605
|
+
dangerouslyAllowInsecureHttp: opts.dangerouslyAllowInsecureHttp,
|
|
4301
4606
|
rateLimit: opts.rateLimit
|
|
4302
4607
|
});
|
|
4303
4608
|
},
|
|
@@ -4306,6 +4611,7 @@ var builtinFactories = {
|
|
|
4306
4611
|
return new AnthropicProvider({
|
|
4307
4612
|
apiKey: opts.apiKey,
|
|
4308
4613
|
baseUrl: opts.baseUrl,
|
|
4614
|
+
dangerouslyAllowInsecureHttp: opts.dangerouslyAllowInsecureHttp,
|
|
4309
4615
|
rateLimit: opts.rateLimit
|
|
4310
4616
|
});
|
|
4311
4617
|
},
|
|
@@ -4314,6 +4620,7 @@ var builtinFactories = {
|
|
|
4314
4620
|
return new GeminiProvider({
|
|
4315
4621
|
apiKey: opts.apiKey,
|
|
4316
4622
|
baseUrl: opts.baseUrl,
|
|
4623
|
+
dangerouslyAllowInsecureHttp: opts.dangerouslyAllowInsecureHttp,
|
|
4317
4624
|
rateLimit: opts.rateLimit
|
|
4318
4625
|
});
|
|
4319
4626
|
}
|
|
@@ -4325,6 +4632,7 @@ function presetFactory(profile) {
|
|
|
4325
4632
|
profile,
|
|
4326
4633
|
apiKey: opts.apiKey,
|
|
4327
4634
|
baseUrl: opts.baseUrl,
|
|
4635
|
+
dangerouslyAllowInsecureHttp: opts.dangerouslyAllowInsecureHttp,
|
|
4328
4636
|
authHeader: opts.authHeader,
|
|
4329
4637
|
rateLimit: opts.rateLimit
|
|
4330
4638
|
});
|
|
@@ -6482,7 +6790,15 @@ function cloneToolArguments(value) {
|
|
|
6482
6790
|
}
|
|
6483
6791
|
}
|
|
6484
6792
|
function parseToolInvocation(options) {
|
|
6485
|
-
const {
|
|
6793
|
+
const {
|
|
6794
|
+
toolCall,
|
|
6795
|
+
configuredTool,
|
|
6796
|
+
override,
|
|
6797
|
+
mcpCall,
|
|
6798
|
+
mcpTraceName,
|
|
6799
|
+
availableTools,
|
|
6800
|
+
providerVisibleSchema
|
|
6801
|
+
} = options;
|
|
6486
6802
|
const requestedTool = toolCall.function.name;
|
|
6487
6803
|
if (!override && !configuredTool && !mcpCall) {
|
|
6488
6804
|
return {
|
|
@@ -6542,7 +6858,7 @@ function parseToolInvocation(options) {
|
|
|
6542
6858
|
args: parsedArguments,
|
|
6543
6859
|
issues: toolArgumentIssues(error)
|
|
6544
6860
|
},
|
|
6545
|
-
modelMessage: INVALID_ARGUMENTS_MODEL_MESSAGE
|
|
6861
|
+
modelMessage: toolArgumentModelMessage(error, providerVisibleSchema) ?? INVALID_ARGUMENTS_MODEL_MESSAGE
|
|
6546
6862
|
};
|
|
6547
6863
|
}
|
|
6548
6864
|
}
|
|
@@ -7445,7 +7761,7 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
7445
7761
|
/** Resolve, execute, and observe one non-handoff tool request. Rejections
|
|
7446
7762
|
* never start. Every accepted request emits one terminal event before a
|
|
7447
7763
|
* continuation message or abort escapes this coordinator. */
|
|
7448
|
-
async observeToolInvocation(agent2, toolCall, currentMessages,
|
|
7764
|
+
async observeToolInvocation(agent2, toolCall, currentMessages, toolDefs) {
|
|
7449
7765
|
const signal = this.currentSignal;
|
|
7450
7766
|
signal?.throwIfAborted();
|
|
7451
7767
|
const requestedTool = toolCall.function.name;
|
|
@@ -7455,6 +7771,7 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
7455
7771
|
const override = this.toolOverrides?.get(requestedTool);
|
|
7456
7772
|
const mcpManager = this.mcpManager;
|
|
7457
7773
|
const mcpMatch = !configuredTool ? mcpManager?.getToolsForAgent(agent2._config.mcp, agent2._config.mcpTools).find(({ tool: tool2 }) => tool2.name === requestedTool) : void 0;
|
|
7774
|
+
const providerVisibleSchema = toolDefs.find((tool2) => tool2.function.name === requestedTool)?.function.parameters;
|
|
7458
7775
|
const parsed = parseToolInvocation({
|
|
7459
7776
|
toolCall,
|
|
7460
7777
|
configuredTool,
|
|
@@ -7463,7 +7780,8 @@ var WorkflowContext = class _WorkflowContext {
|
|
|
7463
7780
|
mcpCall: (args) => mcpManager.callTool(requestedTool, args, mcpMatch.server),
|
|
7464
7781
|
mcpTraceName: `${mcpMatch.server}:${requestedTool}`
|
|
7465
7782
|
} : {},
|
|
7466
|
-
availableTools
|
|
7783
|
+
availableTools: toolDefs.map((tool2) => tool2.function.name),
|
|
7784
|
+
...configuredTool ? { providerVisibleSchema } : {}
|
|
7467
7785
|
});
|
|
7468
7786
|
signal?.throwIfAborted();
|
|
7469
7787
|
if ("kind" in parsed) {
|
|
@@ -8274,12 +8592,7 @@ ${appendedSchemaText}`;
|
|
|
8274
8592
|
return await handoffFn();
|
|
8275
8593
|
}
|
|
8276
8594
|
}
|
|
8277
|
-
await this.observeToolInvocation(
|
|
8278
|
-
agent2,
|
|
8279
|
-
toolCall,
|
|
8280
|
-
currentMessages,
|
|
8281
|
-
toolDefs.map((tool2) => tool2.function.name)
|
|
8282
|
-
);
|
|
8595
|
+
await this.observeToolInvocation(agent2, toolCall, currentMessages, toolDefs);
|
|
8283
8596
|
}
|
|
8284
8597
|
continue;
|
|
8285
8598
|
}
|
|
@@ -11335,6 +11648,14 @@ var HttpMcpClient = class {
|
|
|
11335
11648
|
this.config = config;
|
|
11336
11649
|
this.name = config.name;
|
|
11337
11650
|
this.baseUrl = (config.uri ?? "").replace(/\/$/, "");
|
|
11651
|
+
if (this.baseUrl) {
|
|
11652
|
+
assertSafeHttpEndpoint(
|
|
11653
|
+
this.baseUrl,
|
|
11654
|
+
`MCP server "${this.name}"`,
|
|
11655
|
+
config.dangerouslyAllowInsecureHttp,
|
|
11656
|
+
"tool arguments and results"
|
|
11657
|
+
);
|
|
11658
|
+
}
|
|
11338
11659
|
}
|
|
11339
11660
|
name;
|
|
11340
11661
|
tools = [];
|
|
@@ -11364,7 +11685,9 @@ var HttpMcpClient = class {
|
|
|
11364
11685
|
method: "POST",
|
|
11365
11686
|
headers: { "Content-Type": "application/json" },
|
|
11366
11687
|
body: JSON.stringify(request),
|
|
11367
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
11688
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
11689
|
+
// Tool calls can be non-idempotent: never forward or retry their body.
|
|
11690
|
+
redirect: "manual"
|
|
11368
11691
|
});
|
|
11369
11692
|
if (!res.ok) {
|
|
11370
11693
|
throw new Error(`MCP HTTP error (${res.status}): ${await res.text()}`);
|
|
@@ -14156,6 +14479,11 @@ var OpenAIEmbedder = class {
|
|
|
14156
14479
|
}
|
|
14157
14480
|
this.model = options.model ?? "text-embedding-3-small";
|
|
14158
14481
|
this.baseUrl = options.baseUrl ?? "https://api.openai.com";
|
|
14482
|
+
assertSafeProviderBaseUrl(
|
|
14483
|
+
this.baseUrl,
|
|
14484
|
+
"OpenAI embedder",
|
|
14485
|
+
options.dangerouslyAllowInsecureHttp
|
|
14486
|
+
);
|
|
14159
14487
|
this.dimensions = options.dimensions ?? 1536;
|
|
14160
14488
|
}
|
|
14161
14489
|
async embed(texts, signal) {
|