@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.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-dbgrfviJ.cjs';
2
- export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-dbgrfviJ.cjs';
1
+ import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-4l2etrW-.cjs';
2
+ export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-4l2etrW-.cjs';
3
3
 
4
4
  /**
5
5
  * The loose "DB-shape" input accepted by `normalizeAuth`.
@@ -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
  */
@@ -101,12 +101,19 @@ declare function unregisterAdapter(vendor: string): void;
101
101
  */
102
102
  declare function getAdapterFactory<A extends AuthSpec = AuthSpec>(vendor: string): AdapterFactory<A>;
103
103
  /**
104
- * List all registered vendor ids, sorted alphabetically.
104
+ * Get the manifest for any registered vendor, adapter-backed or
105
+ * credential-only. Throws if unknown vendor. Use this (not
106
+ * `getAdapterFactory`) where only the credential shape matters.
107
+ */
108
+ declare function getVendorManifest(vendor: string): AdapterManifest;
109
+ /**
110
+ * List all registered adapter vendor ids, sorted alphabetically.
111
+ * Credential-only vendors are not included: they cannot be passed to `createLlm`.
105
112
  */
106
113
  declare function listVendors(): string[];
107
114
  /**
108
- * Return an aggregated manifest for all registered adapters. Used by
109
- * api-server's /llm-vendors/manifest endpoint.
115
+ * Return an aggregated manifest for all registered vendors, credential-only
116
+ * ones included. Used by api-server's /llm-vendors/manifest endpoint.
110
117
  */
