@jambonz/llm 0.6.5 → 0.6.7
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.cjs +186 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +186 -3
- package/dist/index.js.map +1 -1
- package/dist/test-kit/index.cjs +185 -3
- package/dist/test-kit/index.cjs.map +1 -1
- package/dist/test-kit/index.js +185 -3
- package/dist/test-kit/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -34,7 +34,7 @@ interface RawCredential {
|
|
|
34
34
|
* Supported vendors: openai, deepseek, baseten, moonshot, zai, xai, bedrock-mantle,
|
|
35
35
|
* anthropic, google, vertex (alias for vertex-gemini + vertex-openai — both accept
|
|
36
36
|
* the same auth shape), vertex-gemini, vertex-openai, bedrock, azure-openai, groq,
|
|
37
|
-
* huggingface.
|
|
37
|
+
* huggingface, openrouter.
|
|
38
38
|
*
|
|
39
39
|
* Throws with a clear message if the raw credential is missing required fields.
|
|
40
40
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ interface RawCredential {
|
|
|
34
34
|
* Supported vendors: openai, deepseek, baseten, moonshot, zai, xai, bedrock-mantle,
|
|
35
35
|
* anthropic, google, vertex (alias for vertex-gemini + vertex-openai — both accept
|
|
36
36
|
* the same auth shape), vertex-gemini, vertex-openai, bedrock, azure-openai, groq,
|
|
37
|
-
* huggingface.
|
|
37
|
+
* huggingface, openrouter.
|
|
38
38
|
*
|
|
39
39
|
* Throws with a clear message if the raw credential is missing required fields.
|
|
40
40
|
*/
|
package/dist/index.js
CHANGED
|
@@ -142,12 +142,20 @@ async function* streamFromOpenAI(client, req, options) {
|
|
|
142
142
|
throw new Error(`OpenAI-compatible stream returned an error: ${message}`);
|
|
143
143
|
}
|
|
144
144
|
if (chunk.usage) {
|
|
145
|
-
const
|
|
145
|
+
const details = chunk.usage.prompt_tokens_details;
|
|
146
|
+
const cachedTokens = details?.cached_tokens;
|
|
147
|
+
const cacheWriteTokens = details?.cache_write_tokens;
|
|
146
148
|
usage = {
|
|
147
|
-
...chunk.usage.prompt_tokens !== void 0 ? {
|
|
149
|
+
...chunk.usage.prompt_tokens !== void 0 ? {
|
|
150
|
+
inputTokens: Math.max(
|
|
151
|
+
0,
|
|
152
|
+
chunk.usage.prompt_tokens - (cachedTokens ?? 0) - (cacheWriteTokens ?? 0)
|
|
153
|
+
)
|
|
154
|
+
} : {},
|
|
148
155
|
...chunk.usage.completion_tokens !== void 0 ? { outputTokens: chunk.usage.completion_tokens } : {},
|
|
149
156
|
...chunk.usage.total_tokens !== void 0 ? { totalTokens: chunk.usage.total_tokens } : {},
|
|
150
|
-
...cachedTokens !== void 0 ? { cacheReadTokens: cachedTokens } : {}
|
|
157
|
+
...cachedTokens !== void 0 ? { cacheReadTokens: cachedTokens } : {},
|
|
158
|
+
...cacheWriteTokens !== void 0 ? { cacheWriteTokens } : {}
|
|
151
159
|
};
|
|
152
160
|
}
|
|
153
161
|
const choice = chunk.choices?.[0];
|
|
@@ -3544,6 +3552,179 @@ var huggingfaceFactory = {
|
|
|
3544
3552
|
create: () => new HuggingfaceAdapter()
|
|
3545
3553
|
};
|
|
3546
3554
|
|
|
3555
|
+
// src/adapters/openrouter/manifest.ts
|
|
3556
|
+
var OPENROUTER_KNOWN_MODELS = [
|
|
3557
|
+
{
|
|
3558
|
+
id: "anthropic/claude-haiku-5.5",
|
|
3559
|
+
displayName: "Claude Haiku 5.5 (OpenRouter)",
|
|
3560
|
+
capabilities: {
|
|
3561
|
+
streaming: true,
|
|
3562
|
+
tools: true,
|
|
3563
|
+
vision: true,
|
|
3564
|
+
systemPrompt: true,
|
|
3565
|
+
maxContextTokens: 1e6
|
|
3566
|
+
}
|
|
3567
|
+
},
|
|
3568
|
+
{
|
|
3569
|
+
id: "anthropic/claude-sonnet-5.5",
|
|
3570
|
+
displayName: "Claude Sonnet 5.5 (OpenRouter)",
|
|
3571
|
+
capabilities: {
|
|
3572
|
+
streaming: true,
|
|
3573
|
+
tools: true,
|
|
3574
|
+
vision: true,
|
|
3575
|
+
systemPrompt: true,
|
|
3576
|
+
maxContextTokens: 1e6
|
|
3577
|
+
}
|
|
3578
|
+
},
|
|
3579
|
+
{
|
|
3580
|
+
id: "openai/gpt-5.4-mini",
|
|
3581
|
+
displayName: "GPT-5.4 Mini (OpenRouter)",
|
|
3582
|
+
capabilities: {
|
|
3583
|
+
streaming: true,
|
|
3584
|
+
tools: true,
|
|
3585
|
+
vision: true,
|
|
3586
|
+
systemPrompt: true,
|
|
3587
|
+
maxContextTokens: 4e5
|
|
3588
|
+
}
|
|
3589
|
+
},
|
|
3590
|
+
{
|
|
3591
|
+
id: "openai/gpt-4.1-mini",
|
|
3592
|
+
displayName: "GPT-4.1 Mini (OpenRouter)",
|
|
3593
|
+
capabilities: {
|
|
3594
|
+
streaming: true,
|
|
3595
|
+
tools: true,
|
|
3596
|
+
vision: true,
|
|
3597
|
+
systemPrompt: true,
|
|
3598
|
+
maxContextTokens: 1047576
|
|
3599
|
+
}
|
|
3600
|
+
},
|
|
3601
|
+
{
|
|
3602
|
+
id: "google/gemini-3.5-flash",
|
|
3603
|
+
displayName: "Gemini 3.5 Flash (OpenRouter)",
|
|
3604
|
+
capabilities: {
|
|
3605
|
+
streaming: true,
|
|
3606
|
+
tools: true,
|
|
3607
|
+
vision: true,
|
|
3608
|
+
systemPrompt: true,
|
|
3609
|
+
maxContextTokens: 1048576
|
|
3610
|
+
}
|
|
3611
|
+
},
|
|
3612
|
+
{
|
|
3613
|
+
id: "meta-llama/llama-3.3-70b-instruct",
|
|
3614
|
+
displayName: "Llama 3.3 70B Instruct (OpenRouter)",
|
|
3615
|
+
capabilities: {
|
|
3616
|
+
streaming: true,
|
|
3617
|
+
tools: true,
|
|
3618
|
+
vision: false,
|
|
3619
|
+
systemPrompt: true,
|
|
3620
|
+
maxContextTokens: 131072
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3623
|
+
];
|
|
3624
|
+
var openRouterManifest = {
|
|
3625
|
+
vendor: "openrouter",
|
|
3626
|
+
displayName: "OpenRouter",
|
|
3627
|
+
authKinds: [
|
|
3628
|
+
{
|
|
3629
|
+
kind: "apiKey",
|
|
3630
|
+
displayName: "API Key",
|
|
3631
|
+
fields: [
|
|
3632
|
+
{
|
|
3633
|
+
name: "apiKey",
|
|
3634
|
+
label: "API Key",
|
|
3635
|
+
type: "password",
|
|
3636
|
+
required: true,
|
|
3637
|
+
help: "Get an API key from https://openrouter.ai/settings/keys"
|
|
3638
|
+
},
|
|
3639
|
+
{
|
|
3640
|
+
name: "baseURL",
|
|
3641
|
+
label: "Base URL",
|
|
3642
|
+
type: "url",
|
|
3643
|
+
required: false,
|
|
3644
|
+
default: "https://openrouter.ai/api/v1",
|
|
3645
|
+
help: "Override only for proxies. Default points at OpenRouter's production endpoint."
|
|
3646
|
+
}
|
|
3647
|
+
]
|
|
3648
|
+
}
|
|
3649
|
+
],
|
|
3650
|
+
knownModels: OPENROUTER_KNOWN_MODELS,
|
|
3651
|
+
// /models is public; the adapter enriches it with OpenRouter's own capability metadata.
|
|
3652
|
+
supportsModelListing: true,
|
|
3653
|
+
docsUrl: "https://openrouter.ai/docs/api_reference/overview"
|
|
3654
|
+
};
|
|
3655
|
+
|
|
3656
|
+
// src/adapters/openrouter/adapter.ts
|
|
3657
|
+
var OPENROUTER_METADATA_EXTRACTOR = makeMetadataExtractor([
|
|
3658
|
+
{ header: "x-generation-id", key: "request_id" }
|
|
3659
|
+
]);
|
|
3660
|
+
var OPENROUTER_ATTRIBUTION_HEADERS = {
|
|
3661
|
+
"HTTP-Referer": "https://jambonz.org",
|
|
3662
|
+
"X-OpenRouter-Title": "jambonz"
|
|
3663
|
+
};
|
|
3664
|
+
var OpenRouterAdapter = class extends OpenAIAdapter {
|
|
3665
|
+
vendor = openRouterManifest.vendor;
|
|
3666
|
+
init(auth, client) {
|
|
3667
|
+
super.init(
|
|
3668
|
+
{
|
|
3669
|
+
...auth,
|
|
3670
|
+
baseURL: auth.baseURL ?? "https://openrouter.ai/api/v1"
|
|
3671
|
+
},
|
|
3672
|
+
client
|
|
3673
|
+
);
|
|
3674
|
+
this.client = this.ensureClient().withOptions({
|
|
3675
|
+
defaultHeaders: OPENROUTER_ATTRIBUTION_HEADERS
|
|
3676
|
+
});
|
|
3677
|
+
}
|
|
3678
|
+
stream(req) {
|
|
3679
|
+
return streamFromOpenAI(this.ensureClient(), req, {
|
|
3680
|
+
knownModels: this.knownModels(),
|
|
3681
|
+
vendorMetadataExtractor: OPENROUTER_METADATA_EXTRACTOR,
|
|
3682
|
+
// Verified accepted by OpenRouter (forwarded to OpenAI-family upstreams).
|
|
3683
|
+
includeCacheKey: true,
|
|
3684
|
+
openRouterAutoCache: this.isOpenRouter
|
|
3685
|
+
});
|
|
3686
|
+
}
|
|
3687
|
+
async listAvailableModels() {
|
|
3688
|
+
const result = await this.ensureClient().models.list();
|
|
3689
|
+
const out = [];
|
|
3690
|
+
for (const m of result.data) {
|
|
3691
|
+
if (m.id.endsWith(":batch")) continue;
|
|
3692
|
+
const outputs = m.architecture?.output_modalities;
|
|
3693
|
+
if (outputs && !outputs.includes("text")) continue;
|
|
3694
|
+
const known = this.knownModels().find((k) => k.id === m.id);
|
|
3695
|
+
if (known) {
|
|
3696
|
+
out.push(known);
|
|
3697
|
+
continue;
|
|
3698
|
+
}
|
|
3699
|
+
out.push({
|
|
3700
|
+
id: m.id,
|
|
3701
|
+
...m.name ? { displayName: m.name } : {},
|
|
3702
|
+
capabilities: {
|
|
3703
|
+
streaming: true,
|
|
3704
|
+
tools: m.supported_parameters?.includes("tools") ?? true,
|
|
3705
|
+
vision: m.architecture?.input_modalities?.includes("image") ?? false,
|
|
3706
|
+
systemPrompt: true,
|
|
3707
|
+
...m.context_length ? { maxContextTokens: m.context_length } : {}
|
|
3708
|
+
}
|
|
3709
|
+
});
|
|
3710
|
+
}
|
|
3711
|
+
return out;
|
|
3712
|
+
}
|
|
3713
|
+
async testCredential() {
|
|
3714
|
+
await this.ensureClient().get("/key");
|
|
3715
|
+
}
|
|
3716
|
+
knownModels() {
|
|
3717
|
+
return openRouterManifest.knownModels;
|
|
3718
|
+
}
|
|
3719
|
+
};
|
|
3720
|
+
|
|
3721
|
+
// src/adapters/openrouter/factory.ts
|
|
3722
|
+
var openRouterFactory = {
|
|
3723
|
+
vendor: openRouterManifest.vendor,
|
|
3724
|
+
manifest: openRouterManifest,
|
|
3725
|
+
create: () => new OpenRouterAdapter()
|
|
3726
|
+
};
|
|
3727
|
+
|
|
3547
3728
|
// src/adapters/index.ts
|
|
3548
3729
|
registerAdapter(openAIFactory);
|
|
3549
3730
|
registerAdapter(deepseekFactory);
|
|
@@ -3560,6 +3741,7 @@ registerAdapter(bedrockFactory);
|
|
|
3560
3741
|
registerAdapter(azureOpenAIFactory);
|
|
3561
3742
|
registerAdapter(groqFactory);
|
|
3562
3743
|
registerAdapter(huggingfaceFactory);
|
|
3744
|
+
registerAdapter(openRouterFactory);
|
|
3563
3745
|
|
|
3564
3746
|
// src/normalize-auth.ts
|
|
3565
3747
|
function normalizeAuth(vendor, raw) {
|
|
@@ -3568,6 +3750,7 @@ function normalizeAuth(vendor, raw) {
|
|
|
3568
3750
|
case "anthropic":
|
|
3569
3751
|
case "groq":
|
|
3570
3752
|
case "huggingface":
|
|
3753
|
+
case "openrouter":
|
|
3571
3754
|
case "moonshot":
|
|
3572
3755
|
case "zai":
|
|
3573
3756
|
case "xai":
|