@jambonz/llm 0.6.6 → 0.6.8
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 +240 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -7
- package/dist/index.d.ts +16 -7
- package/dist/index.js +239 -4
- package/dist/index.js.map +1 -1
- package/dist/test-kit/index.cjs +225 -1
- package/dist/test-kit/index.cjs.map +1 -1
- package/dist/test-kit/index.d.cts +1 -1
- package/dist/test-kit/index.d.ts +1 -1
- package/dist/test-kit/index.js +225 -1
- package/dist/test-kit/index.js.map +1 -1
- package/dist/{types-dbgrfviJ.d.cts → types-4l2etrW-.d.cts} +7 -0
- package/dist/{types-dbgrfviJ.d.ts → types-4l2etrW-.d.ts} +7 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as AdapterFactory, e as AuthKind, A as AuthSpec, L as LlmAdapter, d as ApiKeyAuth, h as ClientOptions, P as PromptRequest, m as LlmEvent, M as Message, p as ToolCallEvent, o as ModelInfo, c as AdapterManifest } from '../types-
|
|
1
|
+
import { b as AdapterFactory, e as AuthKind, A as AuthSpec, L as LlmAdapter, d as ApiKeyAuth, h as ClientOptions, P as PromptRequest, m as LlmEvent, M as Message, p as ToolCallEvent, o as ModelInfo, c as AdapterManifest } from '../types-4l2etrW-.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Named scenarios the harness must be able to stage. Each scenario configures
|
package/dist/test-kit/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as AdapterFactory, e as AuthKind, A as AuthSpec, L as LlmAdapter, d as ApiKeyAuth, h as ClientOptions, P as PromptRequest, m as LlmEvent, M as Message, p as ToolCallEvent, o as ModelInfo, c as AdapterManifest } from '../types-
|
|
1
|
+
import { b as AdapterFactory, e as AuthKind, A as AuthSpec, L as LlmAdapter, d as ApiKeyAuth, h as ClientOptions, P as PromptRequest, m as LlmEvent, M as Message, p as ToolCallEvent, o as ModelInfo, c as AdapterManifest } from '../types-4l2etrW-.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Named scenarios the harness must be able to stage. Each scenario configures
|
package/dist/test-kit/index.js
CHANGED
|
@@ -3,8 +3,9 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
|
3
3
|
|
|
4
4
|
// src/registry.ts
|
|
5
5
|
var registry = /* @__PURE__ */ new Map();
|
|
6
|
+
var credentialVendors = /* @__PURE__ */ new Map();
|
|
6
7
|
function registerAdapter(factory) {
|
|
7
|
-
if (registry.has(factory.vendor)) {
|
|
8
|
+
if (registry.has(factory.vendor) || credentialVendors.has(factory.vendor)) {
|
|
8
9
|
throw new Error(
|
|
9
10
|
`Adapter already registered for vendor '${factory.vendor}'. Use replaceAdapter() if you intended to override.`
|
|
10
11
|
);
|
|
@@ -16,9 +17,23 @@ function registerAdapter(factory) {
|
|
|
16
17
|
}
|
|
17
18
|
registry.set(factory.vendor, factory);
|
|
18
19
|
}
|
|
20
|
+
function registerCredentialVendor(manifest) {
|
|
21
|
+
if (!manifest.credentialOnly) {
|
|
22
|
+
throw new Error(`Vendor '${manifest.vendor}' manifest is not marked credentialOnly.`);
|
|
23
|
+
}
|
|
24
|
+
if (registry.has(manifest.vendor) || credentialVendors.has(manifest.vendor)) {
|
|
25
|
+
throw new Error(`Vendor '${manifest.vendor}' is already registered.`);
|
|
26
|
+
}
|
|
27
|
+
credentialVendors.set(manifest.vendor, manifest);
|
|
28
|
+
}
|
|
19
29
|
function getAdapterFactory(vendor) {
|
|
20
30
|
const factory = registry.get(vendor);
|
|
21
31
|
if (!factory) {
|
|
32
|
+
if (credentialVendors.has(vendor)) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Vendor '${vendor}' is credential-only: @jambonz/llm has no adapter for it.`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
22
37
|
const known = Array.from(registry.keys()).sort().join(", ") || "(none)";
|
|
23
38
|
throw new Error(
|
|
24
39
|
`Unknown vendor '${vendor}'. Registered vendors: ${known}`
|
|
@@ -28,6 +43,7 @@ function getAdapterFactory(vendor) {
|
|
|
28
43
|
}
|
|
29
44
|
function _resetRegistryForTests() {
|
|
30
45
|
registry.clear();
|
|
46
|
+
credentialVendors.clear();
|
|
31
47
|
}
|
|
32
48
|
|
|
33
49
|
// src/adapters/openai/adapter.ts
|
|
@@ -3545,6 +3561,212 @@ var huggingfaceFactory = {
|
|
|
3545
3561
|
create: () => new HuggingfaceAdapter()
|
|
3546
3562
|
};
|
|
3547
3563
|
|
|
3564
|
+
// src/adapters/openrouter/manifest.ts
|
|
3565
|
+
var OPENROUTER_KNOWN_MODELS = [
|
|
3566
|
+
{
|
|
3567
|
+
id: "anthropic/claude-haiku-5.5",
|
|
3568
|
+
displayName: "Claude Haiku 5.5 (OpenRouter)",
|
|
3569
|
+
capabilities: {
|
|
3570
|
+
streaming: true,
|
|
3571
|
+
tools: true,
|
|
3572
|
+
vision: true,
|
|
3573
|
+
systemPrompt: true,
|
|
3574
|
+
maxContextTokens: 1e6
|
|
3575
|
+
}
|
|
3576
|
+
},
|
|
3577
|
+
{
|
|
3578
|
+
id: "anthropic/claude-sonnet-5.5",
|
|
3579
|
+
displayName: "Claude Sonnet 5.5 (OpenRouter)",
|
|
3580
|
+
capabilities: {
|
|
3581
|
+
streaming: true,
|
|
3582
|
+
tools: true,
|
|
3583
|
+
vision: true,
|
|
3584
|
+
systemPrompt: true,
|
|
3585
|
+
maxContextTokens: 1e6
|
|
3586
|
+
}
|
|
3587
|
+
},
|
|
3588
|
+
{
|
|
3589
|
+
id: "openai/gpt-5.4-mini",
|
|
3590
|
+
displayName: "GPT-5.4 Mini (OpenRouter)",
|
|
3591
|
+
capabilities: {
|
|
3592
|
+
streaming: true,
|
|
3593
|
+
tools: true,
|
|
3594
|
+
vision: true,
|
|
3595
|
+
systemPrompt: true,
|
|
3596
|
+
maxContextTokens: 4e5
|
|
3597
|
+
}
|
|
3598
|
+
},
|
|
3599
|
+
{
|
|
3600
|
+
id: "openai/gpt-4.1-mini",
|
|
3601
|
+
displayName: "GPT-4.1 Mini (OpenRouter)",
|
|
3602
|
+
capabilities: {
|
|
3603
|
+
streaming: true,
|
|
3604
|
+
tools: true,
|
|
3605
|
+
vision: true,
|
|
3606
|
+
systemPrompt: true,
|
|
3607
|
+
maxContextTokens: 1047576
|
|
3608
|
+
}
|
|
3609
|
+
},
|
|
3610
|
+
{
|
|
3611
|
+
id: "google/gemini-3.5-flash",
|
|
3612
|
+
displayName: "Gemini 3.5 Flash (OpenRouter)",
|
|
3613
|
+
capabilities: {
|
|
3614
|
+
streaming: true,
|
|
3615
|
+
tools: true,
|
|
3616
|
+
vision: true,
|
|
3617
|
+
systemPrompt: true,
|
|
3618
|
+
maxContextTokens: 1048576
|
|
3619
|
+
}
|
|
3620
|
+
},
|
|
3621
|
+
{
|
|
3622
|
+
id: "meta-llama/llama-3.3-70b-instruct",
|
|
3623
|
+
displayName: "Llama 3.3 70B Instruct (OpenRouter)",
|
|
3624
|
+
capabilities: {
|
|
3625
|
+
streaming: true,
|
|
3626
|
+
tools: true,
|
|
3627
|
+
vision: false,
|
|
3628
|
+
systemPrompt: true,
|
|
3629
|
+
maxContextTokens: 131072
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
];
|
|
3633
|
+
var openRouterManifest = {
|
|
3634
|
+
vendor: "openrouter",
|
|
3635
|
+
displayName: "OpenRouter",
|
|
3636
|
+
authKinds: [
|
|
3637
|
+
{
|
|
3638
|
+
kind: "apiKey",
|
|
3639
|
+
displayName: "API Key",
|
|
3640
|
+
fields: [
|
|
3641
|
+
{
|
|
3642
|
+
name: "apiKey",
|
|
3643
|
+
label: "API Key",
|
|
3644
|
+
type: "password",
|
|
3645
|
+
required: true,
|
|
3646
|
+
help: "Get an API key from https://openrouter.ai/settings/keys"
|
|
3647
|
+
},
|
|
3648
|
+
{
|
|
3649
|
+
name: "baseURL",
|
|
3650
|
+
label: "Base URL",
|
|
3651
|
+
type: "url",
|
|
3652
|
+
required: false,
|
|
3653
|
+
default: "https://openrouter.ai/api/v1",
|
|
3654
|
+
help: "Override only for proxies. Default points at OpenRouter's production endpoint."
|
|
3655
|
+
}
|
|
3656
|
+
]
|
|
3657
|
+
}
|
|
3658
|
+
],
|
|
3659
|
+
knownModels: OPENROUTER_KNOWN_MODELS,
|
|
3660
|
+
// /models is public; the adapter enriches it with OpenRouter's own capability metadata.
|
|
3661
|
+
supportsModelListing: true,
|
|
3662
|
+
docsUrl: "https://openrouter.ai/docs/api_reference/overview"
|
|
3663
|
+
};
|
|
3664
|
+
|
|
3665
|
+
// src/adapters/openrouter/adapter.ts
|
|
3666
|
+
var OPENROUTER_METADATA_EXTRACTOR = makeMetadataExtractor([
|
|
3667
|
+
{ header: "x-generation-id", key: "request_id" }
|
|
3668
|
+
]);
|
|
3669
|
+
var OPENROUTER_ATTRIBUTION_HEADERS = {
|
|
3670
|
+
"HTTP-Referer": "https://jambonz.org",
|
|
3671
|
+
"X-OpenRouter-Title": "jambonz"
|
|
3672
|
+
};
|
|
3673
|
+
var OpenRouterAdapter = class extends OpenAIAdapter {
|
|
3674
|
+
vendor = openRouterManifest.vendor;
|
|
3675
|
+
init(auth, client) {
|
|
3676
|
+
super.init(
|
|
3677
|
+
{
|
|
3678
|
+
...auth,
|
|
3679
|
+
baseURL: auth.baseURL ?? "https://openrouter.ai/api/v1"
|
|
3680
|
+
},
|
|
3681
|
+
client
|
|
3682
|
+
);
|
|
3683
|
+
this.client = this.ensureClient().withOptions({
|
|
3684
|
+
defaultHeaders: OPENROUTER_ATTRIBUTION_HEADERS
|
|
3685
|
+
});
|
|
3686
|
+
}
|
|
3687
|
+
stream(req) {
|
|
3688
|
+
return streamFromOpenAI(this.ensureClient(), req, {
|
|
3689
|
+
knownModels: this.knownModels(),
|
|
3690
|
+
vendorMetadataExtractor: OPENROUTER_METADATA_EXTRACTOR,
|
|
3691
|
+
// Verified accepted by OpenRouter (forwarded to OpenAI-family upstreams).
|
|
3692
|
+
includeCacheKey: true,
|
|
3693
|
+
openRouterAutoCache: this.isOpenRouter
|
|
3694
|
+
});
|
|
3695
|
+
}
|
|
3696
|
+
async listAvailableModels() {
|
|
3697
|
+
const result = await this.ensureClient().models.list();
|
|
3698
|
+
const out = [];
|
|
3699
|
+
for (const m of result.data) {
|
|
3700
|
+
if (m.id.endsWith(":batch")) continue;
|
|
3701
|
+
const outputs = m.architecture?.output_modalities;
|
|
3702
|
+
if (outputs && !outputs.includes("text")) continue;
|
|
3703
|
+
const known = this.knownModels().find((k) => k.id === m.id);
|
|
3704
|
+
if (known) {
|
|
3705
|
+
out.push(known);
|
|
3706
|
+
continue;
|
|
3707
|
+
}
|
|
3708
|
+
out.push({
|
|
3709
|
+
id: m.id,
|
|
3710
|
+
...m.name ? { displayName: m.name } : {},
|
|
3711
|
+
capabilities: {
|
|
3712
|
+
streaming: true,
|
|
3713
|
+
tools: m.supported_parameters?.includes("tools") ?? true,
|
|
3714
|
+
vision: m.architecture?.input_modalities?.includes("image") ?? false,
|
|
3715
|
+
systemPrompt: true,
|
|
3716
|
+
...m.context_length ? { maxContextTokens: m.context_length } : {}
|
|
3717
|
+
}
|
|
3718
|
+
});
|
|
3719
|
+
}
|
|
3720
|
+
return out;
|
|
3721
|
+
}
|
|
3722
|
+
async testCredential() {
|
|
3723
|
+
await this.ensureClient().get("/key");
|
|
3724
|
+
}
|
|
3725
|
+
knownModels() {
|
|
3726
|
+
return openRouterManifest.knownModels;
|
|
3727
|
+
}
|
|
3728
|
+
};
|
|
3729
|
+
|
|
3730
|
+
// src/adapters/openrouter/factory.ts
|
|
3731
|
+
var openRouterFactory = {
|
|
3732
|
+
vendor: openRouterManifest.vendor,
|
|
3733
|
+
manifest: openRouterManifest,
|
|
3734
|
+
create: () => new OpenRouterAdapter()
|
|
3735
|
+
};
|
|
3736
|
+
|
|
3737
|
+
// src/vendors/harness.ts
|
|
3738
|
+
var harnessManifest = {
|
|
3739
|
+
vendor: "harness",
|
|
3740
|
+
displayName: "Harness",
|
|
3741
|
+
authKinds: [
|
|
3742
|
+
{
|
|
3743
|
+
// Only the form schema matters for a credential-only vendor; no
|
|
3744
|
+
// AuthSpec is ever built from it.
|
|
3745
|
+
kind: "apiKey",
|
|
3746
|
+
displayName: "API Key",
|
|
3747
|
+
fields: [
|
|
3748
|
+
{
|
|
3749
|
+
name: "url",
|
|
3750
|
+
label: "WebSocket URL",
|
|
3751
|
+
type: "url",
|
|
3752
|
+
required: true,
|
|
3753
|
+
help: "wss:// URL of your harness. ws:// is accepted only for a private or localhost address."
|
|
3754
|
+
},
|
|
3755
|
+
{
|
|
3756
|
+
name: "apiKey",
|
|
3757
|
+
label: "API Key",
|
|
3758
|
+
type: "password",
|
|
3759
|
+
required: true,
|
|
3760
|
+
help: 'Sent to the harness as "Authorization: Bearer <key>" when each call connects.'
|
|
3761
|
+
}
|
|
3762
|
+
]
|
|
3763
|
+
}
|
|
3764
|
+
],
|
|
3765
|
+
knownModels: [],
|
|
3766
|
+
supportsModelListing: false,
|
|
3767
|
+
credentialOnly: true
|
|
3768
|
+
};
|
|
3769
|
+
|
|
3548
3770
|
// src/adapters/index.ts
|
|
3549
3771
|
registerAdapter(openAIFactory);
|
|
3550
3772
|
registerAdapter(deepseekFactory);
|
|
@@ -3561,6 +3783,8 @@ registerAdapter(bedrockFactory);
|
|
|
3561
3783
|
registerAdapter(azureOpenAIFactory);
|
|
3562
3784
|
registerAdapter(groqFactory);
|
|
3563
3785
|
registerAdapter(huggingfaceFactory);
|
|
3786
|
+
registerAdapter(openRouterFactory);
|
|
3787
|
+
registerCredentialVendor(harnessManifest);
|
|
3564
3788
|
|
|
3565
3789
|
// src/index.ts
|
|
3566
3790
|
async function createLlm(args) {
|