@axlsdk/axl 0.22.1 → 0.22.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/README.md +1 -1
- package/dist/index.cjs +135 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +135 -27
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ agent({ model: 'deepseek:deepseek-reasoner' }); // DEEPSEEK_API_KEY
|
|
|
67
67
|
agent({ model: 'ollama:llama3' }); // local — no key, $0
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
Presets: `openrouter`, `azure`, `xai`, `deepseek`, `mistral`, `groq`, `bedrock`, and self-hosted `ollama` / `vllm` / `lmstudio` / `llamacpp` / `sglang`. The unified `effort` knob and per-call cost tracking work across them. OpenRouter
|
|
70
|
+
Presets: `openrouter`, `azure`, `xai`, `deepseek`, `mistral`, `groq`, `bedrock`, and self-hosted `ollama` / `vllm` / `lmstudio` / `llamacpp` / `sglang`. The unified `effort` knob and per-call cost tracking work across them. OpenAI Responses, Anthropic, Google, and OpenRouter accept image input without hard-coding a model catalog; the selected upstream model remains authoritative. Completed-file transcription is a separate, narrower contract. Build your own compatible provider by cloning a `ProviderProfile`; see [provider details](../../docs/providers.md) and [multimodal input](../../docs/multimodal-input.md).
|
|
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
|
|
package/dist/index.cjs
CHANGED
|
@@ -1427,7 +1427,8 @@ var OpenAICompatibleProvider = class {
|
|
|
1427
1427
|
return this.name === "openrouter" && model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64"] } } : {};
|
|
1428
1428
|
}
|
|
1429
1429
|
validateInput(request) {
|
|
1430
|
-
const
|
|
1430
|
+
const modelOverride = request.providerOptions?.model;
|
|
1431
|
+
const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
|
|
1431
1432
|
const fail = (source, feature) => {
|
|
1432
1433
|
throw new UnsupportedModelInputError({
|
|
1433
1434
|
provider: this.name,
|
|
@@ -1437,6 +1438,9 @@ var OpenAICompatibleProvider = class {
|
|
|
1437
1438
|
...feature ? { feature } : {}
|
|
1438
1439
|
});
|
|
1439
1440
|
};
|
|
1441
|
+
if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
|
|
1442
|
+
fail(void 0, "invalid model providerOptions");
|
|
1443
|
+
}
|
|
1440
1444
|
if (this.name !== "openrouter" || effectiveModel.trim().length === 0) {
|
|
1441
1445
|
fail(void 0, "image input for this model");
|
|
1442
1446
|
}
|
|
@@ -2377,13 +2381,6 @@ var OpenAIProvider = class extends OpenAICompatibleProvider {
|
|
|
2377
2381
|
};
|
|
2378
2382
|
|
|
2379
2383
|
// src/providers/openai-responses.ts
|
|
2380
|
-
var OPENAI_RESPONSES_IMAGE_MODELS = /* @__PURE__ */ new Set([
|
|
2381
|
-
"gpt-4o",
|
|
2382
|
-
"gpt-4o-2024-08-06",
|
|
2383
|
-
"gpt-4o-2024-11-20",
|
|
2384
|
-
"gpt-4o-mini",
|
|
2385
|
-
"gpt-4o-mini-2024-07-18"
|
|
2386
|
-
]);
|
|
2387
2384
|
function base64FromSource(source) {
|
|
2388
2385
|
return source.type === "base64" ? source.data : Buffer.from(source.data.buffer, source.data.byteOffset, source.data.byteLength).toString(
|
|
2389
2386
|
"base64"
|
|
@@ -2422,10 +2419,11 @@ function responseImageParts(parts) {
|
|
|
2422
2419
|
var OpenAIResponsesProvider = class {
|
|
2423
2420
|
name = "openai-responses";
|
|
2424
2421
|
inputCapabilities(model) {
|
|
2425
|
-
return
|
|
2422
|
+
return model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
|
|
2426
2423
|
}
|
|
2427
2424
|
validateInput(request) {
|
|
2428
|
-
const
|
|
2425
|
+
const modelOverride = request.providerOptions?.model;
|
|
2426
|
+
const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
|
|
2429
2427
|
const fail = (source, feature) => {
|
|
2430
2428
|
throw new UnsupportedModelInputError({
|
|
2431
2429
|
provider: this.name,
|
|
@@ -2435,7 +2433,10 @@ var OpenAIResponsesProvider = class {
|
|
|
2435
2433
|
...feature ? { feature } : {}
|
|
2436
2434
|
});
|
|
2437
2435
|
};
|
|
2438
|
-
if (
|
|
2436
|
+
if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
|
|
2437
|
+
fail(void 0, "invalid model providerOptions");
|
|
2438
|
+
}
|
|
2439
|
+
if (effectiveModel.trim().length === 0) {
|
|
2439
2440
|
fail(void 0, "image input for this model");
|
|
2440
2441
|
}
|
|
2441
2442
|
if (request.providerOptions && "input" in request.providerOptions) {
|
|
@@ -2563,7 +2564,7 @@ var OpenAIResponsesProvider = class {
|
|
|
2563
2564
|
const resolved = resolveThinkingOptions(options);
|
|
2564
2565
|
const { includeThoughts } = resolved;
|
|
2565
2566
|
const wireEffort = resolveOpenAIReasoningEffort(effectiveModel, resolved);
|
|
2566
|
-
const stripTemp = oSeries || reasoningCapable && wireEffort !== void 0;
|
|
2567
|
+
const stripTemp = oSeries || supportsMaxReasoningEffort(effectiveModel) || reasoningCapable && wireEffort !== void 0;
|
|
2567
2568
|
const systemMessages = messages.filter((m) => m.role === "system");
|
|
2568
2569
|
const nonSystemMessages = messages.filter((m) => m.role !== "system");
|
|
2569
2570
|
const body = {
|
|
@@ -2911,7 +2912,6 @@ function anthropicImageBlocks(parts) {
|
|
|
2911
2912
|
}
|
|
2912
2913
|
var ANTHROPIC_API_VERSION = "2023-06-01";
|
|
2913
2914
|
var ANTHROPIC_FILES_BETA = "files-api-2025-04-14";
|
|
2914
|
-
var ANTHROPIC_IMAGE_MODELS = /* @__PURE__ */ new Set(["claude-sonnet-4-5", "claude-opus-4-8"]);
|
|
2915
2915
|
function hasAnthropicProviderFileImage(messages) {
|
|
2916
2916
|
return messages.some(
|
|
2917
2917
|
(message) => Array.isArray(message.content) && message.content.some(
|
|
@@ -3030,6 +3030,28 @@ var ANTHROPIC_RATES = {
|
|
|
3030
3030
|
function isValidTokenCount(value) {
|
|
3031
3031
|
return value !== void 0 && Number.isSafeInteger(value) && value >= 0;
|
|
3032
3032
|
}
|
|
3033
|
+
function anthropicStreamErrorStatus(type) {
|
|
3034
|
+
switch (type) {
|
|
3035
|
+
case "invalid_request_error":
|
|
3036
|
+
return 400;
|
|
3037
|
+
case "authentication_error":
|
|
3038
|
+
return 401;
|
|
3039
|
+
case "permission_error":
|
|
3040
|
+
return 403;
|
|
3041
|
+
case "not_found_error":
|
|
3042
|
+
return 404;
|
|
3043
|
+
case "request_too_large":
|
|
3044
|
+
return 413;
|
|
3045
|
+
case "rate_limit_error":
|
|
3046
|
+
return 429;
|
|
3047
|
+
case "api_error":
|
|
3048
|
+
return 500;
|
|
3049
|
+
case "overloaded_error":
|
|
3050
|
+
return 529;
|
|
3051
|
+
default:
|
|
3052
|
+
return 0;
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3033
3055
|
function estimateAnthropicCost(model, usage, now = /* @__PURE__ */ new Date()) {
|
|
3034
3056
|
if (!model || !isValidTokenCount(usage.inputTokens) || !isValidTokenCount(usage.outputTokens)) {
|
|
3035
3057
|
return void 0;
|
|
@@ -3279,10 +3301,11 @@ function mergeAnthropicUsage(initial, update) {
|
|
|
3279
3301
|
var AnthropicProvider = class {
|
|
3280
3302
|
name = "anthropic";
|
|
3281
3303
|
inputCapabilities(model) {
|
|
3282
|
-
return
|
|
3304
|
+
return model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
|
|
3283
3305
|
}
|
|
3284
3306
|
validateInput(request) {
|
|
3285
|
-
const
|
|
3307
|
+
const modelOverride = request.providerOptions?.model;
|
|
3308
|
+
const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
|
|
3286
3309
|
const fail = (source, feature) => {
|
|
3287
3310
|
throw new UnsupportedModelInputError({
|
|
3288
3311
|
provider: this.name,
|
|
@@ -3292,7 +3315,10 @@ var AnthropicProvider = class {
|
|
|
3292
3315
|
...feature ? { feature } : {}
|
|
3293
3316
|
});
|
|
3294
3317
|
};
|
|
3295
|
-
if (
|
|
3318
|
+
if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
|
|
3319
|
+
fail(void 0, "invalid model providerOptions");
|
|
3320
|
+
}
|
|
3321
|
+
if (effectiveModel.trim().length === 0) {
|
|
3296
3322
|
fail(void 0, "image input for this model");
|
|
3297
3323
|
}
|
|
3298
3324
|
if (request.providerOptions && "messages" in request.providerOptions) {
|
|
@@ -3417,7 +3443,7 @@ var AnthropicProvider = class {
|
|
|
3417
3443
|
if (!res.body) {
|
|
3418
3444
|
throw new Error("Anthropic stream response has no body");
|
|
3419
3445
|
}
|
|
3420
|
-
yield* this.parseSSEStream(res.body, pricingContext);
|
|
3446
|
+
yield* this.parseSSEStream(res.body, pricingContext, res.headers);
|
|
3421
3447
|
}
|
|
3422
3448
|
// ---------------------------------------------------------------------------
|
|
3423
3449
|
// Internal: request building
|
|
@@ -3660,7 +3686,7 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
3660
3686
|
// ---------------------------------------------------------------------------
|
|
3661
3687
|
// Internal: SSE stream parsing
|
|
3662
3688
|
// ---------------------------------------------------------------------------
|
|
3663
|
-
async *parseSSEStream(body, pricingContext) {
|
|
3689
|
+
async *parseSSEStream(body, pricingContext, responseHeaders) {
|
|
3664
3690
|
const reader = body.getReader();
|
|
3665
3691
|
const decoder = new TextDecoder();
|
|
3666
3692
|
let buffer = "";
|
|
@@ -3706,6 +3732,15 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
3706
3732
|
continue;
|
|
3707
3733
|
}
|
|
3708
3734
|
switch (event.type) {
|
|
3735
|
+
case "error": {
|
|
3736
|
+
const status = anthropicStreamErrorStatus(event.error?.type);
|
|
3737
|
+
throw buildProviderError({
|
|
3738
|
+
provider: this.name,
|
|
3739
|
+
status,
|
|
3740
|
+
headers: responseHeaders,
|
|
3741
|
+
message: event.error?.message ?? "Anthropic stream failed"
|
|
3742
|
+
});
|
|
3743
|
+
}
|
|
3709
3744
|
case "content_block_start": {
|
|
3710
3745
|
const block = event.content_block;
|
|
3711
3746
|
if (block?.type === "tool_use") {
|
|
@@ -3957,7 +3992,6 @@ var GEMINI_PRICING = {
|
|
|
3957
3992
|
"gemini-3.5-flash-lite": { input: 3e-7, cached: 3e-8, output: 25e-7 },
|
|
3958
3993
|
"gemini-3.6-flash": { input: 15e-7, cached: 15e-8, output: 75e-7 }
|
|
3959
3994
|
};
|
|
3960
|
-
var GEMINI_INTERACTIONS_IMAGE_MODELS = /* @__PURE__ */ new Set(["gemini-3.7-flash"]);
|
|
3961
3995
|
function isValidTokenCount2(value) {
|
|
3962
3996
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
3963
3997
|
}
|
|
@@ -3967,6 +4001,55 @@ function isStandardGeminiRequestTier(value) {
|
|
|
3967
4001
|
function isDefinitiveStandardGeminiResponseTier(value) {
|
|
3968
4002
|
return value === "SERVICE_TIER_UNSPECIFIED" || value === "SERVICE_TIER_STANDARD" || value === "standard";
|
|
3969
4003
|
}
|
|
4004
|
+
function geminiInteractionErrorStatus(code) {
|
|
4005
|
+
if (typeof code === "number" && Number.isInteger(code) && code >= 100 && code <= 599) {
|
|
4006
|
+
return code;
|
|
4007
|
+
}
|
|
4008
|
+
switch (code) {
|
|
4009
|
+
case "invalid_request":
|
|
4010
|
+
case "invalid_argument":
|
|
4011
|
+
case "parameter_unknown":
|
|
4012
|
+
case "failed_precondition":
|
|
4013
|
+
return 400;
|
|
4014
|
+
case "authentication":
|
|
4015
|
+
case "unauthenticated":
|
|
4016
|
+
return 401;
|
|
4017
|
+
case "permission_denied":
|
|
4018
|
+
return 403;
|
|
4019
|
+
case "not_found":
|
|
4020
|
+
case "model_not_found":
|
|
4021
|
+
return 404;
|
|
4022
|
+
case "request_timeout":
|
|
4023
|
+
return 408;
|
|
4024
|
+
case "conflict":
|
|
4025
|
+
case "already_exists":
|
|
4026
|
+
return 409;
|
|
4027
|
+
case "request_too_large":
|
|
4028
|
+
return 413;
|
|
4029
|
+
case "out_of_range":
|
|
4030
|
+
return 416;
|
|
4031
|
+
case "quota_exceeded":
|
|
4032
|
+
case "resource_exhausted":
|
|
4033
|
+
case "rate_limit_exceeded":
|
|
4034
|
+
return 429;
|
|
4035
|
+
case "cancelled":
|
|
4036
|
+
return 499;
|
|
4037
|
+
case "api_error":
|
|
4038
|
+
case "internal":
|
|
4039
|
+
case "internal_server_error":
|
|
4040
|
+
return 500;
|
|
4041
|
+
case "bad_gateway":
|
|
4042
|
+
return 502;
|
|
4043
|
+
case "unavailable":
|
|
4044
|
+
case "service_unavailable":
|
|
4045
|
+
return 503;
|
|
4046
|
+
case "deadline_exceeded":
|
|
4047
|
+
case "gateway_timeout":
|
|
4048
|
+
return 504;
|
|
4049
|
+
default:
|
|
4050
|
+
return void 0;
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
3970
4053
|
function isEligibleGeminiPricing(context, hasDefinitiveStandardResponseTier, hasInvalidResponseTier) {
|
|
3971
4054
|
return context.eligibleRequest && isStandardGeminiRequestTier(context.serviceTier) && hasDefinitiveStandardResponseTier && !hasInvalidResponseTier;
|
|
3972
4055
|
}
|
|
@@ -4048,7 +4131,9 @@ var GEMINI_3X_MIN_THINKING_LEVEL = /* @__PURE__ */ new Map([
|
|
|
4048
4131
|
["gemini-3.6-flash", "minimal"],
|
|
4049
4132
|
// L4 live evidence: Interactions gemini-3.7-flash accepts low/medium/high,
|
|
4050
4133
|
// but rejects minimal. Keep this exact entry isolated from legacy aliases.
|
|
4051
|
-
["gemini-3.7-flash", "low"]
|
|
4134
|
+
["gemini-3.7-flash", "low"],
|
|
4135
|
+
// Current-model live evidence: gemini-3.8-flash has the same low floor.
|
|
4136
|
+
["gemini-3.8-flash", "low"]
|
|
4052
4137
|
]);
|
|
4053
4138
|
var GEMINI_MODELS_WITHOUT_PORTABLE_TEMPERATURE = /* @__PURE__ */ new Set([
|
|
4054
4139
|
"gemini-3.5-flash-lite",
|
|
@@ -4076,10 +4161,11 @@ function warnGemini3xEffortNone(model) {
|
|
|
4076
4161
|
var GeminiProvider = class {
|
|
4077
4162
|
name = "google";
|
|
4078
4163
|
inputCapabilities(model) {
|
|
4079
|
-
return
|
|
4164
|
+
return model.trim().length > 0 ? { image: { sources: ["bytes", "base64", "provider-file"] } } : {};
|
|
4080
4165
|
}
|
|
4081
4166
|
validateInput(request) {
|
|
4082
|
-
const
|
|
4167
|
+
const modelOverride = request.providerOptions?.model;
|
|
4168
|
+
const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
|
|
4083
4169
|
const fail = (source, feature) => {
|
|
4084
4170
|
throw new UnsupportedModelInputError({
|
|
4085
4171
|
provider: this.name,
|
|
@@ -4089,7 +4175,10 @@ var GeminiProvider = class {
|
|
|
4089
4175
|
...feature ? { feature } : {}
|
|
4090
4176
|
});
|
|
4091
4177
|
};
|
|
4092
|
-
if (
|
|
4178
|
+
if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
|
|
4179
|
+
fail(void 0, "invalid model providerOptions");
|
|
4180
|
+
}
|
|
4181
|
+
if (effectiveModel.trim().length === 0) {
|
|
4093
4182
|
fail(void 0, "image input for this model");
|
|
4094
4183
|
}
|
|
4095
4184
|
if (request.providerOptions) {
|
|
@@ -4281,7 +4370,7 @@ var GeminiProvider = class {
|
|
|
4281
4370
|
});
|
|
4282
4371
|
}
|
|
4283
4372
|
if (!res.body) throw new Error("Gemini Interactions stream has no body");
|
|
4284
|
-
yield* this.parseInteractionSSEStream(res.body);
|
|
4373
|
+
yield* this.parseInteractionSSEStream(res.body, res.headers);
|
|
4285
4374
|
}
|
|
4286
4375
|
buildInteractionRequestBody(messages, options, stream) {
|
|
4287
4376
|
const model = this.requestModel(options);
|
|
@@ -4351,6 +4440,7 @@ var GeminiProvider = class {
|
|
|
4351
4440
|
return body;
|
|
4352
4441
|
}
|
|
4353
4442
|
assertSafeInteractionOptions(options) {
|
|
4443
|
+
const modelOverride = options.providerOptions?.model;
|
|
4354
4444
|
const model = this.requestModel(options);
|
|
4355
4445
|
const fail = (feature) => {
|
|
4356
4446
|
throw new UnsupportedModelInputError({
|
|
@@ -4360,7 +4450,10 @@ var GeminiProvider = class {
|
|
|
4360
4450
|
feature
|
|
4361
4451
|
});
|
|
4362
4452
|
};
|
|
4363
|
-
if (
|
|
4453
|
+
if (options.providerOptions && "model" in options.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
|
|
4454
|
+
fail("invalid model providerOptions");
|
|
4455
|
+
}
|
|
4456
|
+
if (model.trim().length === 0) fail("image input for this model");
|
|
4364
4457
|
const forbidden = [
|
|
4365
4458
|
"input",
|
|
4366
4459
|
"contents",
|
|
@@ -4436,7 +4529,7 @@ var GeminiProvider = class {
|
|
|
4436
4529
|
providerMetadata: json.steps?.length ? { geminiInteractionSteps: json.steps.filter(isGeminiInteractionStep) } : void 0
|
|
4437
4530
|
};
|
|
4438
4531
|
}
|
|
4439
|
-
async *parseInteractionSSEStream(body) {
|
|
4532
|
+
async *parseInteractionSSEStream(body, responseHeaders) {
|
|
4440
4533
|
const reader = body.getReader();
|
|
4441
4534
|
const decoder = new TextDecoder();
|
|
4442
4535
|
let buffer = "";
|
|
@@ -4462,7 +4555,22 @@ var GeminiProvider = class {
|
|
|
4462
4555
|
continue;
|
|
4463
4556
|
}
|
|
4464
4557
|
if (event.event_type === "error") {
|
|
4465
|
-
|
|
4558
|
+
const status = geminiInteractionErrorStatus(event.error?.code);
|
|
4559
|
+
const message = event.error?.message ?? "Gemini Interactions stream failed";
|
|
4560
|
+
if (status !== void 0) {
|
|
4561
|
+
throw buildProviderError({
|
|
4562
|
+
provider: this.name,
|
|
4563
|
+
status,
|
|
4564
|
+
headers: responseHeaders,
|
|
4565
|
+
message
|
|
4566
|
+
});
|
|
4567
|
+
}
|
|
4568
|
+
throw new ProviderError({
|
|
4569
|
+
provider: this.name,
|
|
4570
|
+
status: 0,
|
|
4571
|
+
retryable: false,
|
|
4572
|
+
message
|
|
4573
|
+
});
|
|
4466
4574
|
}
|
|
4467
4575
|
if (event.event_type === "step.start" && event.step) {
|
|
4468
4576
|
const index = event.index;
|