@jambonz/llm 0.1.0
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/LICENSE +21 -0
- package/README.md +20 -0
- package/dist/index.cjs +2194 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +100 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.js +2152 -0
- package/dist/index.js.map +1 -0
- package/dist/test-kit/index.cjs +2645 -0
- package/dist/test-kit/index.cjs.map +1 -0
- package/dist/test-kit/index.d.cts +162 -0
- package/dist/test-kit/index.d.ts +162 -0
- package/dist/test-kit/index.js +2608 -0
- package/dist/test-kit/index.js.map +1 -0
- package/dist/types-D8rgMCbi.d.cts +280 -0
- package/dist/types-D8rgMCbi.d.ts +280 -0
- package/package.json +91 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public type surface for @jambonz/llm.
|
|
3
|
+
*
|
|
4
|
+
* These are the types that:
|
|
5
|
+
* - Callers (feature-server, etc.) use to make requests and consume events.
|
|
6
|
+
* - Vendor adapters implement.
|
|
7
|
+
* - api-server consumes to serve the /llm-vendors/manifest endpoint.
|
|
8
|
+
* - webapp consumes (via api-server) to render the add-LLM page.
|
|
9
|
+
*
|
|
10
|
+
* Contract guarantees are documented in docs/adding-a-vendor.md.
|
|
11
|
+
*/
|
|
12
|
+
type Role = 'system' | 'user' | 'assistant' | 'tool';
|
|
13
|
+
/**
|
|
14
|
+
* A single conversation turn. `role: 'system'` is not allowed in `PromptRequest.messages` —
|
|
15
|
+
* pass system prompts via `PromptRequest.system` instead. Adapters still emit/accept
|
|
16
|
+
* `role: 'system'` messages internally for some vendors, but that happens inside the adapter.
|
|
17
|
+
*
|
|
18
|
+
* `vendorRaw` is the escape hatch that preserves vendor-native message shapes
|
|
19
|
+
* (Anthropic content blocks, OpenAI tool_calls arrays, Google parts, Bedrock content[]).
|
|
20
|
+
* When an adapter emits an assistant message during streaming, it populates `vendorRaw`
|
|
21
|
+
* with the vendor's native representation. On subsequent requests the same adapter reads
|
|
22
|
+
* `vendorRaw` back as the source of truth, avoiding lossy normalization.
|
|
23
|
+
*/
|
|
24
|
+
interface Message {
|
|
25
|
+
role: Role;
|
|
26
|
+
content: string | ContentBlock[];
|
|
27
|
+
/** Opaque vendor-native wire shape. Callers should treat this as read-only. */
|
|
28
|
+
vendorRaw?: unknown;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Multi-part message content. Most turns use a plain string; blocks are used for
|
|
32
|
+
* images, tool results (when the vendor requires a specific block shape that differs
|
|
33
|
+
* from the OpenAI `role: 'tool'` convention), and other structured content.
|
|
34
|
+
*/
|
|
35
|
+
type ContentBlock = {
|
|
36
|
+
type: 'text';
|
|
37
|
+
text: string;
|
|
38
|
+
} | {
|
|
39
|
+
type: 'image';
|
|
40
|
+
source: {
|
|
41
|
+
kind: 'url' | 'base64';
|
|
42
|
+
data: string;
|
|
43
|
+
mimeType?: string;
|
|
44
|
+
};
|
|
45
|
+
} | {
|
|
46
|
+
type: 'toolResult';
|
|
47
|
+
toolCallId: string;
|
|
48
|
+
content: string | unknown;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Tool declaration in MCP-style flat shape. Adapters translate outwards per vendor
|
|
52
|
+
* (e.g., OpenAI wraps in `{type: 'function', function: {...}}`).
|
|
53
|
+
*/
|
|
54
|
+
interface Tool {
|
|
55
|
+
name: string;
|
|
56
|
+
description: string;
|
|
57
|
+
/** JSON Schema for the tool's arguments. */
|
|
58
|
+
parameters: JsonSchema;
|
|
59
|
+
}
|
|
60
|
+
/** Minimal JSON Schema type — adapters and the library validate at the boundary. */
|
|
61
|
+
type JsonSchema = Record<string, unknown>;
|
|
62
|
+
interface PromptRequest {
|
|
63
|
+
model: string;
|
|
64
|
+
/**
|
|
65
|
+
* System prompt. The library always passes this as a top-level parameter;
|
|
66
|
+
* adapters place it per-vendor (top-level for Anthropic/Bedrock, config field
|
|
67
|
+
* for Google, prepended as a message for OpenAI, etc.).
|
|
68
|
+
*/
|
|
69
|
+
system?: string;
|
|
70
|
+
/** Conversation turns. Must NOT contain `role: 'system'` — use `system` above. */
|
|
71
|
+
messages: Message[];
|
|
72
|
+
tools?: Tool[];
|
|
73
|
+
temperature?: number;
|
|
74
|
+
maxTokens?: number;
|
|
75
|
+
/** Abort the stream. Adapters MUST honor this and propagate to the vendor SDK. */
|
|
76
|
+
signal?: AbortSignal;
|
|
77
|
+
}
|
|
78
|
+
type LlmEvent = {
|
|
79
|
+
type: 'token';
|
|
80
|
+
text: string;
|
|
81
|
+
} | {
|
|
82
|
+
type: 'toolCallStart';
|
|
83
|
+
id: string;
|
|
84
|
+
name: string;
|
|
85
|
+
} | {
|
|
86
|
+
type: 'toolCall';
|
|
87
|
+
id: string;
|
|
88
|
+
name: string;
|
|
89
|
+
arguments: unknown;
|
|
90
|
+
} | {
|
|
91
|
+
type: 'end';
|
|
92
|
+
finishReason: FinishReason;
|
|
93
|
+
usage?: Usage;
|
|
94
|
+
rawReason?: string;
|
|
95
|
+
};
|
|
96
|
+
type FinishReason = 'stop' | 'tool' | 'length' | 'filtered' | 'error' | 'aborted';
|
|
97
|
+
interface Usage {
|
|
98
|
+
inputTokens?: number;
|
|
99
|
+
outputTokens?: number;
|
|
100
|
+
totalTokens?: number;
|
|
101
|
+
}
|
|
102
|
+
type AuthSpec = ApiKeyAuth | BedrockIamAuth | BedrockApiKeyAuth | GoogleApiKeyAuth | GoogleServiceAccountAuth | VertexServiceAccountAuth;
|
|
103
|
+
interface ApiKeyAuth {
|
|
104
|
+
kind: 'apiKey';
|
|
105
|
+
apiKey: string;
|
|
106
|
+
baseURL?: string;
|
|
107
|
+
}
|
|
108
|
+
interface BedrockIamAuth {
|
|
109
|
+
kind: 'bedrockIam';
|
|
110
|
+
accessKeyId: string;
|
|
111
|
+
secretAccessKey: string;
|
|
112
|
+
sessionToken?: string;
|
|
113
|
+
region: string;
|
|
114
|
+
}
|
|
115
|
+
interface BedrockApiKeyAuth {
|
|
116
|
+
kind: 'bedrockApiKey';
|
|
117
|
+
apiKey: string;
|
|
118
|
+
region: string;
|
|
119
|
+
}
|
|
120
|
+
interface GoogleApiKeyAuth {
|
|
121
|
+
kind: 'googleApiKey';
|
|
122
|
+
apiKey: string;
|
|
123
|
+
}
|
|
124
|
+
interface GoogleServiceAccountAuth {
|
|
125
|
+
kind: 'googleServiceAccount';
|
|
126
|
+
/** Parsed JSON of the service account key file. */
|
|
127
|
+
credentials: ServiceAccountJson;
|
|
128
|
+
}
|
|
129
|
+
interface VertexServiceAccountAuth {
|
|
130
|
+
kind: 'vertexServiceAccount';
|
|
131
|
+
credentials: ServiceAccountJson;
|
|
132
|
+
projectId: string;
|
|
133
|
+
location: string;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Minimal shape of a Google service-account JSON. Kept loose intentionally —
|
|
137
|
+
* validation happens inside the Google Auth library, not here.
|
|
138
|
+
*/
|
|
139
|
+
interface ServiceAccountJson {
|
|
140
|
+
type: string;
|
|
141
|
+
project_id?: string;
|
|
142
|
+
private_key_id?: string;
|
|
143
|
+
private_key: string;
|
|
144
|
+
client_email: string;
|
|
145
|
+
client_id?: string;
|
|
146
|
+
[key: string]: unknown;
|
|
147
|
+
}
|
|
148
|
+
type AuthKind = AuthSpec['kind'];
|
|
149
|
+
interface ClientOptions {
|
|
150
|
+
timeout?: number;
|
|
151
|
+
maxRetries?: number;
|
|
152
|
+
/** Custom endpoint, e.g. Bedrock VPC endpoint. Adapter-specific meaning. */
|
|
153
|
+
endpoint?: string;
|
|
154
|
+
}
|
|
155
|
+
interface ModelInfo {
|
|
156
|
+
id: string;
|
|
157
|
+
displayName?: string;
|
|
158
|
+
capabilities: ModelCapabilities;
|
|
159
|
+
deprecated?: boolean;
|
|
160
|
+
}
|
|
161
|
+
interface ModelCapabilities {
|
|
162
|
+
/** Whether the model supports streaming responses. */
|
|
163
|
+
streaming: boolean;
|
|
164
|
+
/** Whether the model supports function/tool calling. NOT a vendor-wide flag. */
|
|
165
|
+
tools: boolean;
|
|
166
|
+
/** Whether the model accepts image inputs. */
|
|
167
|
+
vision: boolean;
|
|
168
|
+
/** Whether the model accepts a system prompt (a few Gemini models do not). */
|
|
169
|
+
systemPrompt: boolean;
|
|
170
|
+
/** Maximum input context in tokens, if known. */
|
|
171
|
+
maxContextTokens?: number;
|
|
172
|
+
}
|
|
173
|
+
interface AdapterManifest {
|
|
174
|
+
/** Machine-readable vendor id (matches the `vendor` field in createLlm args). */
|
|
175
|
+
vendor: string;
|
|
176
|
+
/** Human-readable vendor name shown in the admin UI. */
|
|
177
|
+
displayName: string;
|
|
178
|
+
/** One or more accepted auth shapes. Webapp renders a toggle when length > 1. */
|
|
179
|
+
authKinds: AuthKindSchema[];
|
|
180
|
+
/** Curated list of known models for this vendor. Safe to ship in the manifest. */
|
|
181
|
+
knownModels: ModelInfo[];
|
|
182
|
+
/** Whether listAvailableModels() hits a live vendor endpoint. */
|
|
183
|
+
supportsModelListing: boolean;
|
|
184
|
+
/** Optional documentation link for this vendor. */
|
|
185
|
+
docsUrl?: string;
|
|
186
|
+
}
|
|
187
|
+
interface AuthKindSchema {
|
|
188
|
+
kind: AuthKind;
|
|
189
|
+
displayName: string;
|
|
190
|
+
fields: FormField[];
|
|
191
|
+
}
|
|
192
|
+
type FormFieldType = 'text' | 'password' | 'url' | 'json-file' | 'select';
|
|
193
|
+
interface FormField {
|
|
194
|
+
name: string;
|
|
195
|
+
label: string;
|
|
196
|
+
type: FormFieldType;
|
|
197
|
+
required: boolean;
|
|
198
|
+
default?: string;
|
|
199
|
+
/** Options for `type: 'select'`. Ignored for other types. */
|
|
200
|
+
options?: {
|
|
201
|
+
value: string;
|
|
202
|
+
label: string;
|
|
203
|
+
}[];
|
|
204
|
+
/** Hint text shown below the input. */
|
|
205
|
+
help?: string;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* The interface every vendor adapter implements.
|
|
209
|
+
*
|
|
210
|
+
* An adapter is a class (or class-like object) that:
|
|
211
|
+
* 1. Declares which auth kinds it accepts (`acceptedAuth`).
|
|
212
|
+
* 2. Initializes a client from an `AuthSpec` (`init`).
|
|
213
|
+
* 3. Streams a prompt as an AsyncIterable of `LlmEvent`s (`stream`).
|
|
214
|
+
* 4. Appends a tool result to history in the vendor's native shape (`appendToolResult`).
|
|
215
|
+
* 5. Lists models accessible to the credential (`listAvailableModels`).
|
|
216
|
+
*
|
|
217
|
+
* The `manifest` is exported as a module-level constant alongside the adapter.
|
|
218
|
+
* See src/adapters/_template/ for a working skeleton.
|
|
219
|
+
*/
|
|
220
|
+
interface LlmAdapter<A extends AuthSpec = AuthSpec> {
|
|
221
|
+
/** Machine-readable vendor id. Must match `manifest.vendor`. */
|
|
222
|
+
readonly vendor: string;
|
|
223
|
+
/** The auth kinds this adapter accepts. Used by validators. */
|
|
224
|
+
readonly acceptedAuth: ReadonlyArray<A['kind']>;
|
|
225
|
+
/** One-time initialization with credentials. Called once per `createLlm` call. */
|
|
226
|
+
init(auth: A, client?: ClientOptions): Promise<void> | void;
|
|
227
|
+
/**
|
|
228
|
+
* Stream a prompt. Yields an AsyncIterable of events:
|
|
229
|
+
* - `token` (zero or more)
|
|
230
|
+
* - `toolCallStart` (optional, zero or more)
|
|
231
|
+
* - `toolCall` (zero or more, fully accumulated)
|
|
232
|
+
* - `end` (exactly one, and last)
|
|
233
|
+
*
|
|
234
|
+
* MUST honor `req.signal` if provided — if aborted, emit `{type: 'end', finishReason: 'aborted'}`
|
|
235
|
+
* and do not emit any pending `toolCall` events.
|
|
236
|
+
*/
|
|
237
|
+
stream(req: PromptRequest): AsyncIterable<LlmEvent>;
|
|
238
|
+
/**
|
|
239
|
+
* Append a tool-result message to history in the vendor's native shape.
|
|
240
|
+
* The returned array MUST be a valid `messages` input for a subsequent `stream()` call
|
|
241
|
+
* on the same adapter.
|
|
242
|
+
*/
|
|
243
|
+
appendToolResult(history: Message[], toolCallId: string, result: unknown): Message[];
|
|
244
|
+
/**
|
|
245
|
+
* Hit the vendor's list-models endpoint and return accessible models.
|
|
246
|
+
* Requires init() to have been called.
|
|
247
|
+
*
|
|
248
|
+
* If the vendor does not support live listing, adapters may return the static
|
|
249
|
+
* `knownModels` from the manifest — but `manifest.supportsModelListing` MUST be `false`
|
|
250
|
+
* in that case.
|
|
251
|
+
*/
|
|
252
|
+
listAvailableModels(): Promise<ModelInfo[]>;
|
|
253
|
+
/**
|
|
254
|
+
* Optional: pre-establish connection to the vendor API. Useful for reducing
|
|
255
|
+
* cold-start latency on the first prompt. No-op if not implemented.
|
|
256
|
+
*/
|
|
257
|
+
warmup?(): Promise<void>;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* The constructor/factory shape for an adapter. Registered at module load via
|
|
261
|
+
* `registerAdapter`. The library calls this once per `createLlm` call.
|
|
262
|
+
*/
|
|
263
|
+
interface AdapterFactory<A extends AuthSpec = AuthSpec> {
|
|
264
|
+
/** Machine-readable vendor id. */
|
|
265
|
+
readonly vendor: string;
|
|
266
|
+
/** Static manifest describing this vendor. */
|
|
267
|
+
readonly manifest: AdapterManifest;
|
|
268
|
+
/** Construct a fresh adapter instance. */
|
|
269
|
+
create(): LlmAdapter<A>;
|
|
270
|
+
}
|
|
271
|
+
interface CreateLlmArgs<A extends AuthSpec = AuthSpec> {
|
|
272
|
+
/** Vendor id. Must match a registered adapter. */
|
|
273
|
+
vendor: string;
|
|
274
|
+
/** Credentials in the shape the adapter declares it accepts. */
|
|
275
|
+
auth: A;
|
|
276
|
+
/** Optional transport knobs. */
|
|
277
|
+
client?: ClientOptions;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export type { AuthSpec as A, BedrockApiKeyAuth as B, CreateLlmArgs as C, FinishReason as F, GoogleApiKeyAuth as G, JsonSchema as J, LlmAdapter as L, Message as M, PromptRequest as P, Role as R, ServiceAccountJson as S, Tool as T, Usage as U, VertexServiceAccountAuth as V, AdapterFactory as a, AdapterManifest as b, ApiKeyAuth as c, AuthKind as d, AuthKindSchema as e, BedrockIamAuth as f, ClientOptions as g, ContentBlock as h, FormField as i, FormFieldType as j, GoogleServiceAccountAuth as k, LlmEvent as l, ModelCapabilities as m, ModelInfo as n };
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public type surface for @jambonz/llm.
|
|
3
|
+
*
|
|
4
|
+
* These are the types that:
|
|
5
|
+
* - Callers (feature-server, etc.) use to make requests and consume events.
|
|
6
|
+
* - Vendor adapters implement.
|
|
7
|
+
* - api-server consumes to serve the /llm-vendors/manifest endpoint.
|
|
8
|
+
* - webapp consumes (via api-server) to render the add-LLM page.
|
|
9
|
+
*
|
|
10
|
+
* Contract guarantees are documented in docs/adding-a-vendor.md.
|
|
11
|
+
*/
|
|
12
|
+
type Role = 'system' | 'user' | 'assistant' | 'tool';
|
|
13
|
+
/**
|
|
14
|
+
* A single conversation turn. `role: 'system'` is not allowed in `PromptRequest.messages` —
|
|
15
|
+
* pass system prompts via `PromptRequest.system` instead. Adapters still emit/accept
|
|
16
|
+
* `role: 'system'` messages internally for some vendors, but that happens inside the adapter.
|
|
17
|
+
*
|
|
18
|
+
* `vendorRaw` is the escape hatch that preserves vendor-native message shapes
|
|
19
|
+
* (Anthropic content blocks, OpenAI tool_calls arrays, Google parts, Bedrock content[]).
|
|
20
|
+
* When an adapter emits an assistant message during streaming, it populates `vendorRaw`
|
|
21
|
+
* with the vendor's native representation. On subsequent requests the same adapter reads
|
|
22
|
+
* `vendorRaw` back as the source of truth, avoiding lossy normalization.
|
|
23
|
+
*/
|
|
24
|
+
interface Message {
|
|
25
|
+
role: Role;
|
|
26
|
+
content: string | ContentBlock[];
|
|
27
|
+
/** Opaque vendor-native wire shape. Callers should treat this as read-only. */
|
|
28
|
+
vendorRaw?: unknown;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Multi-part message content. Most turns use a plain string; blocks are used for
|
|
32
|
+
* images, tool results (when the vendor requires a specific block shape that differs
|
|
33
|
+
* from the OpenAI `role: 'tool'` convention), and other structured content.
|
|
34
|
+
*/
|
|
35
|
+
type ContentBlock = {
|
|
36
|
+
type: 'text';
|
|
37
|
+
text: string;
|
|
38
|
+
} | {
|
|
39
|
+
type: 'image';
|
|
40
|
+
source: {
|
|
41
|
+
kind: 'url' | 'base64';
|
|
42
|
+
data: string;
|
|
43
|
+
mimeType?: string;
|
|
44
|
+
};
|
|
45
|
+
} | {
|
|
46
|
+
type: 'toolResult';
|
|
47
|
+
toolCallId: string;
|
|
48
|
+
content: string | unknown;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Tool declaration in MCP-style flat shape. Adapters translate outwards per vendor
|
|
52
|
+
* (e.g., OpenAI wraps in `{type: 'function', function: {...}}`).
|
|
53
|
+
*/
|
|
54
|
+
interface Tool {
|
|
55
|
+
name: string;
|
|
56
|
+
description: string;
|
|
57
|
+
/** JSON Schema for the tool's arguments. */
|
|
58
|
+
parameters: JsonSchema;
|
|
59
|
+
}
|
|
60
|
+
/** Minimal JSON Schema type — adapters and the library validate at the boundary. */
|
|
61
|
+
type JsonSchema = Record<string, unknown>;
|
|
62
|
+
interface PromptRequest {
|
|
63
|
+
model: string;
|
|
64
|
+
/**
|
|
65
|
+
* System prompt. The library always passes this as a top-level parameter;
|
|
66
|
+
* adapters place it per-vendor (top-level for Anthropic/Bedrock, config field
|
|
67
|
+
* for Google, prepended as a message for OpenAI, etc.).
|
|
68
|
+
*/
|
|
69
|
+
system?: string;
|
|
70
|
+
/** Conversation turns. Must NOT contain `role: 'system'` — use `system` above. */
|
|
71
|
+
messages: Message[];
|
|
72
|
+
tools?: Tool[];
|
|
73
|
+
temperature?: number;
|
|
74
|
+
maxTokens?: number;
|
|
75
|
+
/** Abort the stream. Adapters MUST honor this and propagate to the vendor SDK. */
|
|
76
|
+
signal?: AbortSignal;
|
|
77
|
+
}
|
|
78
|
+
type LlmEvent = {
|
|
79
|
+
type: 'token';
|
|
80
|
+
text: string;
|
|
81
|
+
} | {
|
|
82
|
+
type: 'toolCallStart';
|
|
83
|
+
id: string;
|
|
84
|
+
name: string;
|
|
85
|
+
} | {
|
|
86
|
+
type: 'toolCall';
|
|
87
|
+
id: string;
|
|
88
|
+
name: string;
|
|
89
|
+
arguments: unknown;
|
|
90
|
+
} | {
|
|
91
|
+
type: 'end';
|
|
92
|
+
finishReason: FinishReason;
|
|
93
|
+
usage?: Usage;
|
|
94
|
+
rawReason?: string;
|
|
95
|
+
};
|
|
96
|
+
type FinishReason = 'stop' | 'tool' | 'length' | 'filtered' | 'error' | 'aborted';
|
|
97
|
+
interface Usage {
|
|
98
|
+
inputTokens?: number;
|
|
99
|
+
outputTokens?: number;
|
|
100
|
+
totalTokens?: number;
|
|
101
|
+
}
|
|
102
|
+
type AuthSpec = ApiKeyAuth | BedrockIamAuth | BedrockApiKeyAuth | GoogleApiKeyAuth | GoogleServiceAccountAuth | VertexServiceAccountAuth;
|
|
103
|
+
interface ApiKeyAuth {
|
|
104
|
+
kind: 'apiKey';
|
|
105
|
+
apiKey: string;
|
|
106
|
+
baseURL?: string;
|
|
107
|
+
}
|
|
108
|
+
interface BedrockIamAuth {
|
|
109
|
+
kind: 'bedrockIam';
|
|
110
|
+
accessKeyId: string;
|
|
111
|
+
secretAccessKey: string;
|
|
112
|
+
sessionToken?: string;
|
|
113
|
+
region: string;
|
|
114
|
+
}
|
|
115
|
+
interface BedrockApiKeyAuth {
|
|
116
|
+
kind: 'bedrockApiKey';
|
|
117
|
+
apiKey: string;
|
|
118
|
+
region: string;
|
|
119
|
+
}
|
|
120
|
+
interface GoogleApiKeyAuth {
|
|
121
|
+
kind: 'googleApiKey';
|
|
122
|
+
apiKey: string;
|
|
123
|
+
}
|
|
124
|
+
interface GoogleServiceAccountAuth {
|
|
125
|
+
kind: 'googleServiceAccount';
|
|
126
|
+
/** Parsed JSON of the service account key file. */
|
|
127
|
+
credentials: ServiceAccountJson;
|
|
128
|
+
}
|
|
129
|
+
interface VertexServiceAccountAuth {
|
|
130
|
+
kind: 'vertexServiceAccount';
|
|
131
|
+
credentials: ServiceAccountJson;
|
|
132
|
+
projectId: string;
|
|
133
|
+
location: string;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Minimal shape of a Google service-account JSON. Kept loose intentionally —
|
|
137
|
+
* validation happens inside the Google Auth library, not here.
|
|
138
|
+
*/
|
|
139
|
+
interface ServiceAccountJson {
|
|
140
|
+
type: string;
|
|
141
|
+
project_id?: string;
|
|
142
|
+
private_key_id?: string;
|
|
143
|
+
private_key: string;
|
|
144
|
+
client_email: string;
|
|
145
|
+
client_id?: string;
|
|
146
|
+
[key: string]: unknown;
|
|
147
|
+
}
|
|
148
|
+
type AuthKind = AuthSpec['kind'];
|
|
149
|
+
interface ClientOptions {
|
|
150
|
+
timeout?: number;
|
|
151
|
+
maxRetries?: number;
|
|
152
|
+
/** Custom endpoint, e.g. Bedrock VPC endpoint. Adapter-specific meaning. */
|
|
153
|
+
endpoint?: string;
|
|
154
|
+
}
|
|
155
|
+
interface ModelInfo {
|
|
156
|
+
id: string;
|
|
157
|
+
displayName?: string;
|
|
158
|
+
capabilities: ModelCapabilities;
|
|
159
|
+
deprecated?: boolean;
|
|
160
|
+
}
|
|
161
|
+
interface ModelCapabilities {
|
|
162
|
+
/** Whether the model supports streaming responses. */
|
|
163
|
+
streaming: boolean;
|
|
164
|
+
/** Whether the model supports function/tool calling. NOT a vendor-wide flag. */
|
|
165
|
+
tools: boolean;
|
|
166
|
+
/** Whether the model accepts image inputs. */
|
|
167
|
+
vision: boolean;
|
|
168
|
+
/** Whether the model accepts a system prompt (a few Gemini models do not). */
|
|
169
|
+
systemPrompt: boolean;
|
|
170
|
+
/** Maximum input context in tokens, if known. */
|
|
171
|
+
maxContextTokens?: number;
|
|
172
|
+
}
|
|
173
|
+
interface AdapterManifest {
|
|
174
|
+
/** Machine-readable vendor id (matches the `vendor` field in createLlm args). */
|
|
175
|
+
vendor: string;
|
|
176
|
+
/** Human-readable vendor name shown in the admin UI. */
|
|
177
|
+
displayName: string;
|
|
178
|
+
/** One or more accepted auth shapes. Webapp renders a toggle when length > 1. */
|
|
179
|
+
authKinds: AuthKindSchema[];
|
|
180
|
+
/** Curated list of known models for this vendor. Safe to ship in the manifest. */
|
|
181
|
+
knownModels: ModelInfo[];
|
|
182
|
+
/** Whether listAvailableModels() hits a live vendor endpoint. */
|
|
183
|
+
supportsModelListing: boolean;
|
|
184
|
+
/** Optional documentation link for this vendor. */
|
|
185
|
+
docsUrl?: string;
|
|
186
|
+
}
|
|
187
|
+
interface AuthKindSchema {
|
|
188
|
+
kind: AuthKind;
|
|
189
|
+
displayName: string;
|
|
190
|
+
fields: FormField[];
|
|
191
|
+
}
|
|
192
|
+
type FormFieldType = 'text' | 'password' | 'url' | 'json-file' | 'select';
|
|
193
|
+
interface FormField {
|
|
194
|
+
name: string;
|
|
195
|
+
label: string;
|
|
196
|
+
type: FormFieldType;
|
|
197
|
+
required: boolean;
|
|
198
|
+
default?: string;
|
|
199
|
+
/** Options for `type: 'select'`. Ignored for other types. */
|
|
200
|
+
options?: {
|
|
201
|
+
value: string;
|
|
202
|
+
label: string;
|
|
203
|
+
}[];
|
|
204
|
+
/** Hint text shown below the input. */
|
|
205
|
+
help?: string;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* The interface every vendor adapter implements.
|
|
209
|
+
*
|
|
210
|
+
* An adapter is a class (or class-like object) that:
|
|
211
|
+
* 1. Declares which auth kinds it accepts (`acceptedAuth`).
|
|
212
|
+
* 2. Initializes a client from an `AuthSpec` (`init`).
|
|
213
|
+
* 3. Streams a prompt as an AsyncIterable of `LlmEvent`s (`stream`).
|
|
214
|
+
* 4. Appends a tool result to history in the vendor's native shape (`appendToolResult`).
|
|
215
|
+
* 5. Lists models accessible to the credential (`listAvailableModels`).
|
|
216
|
+
*
|
|
217
|
+
* The `manifest` is exported as a module-level constant alongside the adapter.
|
|
218
|
+
* See src/adapters/_template/ for a working skeleton.
|
|
219
|
+
*/
|
|
220
|
+
interface LlmAdapter<A extends AuthSpec = AuthSpec> {
|
|
221
|
+
/** Machine-readable vendor id. Must match `manifest.vendor`. */
|
|
222
|
+
readonly vendor: string;
|
|
223
|
+
/** The auth kinds this adapter accepts. Used by validators. */
|
|
224
|
+
readonly acceptedAuth: ReadonlyArray<A['kind']>;
|
|
225
|
+
/** One-time initialization with credentials. Called once per `createLlm` call. */
|
|
226
|
+
init(auth: A, client?: ClientOptions): Promise<void> | void;
|
|
227
|
+
/**
|
|
228
|
+
* Stream a prompt. Yields an AsyncIterable of events:
|
|
229
|
+
* - `token` (zero or more)
|
|
230
|
+
* - `toolCallStart` (optional, zero or more)
|
|
231
|
+
* - `toolCall` (zero or more, fully accumulated)
|
|
232
|
+
* - `end` (exactly one, and last)
|
|
233
|
+
*
|
|
234
|
+
* MUST honor `req.signal` if provided — if aborted, emit `{type: 'end', finishReason: 'aborted'}`
|
|
235
|
+
* and do not emit any pending `toolCall` events.
|
|
236
|
+
*/
|
|
237
|
+
stream(req: PromptRequest): AsyncIterable<LlmEvent>;
|
|
238
|
+
/**
|
|
239
|
+
* Append a tool-result message to history in the vendor's native shape.
|
|
240
|
+
* The returned array MUST be a valid `messages` input for a subsequent `stream()` call
|
|
241
|
+
* on the same adapter.
|
|
242
|
+
*/
|
|
243
|
+
appendToolResult(history: Message[], toolCallId: string, result: unknown): Message[];
|
|
244
|
+
/**
|
|
245
|
+
* Hit the vendor's list-models endpoint and return accessible models.
|
|
246
|
+
* Requires init() to have been called.
|
|
247
|
+
*
|
|
248
|
+
* If the vendor does not support live listing, adapters may return the static
|
|
249
|
+
* `knownModels` from the manifest — but `manifest.supportsModelListing` MUST be `false`
|
|
250
|
+
* in that case.
|
|
251
|
+
*/
|
|
252
|
+
listAvailableModels(): Promise<ModelInfo[]>;
|
|
253
|
+
/**
|
|
254
|
+
* Optional: pre-establish connection to the vendor API. Useful for reducing
|
|
255
|
+
* cold-start latency on the first prompt. No-op if not implemented.
|
|
256
|
+
*/
|
|
257
|
+
warmup?(): Promise<void>;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* The constructor/factory shape for an adapter. Registered at module load via
|
|
261
|
+
* `registerAdapter`. The library calls this once per `createLlm` call.
|
|
262
|
+
*/
|
|
263
|
+
interface AdapterFactory<A extends AuthSpec = AuthSpec> {
|
|
264
|
+
/** Machine-readable vendor id. */
|
|
265
|
+
readonly vendor: string;
|
|
266
|
+
/** Static manifest describing this vendor. */
|
|
267
|
+
readonly manifest: AdapterManifest;
|
|
268
|
+
/** Construct a fresh adapter instance. */
|
|
269
|
+
create(): LlmAdapter<A>;
|
|
270
|
+
}
|
|
271
|
+
interface CreateLlmArgs<A extends AuthSpec = AuthSpec> {
|
|
272
|
+
/** Vendor id. Must match a registered adapter. */
|
|
273
|
+
vendor: string;
|
|
274
|
+
/** Credentials in the shape the adapter declares it accepts. */
|
|
275
|
+
auth: A;
|
|
276
|
+
/** Optional transport knobs. */
|
|
277
|
+
client?: ClientOptions;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export type { AuthSpec as A, BedrockApiKeyAuth as B, CreateLlmArgs as C, FinishReason as F, GoogleApiKeyAuth as G, JsonSchema as J, LlmAdapter as L, Message as M, PromptRequest as P, Role as R, ServiceAccountJson as S, Tool as T, Usage as U, VertexServiceAccountAuth as V, AdapterFactory as a, AdapterManifest as b, ApiKeyAuth as c, AuthKind as d, AuthKindSchema as e, BedrockIamAuth as f, ClientOptions as g, ContentBlock as h, FormField as i, FormFieldType as j, GoogleServiceAccountAuth as k, LlmEvent as l, ModelCapabilities as m, ModelInfo as n };
|
package/package.json
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jambonz/llm",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Voice-oriented LLM adapter library — a uniform interface for streaming chat completions from multiple LLM vendors, with first-class support for tool calls, AbortSignal interruption, and lossless history round-tripping.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./test-kit": {
|
|
16
|
+
"types": "./dist/test-kit/index.d.ts",
|
|
17
|
+
"import": "./dist/test-kit/index.js",
|
|
18
|
+
"require": "./dist/test-kit/index.cjs"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=22"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup",
|
|
31
|
+
"lint": "eslint src test",
|
|
32
|
+
"lint:fix": "eslint src test --fix",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"test": "vitest run",
|
|
35
|
+
"test:watch": "vitest",
|
|
36
|
+
"test:coverage": "vitest run --coverage",
|
|
37
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
38
|
+
"prepublishOnly": "npm run lint && npm run typecheck && npm run test && npm run build"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"jambonz",
|
|
42
|
+
"llm",
|
|
43
|
+
"openai",
|
|
44
|
+
"anthropic",
|
|
45
|
+
"google",
|
|
46
|
+
"gemini",
|
|
47
|
+
"vertex",
|
|
48
|
+
"bedrock",
|
|
49
|
+
"streaming",
|
|
50
|
+
"tool-calling",
|
|
51
|
+
"voice-agent"
|
|
52
|
+
],
|
|
53
|
+
"author": "jambonz",
|
|
54
|
+
"license": "MIT",
|
|
55
|
+
"repository": {
|
|
56
|
+
"type": "git",
|
|
57
|
+
"url": "git+https://github.com/jambonz/llm.git"
|
|
58
|
+
},
|
|
59
|
+
"bugs": {
|
|
60
|
+
"url": "https://github.com/jambonz/llm/issues"
|
|
61
|
+
},
|
|
62
|
+
"homepage": "https://github.com/jambonz/llm#readme",
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"vitest": ">=3.0.0"
|
|
65
|
+
},
|
|
66
|
+
"peerDependenciesMeta": {
|
|
67
|
+
"vitest": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@eslint/js": "^9.17.0",
|
|
73
|
+
"@types/node": "^22.10.0",
|
|
74
|
+
"@vitest/coverage-v8": "^3.0.0",
|
|
75
|
+
"aws-sdk-client-mock": "^4.1.0",
|
|
76
|
+
"eslint": "^9.17.0",
|
|
77
|
+
"nock": "^13.5.6",
|
|
78
|
+
"tsup": "^8.3.5",
|
|
79
|
+
"tsx": "^4.19.2",
|
|
80
|
+
"typescript": "^5.7.2",
|
|
81
|
+
"typescript-eslint": "^8.18.0",
|
|
82
|
+
"vitest": "^3.0.0"
|
|
83
|
+
},
|
|
84
|
+
"dependencies": {
|
|
85
|
+
"@anthropic-ai/sdk": "^0.91.0",
|
|
86
|
+
"@aws-sdk/client-bedrock-runtime": "^3.1036.0",
|
|
87
|
+
"@google/genai": "^1.50.1",
|
|
88
|
+
"google-auth-library": "^10.6.2",
|
|
89
|
+
"openai": "^6.34.0"
|
|
90
|
+
}
|
|
91
|
+
}
|