111
118
  declare function getManifest(): {
112
119
  vendors: AdapterManifest[];
@@ -121,6 +128,8 @@ declare function getManifest(): {
121
128
  * Consumers use:
122
129
  * - `createLlm({vendor, auth, client?})` to get a ready-to-stream adapter instance.
123
130
  * - `getManifest()` to enumerate registered vendors (used by api-server).
131
+ * - `getVendorManifest(vendor)` for one vendor's manifest, including
132
+ * credential-only vendors (e.g. `harness`) that have no adapter.
124
133
  * - `normalizeAuth(vendor, rawCred)` to convert DB-shape creds to AuthSpec.
125
134
  * - `pickAuthKind(vendor, rawCred)` to pick the right manifest authKind for
126
135
  * a raw credential (used by api-server's `encryptCredential`).
@@ -129,4 +138,4 @@ declare function getManifest(): {
129
138
 
130
139
  declare function createLlm<A extends AuthSpec = AuthSpec>(args: CreateLlmArgs<A>): Promise<LlmAdapter<A>>;
131
140
 
132
- export { AdapterFactory, AdapterManifest, AuthKindSchema, AuthSpec, CreateLlmArgs, LlmAdapter, PromptRequest, type RawCredential, type RawCredentialLoose, ServiceAccountJson, assertValidRequest, createLlm, getAdapterFactory, getManifest, listVendors, normalizeAuth, pickAuthKind, registerAdapter, replaceAdapter, unregisterAdapter };
141
+ export { AdapterFactory, AdapterManifest, AuthKindSchema, AuthSpec, CreateLlmArgs, LlmAdapter, PromptRequest, type RawCredential, type RawCredentialLoose, ServiceAccountJson, assertValidRequest, createLlm, getAdapterFactory, getManifest, getVendorManifest, listVendors, normalizeAuth, pickAuthKind, registerAdapter, replaceAdapter, unregisterAdapter };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-dbgrfviJ.js';
2
- export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-dbgrfviJ.js';
1
+ import { S as ServiceAccountJson, A as AuthSpec, a as AuthKindSchema, P as PromptRequest, b as AdapterFactory, c as AdapterManifest, C as CreateLlmArgs, L as LlmAdapter } from './types-4l2etrW-.js';
2
+ export { d as ApiKeyAuth, e as AuthKind, f as AzureOpenAIApiKeyAuth, B as BedrockApiKeyAuth, g as BedrockIamAuth, h as ClientOptions, i as ContentBlock, F as FinishReason, j as FormField, k as FormFieldType, G as GoogleApiKeyAuth, l as GoogleServiceAccountAuth, J as JsonSchema, m as LlmEvent, M as Message, n as ModelCapabilities, o as ModelInfo, R as Role, T as Tool, p as ToolCallEvent, U as Usage, V as VertexServiceAccountAuth } from './types-4l2etrW-.js';
3
3
 
4
4
  /**
5
5
  * The loose "DB-shape" input accepted by `normalizeAuth`.
@@ -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
  */
@@ -101,12 +101,19 @@ declare function unregisterAdapter(vendor: string): void;
101
101
  */
102
102
  declare function getAdapterFactory<A extends AuthSpec = AuthSpec>(vendor: string): AdapterFactory<A>;
103
103
  /**
104
- * List all registered vendor ids, sorted alphabetically.
104
+ * Get the manifest for any registered vendor, adapter-backed or
105
+ * credential-only. Throws if unknown vendor. Use this (not
106
+ * `getAdapterFactory`) where only the credential shape matters.
107
+ */
108
+ declare function getVendorManifest(vendor: string): AdapterManifest;
109
+ /**
110
+ * List all registered adapter vendor ids, sorted alphabetically.
111
+ * Credential-only vendors are not included: they cannot be passed to `createLlm`.
105
112
  */
106
113
  declare function listVendors(): string[];
107
114
  /**
108
- * Return an aggregated manifest for all registered adapters. Used by
109
- * api-server's /llm-vendors/manifest endpoint.
115
+ * Return an aggregated manifest for all registered vendors, credential-only
116
+ * ones included. Used by api-server's /llm-vendors/manifest endpoint.
110
117
  */
111
118
  declare function getManifest(): {
112
119
  vendors: AdapterManifest[];
@@ -121,6 +128,8 @@ declare function getManifest(): {
121
128
  * Consumers use:
122
129
  * - `createLlm({vendor, auth, client?})` to get a ready-to-stream adapter instance.
123
130
  * - `getManifest()` to enumerate registered vendors (used by api-server).
131
+ * - `getVendorManifest(vendor)` for one vendor's manifest, including
132
+ * credential-only vendors (e.g. `harness`) that have no adapter.
124
133
  * - `normalizeAuth(vendor, rawCred)` to convert DB-shape creds to AuthSpec.
125
134
  * - `pickAuthKind(vendor, rawCred)` to pick the right manifest authKind for
126
135
  * a raw credential (used by api-server's `encryptCredential`).
@@ -129,4 +138,4 @@ declare function getManifest(): {
129
138
 
130
139
  declare function createLlm<A extends AuthSpec = AuthSpec>(args: CreateLlmArgs<A>): Promise<LlmAdapter<A>>;
131
140
 
132
- export { AdapterFactory, AdapterManifest, AuthKindSchema, AuthSpec, CreateLlmArgs, LlmAdapter, PromptRequest, type RawCredential, type RawCredentialLoose, ServiceAccountJson, assertValidRequest, createLlm, getAdapterFactory, getManifest, listVendors, normalizeAuth, pickAuthKind, registerAdapter, replaceAdapter, unregisterAdapter };
141
+ export { AdapterFactory, AdapterManifest, AuthKindSchema, AuthSpec, CreateLlmArgs, LlmAdapter, PromptRequest, type RawCredential, type RawCredentialLoose, ServiceAccountJson, assertValidRequest, createLlm, getAdapterFactory, getManifest, getVendorManifest, listVendors, normalizeAuth, pickAuthKind, registerAdapter, replaceAdapter, unregisterAdapter };
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  // src/registry.ts
2
2
  var registry = /* @__PURE__ */ new Map();
3
+ var credentialVendors = /* @__PURE__ */ new Map();
3
4
  function registerAdapter(factory) {
4
- if (registry.has(factory.vendor)) {
5
+ if (registry.has(factory.vendor) || credentialVendors.has(factory.vendor)) {
5
6
  throw new Error(
6
7
  `Adapter already registered for vendor '${factory.vendor}'. Use replaceAdapter() if you intended to override.`
7
8
  );
@@ -13,6 +14,15 @@ function registerAdapter(factory) {
13
14
  }
14
15
  registry.set(factory.vendor, factory);
15
16
  }
17
+ function registerCredentialVendor(manifest) {
18
+ if (!manifest.credentialOnly) {
19
+ throw new Error(`Vendor '${manifest.vendor}' manifest is not marked credentialOnly.`);
20
+ }
21
+ if (registry.has(manifest.vendor) || credentialVendors.has(manifest.vendor)) {
22
+ throw new Error(`Vendor '${manifest.vendor}' is already registered.`);
23
+ }
24
+ credentialVendors.set(manifest.vendor, manifest);
25
+ }
16
26
  function replaceAdapter(factory) {
17
27
  registry.set(factory.vendor, factory);
18
28
  }
@@ -22,6 +32,11 @@ function unregisterAdapter(vendor) {
22
32
  function getAdapterFactory(vendor) {
23
33
  const factory = registry.get(vendor);
24
34
  if (!factory) {
35
+ if (credentialVendors.has(vendor)) {
36
+ throw new Error(
37
+ `Vendor '${vendor}' is credential-only: @jambonz/llm has no adapter for it.`
38
+ );
39
+ }
25
40
  const known = Array.from(registry.keys()).sort().join(", ") || "(none)";
26
41
  throw new Error(
27
42
  `Unknown vendor '${vendor}'. Registered vendors: ${known}`
@@ -29,11 +44,22 @@ function getAdapterFactory(vendor) {
29
44
  }
30
45
  return factory;
31
46
  }
47
+ function getVendorManifest(vendor) {
48
+ const manifest = registry.get(vendor)?.manifest ?? credentialVendors.get(vendor);
49
+ if (!manifest) {
50
+ const known = [...registry.keys(), ...credentialVendors.keys()].sort().join(", ") || "(none)";
51
+ throw new Error(`Unknown vendor '${vendor}'. Registered vendors: ${known}`);
52
+ }
53
+ return manifest;
54
+ }
32
55
  function listVendors() {
33
56
  return Array.from(registry.keys()).sort();
34
57
  }
35
58
  function getManifest() {
36
- const vendors = Array.from(registry.values()).map((f) => f.manifest).sort((a, b) => a.vendor.localeCompare(b.vendor));
59
+ const vendors = [
60
+ ...Array.from(registry.values()).map((f) => f.manifest),
61
+ ...credentialVendors.values()
62
+ ].sort((a, b) => a.vendor.localeCompare(b.vendor));
37
63
  return { vendors };
38
64
  }
39
65
 
@@ -3552,6 +3578,212 @@ var huggingfaceFactory = {
3552
3578
  create: () => new HuggingfaceAdapter()
3553
3579
  };
3554
3580
 
3581
+ // src/adapters/openrouter/manifest.ts
3582
+ var OPENROUTER_KNOWN_MODELS = [
3583
+ {
3584
+ id: "anthropic/claude-haiku-5.5",
3585
+ displayName: "Claude Haiku 5.5 (OpenRouter)",
3586
+ capabilities: {
3587
+ streaming: true,
3588
+ tools: true,
3589
+ vision: true,
3590
+ systemPrompt: true,
3591
+ maxContextTokens: 1e6
3592
+ }
3593
+ },
3594
+ {
3595
+ id: "anthropic/claude-sonnet-5.5",
3596
+ displayName: "Claude Sonnet 5.5 (OpenRouter)",
3597
+ capabilities: {
3598
+ streaming: true,
3599
+ tools: true,
3600
+ vision: true,
3601
+ systemPrompt: true,
3602
+ maxContextTokens: 1e6
3603
+ }
3604
+ },
3605
+ {
3606
+ id: "openai/gpt-5.4-mini",
3607
+ displayName: "GPT-5.4 Mini (OpenRouter)",
3608
+ capabilities: {
3609
+ streaming: true,
3610
+ tools: true,
3611
+ vision: true,
3612
+ systemPrompt: true,
3613
+ maxContextTokens: 4e5
3614
+ }
3615
+ },
3616
+ {
3617
+ id: "openai/gpt-4.1-mini",
3618
+ displayName: "GPT-4.1 Mini (OpenRouter)",
3619
+ capabilities: {
3620
+ streaming: true,
3621
+ tools: true,
3622
+ vision: true,
3623
+ systemPrompt: true,
3624
+ maxContextTokens: 1047576
3625
+ }
3626
+ },
3627
+ {
3628
+ id: "google/gemini-3.5-flash",
3629
+ displayName: "Gemini 3.5 Flash (OpenRouter)",
3630
+ capabilities: {
3631
+ streaming: true,
3632
+ tools: true,
3633
+ vision: true,
3634
+ systemPrompt: true,
3635
+ maxContextTokens: 1048576
3636
+ }
3637
+ },
3638
+ {
3639
+ id: "meta-llama/llama-3.3-70b-instruct",
3640
+ displayName: "Llama 3.3 70B Instruct (OpenRouter)",
3641
+ capabilities: {
3642
+ streaming: true,
3643
+ tools: true,
3644
+ vision: false,
3645
+ systemPrompt: true,
3646
+ maxContextTokens: 131072
3647
+ }
3648
+ }
3649
+ ];
3650
+ var openRouterManifest = {
3651
+ vendor: "openrouter",
3652
+ displayName: "OpenRouter",
3653
+ authKinds: [
3654
+ {
3655
+ kind: "apiKey",
3656
+ displayName: "API Key",
3657
+ fields: [
3658
+ {
3659
+ name: "apiKey",
3660
+ label: "API Key",
3661
+ type: "password",
3662
+ required: true,
3663
+ help: "Get an API key from https://openrouter.ai/settings/keys"
3664
+ },
3665
+ {
3666
+ name: "baseURL",
3667
+ label: "Base URL",
3668
+ type: "url",
3669
+ required: false,
3670
+ default: "https://openrouter.ai/api/v1",
3671
+ help: "Override only for proxies. Default points at OpenRouter's production endpoint."
3672
+ }
3673
+ ]
3674
+ }
3675
+ ],
3676
+ knownModels: OPENROUTER_KNOWN_MODELS,
3677
+ // /models is public; the adapter enriches it with OpenRouter's own capability metadata.
3678
+ supportsModelListing: true,
3679
+ docsUrl: "https://openrouter.ai/docs/api_reference/overview"
3680
+ };
3681
+
3682
+ // src/adapters/openrouter/adapter.ts
3683
+ var OPENROUTER_METADATA_EXTRACTOR = makeMetadataExtractor([
3684
+ { header: "x-generation-id", key: "request_id" }
3685
+ ]);
3686
+ var OPENROUTER_ATTRIBUTION_HEADERS = {
3687
+ "HTTP-Referer": "https://jambonz.org",
3688
+ "X-OpenRouter-Title": "jambonz"
3689
+ };
3690
+ var OpenRouterAdapter = class extends OpenAIAdapter {
3691
+ vendor = openRouterManifest.vendor;
3692
+ init(auth, client) {
3693
+ super.init(
3694
+ {
3695
+ ...auth,
3696
+ baseURL: auth.baseURL ?? "https://openrouter.ai/api/v1"
3697
+ },
3698
+ client
3699
+ );
3700
+ this.client = this.ensureClient().withOptions({
3701
+ defaultHeaders: OPENROUTER_ATTRIBUTION_HEADERS
3702
+ });
3703
+ }
3704
+ stream(req) {
3705
+ return streamFromOpenAI(this.ensureClient(), req, {
3706
+ knownModels: this.knownModels(),
3707
+ vendorMetadataExtractor: OPENROUTER_METADATA_EXTRACTOR,
3708
+ // Verified accepted by OpenRouter (forwarded to OpenAI-family upstreams).
3709
+ includeCacheKey: true,
3710
+ openRouterAutoCache: this.isOpenRouter
3711
+ });
3712
+ }
3713
+ async listAvailableModels() {
3714
+ const result = await this.ensureClient().models.list();
3715
+ const out = [];
3716
+ for (const m of result.data) {
3717
+ if (m.id.endsWith(":batch")) continue;
3718
+ const outputs = m.architecture?.output_modalities;
3719
+ if (outputs && !outputs.includes("text")) continue;
3720
+ const known = this.knownModels().find((k) => k.id === m.id);
3721
+ if (known) {
3722
+ out.push(known);
3723
+ continue;
3724
+ }
3725
+ out.push({
3726
+ id: m.id,
3727
+ ...m.name ? { displayName: m.name } : {},
3728
+ capabilities: {
3729
+ streaming: true,
3730
+ tools: m.supported_parameters?.includes("tools") ?? true,
3731
+ vision: m.architecture?.input_modalities?.includes("image") ?? false,
3732
+ systemPrompt: true,
3733
+ ...m.context_length ? { maxContextTokens: m.context_length } : {}
3734
+ }
3735
+ });
3736
+ }
3737
+ return out;
3738
+ }
3739
+ async testCredential() {
3740
+ await this.ensureClient().get("/key");
3741
+ }
3742
+ knownModels() {
3743
+ return openRouterManifest.knownModels;
3744
+ }
3745
+ };
3746
+
3747
+ // src/adapters/openrouter/factory.ts
3748
+ var openRouterFactory = {
3749
+ vendor: openRouterManifest.vendor,
3750
+ manifest: openRouterManifest,
3751
+ create: () => new OpenRouterAdapter()
3752
+ };
3753
+
3754
+ // src/vendors/harness.ts
3755
+ var harnessManifest = {
3756
+ vendor: "harness",
3757
+ displayName: "Harness",
3758
+ authKinds: [
3759
+ {
3760
+ // Only the form schema matters for a credential-only vendor; no
3761
+ // AuthSpec is ever built from it.
3762
+ kind: "apiKey",
3763
+ displayName: "API Key",
3764
+ fields: [
3765
+ {
3766
+ name: "url",
3767
+ label: "WebSocket URL",
3768
+ type: "url",
3769
+ required: true,
3770
+ help: "wss:// URL of your harness. ws:// is accepted only for a private or localhost address."
3771
+ },
3772
+ {
3773
+ name: "apiKey",
3774
+ label: "API Key",
3775
+ type: "password",
3776
+ required: true,
3777
+ help: 'Sent to the harness as "Authorization: Bearer <key>" when each call connects.'
3778
+ }
3779
+ ]
3780
+ }
3781
+ ],
3782
+ knownModels: [],
3783
+ supportsModelListing: false,
3784
+ credentialOnly: true
3785
+ };
3786
+
3555
3787
  // src/adapters/index.ts
3556
3788
  registerAdapter(openAIFactory);
3557
3789
  registerAdapter(deepseekFactory);
@@ -3568,6 +3800,8 @@ registerAdapter(bedrockFactory);
3568
3800
  registerAdapter(azureOpenAIFactory);
3569
3801
  registerAdapter(groqFactory);
3570
3802
  registerAdapter(huggingfaceFactory);
3803
+ registerAdapter(openRouterFactory);
3804
+ registerCredentialVendor(harnessManifest);
3571
3805
 
3572
3806
  // src/normalize-auth.ts
3573
3807
  function normalizeAuth(vendor, raw) {
@@ -3576,6 +3810,7 @@ function normalizeAuth(vendor, raw) {
3576
3810
  case "anthropic":
3577
3811
  case "groq":
3578
3812
  case "huggingface":
3813
+ case "openrouter":
3579
3814
  case "moonshot":
3580
3815
  case "zai":
3581
3816
  case "xai":
@@ -3714,8 +3949,7 @@ function parseServiceKey(value) {
3714
3949
 
3715
3950
  // src/pick-auth-kind.ts
3716
3951
  function pickAuthKind(vendor, raw) {
3717
- const factory = getAdapterFactory(vendor);
3718
- const { authKinds } = factory.manifest;
3952
+ const { authKinds } = getVendorManifest(vendor);
3719
3953
  if (authKinds.length === 1) {
3720
3954
  return authKinds[0];
3721
3955
  }
@@ -3775,6 +4009,7 @@ export {
3775
4009
  createLlm,
3776
4010
  getAdapterFactory,
3777
4011
  getManifest,
4012
+ getVendorManifest,
3778
4013
  listVendors,
3779
4014
  normalizeAuth,
3780
4015
  pickAuthKind,