@axlsdk/axl 0.22.0 → 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 +7 -5
- package/dist/index.cjs +149 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +149 -38
- 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. Build your own by cloning a `ProviderProfile
|
|
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
|
|
|
@@ -792,10 +792,12 @@ See [docs/providers.md](../../docs/providers.md) for the full model list includi
|
|
|
792
792
|
|
|
793
793
|
Use `ctx.transcribe()` for finite recordings, then explicitly pass
|
|
794
794
|
`Transcript.text` to an agent if analysis is needed. It is separate from chat
|
|
795
|
-
history and chat providers.
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
795
|
+
history and chat providers. OpenAI and Gemini use their documented model
|
|
796
|
+
contracts; any nonblank `openrouter-transcription:<vendor/model>` URI can
|
|
797
|
+
dispatch supported bytes/base64 to OpenRouter, where the selected model/route
|
|
798
|
+
decides endpoint compatibility. See [Multimodal input](../../docs/multimodal-input.md)
|
|
799
|
+
for the 25 MiB inline bound, source types, options, transcript redaction,
|
|
800
|
+
temporary Gemini Files cleanup, and live-verification commands.
|
|
799
801
|
|
|
800
802
|
## License
|
|
801
803
|
|
package/dist/index.cjs
CHANGED
|
@@ -1277,13 +1277,12 @@ function unsafeTransportError(surface, remediation, exposedData) {
|
|
|
1277
1277
|
}
|
|
1278
1278
|
|
|
1279
1279
|
// src/providers/openai-compatible.ts
|
|
1280
|
-
var OPENROUTER_IMAGE_MODEL = "openai/gpt-4o-mini";
|
|
1281
1280
|
function compatibleImageBase64(source) {
|
|
1282
1281
|
return source.type === "base64" ? source.data : Buffer.from(source.data.buffer, source.data.byteOffset, source.data.byteLength).toString(
|
|
1283
1282
|
"base64"
|
|
1284
1283
|
);
|
|
1285
1284
|
}
|
|
1286
|
-
function openRouterImageParts(parts) {
|
|
1285
|
+
function openRouterImageParts(parts, model) {
|
|
1287
1286
|
const content = [];
|
|
1288
1287
|
for (const part of parts) {
|
|
1289
1288
|
if (part.type === "text") {
|
|
@@ -1294,7 +1293,7 @@ function openRouterImageParts(parts) {
|
|
|
1294
1293
|
if (source.type === "provider-file") {
|
|
1295
1294
|
throw new UnsupportedModelInputError({
|
|
1296
1295
|
provider: "openrouter",
|
|
1297
|
-
model
|
|
1296
|
+
model,
|
|
1298
1297
|
modality: "image",
|
|
1299
1298
|
source: "provider-file"
|
|
1300
1299
|
});
|
|
@@ -1425,10 +1424,11 @@ function normalizeMessageContent(content) {
|
|
|
1425
1424
|
var OpenAICompatibleProvider = class {
|
|
1426
1425
|
name;
|
|
1427
1426
|
inputCapabilities(model) {
|
|
1428
|
-
return this.name === "openrouter" && model
|
|
1427
|
+
return this.name === "openrouter" && model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64"] } } : {};
|
|
1429
1428
|
}
|
|
1430
1429
|
validateInput(request) {
|
|
1431
|
-
const
|
|
1430
|
+
const modelOverride = request.providerOptions?.model;
|
|
1431
|
+
const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
|
|
1432
1432
|
const fail = (source, feature) => {
|
|
1433
1433
|
throw new UnsupportedModelInputError({
|
|
1434
1434
|
provider: this.name,
|
|
@@ -1438,13 +1438,15 @@ var OpenAICompatibleProvider = class {
|
|
|
1438
1438
|
...feature ? { feature } : {}
|
|
1439
1439
|
});
|
|
1440
1440
|
};
|
|
1441
|
-
if (
|
|
1441
|
+
if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
|
|
1442
|
+
fail(void 0, "invalid model providerOptions");
|
|
1443
|
+
}
|
|
1444
|
+
if (this.name !== "openrouter" || effectiveModel.trim().length === 0) {
|
|
1442
1445
|
fail(void 0, "image input for this model");
|
|
1443
1446
|
}
|
|
1444
1447
|
if (request.providerOptions && "messages" in request.providerOptions) {
|
|
1445
1448
|
fail(void 0, "raw messages providerOptions");
|
|
1446
1449
|
}
|
|
1447
|
-
if (request.hasTools) fail(void 0, "tools with image input");
|
|
1448
1450
|
for (const message of request.history) {
|
|
1449
1451
|
if (!Array.isArray(message.content)) continue;
|
|
1450
1452
|
if (message.role !== "user") fail(void 0, "rich non-user history");
|
|
@@ -1632,7 +1634,7 @@ var OpenAICompatibleProvider = class {
|
|
|
1632
1634
|
formatMessage(msg, model) {
|
|
1633
1635
|
const out = {
|
|
1634
1636
|
role: this.profile.roleFor ? this.profile.roleFor(msg.role, model) : msg.role,
|
|
1635
|
-
content: Array.isArray(msg.content) && this.name === "openrouter"
|
|
1637
|
+
content: Array.isArray(msg.content) && this.name === "openrouter" ? openRouterImageParts(msg.content, model) : msg.content
|
|
1636
1638
|
};
|
|
1637
1639
|
if (msg.name && (this.profile.capabilities?.emitsMessageName ?? true)) out.name = msg.name;
|
|
1638
1640
|
if (msg.tool_calls) out.tool_calls = msg.tool_calls;
|
|
@@ -2379,13 +2381,6 @@ var OpenAIProvider = class extends OpenAICompatibleProvider {
|
|
|
2379
2381
|
};
|
|
2380
2382
|
|
|
2381
2383
|
// src/providers/openai-responses.ts
|
|
2382
|
-
var OPENAI_RESPONSES_IMAGE_MODELS = /* @__PURE__ */ new Set([
|
|
2383
|
-
"gpt-4o",
|
|
2384
|
-
"gpt-4o-2024-08-06",
|
|
2385
|
-
"gpt-4o-2024-11-20",
|
|
2386
|
-
"gpt-4o-mini",
|
|
2387
|
-
"gpt-4o-mini-2024-07-18"
|
|
2388
|
-
]);
|
|
2389
2384
|
function base64FromSource(source) {
|
|
2390
2385
|
return source.type === "base64" ? source.data : Buffer.from(source.data.buffer, source.data.byteOffset, source.data.byteLength).toString(
|
|
2391
2386
|
"base64"
|
|
@@ -2424,10 +2419,11 @@ function responseImageParts(parts) {
|
|
|
2424
2419
|
var OpenAIResponsesProvider = class {
|
|
2425
2420
|
name = "openai-responses";
|
|
2426
2421
|
inputCapabilities(model) {
|
|
2427
|
-
return
|
|
2422
|
+
return model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
|
|
2428
2423
|
}
|
|
2429
2424
|
validateInput(request) {
|
|
2430
|
-
const
|
|
2425
|
+
const modelOverride = request.providerOptions?.model;
|
|
2426
|
+
const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
|
|
2431
2427
|
const fail = (source, feature) => {
|
|
2432
2428
|
throw new UnsupportedModelInputError({
|
|
2433
2429
|
provider: this.name,
|
|
@@ -2437,7 +2433,10 @@ var OpenAIResponsesProvider = class {
|
|
|
2437
2433
|
...feature ? { feature } : {}
|
|
2438
2434
|
});
|
|
2439
2435
|
};
|
|
2440
|
-
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) {
|
|
2441
2440
|
fail(void 0, "image input for this model");
|
|
2442
2441
|
}
|
|
2443
2442
|
if (request.providerOptions && "input" in request.providerOptions) {
|
|
@@ -2565,7 +2564,7 @@ var OpenAIResponsesProvider = class {
|
|
|
2565
2564
|
const resolved = resolveThinkingOptions(options);
|
|
2566
2565
|
const { includeThoughts } = resolved;
|
|
2567
2566
|
const wireEffort = resolveOpenAIReasoningEffort(effectiveModel, resolved);
|
|
2568
|
-
const stripTemp = oSeries || reasoningCapable && wireEffort !== void 0;
|
|
2567
|
+
const stripTemp = oSeries || supportsMaxReasoningEffort(effectiveModel) || reasoningCapable && wireEffort !== void 0;
|
|
2569
2568
|
const systemMessages = messages.filter((m) => m.role === "system");
|
|
2570
2569
|
const nonSystemMessages = messages.filter((m) => m.role !== "system");
|
|
2571
2570
|
const body = {
|
|
@@ -2913,7 +2912,6 @@ function anthropicImageBlocks(parts) {
|
|
|
2913
2912
|
}
|
|
2914
2913
|
var ANTHROPIC_API_VERSION = "2023-06-01";
|
|
2915
2914
|
var ANTHROPIC_FILES_BETA = "files-api-2025-04-14";
|
|
2916
|
-
var ANTHROPIC_IMAGE_MODELS = /* @__PURE__ */ new Set(["claude-sonnet-4-5", "claude-opus-4-8"]);
|
|
2917
2915
|
function hasAnthropicProviderFileImage(messages) {
|
|
2918
2916
|
return messages.some(
|
|
2919
2917
|
(message) => Array.isArray(message.content) && message.content.some(
|
|
@@ -3032,6 +3030,28 @@ var ANTHROPIC_RATES = {
|
|
|
3032
3030
|
function isValidTokenCount(value) {
|
|
3033
3031
|
return value !== void 0 && Number.isSafeInteger(value) && value >= 0;
|
|
3034
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
|
+
}
|
|
3035
3055
|
function estimateAnthropicCost(model, usage, now = /* @__PURE__ */ new Date()) {
|
|
3036
3056
|
if (!model || !isValidTokenCount(usage.inputTokens) || !isValidTokenCount(usage.outputTokens)) {
|
|
3037
3057
|
return void 0;
|
|
@@ -3281,10 +3301,11 @@ function mergeAnthropicUsage(initial, update) {
|
|
|
3281
3301
|
var AnthropicProvider = class {
|
|
3282
3302
|
name = "anthropic";
|
|
3283
3303
|
inputCapabilities(model) {
|
|
3284
|
-
return
|
|
3304
|
+
return model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
|
|
3285
3305
|
}
|
|
3286
3306
|
validateInput(request) {
|
|
3287
|
-
const
|
|
3307
|
+
const modelOverride = request.providerOptions?.model;
|
|
3308
|
+
const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
|
|
3288
3309
|
const fail = (source, feature) => {
|
|
3289
3310
|
throw new UnsupportedModelInputError({
|
|
3290
3311
|
provider: this.name,
|
|
@@ -3294,7 +3315,10 @@ var AnthropicProvider = class {
|
|
|
3294
3315
|
...feature ? { feature } : {}
|
|
3295
3316
|
});
|
|
3296
3317
|
};
|
|
3297
|
-
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) {
|
|
3298
3322
|
fail(void 0, "image input for this model");
|
|
3299
3323
|
}
|
|
3300
3324
|
if (request.providerOptions && "messages" in request.providerOptions) {
|
|
@@ -3419,7 +3443,7 @@ var AnthropicProvider = class {
|
|
|
3419
3443
|
if (!res.body) {
|
|
3420
3444
|
throw new Error("Anthropic stream response has no body");
|
|
3421
3445
|
}
|
|
3422
|
-
yield* this.parseSSEStream(res.body, pricingContext);
|
|
3446
|
+
yield* this.parseSSEStream(res.body, pricingContext, res.headers);
|
|
3423
3447
|
}
|
|
3424
3448
|
// ---------------------------------------------------------------------------
|
|
3425
3449
|
// Internal: request building
|
|
@@ -3662,7 +3686,7 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
3662
3686
|
// ---------------------------------------------------------------------------
|
|
3663
3687
|
// Internal: SSE stream parsing
|
|
3664
3688
|
// ---------------------------------------------------------------------------
|
|
3665
|
-
async *parseSSEStream(body, pricingContext) {
|
|
3689
|
+
async *parseSSEStream(body, pricingContext, responseHeaders) {
|
|
3666
3690
|
const reader = body.getReader();
|
|
3667
3691
|
const decoder = new TextDecoder();
|
|
3668
3692
|
let buffer = "";
|
|
@@ -3708,6 +3732,15 @@ ${jsonInstruction}` : jsonInstruction;
|
|
|
3708
3732
|
continue;
|
|
3709
3733
|
}
|
|
3710
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
|
+
}
|
|
3711
3744
|
case "content_block_start": {
|
|
3712
3745
|
const block = event.content_block;
|
|
3713
3746
|
if (block?.type === "tool_use") {
|
|
@@ -3959,7 +3992,6 @@ var GEMINI_PRICING = {
|
|
|
3959
3992
|
"gemini-3.5-flash-lite": { input: 3e-7, cached: 3e-8, output: 25e-7 },
|
|
3960
3993
|
"gemini-3.6-flash": { input: 15e-7, cached: 15e-8, output: 75e-7 }
|
|
3961
3994
|
};
|
|
3962
|
-
var GEMINI_INTERACTIONS_IMAGE_MODELS = /* @__PURE__ */ new Set(["gemini-3.7-flash"]);
|
|
3963
3995
|
function isValidTokenCount2(value) {
|
|
3964
3996
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
3965
3997
|
}
|
|
@@ -3969,6 +4001,55 @@ function isStandardGeminiRequestTier(value) {
|
|
|
3969
4001
|
function isDefinitiveStandardGeminiResponseTier(value) {
|
|
3970
4002
|
return value === "SERVICE_TIER_UNSPECIFIED" || value === "SERVICE_TIER_STANDARD" || value === "standard";
|
|
3971
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
|
+
}
|
|
3972
4053
|
function isEligibleGeminiPricing(context, hasDefinitiveStandardResponseTier, hasInvalidResponseTier) {
|
|
3973
4054
|
return context.eligibleRequest && isStandardGeminiRequestTier(context.serviceTier) && hasDefinitiveStandardResponseTier && !hasInvalidResponseTier;
|
|
3974
4055
|
}
|
|
@@ -4050,7 +4131,9 @@ var GEMINI_3X_MIN_THINKING_LEVEL = /* @__PURE__ */ new Map([
|
|
|
4050
4131
|
["gemini-3.6-flash", "minimal"],
|
|
4051
4132
|
// L4 live evidence: Interactions gemini-3.7-flash accepts low/medium/high,
|
|
4052
4133
|
// but rejects minimal. Keep this exact entry isolated from legacy aliases.
|
|
4053
|
-
["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"]
|
|
4054
4137
|
]);
|
|
4055
4138
|
var GEMINI_MODELS_WITHOUT_PORTABLE_TEMPERATURE = /* @__PURE__ */ new Set([
|
|
4056
4139
|
"gemini-3.5-flash-lite",
|
|
@@ -4078,10 +4161,11 @@ function warnGemini3xEffortNone(model) {
|
|
|
4078
4161
|
var GeminiProvider = class {
|
|
4079
4162
|
name = "google";
|
|
4080
4163
|
inputCapabilities(model) {
|
|
4081
|
-
return
|
|
4164
|
+
return model.trim().length > 0 ? { image: { sources: ["bytes", "base64", "provider-file"] } } : {};
|
|
4082
4165
|
}
|
|
4083
4166
|
validateInput(request) {
|
|
4084
|
-
const
|
|
4167
|
+
const modelOverride = request.providerOptions?.model;
|
|
4168
|
+
const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
|
|
4085
4169
|
const fail = (source, feature) => {
|
|
4086
4170
|
throw new UnsupportedModelInputError({
|
|
4087
4171
|
provider: this.name,
|
|
@@ -4091,7 +4175,10 @@ var GeminiProvider = class {
|
|
|
4091
4175
|
...feature ? { feature } : {}
|
|
4092
4176
|
});
|
|
4093
4177
|
};
|
|
4094
|
-
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) {
|
|
4095
4182
|
fail(void 0, "image input for this model");
|
|
4096
4183
|
}
|
|
4097
4184
|
if (request.providerOptions) {
|
|
@@ -4283,7 +4370,7 @@ var GeminiProvider = class {
|
|
|
4283
4370
|
});
|
|
4284
4371
|
}
|
|
4285
4372
|
if (!res.body) throw new Error("Gemini Interactions stream has no body");
|
|
4286
|
-
yield* this.parseInteractionSSEStream(res.body);
|
|
4373
|
+
yield* this.parseInteractionSSEStream(res.body, res.headers);
|
|
4287
4374
|
}
|
|
4288
4375
|
buildInteractionRequestBody(messages, options, stream) {
|
|
4289
4376
|
const model = this.requestModel(options);
|
|
@@ -4353,6 +4440,7 @@ var GeminiProvider = class {
|
|
|
4353
4440
|
return body;
|
|
4354
4441
|
}
|
|
4355
4442
|
assertSafeInteractionOptions(options) {
|
|
4443
|
+
const modelOverride = options.providerOptions?.model;
|
|
4356
4444
|
const model = this.requestModel(options);
|
|
4357
4445
|
const fail = (feature) => {
|
|
4358
4446
|
throw new UnsupportedModelInputError({
|
|
@@ -4362,7 +4450,10 @@ var GeminiProvider = class {
|
|
|
4362
4450
|
feature
|
|
4363
4451
|
});
|
|
4364
4452
|
};
|
|
4365
|
-
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");
|
|
4366
4457
|
const forbidden = [
|
|
4367
4458
|
"input",
|
|
4368
4459
|
"contents",
|
|
@@ -4438,7 +4529,7 @@ var GeminiProvider = class {
|
|
|
4438
4529
|
providerMetadata: json.steps?.length ? { geminiInteractionSteps: json.steps.filter(isGeminiInteractionStep) } : void 0
|
|
4439
4530
|
};
|
|
4440
4531
|
}
|
|
4441
|
-
async *parseInteractionSSEStream(body) {
|
|
4532
|
+
async *parseInteractionSSEStream(body, responseHeaders) {
|
|
4442
4533
|
const reader = body.getReader();
|
|
4443
4534
|
const decoder = new TextDecoder();
|
|
4444
4535
|
let buffer = "";
|
|
@@ -4464,7 +4555,22 @@ var GeminiProvider = class {
|
|
|
4464
4555
|
continue;
|
|
4465
4556
|
}
|
|
4466
4557
|
if (event.event_type === "error") {
|
|
4467
|
-
|
|
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
|
+
});
|
|
4468
4574
|
}
|
|
4469
4575
|
if (event.event_type === "step.start" && event.step) {
|
|
4470
4576
|
const index = event.index;
|
|
@@ -5783,7 +5889,6 @@ function normalizeTranscriptionAccounting(usageValue, pricingValue) {
|
|
|
5783
5889
|
// src/providers/transcription-utils.ts
|
|
5784
5890
|
var OPENAI_TRANSCRIPTION_MODEL = "gpt-transcribe";
|
|
5785
5891
|
var GEMINI_TRANSCRIPTION_MODEL = "gemini-3.5-transcribe";
|
|
5786
|
-
var OPENROUTER_TRANSCRIPTION_MODEL = "openai/whisper-1";
|
|
5787
5892
|
function requireExactTranscriptionModel(provider, model, expected) {
|
|
5788
5893
|
if (model !== expected) {
|
|
5789
5894
|
throw new UnsupportedTranscriptionInputError({
|
|
@@ -6434,10 +6539,16 @@ var OpenRouterTranscriptionProvider = class {
|
|
|
6434
6539
|
this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
|
|
6435
6540
|
}
|
|
6436
6541
|
capabilities(model) {
|
|
6437
|
-
return model
|
|
6542
|
+
return model.trim().length > 0 ? { sources: ["bytes", "base64"] } : void 0;
|
|
6438
6543
|
}
|
|
6439
6544
|
async transcribe(request) {
|
|
6440
|
-
|
|
6545
|
+
if (request.model.trim().length === 0) {
|
|
6546
|
+
throw new UnsupportedTranscriptionInputError({
|
|
6547
|
+
provider: this.name,
|
|
6548
|
+
model: request.model,
|
|
6549
|
+
feature: "this transcription model"
|
|
6550
|
+
});
|
|
6551
|
+
}
|
|
6441
6552
|
requireNoProviderFile(request.audio, this.name, request.model);
|
|
6442
6553
|
if (request.audio.type === "provider-file")
|
|
6443
6554
|
throw new UnsupportedTranscriptionInputError({
|
|
@@ -6577,7 +6688,7 @@ var TranscriptionProviderRegistry = class {
|
|
|
6577
6688
|
}
|
|
6578
6689
|
resolve(uri, config = {}) {
|
|
6579
6690
|
const colon = typeof uri === "string" ? uri.indexOf(":") : -1;
|
|
6580
|
-
if (colon <= 0 || colon === uri.length - 1
|
|
6691
|
+
if (colon <= 0 || colon === uri.length - 1) {
|
|
6581
6692
|
throw new UnsupportedTranscriptionInputError({
|
|
6582
6693
|
provider: "unknown",
|
|
6583
6694
|
model: "",
|