@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/dist/index.cjs ADDED
@@ -0,0 +1,2194 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ assertValidRequest: () => assertValidRequest,
34
+ createLlm: () => createLlm,
35
+ getAdapterFactory: () => getAdapterFactory,
36
+ getManifest: () => getManifest,
37
+ listVendors: () => listVendors,
38
+ normalizeAuth: () => normalizeAuth,
39
+ registerAdapter: () => registerAdapter,
40
+ replaceAdapter: () => replaceAdapter,
41
+ unregisterAdapter: () => unregisterAdapter
42
+ });
43
+ module.exports = __toCommonJS(src_exports);
44
+
45
+ // src/registry.ts
46
+ var registry = /* @__PURE__ */ new Map();
47
+ function registerAdapter(factory) {
48
+ if (registry.has(factory.vendor)) {
49
+ throw new Error(
50
+ `Adapter already registered for vendor '${factory.vendor}'. Use replaceAdapter() if you intended to override.`
51
+ );
52
+ }
53
+ if (factory.vendor !== factory.manifest.vendor) {
54
+ throw new Error(
55
+ `Adapter factory vendor '${factory.vendor}' does not match manifest.vendor '${factory.manifest.vendor}'.`
56
+ );
57
+ }
58
+ registry.set(factory.vendor, factory);
59
+ }
60
+ function replaceAdapter(factory) {
61
+ registry.set(factory.vendor, factory);
62
+ }
63
+ function unregisterAdapter(vendor) {
64
+ registry.delete(vendor);
65
+ }
66
+ function getAdapterFactory(vendor) {
67
+ const factory = registry.get(vendor);
68
+ if (!factory) {
69
+ const known = Array.from(registry.keys()).sort().join(", ") || "(none)";
70
+ throw new Error(
71
+ `Unknown vendor '${vendor}'. Registered vendors: ${known}`
72
+ );
73
+ }
74
+ return factory;
75
+ }
76
+ function listVendors() {
77
+ return Array.from(registry.keys()).sort();
78
+ }
79
+ function getManifest() {
80
+ const vendors = Array.from(registry.values()).map((f) => f.manifest).sort((a, b) => a.vendor.localeCompare(b.vendor));
81
+ return { vendors };
82
+ }
83
+
84
+ // src/adapters/openai/adapter.ts
85
+ var import_openai = __toESM(require("openai"), 1);
86
+
87
+ // src/validate.ts
88
+ function assertValidRequest(req) {
89
+ if (!req || typeof req !== "object") {
90
+ throw new Error("PromptRequest must be an object");
91
+ }
92
+ if (typeof req.model !== "string" || req.model.length === 0) {
93
+ throw new Error("PromptRequest.model must be a non-empty string");
94
+ }
95
+ if (!Array.isArray(req.messages) || req.messages.length === 0) {
96
+ throw new Error("PromptRequest.messages must be a non-empty array");
97
+ }
98
+ if (req.messages.some((m) => m.role === "system")) {
99
+ throw new Error(
100
+ "PromptRequest.messages must not contain role: 'system'. Pass the system prompt via PromptRequest.system instead."
101
+ );
102
+ }
103
+ }
104
+
105
+ // src/adapters/openai/_streaming.ts
106
+ async function* streamFromOpenAI(client, req, options) {
107
+ assertValidRequest(req);
108
+ if (req.signal?.aborted) {
109
+ yield { type: "end", finishReason: "aborted" };
110
+ return;
111
+ }
112
+ const capabilities = capabilitiesFor(req.model, options.knownModels);
113
+ const useTools = req.tools && req.tools.length > 0 && capabilities.tools;
114
+ const messages = buildWireMessages(req);
115
+ const tools = useTools ? formatTools(req.tools) : void 0;
116
+ const body = {
117
+ model: req.model,
118
+ messages,
119
+ stream: true,
120
+ stream_options: { include_usage: true }
121
+ };
122
+ if (tools) {
123
+ body.tools = tools;
124
+ body.tool_choice = "auto";
125
+ }
126
+ if (req.temperature !== void 0) body.temperature = req.temperature;
127
+ if (req.maxTokens !== void 0) body.max_tokens = req.maxTokens;
128
+ let stream;
129
+ try {
130
+ stream = await client.chat.completions.create(body, { signal: req.signal });
131
+ } catch (err) {
132
+ if (isAbortError(err)) {
133
+ yield { type: "end", finishReason: "aborted" };
134
+ return;
135
+ }
136
+ throw err;
137
+ }
138
+ const pending = {};
139
+ const startedIds = /* @__PURE__ */ new Set();
140
+ const toolCallsEmitted = /* @__PURE__ */ new Set();
141
+ let usage;
142
+ let finalFinishReason = null;
143
+ let finalRawReason;
144
+ try {
145
+ for await (const chunk of stream) {
146
+ if (req.signal?.aborted) {
147
+ yield { type: "end", finishReason: "aborted" };
148
+ return;
149
+ }
150
+ if (chunk.usage) {
151
+ usage = {
152
+ ...chunk.usage.prompt_tokens !== void 0 ? { inputTokens: chunk.usage.prompt_tokens } : {},
153
+ ...chunk.usage.completion_tokens !== void 0 ? { outputTokens: chunk.usage.completion_tokens } : {},
154
+ ...chunk.usage.total_tokens !== void 0 ? { totalTokens: chunk.usage.total_tokens } : {}
155
+ };
156
+ }
157
+ const choice = chunk.choices?.[0];
158
+ if (!choice) continue;
159
+ const delta = choice.delta;
160
+ const finishReason = choice.finish_reason;
161
+ if (delta?.content) {
162
+ yield { type: "token", text: delta.content };
163
+ }
164
+ if (delta?.tool_calls) {
165
+ for (const tc of delta.tool_calls) {
166
+ const idx = tc.index;
167
+ if (!pending[idx]) {
168
+ pending[idx] = { id: "", name: "", arguments: "" };
169
+ }
170
+ if (tc.id) pending[idx].id += tc.id;
171
+ if (tc.function?.name) pending[idx].name += tc.function.name;
172
+ if (tc.function?.arguments) pending[idx].arguments += tc.function.arguments;
173
+ if (pending[idx].id && pending[idx].name && !startedIds.has(pending[idx].id)) {
174
+ startedIds.add(pending[idx].id);
175
+ yield {
176
+ type: "toolCallStart",
177
+ id: pending[idx].id,
178
+ name: pending[idx].name
179
+ };
180
+ }
181
+ }
182
+ }
183
+ if (finishReason === "tool_calls") {
184
+ if (req.signal?.aborted) {
185
+ yield { type: "end", finishReason: "aborted" };
186
+ return;
187
+ }
188
+ for (const tc of Object.values(pending)) {
189
+ if (!tc.id || !tc.name) continue;
190
+ if (toolCallsEmitted.has(tc.id)) continue;
191
+ toolCallsEmitted.add(tc.id);
192
+ let args = {};
193
+ try {
194
+ args = tc.arguments ? JSON.parse(tc.arguments) : {};
195
+ } catch {
196
+ args = {};
197
+ }
198
+ yield {
199
+ type: "toolCall",
200
+ id: tc.id,
201
+ name: tc.name,
202
+ arguments: args
203
+ };
204
+ }
205
+ finalFinishReason = "tool";
206
+ finalRawReason = finishReason;
207
+ } else if (finishReason) {
208
+ finalFinishReason = mapFinishReason(finishReason);
209
+ finalRawReason = finishReason;
210
+ }
211
+ }
212
+ } catch (err) {
213
+ if (isAbortError(err)) {
214
+ yield { type: "end", finishReason: "aborted" };
215
+ return;
216
+ }
217
+ throw err;
218
+ }
219
+ const endEvent = {
220
+ type: "end",
221
+ finishReason: finalFinishReason ?? "stop",
222
+ ...usage ? { usage } : {},
223
+ ...finalRawReason ? { rawReason: finalRawReason } : {}
224
+ };
225
+ yield endEvent;
226
+ }
227
+ function appendOpenAIToolResult(history, toolCallId, result) {
228
+ const content = typeof result === "string" ? result : JSON.stringify(result);
229
+ const wireMessage = {
230
+ role: "tool",
231
+ tool_call_id: toolCallId,
232
+ content
233
+ };
234
+ return [
235
+ ...history,
236
+ {
237
+ role: "tool",
238
+ content,
239
+ vendorRaw: wireMessage
240
+ }
241
+ ];
242
+ }
243
+ async function listOpenAICompatibleModels(client, knownModels) {
244
+ const result = await client.models.list();
245
+ const out = [];
246
+ for (const m of result.data) {
247
+ const known = knownModels.find((k) => k.id === m.id);
248
+ if (known) {
249
+ out.push(known);
250
+ } else {
251
+ out.push({
252
+ id: m.id,
253
+ capabilities: defaultCapabilitiesForUnknown(m.id)
254
+ });
255
+ }
256
+ }
257
+ return out;
258
+ }
259
+ function buildWireMessages(req) {
260
+ const out = [];
261
+ if (req.system) {
262
+ out.push({ role: "system", content: req.system });
263
+ }
264
+ for (const msg of req.messages) {
265
+ if (msg.vendorRaw && typeof msg.vendorRaw === "object") {
266
+ out.push(msg.vendorRaw);
267
+ } else {
268
+ out.push({ role: msg.role, content: msg.content });
269
+ }
270
+ }
271
+ return out;
272
+ }
273
+ function formatTools(tools) {
274
+ return tools.map((t) => ({
275
+ type: "function",
276
+ function: {
277
+ name: t.name,
278
+ description: t.description ?? "",
279
+ parameters: t.parameters ?? { type: "object", properties: {} }
280
+ }
281
+ }));
282
+ }
283
+ function capabilitiesFor(modelId, knownModels) {
284
+ const known = knownModels.find((k) => k.id === modelId);
285
+ if (known) return known.capabilities;
286
+ return defaultCapabilitiesForUnknown(modelId);
287
+ }
288
+ function defaultCapabilitiesForUnknown(modelId) {
289
+ const isReasoning = /^o[13]([-/]|$)/i.test(modelId);
290
+ if (isReasoning) {
291
+ return {
292
+ streaming: false,
293
+ tools: false,
294
+ vision: false,
295
+ systemPrompt: false
296
+ };
297
+ }
298
+ return {
299
+ streaming: true,
300
+ tools: true,
301
+ vision: false,
302
+ systemPrompt: true
303
+ };
304
+ }
305
+ function mapFinishReason(r) {
306
+ switch (r) {
307
+ case "stop":
308
+ return "stop";
309
+ case "tool_calls":
310
+ return "tool";
311
+ case "function_call":
312
+ return "tool";
313
+ case "length":
314
+ return "length";
315
+ case "content_filter":
316
+ return "filtered";
317
+ default:
318
+ return "stop";
319
+ }
320
+ }
321
+ function isAbortError(err) {
322
+ if (!err || typeof err !== "object") return false;
323
+ const e = err;
324
+ return e.name === "APIUserAbortError" || e.name === "AbortError" || e.code === "ABORT_ERR" || typeof e.message === "string" && /aborted/i.test(e.message);
325
+ }
326
+
327
+ // src/adapters/openai/manifest.ts
328
+ var OPENAI_KNOWN_MODELS = [
329
+ {
330
+ id: "gpt-4o",
331
+ displayName: "GPT-4o",
332
+ capabilities: {
333
+ streaming: true,
334
+ tools: true,
335
+ vision: true,
336
+ systemPrompt: true,
337
+ maxContextTokens: 128e3
338
+ }
339
+ },
340
+ {
341
+ id: "gpt-4o-mini",
342
+ displayName: "GPT-4o mini",
343
+ capabilities: {
344
+ streaming: true,
345
+ tools: true,
346
+ vision: true,
347
+ systemPrompt: true,
348
+ maxContextTokens: 128e3
349
+ }
350
+ },
351
+ {
352
+ id: "gpt-4-turbo",
353
+ displayName: "GPT-4 Turbo",
354
+ capabilities: {
355
+ streaming: true,
356
+ tools: true,
357
+ vision: true,
358
+ systemPrompt: true,
359
+ maxContextTokens: 128e3
360
+ }
361
+ },
362
+ {
363
+ id: "gpt-3.5-turbo",
364
+ displayName: "GPT-3.5 Turbo",
365
+ capabilities: {
366
+ streaming: true,
367
+ tools: true,
368
+ vision: false,
369
+ systemPrompt: true,
370
+ maxContextTokens: 16385
371
+ }
372
+ },
373
+ {
374
+ id: "o1-preview",
375
+ displayName: "o1 preview (reasoning)",
376
+ capabilities: {
377
+ streaming: false,
378
+ tools: false,
379
+ vision: false,
380
+ systemPrompt: false,
381
+ maxContextTokens: 128e3
382
+ }
383
+ },
384
+ {
385
+ id: "o1-mini",
386
+ displayName: "o1 mini (reasoning)",
387
+ capabilities: {
388
+ streaming: false,
389
+ tools: false,
390
+ vision: false,
391
+ systemPrompt: false,
392
+ maxContextTokens: 128e3
393
+ }
394
+ }
395
+ ];
396
+ var openAIManifest = {
397
+ vendor: "openai",
398
+ displayName: "OpenAI",
399
+ authKinds: [
400
+ {
401
+ kind: "apiKey",
402
+ displayName: "API Key",
403
+ fields: [
404
+ {
405
+ name: "apiKey",
406
+ label: "API Key",
407
+ type: "password",
408
+ required: true,
409
+ help: "Get an API key from https://platform.openai.com/api-keys"
410
+ },
411
+ {
412
+ name: "baseURL",
413
+ label: "Base URL",
414
+ type: "url",
415
+ required: false,
416
+ default: "https://api.openai.com/v1",
417
+ help: "Override for OpenAI-compatible endpoints (LM Studio, Ollama, vLLM, proxies)."
418
+ }
419
+ ]
420
+ }
421
+ ],
422
+ knownModels: OPENAI_KNOWN_MODELS,
423
+ supportsModelListing: true,
424
+ docsUrl: "https://platform.openai.com/docs/api-reference"
425
+ };
426
+
427
+ // src/adapters/openai/adapter.ts
428
+ var OpenAIAdapter = class {
429
+ vendor = openAIManifest.vendor;
430
+ acceptedAuth = ["apiKey"];
431
+ client;
432
+ init(auth, client) {
433
+ if (!auth.apiKey) {
434
+ throw new Error("OpenAIAdapter: apiKey is required");
435
+ }
436
+ this.client = new import_openai.default({
437
+ apiKey: auth.apiKey,
438
+ ...auth.baseURL ? { baseURL: auth.baseURL } : {},
439
+ ...client?.timeout !== void 0 ? { timeout: client.timeout } : {},
440
+ ...client?.maxRetries !== void 0 ? { maxRetries: client.maxRetries } : {}
441
+ });
442
+ }
443
+ stream(req) {
444
+ return streamFromOpenAI(this.ensureClient(), req, {
445
+ knownModels: openAIManifest.knownModels
446
+ });
447
+ }
448
+ appendToolResult(history, toolCallId, result) {
449
+ return appendOpenAIToolResult(history, toolCallId, result);
450
+ }
451
+ async listAvailableModels() {
452
+ return listOpenAICompatibleModels(this.ensureClient(), openAIManifest.knownModels);
453
+ }
454
+ async warmup() {
455
+ const client = this.ensureClient();
456
+ await client.models.list().catch(() => void 0);
457
+ }
458
+ ensureClient() {
459
+ if (!this.client) {
460
+ throw new Error("OpenAIAdapter: init() must be called before stream()/listAvailableModels()");
461
+ }
462
+ return this.client;
463
+ }
464
+ };
465
+
466
+ // src/adapters/openai/factory.ts
467
+ var openAIFactory = {
468
+ vendor: openAIManifest.vendor,
469
+ manifest: openAIManifest,
470
+ create: () => new OpenAIAdapter()
471
+ };
472
+ var deepseekManifest = {
473
+ vendor: "deepseek",
474
+ displayName: "DeepSeek",
475
+ authKinds: [
476
+ {
477
+ kind: "apiKey",
478
+ displayName: "API Key",
479
+ fields: [
480
+ {
481
+ name: "apiKey",
482
+ label: "API Key",
483
+ type: "password",
484
+ required: true,
485
+ help: "Get an API key from https://platform.deepseek.com/api_keys"
486
+ },
487
+ {
488
+ name: "baseURL",
489
+ label: "Base URL",
490
+ type: "url",
491
+ required: false,
492
+ default: "https://api.deepseek.com/v1",
493
+ help: "Override for self-hosted DeepSeek or proxy endpoints."
494
+ }
495
+ ]
496
+ }
497
+ ],
498
+ knownModels: [
499
+ {
500
+ id: "deepseek-chat",
501
+ displayName: "DeepSeek Chat",
502
+ capabilities: {
503
+ streaming: true,
504
+ tools: true,
505
+ vision: false,
506
+ systemPrompt: true,
507
+ maxContextTokens: 64e3
508
+ }
509
+ },
510
+ {
511
+ id: "deepseek-reasoner",
512
+ displayName: "DeepSeek Reasoner",
513
+ capabilities: {
514
+ streaming: true,
515
+ tools: false,
516
+ vision: false,
517
+ systemPrompt: true,
518
+ maxContextTokens: 64e3
519
+ }
520
+ }
521
+ ],
522
+ supportsModelListing: true,
523
+ docsUrl: "https://api-docs.deepseek.com/"
524
+ };
525
+ var DeepSeekAdapter = class extends OpenAIAdapter {
526
+ vendor = deepseekManifest.vendor;
527
+ init(auth, client) {
528
+ super.init(
529
+ {
530
+ ...auth,
531
+ baseURL: auth.baseURL ?? "https://api.deepseek.com/v1"
532
+ },
533
+ client
534
+ );
535
+ }
536
+ };
537
+ var deepseekFactory = {
538
+ vendor: deepseekManifest.vendor,
539
+ manifest: deepseekManifest,
540
+ create: () => new DeepSeekAdapter()
541
+ };
542
+
543
+ // src/adapters/anthropic/adapter.ts
544
+ var import_sdk = __toESM(require("@anthropic-ai/sdk"), 1);
545
+
546
+ // src/adapters/anthropic/manifest.ts
547
+ var ANTHROPIC_KNOWN_MODELS = [
548
+ {
549
+ id: "claude-opus-4-7",
550
+ displayName: "Claude Opus 4.7",
551
+ capabilities: {
552
+ streaming: true,
553
+ tools: true,
554
+ vision: true,
555
+ systemPrompt: true,
556
+ maxContextTokens: 2e5
557
+ }
558
+ },
559
+ {
560
+ id: "claude-sonnet-4-6",
561
+ displayName: "Claude Sonnet 4.6",
562
+ capabilities: {
563
+ streaming: true,
564
+ tools: true,
565
+ vision: true,
566
+ systemPrompt: true,
567
+ maxContextTokens: 2e5
568
+ }
569
+ },
570
+ {
571
+ id: "claude-haiku-4-5-20251001",
572
+ displayName: "Claude Haiku 4.5",
573
+ capabilities: {
574
+ streaming: true,
575
+ tools: true,
576
+ vision: true,
577
+ systemPrompt: true,
578
+ maxContextTokens: 2e5
579
+ }
580
+ },
581
+ {
582
+ id: "claude-3-7-sonnet-20250219",
583
+ displayName: "Claude 3.7 Sonnet",
584
+ capabilities: {
585
+ streaming: true,
586
+ tools: true,
587
+ vision: true,
588
+ systemPrompt: true,
589
+ maxContextTokens: 2e5
590
+ }
591
+ },
592
+ {
593
+ id: "claude-3-5-sonnet-20241022",
594
+ displayName: "Claude 3.5 Sonnet",
595
+ capabilities: {
596
+ streaming: true,
597
+ tools: true,
598
+ vision: true,
599
+ systemPrompt: true,
600
+ maxContextTokens: 2e5
601
+ }
602
+ },
603
+ {
604
+ id: "claude-3-5-haiku-20241022",
605
+ displayName: "Claude 3.5 Haiku",
606
+ capabilities: {
607
+ streaming: true,
608
+ tools: true,
609
+ vision: false,
610
+ systemPrompt: true,
611
+ maxContextTokens: 2e5
612
+ }
613
+ }
614
+ ];
615
+ var anthropicManifest = {
616
+ vendor: "anthropic",
617
+ displayName: "Anthropic Claude",
618
+ authKinds: [
619
+ {
620
+ kind: "apiKey",
621
+ displayName: "API Key",
622
+ fields: [
623
+ {
624
+ name: "apiKey",
625
+ label: "API Key",
626
+ type: "password",
627
+ required: true,
628
+ help: "Get an API key from https://console.anthropic.com/settings/keys"
629
+ },
630
+ {
631
+ name: "baseURL",
632
+ label: "Base URL",
633
+ type: "url",
634
+ required: false,
635
+ default: "https://api.anthropic.com",
636
+ help: "Override for proxies or enterprise deployments."
637
+ }
638
+ ]
639
+ }
640
+ ],
641
+ knownModels: ANTHROPIC_KNOWN_MODELS,
642
+ supportsModelListing: true,
643
+ docsUrl: "https://docs.anthropic.com/en/api/overview"
644
+ };
645
+
646
+ // src/adapters/anthropic/adapter.ts
647
+ var AnthropicAdapter = class {
648
+ vendor = anthropicManifest.vendor;
649
+ acceptedAuth = ["apiKey"];
650
+ client;
651
+ init(auth, client) {
652
+ if (!auth.apiKey) {
653
+ throw new Error("AnthropicAdapter: apiKey is required");
654
+ }
655
+ this.client = new import_sdk.default({
656
+ apiKey: auth.apiKey,
657
+ ...auth.baseURL ? { baseURL: auth.baseURL } : {},
658
+ ...client?.timeout !== void 0 ? { timeout: client.timeout } : {},
659
+ ...client?.maxRetries !== void 0 ? { maxRetries: client.maxRetries } : {}
660
+ });
661
+ }
662
+ async *stream(req) {
663
+ assertValidRequest(req);
664
+ const client = this.ensureClient();
665
+ if (req.signal?.aborted) {
666
+ yield { type: "end", finishReason: "aborted" };
667
+ return;
668
+ }
669
+ const messages = buildWireMessages2(req);
670
+ const tools = req.tools && req.tools.length > 0 ? formatTools2(req.tools) : void 0;
671
+ const body = {
672
+ model: req.model,
673
+ messages,
674
+ max_tokens: req.maxTokens ?? 4096,
675
+ stream: true
676
+ };
677
+ if (req.system) body.system = req.system;
678
+ if (tools) body.tools = tools;
679
+ if (req.temperature !== void 0) body.temperature = req.temperature;
680
+ let stream;
681
+ try {
682
+ stream = await client.messages.create(
683
+ body,
684
+ { signal: req.signal }
685
+ );
686
+ } catch (err) {
687
+ if (isAbortError2(err)) {
688
+ yield { type: "end", finishReason: "aborted" };
689
+ return;
690
+ }
691
+ throw err;
692
+ }
693
+ let currentToolUse = null;
694
+ const completedToolCalls = [];
695
+ let stopReason;
696
+ let inputTokens;
697
+ let outputTokens;
698
+ try {
699
+ for await (const event of stream) {
700
+ if (req.signal?.aborted) {
701
+ yield { type: "end", finishReason: "aborted" };
702
+ return;
703
+ }
704
+ switch (event.type) {
705
+ case "message_start":
706
+ inputTokens = event.message?.usage?.input_tokens;
707
+ break;
708
+ case "content_block_start": {
709
+ const block = event.content_block;
710
+ if (block?.type === "tool_use") {
711
+ currentToolUse = {
712
+ id: block.id ?? "",
713
+ name: block.name ?? "",
714
+ argumentsText: ""
715
+ };
716
+ if (currentToolUse.id && currentToolUse.name) {
717
+ yield {
718
+ type: "toolCallStart",
719
+ id: currentToolUse.id,
720
+ name: currentToolUse.name
721
+ };
722
+ }
723
+ }
724
+ break;
725
+ }
726
+ case "content_block_delta": {
727
+ const delta = event.delta;
728
+ if (delta?.type === "text_delta" && delta.text) {
729
+ yield { type: "token", text: delta.text };
730
+ } else if (delta?.type === "input_json_delta" && currentToolUse && delta.partial_json) {
731
+ currentToolUse.argumentsText += delta.partial_json;
732
+ }
733
+ break;
734
+ }
735
+ case "content_block_stop":
736
+ if (currentToolUse && currentToolUse.id && currentToolUse.name) {
737
+ let parsed = {};
738
+ try {
739
+ parsed = currentToolUse.argumentsText ? JSON.parse(currentToolUse.argumentsText) : {};
740
+ } catch {
741
+ parsed = {};
742
+ }
743
+ completedToolCalls.push({
744
+ id: currentToolUse.id,
745
+ name: currentToolUse.name,
746
+ arguments: parsed
747
+ });
748
+ }
749
+ currentToolUse = null;
750
+ break;
751
+ case "message_delta":
752
+ if (event.delta?.stop_reason) {
753
+ stopReason = event.delta.stop_reason;
754
+ }
755
+ if (event.usage?.output_tokens !== void 0) {
756
+ outputTokens = event.usage.output_tokens;
757
+ }
758
+ break;
759
+ case "message_stop":
760
+ break;
761
+ default:
762
+ break;
763
+ }
764
+ }
765
+ } catch (err) {
766
+ if (isAbortError2(err)) {
767
+ yield { type: "end", finishReason: "aborted" };
768
+ return;
769
+ }
770
+ throw err;
771
+ }
772
+ if (req.signal?.aborted) {
773
+ yield { type: "end", finishReason: "aborted" };
774
+ return;
775
+ }
776
+ for (const tc of completedToolCalls) {
777
+ yield {
778
+ type: "toolCall",
779
+ id: tc.id,
780
+ name: tc.name,
781
+ arguments: tc.arguments
782
+ };
783
+ }
784
+ const finishReason = mapStopReason(stopReason, completedToolCalls.length > 0);
785
+ const usage = inputTokens !== void 0 || outputTokens !== void 0 ? {
786
+ ...inputTokens !== void 0 ? { inputTokens } : {},
787
+ ...outputTokens !== void 0 ? { outputTokens } : {},
788
+ ...inputTokens !== void 0 && outputTokens !== void 0 ? { totalTokens: inputTokens + outputTokens } : {}
789
+ } : void 0;
790
+ const endEvent = {
791
+ type: "end",
792
+ finishReason,
793
+ ...usage ? { usage } : {},
794
+ ...stopReason ? { rawReason: stopReason } : {}
795
+ };
796
+ yield endEvent;
797
+ }
798
+ appendToolResult(history, toolCallId, result) {
799
+ const content = typeof result === "string" ? result : JSON.stringify(result);
800
+ const wireMessage = {
801
+ role: "user",
802
+ content: [
803
+ {
804
+ type: "tool_result",
805
+ tool_use_id: toolCallId,
806
+ content
807
+ }
808
+ ]
809
+ };
810
+ return [
811
+ ...history,
812
+ {
813
+ role: "tool",
814
+ content,
815
+ vendorRaw: wireMessage
816
+ }
817
+ ];
818
+ }
819
+ async listAvailableModels() {
820
+ const client = this.ensureClient();
821
+ const result = await client.models.list();
822
+ const models = [];
823
+ for (const m of result.data) {
824
+ const known = anthropicManifest.knownModels.find((k) => k.id === m.id);
825
+ if (known) {
826
+ models.push(known);
827
+ } else {
828
+ models.push({
829
+ id: m.id,
830
+ displayName: m.display_name ?? void 0,
831
+ capabilities: defaultClaudeCapabilities()
832
+ });
833
+ }
834
+ }
835
+ return models;
836
+ }
837
+ async warmup() {
838
+ const client = this.ensureClient();
839
+ await client.models.list().catch(() => void 0);
840
+ }
841
+ ensureClient() {
842
+ if (!this.client) {
843
+ throw new Error("AnthropicAdapter: init() must be called before stream()/listAvailableModels()");
844
+ }
845
+ return this.client;
846
+ }
847
+ };
848
+ function buildWireMessages2(req) {
849
+ const out = [];
850
+ for (const msg of req.messages) {
851
+ if (msg.vendorRaw && typeof msg.vendorRaw === "object") {
852
+ out.push(msg.vendorRaw);
853
+ } else {
854
+ out.push({ role: msg.role, content: msg.content });
855
+ }
856
+ }
857
+ return out;
858
+ }
859
+ function formatTools2(tools) {
860
+ return tools.map((t) => ({
861
+ name: t.name,
862
+ description: t.description ?? "",
863
+ input_schema: t.parameters ?? { type: "object", properties: {} }
864
+ }));
865
+ }
866
+ function mapStopReason(r, hadToolCalls) {
867
+ if (hadToolCalls) return "tool";
868
+ switch (r) {
869
+ case "end_turn":
870
+ case "stop_sequence":
871
+ return "stop";
872
+ case "tool_use":
873
+ return "tool";
874
+ case "max_tokens":
875
+ return "length";
876
+ default:
877
+ return "stop";
878
+ }
879
+ }
880
+ function defaultClaudeCapabilities() {
881
+ return {
882
+ streaming: true,
883
+ tools: true,
884
+ vision: true,
885
+ systemPrompt: true
886
+ };
887
+ }
888
+ function isAbortError2(err) {
889
+ if (!err || typeof err !== "object") return false;
890
+ const e = err;
891
+ return e.name === "APIUserAbortError" || e.name === "AbortError" || e.code === "ABORT_ERR" || typeof e.message === "string" && /aborted/i.test(e.message);
892
+ }
893
+
894
+ // src/adapters/anthropic/factory.ts
895
+ var anthropicFactory = {
896
+ vendor: anthropicManifest.vendor,
897
+ manifest: anthropicManifest,
898
+ create: () => new AnthropicAdapter()
899
+ };
900
+
901
+ // src/adapters/google/adapter.ts
902
+ var import_genai = require("@google/genai");
903
+
904
+ // src/adapters/google/_streaming.ts
905
+ async function* streamFromGemini(client, req) {
906
+ assertValidRequest(req);
907
+ if (req.signal?.aborted) {
908
+ yield { type: "end", finishReason: "aborted" };
909
+ return;
910
+ }
911
+ const contents = buildWireContents(req);
912
+ const tools = req.tools && req.tools.length > 0 ? formatTools3(req.tools) : void 0;
913
+ const config = {};
914
+ if (req.system) {
915
+ config.systemInstruction = { parts: [{ text: req.system }] };
916
+ }
917
+ if (tools) config.tools = tools;
918
+ if (req.temperature !== void 0) config.temperature = req.temperature;
919
+ if (req.maxTokens !== void 0) config.maxOutputTokens = req.maxTokens;
920
+ if (req.signal) config.abortSignal = req.signal;
921
+ let stream;
922
+ try {
923
+ stream = await client.models.generateContentStream({
924
+ model: req.model,
925
+ contents,
926
+ config
927
+ });
928
+ } catch (err) {
929
+ if (isAbortError3(err)) {
930
+ yield { type: "end", finishReason: "aborted" };
931
+ return;
932
+ }
933
+ throw err;
934
+ }
935
+ const toolCallCounter = /* @__PURE__ */ new Map();
936
+ const completedToolCalls = [];
937
+ let stopReason;
938
+ let inputTokens;
939
+ let outputTokens;
940
+ let totalTokens;
941
+ try {
942
+ for await (const chunk of stream) {
943
+ if (req.signal?.aborted) {
944
+ yield { type: "end", finishReason: "aborted" };
945
+ return;
946
+ }
947
+ const usage2 = chunk.usageMetadata;
948
+ if (usage2) {
949
+ if (usage2.promptTokenCount !== void 0) inputTokens = usage2.promptTokenCount;
950
+ if (usage2.candidatesTokenCount !== void 0) outputTokens = usage2.candidatesTokenCount;
951
+ if (usage2.totalTokenCount !== void 0) totalTokens = usage2.totalTokenCount;
952
+ }
953
+ const candidate = chunk.candidates?.[0];
954
+ if (!candidate?.content?.parts) {
955
+ if (candidate?.finishReason) stopReason = candidate.finishReason;
956
+ continue;
957
+ }
958
+ for (const part of candidate.content.parts) {
959
+ if (typeof part.text === "string" && part.text.length > 0) {
960
+ yield { type: "token", text: part.text };
961
+ }
962
+ if (part.functionCall) {
963
+ const name = part.functionCall.name ?? "";
964
+ if (!name) continue;
965
+ const count = toolCallCounter.get(name) ?? 0;
966
+ toolCallCounter.set(name, count + 1);
967
+ const id = count === 0 ? name : `${name}#${count}`;
968
+ yield { type: "toolCallStart", id, name };
969
+ completedToolCalls.push({
970
+ id,
971
+ name,
972
+ arguments: part.functionCall.args ?? {}
973
+ });
974
+ }
975
+ }
976
+ if (candidate.finishReason) {
977
+ stopReason = candidate.finishReason;
978
+ }
979
+ }
980
+ } catch (err) {
981
+ if (isAbortError3(err)) {
982
+ yield { type: "end", finishReason: "aborted" };
983
+ return;
984
+ }
985
+ throw err;
986
+ }
987
+ if (req.signal?.aborted) {
988
+ yield { type: "end", finishReason: "aborted" };
989
+ return;
990
+ }
991
+ for (const tc of completedToolCalls) {
992
+ yield {
993
+ type: "toolCall",
994
+ id: tc.id,
995
+ name: tc.name,
996
+ arguments: tc.arguments
997
+ };
998
+ }
999
+ const finishReason = mapFinishReason2(stopReason, completedToolCalls.length > 0);
1000
+ const usage = inputTokens !== void 0 || outputTokens !== void 0 || totalTokens !== void 0 ? {
1001
+ ...inputTokens !== void 0 ? { inputTokens } : {},
1002
+ ...outputTokens !== void 0 ? { outputTokens } : {},
1003
+ ...totalTokens !== void 0 ? { totalTokens } : {}
1004
+ } : void 0;
1005
+ const endEvent = {
1006
+ type: "end",
1007
+ finishReason,
1008
+ ...usage ? { usage } : {},
1009
+ ...stopReason ? { rawReason: stopReason } : {}
1010
+ };
1011
+ yield endEvent;
1012
+ }
1013
+ function appendGeminiToolResult(history, toolCallId, result) {
1014
+ const name = parseToolName(toolCallId);
1015
+ const content = typeof result === "string" ? result : JSON.stringify(result);
1016
+ const wireMessage = {
1017
+ role: "user",
1018
+ parts: [
1019
+ {
1020
+ functionResponse: {
1021
+ name,
1022
+ response: { result: content }
1023
+ }
1024
+ }
1025
+ ]
1026
+ };
1027
+ return [
1028
+ ...history,
1029
+ {
1030
+ role: "tool",
1031
+ content,
1032
+ vendorRaw: wireMessage
1033
+ }
1034
+ ];
1035
+ }
1036
+ async function listGeminiModels(client, knownModels) {
1037
+ const out = [];
1038
+ const pager = await client.models.list();
1039
+ for await (const m of pager) {
1040
+ const id = stripModelPrefix(m.name ?? "");
1041
+ if (!id) continue;
1042
+ const known = knownModels.find((k) => k.id === id);
1043
+ if (known) {
1044
+ out.push(known);
1045
+ } else {
1046
+ out.push({
1047
+ id,
1048
+ displayName: m.displayName ?? void 0,
1049
+ capabilities: defaultGeminiCapabilities()
1050
+ });
1051
+ }
1052
+ }
1053
+ return out;
1054
+ }
1055
+ function buildWireContents(req) {
1056
+ const out = [];
1057
+ for (const msg of req.messages) {
1058
+ if (msg.vendorRaw && typeof msg.vendorRaw === "object") {
1059
+ out.push(msg.vendorRaw);
1060
+ continue;
1061
+ }
1062
+ const text = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
1063
+ out.push({
1064
+ role: toGeminiRole(msg.role),
1065
+ parts: [{ text }]
1066
+ });
1067
+ }
1068
+ return out;
1069
+ }
1070
+ function toGeminiRole(role) {
1071
+ return role === "assistant" || role === "model" ? "model" : "user";
1072
+ }
1073
+ function formatTools3(tools) {
1074
+ return [
1075
+ {
1076
+ functionDeclarations: tools.map((t) => ({
1077
+ name: t.name,
1078
+ description: t.description ?? "",
1079
+ parameters: t.parameters ?? { type: "object", properties: {} }
1080
+ }))
1081
+ }
1082
+ ];
1083
+ }
1084
+ function mapFinishReason2(r, hadToolCalls) {
1085
+ if (hadToolCalls && (r === "STOP" || r === "TOOL_CALLS" || !r)) return "tool";
1086
+ switch (r) {
1087
+ case "STOP":
1088
+ return "stop";
1089
+ case "MAX_TOKENS":
1090
+ return "length";
1091
+ case "SAFETY":
1092
+ case "RECITATION":
1093
+ return "filtered";
1094
+ case "TOOL_CALLS":
1095
+ return "tool";
1096
+ default:
1097
+ return "stop";
1098
+ }
1099
+ }
1100
+ function parseToolName(id) {
1101
+ const hashIdx = id.lastIndexOf("#");
1102
+ if (hashIdx === -1) return id;
1103
+ const suffix = id.slice(hashIdx + 1);
1104
+ if (/^\d+$/.test(suffix)) return id.slice(0, hashIdx);
1105
+ return id;
1106
+ }
1107
+ function stripModelPrefix(name) {
1108
+ return name.startsWith("models/") ? name.slice("models/".length) : name;
1109
+ }
1110
+ function defaultGeminiCapabilities() {
1111
+ return {
1112
+ streaming: true,
1113
+ tools: true,
1114
+ vision: true,
1115
+ systemPrompt: true
1116
+ };
1117
+ }
1118
+ function isAbortError3(err) {
1119
+ if (!err || typeof err !== "object") return false;
1120
+ const e = err;
1121
+ return e.name === "APIUserAbortError" || e.name === "AbortError" || e.code === "ABORT_ERR" || typeof e.message === "string" && /aborted/i.test(e.message);
1122
+ }
1123
+
1124
+ // src/adapters/google/manifest.ts
1125
+ var GOOGLE_KNOWN_MODELS = [
1126
+ {
1127
+ id: "gemini-2.5-pro",
1128
+ displayName: "Gemini 2.5 Pro",
1129
+ capabilities: {
1130
+ streaming: true,
1131
+ tools: true,
1132
+ vision: true,
1133
+ systemPrompt: true,
1134
+ maxContextTokens: 1e6
1135
+ }
1136
+ },
1137
+ {
1138
+ id: "gemini-2.5-flash",
1139
+ displayName: "Gemini 2.5 Flash",
1140
+ capabilities: {
1141
+ streaming: true,
1142
+ tools: true,
1143
+ vision: true,
1144
+ systemPrompt: true,
1145
+ maxContextTokens: 1e6
1146
+ }
1147
+ },
1148
+ {
1149
+ id: "gemini-2.0-flash",
1150
+ displayName: "Gemini 2.0 Flash",
1151
+ capabilities: {
1152
+ streaming: true,
1153
+ tools: true,
1154
+ vision: true,
1155
+ systemPrompt: true,
1156
+ maxContextTokens: 1e6
1157
+ }
1158
+ },
1159
+ {
1160
+ id: "gemini-2.0-flash-lite",
1161
+ displayName: "Gemini 2.0 Flash Lite",
1162
+ capabilities: {
1163
+ streaming: true,
1164
+ tools: true,
1165
+ vision: false,
1166
+ systemPrompt: true,
1167
+ maxContextTokens: 1e6
1168
+ }
1169
+ },
1170
+ {
1171
+ id: "gemini-1.5-pro",
1172
+ displayName: "Gemini 1.5 Pro",
1173
+ capabilities: {
1174
+ streaming: true,
1175
+ tools: true,
1176
+ vision: true,
1177
+ systemPrompt: true,
1178
+ maxContextTokens: 2e6
1179
+ }
1180
+ },
1181
+ {
1182
+ id: "gemini-1.5-flash",
1183
+ displayName: "Gemini 1.5 Flash",
1184
+ capabilities: {
1185
+ streaming: true,
1186
+ tools: true,
1187
+ vision: true,
1188
+ systemPrompt: true,
1189
+ maxContextTokens: 1e6
1190
+ }
1191
+ }
1192
+ ];
1193
+ var googleManifest = {
1194
+ vendor: "google",
1195
+ displayName: "Google Gemini",
1196
+ authKinds: [
1197
+ {
1198
+ kind: "googleApiKey",
1199
+ displayName: "API Key",
1200
+ fields: [
1201
+ {
1202
+ name: "apiKey",
1203
+ label: "API Key",
1204
+ type: "password",
1205
+ required: true,
1206
+ help: "Get an API key from https://aistudio.google.com/apikey"
1207
+ }
1208
+ ]
1209
+ }
1210
+ ],
1211
+ knownModels: GOOGLE_KNOWN_MODELS,
1212
+ supportsModelListing: true,
1213
+ docsUrl: "https://ai.google.dev/gemini-api/docs"
1214
+ };
1215
+
1216
+ // src/adapters/google/adapter.ts
1217
+ var GoogleAdapter = class {
1218
+ vendor = googleManifest.vendor;
1219
+ acceptedAuth = ["googleApiKey"];
1220
+ client;
1221
+ init(auth, _client) {
1222
+ if (auth.kind !== "googleApiKey") {
1223
+ throw new Error(
1224
+ `GoogleAdapter: unsupported auth kind '${auth.kind}'`
1225
+ );
1226
+ }
1227
+ if (!auth.apiKey) {
1228
+ throw new Error("GoogleAdapter: apiKey is required");
1229
+ }
1230
+ this.client = new import_genai.GoogleGenAI({ apiKey: auth.apiKey });
1231
+ }
1232
+ stream(req) {
1233
+ return streamFromGemini(this.ensureClient(), req);
1234
+ }
1235
+ appendToolResult(history, toolCallId, result) {
1236
+ return appendGeminiToolResult(history, toolCallId, result);
1237
+ }
1238
+ async listAvailableModels() {
1239
+ return listGeminiModels(this.ensureClient(), googleManifest.knownModels);
1240
+ }
1241
+ async warmup() {
1242
+ }
1243
+ ensureClient() {
1244
+ if (!this.client) {
1245
+ throw new Error("GoogleAdapter: init() must be called before stream()/listAvailableModels()");
1246
+ }
1247
+ return this.client;
1248
+ }
1249
+ };
1250
+
1251
+ // src/adapters/google/factory.ts
1252
+ var googleFactory = {
1253
+ vendor: googleManifest.vendor,
1254
+ manifest: googleManifest,
1255
+ create: () => new GoogleAdapter()
1256
+ };
1257
+
1258
+ // src/adapters/vertex-gemini/adapter.ts
1259
+ var import_genai2 = require("@google/genai");
1260
+
1261
+ // src/adapters/vertex-gemini/manifest.ts
1262
+ var VERTEX_GEMINI_KNOWN_MODELS = [
1263
+ {
1264
+ id: "gemini-2.5-pro",
1265
+ displayName: "Gemini 2.5 Pro",
1266
+ capabilities: {
1267
+ streaming: true,
1268
+ tools: true,
1269
+ vision: true,
1270
+ systemPrompt: true,
1271
+ maxContextTokens: 1e6
1272
+ }
1273
+ },
1274
+ {
1275
+ id: "gemini-2.5-flash",
1276
+ displayName: "Gemini 2.5 Flash",
1277
+ capabilities: {
1278
+ streaming: true,
1279
+ tools: true,
1280
+ vision: true,
1281
+ systemPrompt: true,
1282
+ maxContextTokens: 1e6
1283
+ }
1284
+ },
1285
+ {
1286
+ id: "gemini-2.0-flash",
1287
+ displayName: "Gemini 2.0 Flash",
1288
+ capabilities: {
1289
+ streaming: true,
1290
+ tools: true,
1291
+ vision: true,
1292
+ systemPrompt: true,
1293
+ maxContextTokens: 1e6
1294
+ }
1295
+ },
1296
+ {
1297
+ id: "gemini-1.5-pro",
1298
+ displayName: "Gemini 1.5 Pro",
1299
+ capabilities: {
1300
+ streaming: true,
1301
+ tools: true,
1302
+ vision: true,
1303
+ systemPrompt: true,
1304
+ maxContextTokens: 2e6
1305
+ }
1306
+ },
1307
+ {
1308
+ id: "gemini-1.5-flash",
1309
+ displayName: "Gemini 1.5 Flash",
1310
+ capabilities: {
1311
+ streaming: true,
1312
+ tools: true,
1313
+ vision: true,
1314
+ systemPrompt: true,
1315
+ maxContextTokens: 1e6
1316
+ }
1317
+ }
1318
+ ];
1319
+ var vertexGeminiManifest = {
1320
+ vendor: "vertex-gemini",
1321
+ displayName: "Vertex AI \u2014 Gemini",
1322
+ authKinds: [
1323
+ {
1324
+ kind: "vertexServiceAccount",
1325
+ displayName: "Service Account JSON",
1326
+ fields: [
1327
+ {
1328
+ name: "credentials",
1329
+ label: "Service Account Key (JSON)",
1330
+ type: "json-file",
1331
+ required: true,
1332
+ help: "Upload the service account key JSON from Google Cloud Console."
1333
+ },
1334
+ {
1335
+ name: "projectId",
1336
+ label: "Project ID",
1337
+ type: "text",
1338
+ required: true,
1339
+ help: "GCP project that hosts the Vertex AI deployment."
1340
+ },
1341
+ {
1342
+ name: "location",
1343
+ label: "Region",
1344
+ type: "select",
1345
+ required: true,
1346
+ default: "us-central1",
1347
+ options: [
1348
+ { value: "us-central1", label: "us-central1" },
1349
+ { value: "us-east1", label: "us-east1" },
1350
+ { value: "us-east4", label: "us-east4" },
1351
+ { value: "us-west1", label: "us-west1" },
1352
+ { value: "us-west4", label: "us-west4" },
1353
+ { value: "europe-west1", label: "europe-west1" },
1354
+ { value: "europe-west2", label: "europe-west2" },
1355
+ { value: "europe-west3", label: "europe-west3" },
1356
+ { value: "europe-west4", label: "europe-west4" },
1357
+ { value: "asia-east1", label: "asia-east1" },
1358
+ { value: "asia-northeast1", label: "asia-northeast1" },
1359
+ { value: "asia-southeast1", label: "asia-southeast1" }
1360
+ ]
1361
+ }
1362
+ ]
1363
+ }
1364
+ ],
1365
+ knownModels: VERTEX_GEMINI_KNOWN_MODELS,
1366
+ supportsModelListing: true,
1367
+ docsUrl: "https://cloud.google.com/vertex-ai/generative-ai/docs"
1368
+ };
1369
+
1370
+ // src/adapters/vertex-gemini/adapter.ts
1371
+ var VertexGeminiAdapter = class {
1372
+ vendor = vertexGeminiManifest.vendor;
1373
+ acceptedAuth = ["vertexServiceAccount"];
1374
+ client;
1375
+ init(auth, _client) {
1376
+ if (auth.kind !== "vertexServiceAccount") {
1377
+ throw new Error(
1378
+ `VertexGeminiAdapter: unsupported auth kind '${auth.kind}'`
1379
+ );
1380
+ }
1381
+ if (!auth.credentials) {
1382
+ throw new Error("VertexGeminiAdapter: service-account credentials are required");
1383
+ }
1384
+ if (!auth.projectId) {
1385
+ throw new Error("VertexGeminiAdapter: projectId is required");
1386
+ }
1387
+ if (!auth.location) {
1388
+ throw new Error("VertexGeminiAdapter: location is required");
1389
+ }
1390
+ this.client = new import_genai2.GoogleGenAI({
1391
+ vertexai: true,
1392
+ project: auth.projectId,
1393
+ location: auth.location,
1394
+ googleAuthOptions: {
1395
+ credentials: auth.credentials
1396
+ }
1397
+ });
1398
+ }
1399
+ stream(req) {
1400
+ return streamFromGemini(this.ensureClient(), req);
1401
+ }
1402
+ appendToolResult(history, toolCallId, result) {
1403
+ return appendGeminiToolResult(history, toolCallId, result);
1404
+ }
1405
+ async listAvailableModels() {
1406
+ return listGeminiModels(this.ensureClient(), vertexGeminiManifest.knownModels);
1407
+ }
1408
+ async warmup() {
1409
+ }
1410
+ ensureClient() {
1411
+ if (!this.client) {
1412
+ throw new Error(
1413
+ "VertexGeminiAdapter: init() must be called before stream()/listAvailableModels()"
1414
+ );
1415
+ }
1416
+ return this.client;
1417
+ }
1418
+ };
1419
+
1420
+ // src/adapters/vertex-gemini/factory.ts
1421
+ var vertexGeminiFactory = {
1422
+ vendor: vertexGeminiManifest.vendor,
1423
+ manifest: vertexGeminiManifest,
1424
+ create: () => new VertexGeminiAdapter()
1425
+ };
1426
+
1427
+ // src/adapters/vertex-openai/adapter.ts
1428
+ var import_openai2 = __toESM(require("openai"), 1);
1429
+ var import_google_auth_library = require("google-auth-library");
1430
+
1431
+ // src/adapters/vertex-openai/manifest.ts
1432
+ var VERTEX_OPENAI_KNOWN_MODELS = [
1433
+ {
1434
+ id: "mistral-large",
1435
+ displayName: "Mistral Large (on Vertex)",
1436
+ capabilities: {
1437
+ streaming: true,
1438
+ tools: true,
1439
+ vision: false,
1440
+ systemPrompt: true,
1441
+ maxContextTokens: 128e3
1442
+ }
1443
+ },
1444
+ {
1445
+ id: "mistral-small",
1446
+ displayName: "Mistral Small (on Vertex)",
1447
+ capabilities: {
1448
+ streaming: true,
1449
+ tools: true,
1450
+ vision: false,
1451
+ systemPrompt: true,
1452
+ maxContextTokens: 32e3
1453
+ }
1454
+ },
1455
+ {
1456
+ id: "meta/llama-3.3-70b-instruct-maas",
1457
+ displayName: "Llama 3.3 70B Instruct (on Vertex)",
1458
+ capabilities: {
1459
+ streaming: true,
1460
+ tools: true,
1461
+ vision: false,
1462
+ systemPrompt: true,
1463
+ maxContextTokens: 128e3
1464
+ }
1465
+ },
1466
+ {
1467
+ id: "meta/llama-3.1-405b-instruct-maas",
1468
+ displayName: "Llama 3.1 405B Instruct (on Vertex)",
1469
+ capabilities: {
1470
+ streaming: true,
1471
+ tools: true,
1472
+ vision: false,
1473
+ systemPrompt: true,
1474
+ maxContextTokens: 128e3
1475
+ }
1476
+ }
1477
+ ];
1478
+ var vertexOpenAIManifest = {
1479
+ vendor: "vertex-openai",
1480
+ displayName: "Vertex AI \u2014 OpenAI-compatible",
1481
+ authKinds: [
1482
+ {
1483
+ kind: "vertexServiceAccount",
1484
+ displayName: "Service Account JSON",
1485
+ fields: [
1486
+ {
1487
+ name: "credentials",
1488
+ label: "Service Account Key (JSON)",
1489
+ type: "json-file",
1490
+ required: true,
1491
+ help: "Upload the service account key JSON from Google Cloud Console."
1492
+ },
1493
+ {
1494
+ name: "projectId",
1495
+ label: "Project ID",
1496
+ type: "text",
1497
+ required: true,
1498
+ help: "GCP project that hosts the Vertex AI deployment."
1499
+ },
1500
+ {
1501
+ name: "location",
1502
+ label: "Region",
1503
+ type: "select",
1504
+ required: true,
1505
+ default: "us-central1",
1506
+ options: [
1507
+ { value: "us-central1", label: "us-central1" },
1508
+ { value: "us-east4", label: "us-east4" },
1509
+ { value: "europe-west1", label: "europe-west1" },
1510
+ { value: "europe-west4", label: "europe-west4" },
1511
+ { value: "asia-southeast1", label: "asia-southeast1" }
1512
+ ]
1513
+ }
1514
+ ]
1515
+ }
1516
+ ],
1517
+ knownModels: VERTEX_OPENAI_KNOWN_MODELS,
1518
+ // The OpenAI-compatible endpoint on Vertex does not expose a /models list.
1519
+ supportsModelListing: false,
1520
+ docsUrl: "https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-openai"
1521
+ };
1522
+
1523
+ // src/adapters/vertex-openai/adapter.ts
1524
+ var VertexOpenAIAdapter = class {
1525
+ vendor = vertexOpenAIManifest.vendor;
1526
+ acceptedAuth = ["vertexServiceAccount"];
1527
+ client;
1528
+ init(auth, client) {
1529
+ if (auth.kind !== "vertexServiceAccount") {
1530
+ throw new Error(
1531
+ `VertexOpenAIAdapter: unsupported auth kind '${auth.kind}'`
1532
+ );
1533
+ }
1534
+ if (!auth.credentials) {
1535
+ throw new Error("VertexOpenAIAdapter: service-account credentials are required");
1536
+ }
1537
+ if (!auth.projectId) {
1538
+ throw new Error("VertexOpenAIAdapter: projectId is required");
1539
+ }
1540
+ if (!auth.location) {
1541
+ throw new Error("VertexOpenAIAdapter: location is required");
1542
+ }
1543
+ const baseURL = `https://${auth.location}-aiplatform.googleapis.com/v1/projects/${auth.projectId}/locations/${auth.location}/endpoints/openapi`;
1544
+ const googleAuth = new import_google_auth_library.GoogleAuth({
1545
+ credentials: auth.credentials,
1546
+ scopes: ["https://www.googleapis.com/auth/cloud-platform"]
1547
+ });
1548
+ const authedFetch = async (input, init) => {
1549
+ const googleClient = await googleAuth.getClient();
1550
+ const token = await googleClient.getAccessToken();
1551
+ const headers = new Headers(init?.headers);
1552
+ headers.set("Authorization", `Bearer ${token.token ?? ""}`);
1553
+ return fetch(input, { ...init, headers });
1554
+ };
1555
+ this.client = new import_openai2.default({
1556
+ apiKey: "vertex-ai",
1557
+ baseURL,
1558
+ fetch: authedFetch,
1559
+ ...client?.timeout !== void 0 ? { timeout: client.timeout } : {},
1560
+ ...client?.maxRetries !== void 0 ? { maxRetries: client.maxRetries } : {}
1561
+ });
1562
+ }
1563
+ stream(req) {
1564
+ return streamFromOpenAI(this.ensureClient(), req, {
1565
+ knownModels: vertexOpenAIManifest.knownModels
1566
+ });
1567
+ }
1568
+ appendToolResult(history, toolCallId, result) {
1569
+ return appendOpenAIToolResult(history, toolCallId, result);
1570
+ }
1571
+ async listAvailableModels() {
1572
+ return [...vertexOpenAIManifest.knownModels];
1573
+ }
1574
+ async warmup() {
1575
+ }
1576
+ ensureClient() {
1577
+ if (!this.client) {
1578
+ throw new Error(
1579
+ "VertexOpenAIAdapter: init() must be called before stream()/listAvailableModels()"
1580
+ );
1581
+ }
1582
+ return this.client;
1583
+ }
1584
+ };
1585
+
1586
+ // src/adapters/vertex-openai/factory.ts
1587
+ var vertexOpenAIFactory = {
1588
+ vendor: vertexOpenAIManifest.vendor,
1589
+ manifest: vertexOpenAIManifest,
1590
+ create: () => new VertexOpenAIAdapter()
1591
+ };
1592
+
1593
+ // src/adapters/bedrock/adapter.ts
1594
+ var import_client_bedrock_runtime = require("@aws-sdk/client-bedrock-runtime");
1595
+
1596
+ // src/adapters/bedrock/manifest.ts
1597
+ var BEDROCK_KNOWN_MODELS = [
1598
+ {
1599
+ id: "anthropic.claude-opus-4-v1:0",
1600
+ displayName: "Claude Opus 4 (on Bedrock)",
1601
+ capabilities: {
1602
+ streaming: true,
1603
+ tools: true,
1604
+ vision: true,
1605
+ systemPrompt: true,
1606
+ maxContextTokens: 2e5
1607
+ }
1608
+ },
1609
+ {
1610
+ id: "anthropic.claude-sonnet-4-v1:0",
1611
+ displayName: "Claude Sonnet 4 (on Bedrock)",
1612
+ capabilities: {
1613
+ streaming: true,
1614
+ tools: true,
1615
+ vision: true,
1616
+ systemPrompt: true,
1617
+ maxContextTokens: 2e5
1618
+ }
1619
+ },
1620
+ {
1621
+ id: "anthropic.claude-3-7-sonnet-20250219-v1:0",
1622
+ displayName: "Claude 3.7 Sonnet (on Bedrock)",
1623
+ capabilities: {
1624
+ streaming: true,
1625
+ tools: true,
1626
+ vision: true,
1627
+ systemPrompt: true,
1628
+ maxContextTokens: 2e5
1629
+ }
1630
+ },
1631
+ {
1632
+ id: "anthropic.claude-3-5-sonnet-20241022-v2:0",
1633
+ displayName: "Claude 3.5 Sonnet v2 (on Bedrock)",
1634
+ capabilities: {
1635
+ streaming: true,
1636
+ tools: true,
1637
+ vision: true,
1638
+ systemPrompt: true,
1639
+ maxContextTokens: 2e5
1640
+ }
1641
+ },
1642
+ {
1643
+ id: "anthropic.claude-3-5-haiku-20241022-v1:0",
1644
+ displayName: "Claude 3.5 Haiku (on Bedrock)",
1645
+ capabilities: {
1646
+ streaming: true,
1647
+ tools: true,
1648
+ vision: false,
1649
+ systemPrompt: true,
1650
+ maxContextTokens: 2e5
1651
+ }
1652
+ },
1653
+ {
1654
+ id: "meta.llama3-3-70b-instruct-v1:0",
1655
+ displayName: "Llama 3.3 70B Instruct (on Bedrock)",
1656
+ capabilities: {
1657
+ streaming: true,
1658
+ tools: true,
1659
+ vision: false,
1660
+ systemPrompt: true,
1661
+ maxContextTokens: 128e3
1662
+ }
1663
+ },
1664
+ {
1665
+ id: "mistral.mistral-large-2407-v1:0",
1666
+ displayName: "Mistral Large (on Bedrock)",
1667
+ capabilities: {
1668
+ streaming: true,
1669
+ tools: true,
1670
+ vision: false,
1671
+ systemPrompt: true,
1672
+ maxContextTokens: 128e3
1673
+ }
1674
+ },
1675
+ {
1676
+ id: "amazon.nova-pro-v1:0",
1677
+ displayName: "Amazon Nova Pro",
1678
+ capabilities: {
1679
+ streaming: true,
1680
+ tools: true,
1681
+ vision: true,
1682
+ systemPrompt: true,
1683
+ maxContextTokens: 3e5
1684
+ }
1685
+ },
1686
+ {
1687
+ id: "amazon.nova-lite-v1:0",
1688
+ displayName: "Amazon Nova Lite",
1689
+ capabilities: {
1690
+ streaming: true,
1691
+ tools: true,
1692
+ vision: true,
1693
+ systemPrompt: true,
1694
+ maxContextTokens: 3e5
1695
+ }
1696
+ },
1697
+ {
1698
+ id: "amazon.nova-micro-v1:0",
1699
+ displayName: "Amazon Nova Micro",
1700
+ capabilities: {
1701
+ streaming: true,
1702
+ tools: true,
1703
+ vision: false,
1704
+ systemPrompt: true,
1705
+ maxContextTokens: 128e3
1706
+ }
1707
+ }
1708
+ ];
1709
+ var BEDROCK_REGIONS = [
1710
+ { value: "us-east-1", label: "us-east-1 (N. Virginia)" },
1711
+ { value: "us-east-2", label: "us-east-2 (Ohio)" },
1712
+ { value: "us-west-2", label: "us-west-2 (Oregon)" },
1713
+ { value: "eu-west-1", label: "eu-west-1 (Ireland)" },
1714
+ { value: "eu-west-3", label: "eu-west-3 (Paris)" },
1715
+ { value: "eu-central-1", label: "eu-central-1 (Frankfurt)" },
1716
+ { value: "ap-northeast-1", label: "ap-northeast-1 (Tokyo)" },
1717
+ { value: "ap-south-1", label: "ap-south-1 (Mumbai)" },
1718
+ { value: "ap-southeast-1", label: "ap-southeast-1 (Singapore)" },
1719
+ { value: "ap-southeast-2", label: "ap-southeast-2 (Sydney)" },
1720
+ { value: "ca-central-1", label: "ca-central-1 (Canada)" }
1721
+ ];
1722
+ var bedrockManifest = {
1723
+ vendor: "bedrock",
1724
+ displayName: "AWS Bedrock",
1725
+ authKinds: [
1726
+ {
1727
+ kind: "bedrockApiKey",
1728
+ displayName: "API Key",
1729
+ fields: [
1730
+ {
1731
+ name: "apiKey",
1732
+ label: "API Key",
1733
+ type: "password",
1734
+ required: true,
1735
+ help: "Bedrock API key (bearer token). Create one in the AWS console under Amazon Bedrock \u2192 API keys."
1736
+ },
1737
+ {
1738
+ name: "region",
1739
+ label: "Region",
1740
+ type: "select",
1741
+ required: true,
1742
+ default: "us-east-1",
1743
+ options: BEDROCK_REGIONS
1744
+ }
1745
+ ]
1746
+ },
1747
+ {
1748
+ kind: "bedrockIam",
1749
+ displayName: "IAM Credentials",
1750
+ fields: [
1751
+ {
1752
+ name: "accessKeyId",
1753
+ label: "Access Key ID",
1754
+ type: "text",
1755
+ required: true
1756
+ },
1757
+ {
1758
+ name: "secretAccessKey",
1759
+ label: "Secret Access Key",
1760
+ type: "password",
1761
+ required: true
1762
+ },
1763
+ {
1764
+ name: "sessionToken",
1765
+ label: "Session Token",
1766
+ type: "password",
1767
+ required: false,
1768
+ help: "Only required when using temporary credentials (e.g., STS)."
1769
+ },
1770
+ {
1771
+ name: "region",
1772
+ label: "Region",
1773
+ type: "select",
1774
+ required: true,
1775
+ default: "us-east-1",
1776
+ options: BEDROCK_REGIONS
1777
+ }
1778
+ ]
1779
+ }
1780
+ ],
1781
+ knownModels: BEDROCK_KNOWN_MODELS,
1782
+ // The Bedrock runtime client does not expose a `/models` listing — model
1783
+ // enumeration lives in `@aws-sdk/client-bedrock` (control plane), which we
1784
+ // don't pull in. Return the curated set from the manifest.
1785
+ supportsModelListing: false,
1786
+ docsUrl: "https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference.html"
1787
+ };
1788
+
1789
+ // src/adapters/bedrock/adapter.ts
1790
+ var BedrockAdapter = class {
1791
+ vendor = bedrockManifest.vendor;
1792
+ acceptedAuth = ["bedrockApiKey", "bedrockIam"];
1793
+ client;
1794
+ init(auth, client) {
1795
+ if (!auth.region) {
1796
+ throw new Error("BedrockAdapter: region is required");
1797
+ }
1798
+ const config = {
1799
+ region: auth.region,
1800
+ ...client?.endpoint ? { endpoint: client.endpoint } : {},
1801
+ ...client?.maxRetries !== void 0 ? { maxAttempts: client.maxRetries + 1 } : {}
1802
+ };
1803
+ if (auth.kind === "bedrockApiKey") {
1804
+ if (!auth.apiKey) {
1805
+ throw new Error("BedrockAdapter: apiKey is required for bedrockApiKey auth");
1806
+ }
1807
+ config.token = { token: auth.apiKey };
1808
+ config.authSchemePreference = ["httpBearerAuth"];
1809
+ } else if (auth.kind === "bedrockIam") {
1810
+ if (!auth.accessKeyId || !auth.secretAccessKey) {
1811
+ throw new Error("BedrockAdapter: accessKeyId and secretAccessKey required for bedrockIam auth");
1812
+ }
1813
+ config.credentials = {
1814
+ accessKeyId: auth.accessKeyId,
1815
+ secretAccessKey: auth.secretAccessKey,
1816
+ ...auth.sessionToken ? { sessionToken: auth.sessionToken } : {}
1817
+ };
1818
+ } else {
1819
+ throw new Error(
1820
+ `BedrockAdapter: unsupported auth kind '${auth.kind}'`
1821
+ );
1822
+ }
1823
+ this.client = new import_client_bedrock_runtime.BedrockRuntimeClient(config);
1824
+ }
1825
+ async *stream(req) {
1826
+ assertValidRequest(req);
1827
+ const client = this.ensureClient();
1828
+ if (req.signal?.aborted) {
1829
+ yield { type: "end", finishReason: "aborted" };
1830
+ return;
1831
+ }
1832
+ const messages = buildWireMessages3(req);
1833
+ const tools = req.tools && req.tools.length > 0 ? { tools: formatTools4(req.tools) } : void 0;
1834
+ const inferenceConfig = {};
1835
+ if (req.maxTokens !== void 0) inferenceConfig.maxTokens = req.maxTokens;
1836
+ if (req.temperature !== void 0) inferenceConfig.temperature = req.temperature;
1837
+ const commandInput = {
1838
+ modelId: req.model,
1839
+ messages
1840
+ };
1841
+ if (req.system) commandInput.system = [{ text: req.system }];
1842
+ if (tools) commandInput.toolConfig = tools;
1843
+ if (Object.keys(inferenceConfig).length > 0) {
1844
+ commandInput.inferenceConfig = inferenceConfig;
1845
+ }
1846
+ const command = new import_client_bedrock_runtime.ConverseStreamCommand(
1847
+ commandInput
1848
+ );
1849
+ let response;
1850
+ try {
1851
+ response = await client.send(command, { abortSignal: req.signal });
1852
+ } catch (err) {
1853
+ if (isAbortError4(err)) {
1854
+ yield { type: "end", finishReason: "aborted" };
1855
+ return;
1856
+ }
1857
+ throw err;
1858
+ }
1859
+ if (!response.stream) {
1860
+ yield { type: "end", finishReason: "stop" };
1861
+ return;
1862
+ }
1863
+ let currentToolUse = null;
1864
+ const completedToolCalls = [];
1865
+ let stopReason;
1866
+ let inputTokens;
1867
+ let outputTokens;
1868
+ let totalTokens;
1869
+ try {
1870
+ for await (const event of response.stream) {
1871
+ if (req.signal?.aborted) {
1872
+ yield { type: "end", finishReason: "aborted" };
1873
+ return;
1874
+ }
1875
+ if (event.contentBlockStart) {
1876
+ const start = event.contentBlockStart.start;
1877
+ if (start?.toolUse) {
1878
+ currentToolUse = {
1879
+ id: start.toolUse.toolUseId ?? "",
1880
+ name: start.toolUse.name ?? "",
1881
+ inputText: ""
1882
+ };
1883
+ if (currentToolUse.id && currentToolUse.name) {
1884
+ yield {
1885
+ type: "toolCallStart",
1886
+ id: currentToolUse.id,
1887
+ name: currentToolUse.name
1888
+ };
1889
+ }
1890
+ }
1891
+ } else if (event.contentBlockDelta) {
1892
+ const delta = event.contentBlockDelta.delta;
1893
+ if (delta?.text) {
1894
+ yield { type: "token", text: delta.text };
1895
+ }
1896
+ if (delta?.toolUse && currentToolUse && typeof delta.toolUse.input === "string") {
1897
+ currentToolUse.inputText += delta.toolUse.input;
1898
+ }
1899
+ } else if (event.contentBlockStop) {
1900
+ if (currentToolUse && currentToolUse.id && currentToolUse.name) {
1901
+ let parsed = {};
1902
+ try {
1903
+ parsed = currentToolUse.inputText ? JSON.parse(currentToolUse.inputText) : {};
1904
+ } catch {
1905
+ parsed = {};
1906
+ }
1907
+ completedToolCalls.push({
1908
+ id: currentToolUse.id,
1909
+ name: currentToolUse.name,
1910
+ arguments: parsed
1911
+ });
1912
+ }
1913
+ currentToolUse = null;
1914
+ } else if (event.messageStop) {
1915
+ stopReason = event.messageStop.stopReason;
1916
+ } else if (event.metadata) {
1917
+ if (event.metadata.usage) {
1918
+ inputTokens = event.metadata.usage.inputTokens;
1919
+ outputTokens = event.metadata.usage.outputTokens;
1920
+ totalTokens = event.metadata.usage.totalTokens;
1921
+ }
1922
+ }
1923
+ }
1924
+ } catch (err) {
1925
+ if (isAbortError4(err)) {
1926
+ yield { type: "end", finishReason: "aborted" };
1927
+ return;
1928
+ }
1929
+ throw err;
1930
+ }
1931
+ if (req.signal?.aborted) {
1932
+ yield { type: "end", finishReason: "aborted" };
1933
+ return;
1934
+ }
1935
+ for (const tc of completedToolCalls) {
1936
+ yield {
1937
+ type: "toolCall",
1938
+ id: tc.id,
1939
+ name: tc.name,
1940
+ arguments: tc.arguments
1941
+ };
1942
+ }
1943
+ const finishReason = mapStopReason2(stopReason, completedToolCalls.length > 0);
1944
+ const usage = inputTokens !== void 0 || outputTokens !== void 0 || totalTokens !== void 0 ? {
1945
+ ...inputTokens !== void 0 ? { inputTokens } : {},
1946
+ ...outputTokens !== void 0 ? { outputTokens } : {},
1947
+ ...totalTokens !== void 0 ? { totalTokens } : {}
1948
+ } : void 0;
1949
+ const endEvent = {
1950
+ type: "end",
1951
+ finishReason,
1952
+ ...usage ? { usage } : {},
1953
+ ...stopReason ? { rawReason: stopReason } : {}
1954
+ };
1955
+ yield endEvent;
1956
+ }
1957
+ appendToolResult(history, toolCallId, result) {
1958
+ const text = typeof result === "string" ? result : JSON.stringify(result);
1959
+ const wireMessage = {
1960
+ role: "user",
1961
+ content: [
1962
+ {
1963
+ toolResult: {
1964
+ toolUseId: toolCallId,
1965
+ content: [{ text }]
1966
+ }
1967
+ }
1968
+ ]
1969
+ };
1970
+ return [
1971
+ ...history,
1972
+ {
1973
+ role: "tool",
1974
+ content: text,
1975
+ vendorRaw: wireMessage
1976
+ }
1977
+ ];
1978
+ }
1979
+ async listAvailableModels() {
1980
+ return [...bedrockManifest.knownModels];
1981
+ }
1982
+ async warmup() {
1983
+ }
1984
+ ensureClient() {
1985
+ if (!this.client) {
1986
+ throw new Error(
1987
+ "BedrockAdapter: init() must be called before stream()/listAvailableModels()"
1988
+ );
1989
+ }
1990
+ return this.client;
1991
+ }
1992
+ };
1993
+ function buildWireMessages3(req) {
1994
+ const out = [];
1995
+ for (const msg of req.messages) {
1996
+ if (msg.vendorRaw && typeof msg.vendorRaw === "object") {
1997
+ out.push(msg.vendorRaw);
1998
+ continue;
1999
+ }
2000
+ const text = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
2001
+ const role = msg.role === "tool" ? "user" : msg.role;
2002
+ out.push({
2003
+ role,
2004
+ content: [{ text }]
2005
+ });
2006
+ }
2007
+ return out;
2008
+ }
2009
+ function formatTools4(tools) {
2010
+ return tools.map((t) => ({
2011
+ toolSpec: {
2012
+ name: t.name,
2013
+ // Bedrock rejects empty-string descriptions; fall back to a single space.
2014
+ description: t.description && t.description.length > 0 ? t.description : " ",
2015
+ inputSchema: {
2016
+ json: t.parameters ?? { type: "object", properties: {} }
2017
+ }
2018
+ }
2019
+ }));
2020
+ }
2021
+ function mapStopReason2(r, hadToolCalls) {
2022
+ if (hadToolCalls) return "tool";
2023
+ switch (r) {
2024
+ case "end_turn":
2025
+ case "stop_sequence":
2026
+ return "stop";
2027
+ case "tool_use":
2028
+ return "tool";
2029
+ case "max_tokens":
2030
+ return "length";
2031
+ case "content_filtered":
2032
+ case "guardrail_intervened":
2033
+ return "filtered";
2034
+ default:
2035
+ return "stop";
2036
+ }
2037
+ }
2038
+ function isAbortError4(err) {
2039
+ if (!err || typeof err !== "object") return false;
2040
+ const e = err;
2041
+ return e.name === "AbortError" || e.name === "APIUserAbortError" || e.code === "ABORT_ERR" || typeof e.message === "string" && /aborted/i.test(e.message);
2042
+ }
2043
+
2044
+ // src/adapters/bedrock/factory.ts
2045
+ var bedrockFactory = {
2046
+ vendor: bedrockManifest.vendor,
2047
+ manifest: bedrockManifest,
2048
+ create: () => new BedrockAdapter()
2049
+ };
2050
+
2051
+ // src/adapters/index.ts
2052
+ registerAdapter(openAIFactory);
2053
+ registerAdapter(deepseekFactory);
2054
+ registerAdapter(anthropicFactory);
2055
+ registerAdapter(googleFactory);
2056
+ registerAdapter(vertexGeminiFactory);
2057
+ registerAdapter(vertexOpenAIFactory);
2058
+ registerAdapter(bedrockFactory);
2059
+
2060
+ // src/normalize-auth.ts
2061
+ function normalizeAuth(vendor, raw) {
2062
+ switch (vendor) {
2063
+ case "openai":
2064
+ case "anthropic":
2065
+ return requireApiKey(vendor, raw);
2066
+ case "deepseek":
2067
+ return {
2068
+ ...requireApiKey(vendor, raw),
2069
+ baseURL: raw.api_url ?? "https://api.deepseek.com/v1"
2070
+ };
2071
+ case "google":
2072
+ return normalizeGoogle(raw);
2073
+ case "vertex":
2074
+ case "vertex-gemini":
2075
+ case "vertex-openai":
2076
+ return normalizeVertex(vendor, raw);
2077
+ case "bedrock":
2078
+ return normalizeBedrock(raw);
2079
+ default:
2080
+ throw new Error(
2081
+ `normalizeAuth: unknown vendor '${vendor}'. If this is a custom adapter, construct the AuthSpec directly.`
2082
+ );
2083
+ }
2084
+ }
2085
+ function requireApiKey(vendor, raw) {
2086
+ if (!raw.api_key) {
2087
+ throw new Error(`normalizeAuth: vendor '${vendor}' requires 'api_key'`);
2088
+ }
2089
+ const result = {
2090
+ kind: "apiKey",
2091
+ apiKey: raw.api_key
2092
+ };
2093
+ if (raw.api_url) {
2094
+ result.baseURL = raw.api_url;
2095
+ }
2096
+ return result;
2097
+ }
2098
+ function normalizeGoogle(raw) {
2099
+ if (raw.service_key) {
2100
+ return {
2101
+ kind: "googleServiceAccount",
2102
+ credentials: parseServiceKey(raw.service_key)
2103
+ };
2104
+ }
2105
+ if (raw.api_key) {
2106
+ return { kind: "googleApiKey", apiKey: raw.api_key };
2107
+ }
2108
+ throw new Error(`normalizeAuth: vendor 'google' requires either 'api_key' or 'service_key'`);
2109
+ }
2110
+ function normalizeVertex(vendor, raw) {
2111
+ if (!raw.service_key) {
2112
+ throw new Error(`normalizeAuth: vendor '${vendor}' requires 'service_key'`);
2113
+ }
2114
+ if (!raw.location) {
2115
+ throw new Error(`normalizeAuth: vendor '${vendor}' requires 'location'`);
2116
+ }
2117
+ const credentials = parseServiceKey(raw.service_key);
2118
+ const projectId = raw.project_id ?? credentials.project_id;
2119
+ if (!projectId) {
2120
+ throw new Error(
2121
+ `normalizeAuth: vendor '${vendor}' requires 'project_id' (not present in raw credential or service_key.project_id)`
2122
+ );
2123
+ }
2124
+ return {
2125
+ kind: "vertexServiceAccount",
2126
+ credentials,
2127
+ projectId,
2128
+ location: raw.location
2129
+ };
2130
+ }
2131
+ function normalizeBedrock(raw) {
2132
+ if (!raw.region) {
2133
+ throw new Error(`normalizeAuth: vendor 'bedrock' requires 'region'`);
2134
+ }
2135
+ if (raw.access_key_id && raw.secret_access_key) {
2136
+ const result = {
2137
+ kind: "bedrockIam",
2138
+ accessKeyId: raw.access_key_id,
2139
+ secretAccessKey: raw.secret_access_key,
2140
+ region: raw.region
2141
+ };
2142
+ if (raw.session_token) {
2143
+ result.sessionToken = raw.session_token;
2144
+ }
2145
+ return result;
2146
+ }
2147
+ if (raw.api_key) {
2148
+ return {
2149
+ kind: "bedrockApiKey",
2150
+ apiKey: raw.api_key,
2151
+ region: raw.region
2152
+ };
2153
+ }
2154
+ throw new Error(
2155
+ `normalizeAuth: vendor 'bedrock' requires either (access_key_id + secret_access_key) or api_key`
2156
+ );
2157
+ }
2158
+ function parseServiceKey(value) {
2159
+ if (typeof value === "string") {
2160
+ try {
2161
+ return JSON.parse(value);
2162
+ } catch {
2163
+ throw new Error(`normalizeAuth: 'service_key' is not valid JSON`);
2164
+ }
2165
+ }
2166
+ return value;
2167
+ }
2168
+
2169
+ // src/index.ts
2170
+ async function createLlm(args) {
2171
+ const factory = getAdapterFactory(args.vendor);
2172
+ if (!factory.manifest.authKinds.some((k) => k.kind === args.auth.kind)) {
2173
+ const accepted = factory.manifest.authKinds.map((k) => k.kind).join(", ");
2174
+ throw new Error(
2175
+ `Vendor '${args.vendor}' does not accept auth kind '${args.auth.kind}'. Accepted kinds: ${accepted}`
2176
+ );
2177
+ }
2178
+ const instance = factory.create();
2179
+ await Promise.resolve(instance.init(args.auth, args.client));
2180
+ return instance;
2181
+ }
2182
+ // Annotate the CommonJS export names for ESM import in node:
2183
+ 0 && (module.exports = {
2184
+ assertValidRequest,
2185
+ createLlm,
2186
+ getAdapterFactory,
2187
+ getManifest,
2188
+ listVendors,
2189
+ normalizeAuth,
2190
+ registerAdapter,
2191
+ replaceAdapter,
2192
+ unregisterAdapter
2193
+ });
2194
+ //# sourceMappingURL=index.cjs.map