@oai2lmapi/opencode-provider 0.3.11 → 0.3.12

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.js CHANGED
@@ -2157,6 +2157,1031 @@ function wrapWithEnhancements(baseModel, modelId, override) {
2157
2157
  return baseModel;
2158
2158
  }
2159
2159
 
2160
+ // src/clients/geminiClient.ts
2161
+ var idCounter2 = 0;
2162
+ function generateId2() {
2163
+ return `gemini_${Date.now()}_${++idCounter2}`;
2164
+ }
2165
+ function normalizeGeminiEndpoint(endpoint) {
2166
+ let normalized = endpoint.replace(/\/+$/, "");
2167
+ if (normalized.endsWith("/v1")) {
2168
+ normalized = normalized.slice(0, -3);
2169
+ }
2170
+ return normalized;
2171
+ }
2172
+ function convertMessagesToGemini(messages) {
2173
+ const contents = [];
2174
+ let systemInstruction;
2175
+ for (const message of messages) {
2176
+ if (message.role === "system") {
2177
+ systemInstruction = (systemInstruction || "") + message.content;
2178
+ } else if (message.role === "user") {
2179
+ const parts = [];
2180
+ for (const part of message.content) {
2181
+ if (part.type === "text") {
2182
+ parts.push({ text: part.text });
2183
+ } else if (part.type === "file") {
2184
+ const filePart = part;
2185
+ if (filePart.mediaType.startsWith("image/")) {
2186
+ if (typeof filePart.data === "string") {
2187
+ if (filePart.data.startsWith("data:")) {
2188
+ const match = filePart.data.match(/^data:([^;]+);base64,(.+)$/);
2189
+ if (match) {
2190
+ parts.push({
2191
+ inlineData: {
2192
+ mimeType: match[1],
2193
+ data: match[2]
2194
+ }
2195
+ });
2196
+ }
2197
+ } else if (filePart.data.startsWith("http")) {
2198
+ parts.push({ text: `[Image URL: ${filePart.data}]` });
2199
+ } else {
2200
+ parts.push({
2201
+ inlineData: {
2202
+ mimeType: filePart.mediaType,
2203
+ data: filePart.data
2204
+ }
2205
+ });
2206
+ }
2207
+ } else if (filePart.data instanceof URL) {
2208
+ parts.push({ text: `[Image URL: ${filePart.data.toString()}]` });
2209
+ } else if (filePart.data instanceof Uint8Array) {
2210
+ const base64 = Buffer.from(filePart.data).toString("base64");
2211
+ parts.push({
2212
+ inlineData: {
2213
+ mimeType: filePart.mediaType,
2214
+ data: base64
2215
+ }
2216
+ });
2217
+ }
2218
+ }
2219
+ }
2220
+ }
2221
+ if (parts.length > 0) {
2222
+ contents.push({ role: "user", parts });
2223
+ }
2224
+ } else if (message.role === "assistant") {
2225
+ const parts = [];
2226
+ for (const part of message.content) {
2227
+ if (part.type === "text") {
2228
+ parts.push({ text: part.text });
2229
+ } else if (part.type === "tool-call") {
2230
+ const input = part.input;
2231
+ parts.push({
2232
+ functionCall: {
2233
+ name: part.toolName,
2234
+ args: input
2235
+ }
2236
+ });
2237
+ }
2238
+ }
2239
+ if (parts.length > 0) {
2240
+ contents.push({ role: "model", parts });
2241
+ }
2242
+ } else if (message.role === "tool") {
2243
+ const parts = [];
2244
+ for (const part of message.content) {
2245
+ if (part.type === "tool-result") {
2246
+ let response;
2247
+ const output = part.output;
2248
+ if (output.type === "text" || output.type === "error-text") {
2249
+ response = { result: output.value };
2250
+ } else if (output.type === "json" || output.type === "error-json") {
2251
+ response = typeof output.value === "object" && output.value !== null ? output.value : { result: output.value };
2252
+ } else if (output.type === "content") {
2253
+ const text = output.value.map(
2254
+ (c) => c.type === "text" ? c.text : "[media]"
2255
+ ).join("\n");
2256
+ response = { result: text };
2257
+ } else {
2258
+ response = { result: String(output) };
2259
+ }
2260
+ parts.push({
2261
+ functionResponse: {
2262
+ name: part.toolName,
2263
+ response
2264
+ }
2265
+ });
2266
+ }
2267
+ }
2268
+ if (parts.length > 0) {
2269
+ contents.push({ role: "user", parts });
2270
+ }
2271
+ }
2272
+ }
2273
+ return { contents, systemInstruction };
2274
+ }
2275
+ function convertToolsToGemini(tools) {
2276
+ if (!tools || tools.length === 0) {
2277
+ return void 0;
2278
+ }
2279
+ return tools.map((tool) => ({
2280
+ name: tool.name,
2281
+ description: tool.description,
2282
+ parameters: tool.inputSchema
2283
+ }));
2284
+ }
2285
+ function mapFinishReason(geminiReason) {
2286
+ switch (geminiReason) {
2287
+ case "STOP":
2288
+ return "stop";
2289
+ case "MAX_TOKENS":
2290
+ return "length";
2291
+ case "SAFETY":
2292
+ case "RECITATION":
2293
+ case "OTHER":
2294
+ return "content-filter";
2295
+ case "FUNCTION_CALL":
2296
+ return "tool-calls";
2297
+ default:
2298
+ return "stop";
2299
+ }
2300
+ }
2301
+ var GeminiClient = class {
2302
+ baseURL;
2303
+ apiKey;
2304
+ headers;
2305
+ constructor(config) {
2306
+ this.baseURL = normalizeGeminiEndpoint(config.baseURL);
2307
+ this.apiKey = config.apiKey;
2308
+ this.headers = config.headers || {};
2309
+ }
2310
+ /**
2311
+ * Generate content (non-streaming)
2312
+ */
2313
+ async doGenerate(modelId, options) {
2314
+ const { contents, systemInstruction } = convertMessagesToGemini(
2315
+ options.prompt
2316
+ );
2317
+ const tools = convertToolsToGemini(
2318
+ options.tools?.filter(
2319
+ (t) => t.type === "function"
2320
+ )
2321
+ );
2322
+ const modelPath = modelId.startsWith("models/") ? modelId : `models/${modelId}`;
2323
+ const url = `${this.baseURL}/v1beta/${modelPath}:generateContent`;
2324
+ const request = { contents };
2325
+ if (systemInstruction) {
2326
+ request.systemInstruction = { parts: [{ text: systemInstruction }] };
2327
+ }
2328
+ if (tools && tools.length > 0) {
2329
+ request.tools = [{ functionDeclarations: tools }];
2330
+ request.toolConfig = {
2331
+ functionCallingConfig: {
2332
+ mode: options.toolChoice?.type === "required" ? "ANY" : options.toolChoice?.type === "none" ? "NONE" : "AUTO"
2333
+ }
2334
+ };
2335
+ }
2336
+ const generationConfig = {};
2337
+ if (options.maxOutputTokens) {
2338
+ generationConfig.maxOutputTokens = options.maxOutputTokens;
2339
+ }
2340
+ if (options.temperature !== void 0) {
2341
+ generationConfig.temperature = options.temperature;
2342
+ }
2343
+ if (options.topP !== void 0) {
2344
+ generationConfig.topP = options.topP;
2345
+ }
2346
+ if (options.topK !== void 0) {
2347
+ generationConfig.topK = options.topK;
2348
+ }
2349
+ if (options.stopSequences && options.stopSequences.length > 0) {
2350
+ generationConfig.stopSequences = options.stopSequences;
2351
+ }
2352
+ if (Object.keys(generationConfig).length > 0) {
2353
+ request.generationConfig = generationConfig;
2354
+ }
2355
+ const response = await fetch(url, {
2356
+ method: "POST",
2357
+ headers: {
2358
+ "Content-Type": "application/json",
2359
+ "X-Goog-Api-Key": this.apiKey,
2360
+ ...this.headers
2361
+ },
2362
+ body: JSON.stringify(request),
2363
+ signal: options.abortSignal
2364
+ });
2365
+ if (!response.ok) {
2366
+ const errorText = await response.text();
2367
+ throw new Error(
2368
+ `Gemini API error: ${response.status} ${response.statusText} - ${errorText}`
2369
+ );
2370
+ }
2371
+ const data = await response.json();
2372
+ const candidate = data.candidates?.[0];
2373
+ const parts = candidate?.content?.parts || [];
2374
+ const content = [];
2375
+ for (const part of parts) {
2376
+ if (part.thought && part.text) {
2377
+ content.push({ type: "reasoning", text: part.text });
2378
+ } else if (part.text) {
2379
+ content.push({ type: "text", text: part.text });
2380
+ } else if (part.functionCall) {
2381
+ content.push({
2382
+ type: "tool-call",
2383
+ toolCallId: generateId2(),
2384
+ toolName: part.functionCall.name,
2385
+ input: JSON.stringify(part.functionCall.args)
2386
+ });
2387
+ }
2388
+ }
2389
+ return {
2390
+ content,
2391
+ finishReason: mapFinishReason(candidate?.finishReason),
2392
+ usage: {
2393
+ inputTokens: data.usageMetadata?.promptTokenCount,
2394
+ outputTokens: data.usageMetadata?.candidatesTokenCount
2395
+ }
2396
+ };
2397
+ }
2398
+ /**
2399
+ * Stream content generation
2400
+ */
2401
+ async doStream(modelId, options) {
2402
+ const { contents, systemInstruction } = convertMessagesToGemini(
2403
+ options.prompt
2404
+ );
2405
+ const tools = convertToolsToGemini(
2406
+ options.tools?.filter(
2407
+ (t) => t.type === "function"
2408
+ )
2409
+ );
2410
+ const modelPath = modelId.startsWith("models/") ? modelId : `models/${modelId}`;
2411
+ const url = `${this.baseURL}/v1beta/${modelPath}:streamGenerateContent?alt=sse`;
2412
+ const request = { contents };
2413
+ if (systemInstruction) {
2414
+ request.systemInstruction = { parts: [{ text: systemInstruction }] };
2415
+ }
2416
+ if (tools && tools.length > 0) {
2417
+ request.tools = [{ functionDeclarations: tools }];
2418
+ request.toolConfig = {
2419
+ functionCallingConfig: {
2420
+ mode: options.toolChoice?.type === "required" ? "ANY" : options.toolChoice?.type === "none" ? "NONE" : "AUTO"
2421
+ }
2422
+ };
2423
+ }
2424
+ const generationConfig = {};
2425
+ if (options.maxOutputTokens) {
2426
+ generationConfig.maxOutputTokens = options.maxOutputTokens;
2427
+ }
2428
+ if (options.temperature !== void 0) {
2429
+ generationConfig.temperature = options.temperature;
2430
+ }
2431
+ if (options.topP !== void 0) {
2432
+ generationConfig.topP = options.topP;
2433
+ }
2434
+ if (options.topK !== void 0) {
2435
+ generationConfig.topK = options.topK;
2436
+ }
2437
+ if (options.stopSequences && options.stopSequences.length > 0) {
2438
+ generationConfig.stopSequences = options.stopSequences;
2439
+ }
2440
+ if (Object.keys(generationConfig).length > 0) {
2441
+ request.generationConfig = generationConfig;
2442
+ }
2443
+ const response = await fetch(url, {
2444
+ method: "POST",
2445
+ headers: {
2446
+ "Content-Type": "application/json",
2447
+ "X-Goog-Api-Key": this.apiKey,
2448
+ ...this.headers
2449
+ },
2450
+ body: JSON.stringify(request),
2451
+ signal: options.abortSignal
2452
+ });
2453
+ if (!response.ok) {
2454
+ const errorText = await response.text();
2455
+ throw new Error(
2456
+ `Gemini API error: ${response.status} ${response.statusText} - ${errorText}`
2457
+ );
2458
+ }
2459
+ if (!response.body) {
2460
+ throw new Error("Response body is null");
2461
+ }
2462
+ const reader = response.body.getReader();
2463
+ const decoder = new TextDecoder();
2464
+ const stream = new ReadableStream({
2465
+ async start(controller) {
2466
+ let buffer = "";
2467
+ let textId;
2468
+ let reasoningId;
2469
+ let hasEmittedTextStart = false;
2470
+ let hasEmittedReasoningStart = false;
2471
+ const toolCalls = [];
2472
+ let finishReason = "stop";
2473
+ let usage = { inputTokens: void 0, outputTokens: void 0 };
2474
+ try {
2475
+ while (true) {
2476
+ const { done, value } = await reader.read();
2477
+ if (done) {
2478
+ break;
2479
+ }
2480
+ buffer += decoder.decode(value, { stream: true });
2481
+ const events = buffer.split(/\n\n/);
2482
+ buffer = events.pop() || "";
2483
+ for (const event of events) {
2484
+ const lines = event.split("\n");
2485
+ for (const line of lines) {
2486
+ if (line.startsWith("data: ")) {
2487
+ const jsonStr = line.substring(6).trim();
2488
+ if (!jsonStr || jsonStr === "[DONE]") {
2489
+ continue;
2490
+ }
2491
+ try {
2492
+ const chunk = JSON.parse(jsonStr);
2493
+ const candidate = chunk.candidates?.[0];
2494
+ const parts = candidate?.content?.parts;
2495
+ if (chunk.usageMetadata) {
2496
+ usage = {
2497
+ inputTokens: chunk.usageMetadata.promptTokenCount,
2498
+ outputTokens: chunk.usageMetadata.candidatesTokenCount
2499
+ };
2500
+ }
2501
+ if (candidate?.finishReason) {
2502
+ finishReason = mapFinishReason(candidate.finishReason);
2503
+ }
2504
+ if (parts) {
2505
+ for (const part of parts) {
2506
+ if (part.thought && part.text) {
2507
+ if (!hasEmittedReasoningStart) {
2508
+ reasoningId = generateId2();
2509
+ controller.enqueue({
2510
+ type: "reasoning-start",
2511
+ id: reasoningId
2512
+ });
2513
+ hasEmittedReasoningStart = true;
2514
+ }
2515
+ controller.enqueue({
2516
+ type: "reasoning-delta",
2517
+ id: reasoningId,
2518
+ delta: part.text
2519
+ });
2520
+ } else if (part.text && !part.thought) {
2521
+ if (!hasEmittedTextStart) {
2522
+ textId = generateId2();
2523
+ controller.enqueue({
2524
+ type: "text-start",
2525
+ id: textId
2526
+ });
2527
+ hasEmittedTextStart = true;
2528
+ }
2529
+ controller.enqueue({
2530
+ type: "text-delta",
2531
+ id: textId,
2532
+ delta: part.text
2533
+ });
2534
+ } else if (part.functionCall) {
2535
+ const callId = generateId2();
2536
+ toolCalls.push({
2537
+ id: callId,
2538
+ name: part.functionCall.name,
2539
+ args: part.functionCall.args
2540
+ });
2541
+ }
2542
+ }
2543
+ }
2544
+ } catch {
2545
+ }
2546
+ }
2547
+ }
2548
+ }
2549
+ }
2550
+ if (hasEmittedReasoningStart && reasoningId) {
2551
+ controller.enqueue({ type: "reasoning-end", id: reasoningId });
2552
+ }
2553
+ if (hasEmittedTextStart && textId) {
2554
+ controller.enqueue({ type: "text-end", id: textId });
2555
+ }
2556
+ if (toolCalls.length > 0) {
2557
+ finishReason = "tool-calls";
2558
+ for (const tc of toolCalls) {
2559
+ const inputJson = JSON.stringify(tc.args);
2560
+ controller.enqueue({
2561
+ type: "tool-input-start",
2562
+ id: tc.id,
2563
+ toolName: tc.name
2564
+ });
2565
+ controller.enqueue({
2566
+ type: "tool-input-delta",
2567
+ id: tc.id,
2568
+ delta: inputJson
2569
+ });
2570
+ controller.enqueue({
2571
+ type: "tool-input-end",
2572
+ id: tc.id
2573
+ });
2574
+ controller.enqueue({
2575
+ type: "tool-call",
2576
+ toolCallId: tc.id,
2577
+ toolName: tc.name,
2578
+ input: inputJson
2579
+ });
2580
+ }
2581
+ }
2582
+ controller.enqueue({
2583
+ type: "finish",
2584
+ finishReason,
2585
+ usage: {
2586
+ inputTokens: usage.inputTokens,
2587
+ outputTokens: usage.outputTokens,
2588
+ totalTokens: usage.inputTokens !== void 0 && usage.outputTokens !== void 0 ? usage.inputTokens + usage.outputTokens : void 0
2589
+ }
2590
+ });
2591
+ controller.close();
2592
+ } catch (error) {
2593
+ controller.error(error);
2594
+ }
2595
+ }
2596
+ });
2597
+ return { stream };
2598
+ }
2599
+ };
2600
+
2601
+ // src/clients/claudeClient.ts
2602
+ var idCounter3 = 0;
2603
+ function generateId3() {
2604
+ return `claude_${Date.now()}_${++idCounter3}`;
2605
+ }
2606
+ function normalizeClaudeEndpoint(endpoint) {
2607
+ let normalized = endpoint.replace(/\/+$/, "");
2608
+ if (normalized.endsWith("/v1")) {
2609
+ normalized = normalized.slice(0, -3);
2610
+ }
2611
+ return normalized;
2612
+ }
2613
+ function convertMessagesToClaude(messages) {
2614
+ const claudeMessages = [];
2615
+ let systemContent;
2616
+ for (const message of messages) {
2617
+ if (message.role === "system") {
2618
+ systemContent = (systemContent || "") + message.content;
2619
+ } else if (message.role === "user") {
2620
+ const content = [];
2621
+ for (const part of message.content) {
2622
+ if (part.type === "text") {
2623
+ content.push({ type: "text", text: part.text });
2624
+ } else if (part.type === "file") {
2625
+ const filePart = part;
2626
+ if (filePart.mediaType.startsWith("image/")) {
2627
+ if (typeof filePart.data === "string") {
2628
+ if (filePart.data.startsWith("data:")) {
2629
+ const match = filePart.data.match(/^data:([^;]+);base64,(.+)$/);
2630
+ if (match) {
2631
+ content.push({
2632
+ type: "image",
2633
+ source: {
2634
+ type: "base64",
2635
+ media_type: match[1],
2636
+ data: match[2]
2637
+ }
2638
+ });
2639
+ }
2640
+ } else {
2641
+ content.push({
2642
+ type: "image",
2643
+ source: {
2644
+ type: "base64",
2645
+ media_type: filePart.mediaType,
2646
+ data: filePart.data
2647
+ }
2648
+ });
2649
+ }
2650
+ } else if (filePart.data instanceof Uint8Array) {
2651
+ const base64 = Buffer.from(filePart.data).toString("base64");
2652
+ content.push({
2653
+ type: "image",
2654
+ source: {
2655
+ type: "base64",
2656
+ media_type: filePart.mediaType,
2657
+ data: base64
2658
+ }
2659
+ });
2660
+ }
2661
+ }
2662
+ }
2663
+ }
2664
+ if (content.length > 0) {
2665
+ claudeMessages.push({
2666
+ role: "user",
2667
+ content: content.length === 1 && content[0].type === "text" ? content[0].text : content
2668
+ });
2669
+ }
2670
+ } else if (message.role === "assistant") {
2671
+ const content = [];
2672
+ for (const part of message.content) {
2673
+ if (part.type === "text") {
2674
+ content.push({ type: "text", text: part.text });
2675
+ } else if (part.type === "reasoning") {
2676
+ content.push({ type: "thinking", thinking: part.text });
2677
+ } else if (part.type === "tool-call") {
2678
+ const input = part.input;
2679
+ content.push({
2680
+ type: "tool_use",
2681
+ id: part.toolCallId,
2682
+ name: part.toolName,
2683
+ input
2684
+ });
2685
+ }
2686
+ }
2687
+ if (content.length > 0) {
2688
+ claudeMessages.push({ role: "assistant", content });
2689
+ }
2690
+ } else if (message.role === "tool") {
2691
+ const content = [];
2692
+ for (const part of message.content) {
2693
+ if (part.type === "tool-result") {
2694
+ let resultContent;
2695
+ const output = part.output;
2696
+ if (output.type === "text" || output.type === "error-text") {
2697
+ resultContent = output.value;
2698
+ } else if (output.type === "json" || output.type === "error-json") {
2699
+ resultContent = JSON.stringify(output.value);
2700
+ } else if (output.type === "content") {
2701
+ resultContent = output.value.map(
2702
+ (c) => c.type === "text" ? c.text : "[media]"
2703
+ ).join("\n");
2704
+ } else {
2705
+ resultContent = String(output);
2706
+ }
2707
+ const isError = output.type === "error-text" || output.type === "error-json";
2708
+ content.push({
2709
+ type: "tool_result",
2710
+ tool_use_id: part.toolCallId,
2711
+ content: resultContent,
2712
+ is_error: isError
2713
+ });
2714
+ }
2715
+ }
2716
+ if (content.length > 0) {
2717
+ claudeMessages.push({ role: "user", content });
2718
+ }
2719
+ }
2720
+ }
2721
+ return { messages: claudeMessages, system: systemContent };
2722
+ }
2723
+ function convertToolsToClaude(tools) {
2724
+ if (!tools || tools.length === 0) {
2725
+ return void 0;
2726
+ }
2727
+ return tools.map((tool) => ({
2728
+ name: tool.name,
2729
+ description: tool.description,
2730
+ input_schema: tool.inputSchema
2731
+ }));
2732
+ }
2733
+ function mapFinishReason2(claudeReason) {
2734
+ switch (claudeReason) {
2735
+ case "end_turn":
2736
+ case "stop_sequence":
2737
+ return "stop";
2738
+ case "max_tokens":
2739
+ return "length";
2740
+ case "tool_use":
2741
+ return "tool-calls";
2742
+ default:
2743
+ return "stop";
2744
+ }
2745
+ }
2746
+ var ClaudeClient = class {
2747
+ baseURL;
2748
+ apiKey;
2749
+ headers;
2750
+ constructor(config) {
2751
+ this.baseURL = normalizeClaudeEndpoint(config.baseURL);
2752
+ this.apiKey = config.apiKey;
2753
+ this.headers = config.headers || {};
2754
+ }
2755
+ /**
2756
+ * Generate content (non-streaming)
2757
+ */
2758
+ async doGenerate(modelId, options) {
2759
+ const { messages, system } = convertMessagesToClaude(options.prompt);
2760
+ const tools = convertToolsToClaude(
2761
+ options.tools?.filter(
2762
+ (t) => t.type === "function"
2763
+ )
2764
+ );
2765
+ const url = `${this.baseURL}/v1/messages`;
2766
+ const request = {
2767
+ model: modelId,
2768
+ messages,
2769
+ max_tokens: options.maxOutputTokens || 8192,
2770
+ stream: false
2771
+ };
2772
+ if (system) {
2773
+ request.system = system;
2774
+ }
2775
+ if (tools && tools.length > 0) {
2776
+ request.tools = tools;
2777
+ if (options.toolChoice?.type === "required") {
2778
+ request.tool_choice = { type: "any" };
2779
+ } else if (options.toolChoice?.type === "none") {
2780
+ delete request.tools;
2781
+ } else if (options.toolChoice?.type === "tool") {
2782
+ request.tool_choice = {
2783
+ type: "tool",
2784
+ name: options.toolChoice.toolName
2785
+ };
2786
+ } else {
2787
+ request.tool_choice = { type: "auto" };
2788
+ }
2789
+ }
2790
+ if (options.temperature !== void 0) {
2791
+ request.temperature = options.temperature;
2792
+ }
2793
+ if (options.topP !== void 0) {
2794
+ request.top_p = options.topP;
2795
+ }
2796
+ if (options.topK !== void 0) {
2797
+ request.top_k = options.topK;
2798
+ }
2799
+ if (options.stopSequences && options.stopSequences.length > 0) {
2800
+ request.stop_sequences = options.stopSequences;
2801
+ }
2802
+ const response = await fetch(url, {
2803
+ method: "POST",
2804
+ headers: {
2805
+ "Content-Type": "application/json",
2806
+ "x-api-key": this.apiKey,
2807
+ "anthropic-version": "2023-06-01",
2808
+ ...this.headers
2809
+ },
2810
+ body: JSON.stringify(request),
2811
+ signal: options.abortSignal
2812
+ });
2813
+ if (!response.ok) {
2814
+ const errorText = await response.text();
2815
+ throw new Error(
2816
+ `Claude API error: ${response.status} ${response.statusText} - ${errorText}`
2817
+ );
2818
+ }
2819
+ const data = await response.json();
2820
+ const content = [];
2821
+ for (const block of data.content) {
2822
+ if (block.type === "text") {
2823
+ content.push({ type: "text", text: block.text });
2824
+ } else if (block.type === "thinking") {
2825
+ content.push({ type: "reasoning", text: block.thinking });
2826
+ } else if (block.type === "tool_use") {
2827
+ content.push({
2828
+ type: "tool-call",
2829
+ toolCallId: block.id,
2830
+ toolName: block.name,
2831
+ input: JSON.stringify(block.input)
2832
+ });
2833
+ }
2834
+ }
2835
+ return {
2836
+ content,
2837
+ finishReason: mapFinishReason2(data.stop_reason),
2838
+ usage: {
2839
+ inputTokens: data.usage?.input_tokens,
2840
+ outputTokens: data.usage?.output_tokens
2841
+ }
2842
+ };
2843
+ }
2844
+ /**
2845
+ * Stream content generation
2846
+ */
2847
+ async doStream(modelId, options) {
2848
+ const { messages, system } = convertMessagesToClaude(options.prompt);
2849
+ const tools = convertToolsToClaude(
2850
+ options.tools?.filter(
2851
+ (t) => t.type === "function"
2852
+ )
2853
+ );
2854
+ const url = `${this.baseURL}/v1/messages`;
2855
+ const request = {
2856
+ model: modelId,
2857
+ messages,
2858
+ max_tokens: options.maxOutputTokens || 8192,
2859
+ stream: true
2860
+ };
2861
+ if (system) {
2862
+ request.system = system;
2863
+ }
2864
+ if (tools && tools.length > 0) {
2865
+ request.tools = tools;
2866
+ if (options.toolChoice?.type === "required") {
2867
+ request.tool_choice = { type: "any" };
2868
+ } else if (options.toolChoice?.type === "none") {
2869
+ delete request.tools;
2870
+ } else if (options.toolChoice?.type === "tool") {
2871
+ request.tool_choice = {
2872
+ type: "tool",
2873
+ name: options.toolChoice.toolName
2874
+ };
2875
+ } else {
2876
+ request.tool_choice = { type: "auto" };
2877
+ }
2878
+ }
2879
+ if (options.temperature !== void 0) {
2880
+ request.temperature = options.temperature;
2881
+ }
2882
+ if (options.topP !== void 0) {
2883
+ request.top_p = options.topP;
2884
+ }
2885
+ if (options.topK !== void 0) {
2886
+ request.top_k = options.topK;
2887
+ }
2888
+ if (options.stopSequences && options.stopSequences.length > 0) {
2889
+ request.stop_sequences = options.stopSequences;
2890
+ }
2891
+ const response = await fetch(url, {
2892
+ method: "POST",
2893
+ headers: {
2894
+ "Content-Type": "application/json",
2895
+ "x-api-key": this.apiKey,
2896
+ "anthropic-version": "2023-06-01",
2897
+ ...this.headers
2898
+ },
2899
+ body: JSON.stringify(request),
2900
+ signal: options.abortSignal
2901
+ });
2902
+ if (!response.ok) {
2903
+ const errorText = await response.text();
2904
+ throw new Error(
2905
+ `Claude API error: ${response.status} ${response.statusText} - ${errorText}`
2906
+ );
2907
+ }
2908
+ if (!response.body) {
2909
+ throw new Error("Response body is null");
2910
+ }
2911
+ const reader = response.body.getReader();
2912
+ const decoder = new TextDecoder();
2913
+ const stream = new ReadableStream({
2914
+ async start(controller) {
2915
+ let buffer = "";
2916
+ let textId;
2917
+ let reasoningId;
2918
+ let hasEmittedTextStart = false;
2919
+ let hasEmittedReasoningStart = false;
2920
+ const toolCalls = /* @__PURE__ */ new Map();
2921
+ let finishReason = "stop";
2922
+ let usage = { inputTokens: void 0, outputTokens: void 0 };
2923
+ try {
2924
+ while (true) {
2925
+ const { done, value } = await reader.read();
2926
+ if (done) {
2927
+ break;
2928
+ }
2929
+ buffer += decoder.decode(value, { stream: true });
2930
+ const lines = buffer.split("\n");
2931
+ buffer = lines.pop() || "";
2932
+ for (const line of lines) {
2933
+ if (line.startsWith("data: ")) {
2934
+ const jsonStr = line.substring(6).trim();
2935
+ if (!jsonStr || jsonStr === "[DONE]") {
2936
+ continue;
2937
+ }
2938
+ try {
2939
+ const event = JSON.parse(jsonStr);
2940
+ switch (event.type) {
2941
+ case "message_start":
2942
+ if (event.message?.usage) {
2943
+ usage.inputTokens = event.message.usage.input_tokens;
2944
+ }
2945
+ break;
2946
+ case "content_block_start":
2947
+ if (event.content_block) {
2948
+ if (event.content_block.type === "text") {
2949
+ if (!hasEmittedTextStart) {
2950
+ textId = generateId3();
2951
+ controller.enqueue({
2952
+ type: "text-start",
2953
+ id: textId
2954
+ });
2955
+ hasEmittedTextStart = true;
2956
+ }
2957
+ } else if (event.content_block.type === "thinking") {
2958
+ if (!hasEmittedReasoningStart) {
2959
+ reasoningId = generateId3();
2960
+ controller.enqueue({
2961
+ type: "reasoning-start",
2962
+ id: reasoningId
2963
+ });
2964
+ hasEmittedReasoningStart = true;
2965
+ }
2966
+ } else if (event.content_block.type === "tool_use") {
2967
+ const block = event.content_block;
2968
+ toolCalls.set(event.index, {
2969
+ id: block.id,
2970
+ name: block.name,
2971
+ inputJson: ""
2972
+ });
2973
+ controller.enqueue({
2974
+ type: "tool-input-start",
2975
+ id: block.id,
2976
+ toolName: block.name
2977
+ });
2978
+ }
2979
+ }
2980
+ break;
2981
+ case "content_block_delta":
2982
+ if (event.delta) {
2983
+ if (event.delta.type === "text_delta" && event.delta.text) {
2984
+ if (!hasEmittedTextStart) {
2985
+ textId = generateId3();
2986
+ controller.enqueue({
2987
+ type: "text-start",
2988
+ id: textId
2989
+ });
2990
+ hasEmittedTextStart = true;
2991
+ }
2992
+ controller.enqueue({
2993
+ type: "text-delta",
2994
+ id: textId,
2995
+ delta: event.delta.text
2996
+ });
2997
+ } else if (event.delta.type === "thinking_delta" && event.delta.thinking) {
2998
+ if (!hasEmittedReasoningStart) {
2999
+ reasoningId = generateId3();
3000
+ controller.enqueue({
3001
+ type: "reasoning-start",
3002
+ id: reasoningId
3003
+ });
3004
+ hasEmittedReasoningStart = true;
3005
+ }
3006
+ controller.enqueue({
3007
+ type: "reasoning-delta",
3008
+ id: reasoningId,
3009
+ delta: event.delta.thinking
3010
+ });
3011
+ } else if (event.delta.type === "input_json_delta" && event.delta.partial_json !== void 0) {
3012
+ const tc2 = toolCalls.get(event.index);
3013
+ if (tc2) {
3014
+ tc2.inputJson += event.delta.partial_json;
3015
+ controller.enqueue({
3016
+ type: "tool-input-delta",
3017
+ id: tc2.id,
3018
+ delta: event.delta.partial_json
3019
+ });
3020
+ }
3021
+ }
3022
+ }
3023
+ break;
3024
+ case "content_block_stop":
3025
+ const tc = toolCalls.get(event.index);
3026
+ if (tc) {
3027
+ controller.enqueue({
3028
+ type: "tool-input-end",
3029
+ id: tc.id
3030
+ });
3031
+ controller.enqueue({
3032
+ type: "tool-call",
3033
+ toolCallId: tc.id,
3034
+ toolName: tc.name,
3035
+ input: tc.inputJson
3036
+ });
3037
+ }
3038
+ break;
3039
+ case "message_delta":
3040
+ if (event.delta && "stop_reason" in event.delta) {
3041
+ finishReason = mapFinishReason2(
3042
+ event.delta.stop_reason
3043
+ );
3044
+ }
3045
+ if (event.usage) {
3046
+ usage.outputTokens = event.usage.output_tokens;
3047
+ }
3048
+ break;
3049
+ case "message_stop":
3050
+ break;
3051
+ }
3052
+ } catch {
3053
+ }
3054
+ }
3055
+ }
3056
+ }
3057
+ if (hasEmittedReasoningStart && reasoningId) {
3058
+ controller.enqueue({ type: "reasoning-end", id: reasoningId });
3059
+ }
3060
+ if (hasEmittedTextStart && textId) {
3061
+ controller.enqueue({ type: "text-end", id: textId });
3062
+ }
3063
+ controller.enqueue({
3064
+ type: "finish",
3065
+ finishReason,
3066
+ usage: {
3067
+ inputTokens: usage.inputTokens,
3068
+ outputTokens: usage.outputTokens,
3069
+ totalTokens: usage.inputTokens !== void 0 && usage.outputTokens !== void 0 ? usage.inputTokens + usage.outputTokens : void 0
3070
+ }
3071
+ });
3072
+ controller.close();
3073
+ } catch (error) {
3074
+ controller.error(error);
3075
+ }
3076
+ }
3077
+ });
3078
+ return { stream };
3079
+ }
3080
+ };
3081
+
3082
+ // src/apiAdapters.ts
3083
+ var GeminiLanguageModel = class {
3084
+ specificationVersion = "v2";
3085
+ modelId;
3086
+ provider = "gemini";
3087
+ client;
3088
+ _override;
3089
+ constructor(modelId, config, override) {
3090
+ this.modelId = modelId;
3091
+ this.client = new GeminiClient(config);
3092
+ this._override = override;
3093
+ }
3094
+ get supportsStructuredOutputs() {
3095
+ return true;
3096
+ }
3097
+ get supportedUrls() {
3098
+ return {};
3099
+ }
3100
+ get defaultObjectGenerationMode() {
3101
+ return "json";
3102
+ }
3103
+ async doGenerate(options) {
3104
+ const result = await this.client.doGenerate(this.modelId, options);
3105
+ return {
3106
+ content: result.content,
3107
+ finishReason: result.finishReason,
3108
+ usage: {
3109
+ inputTokens: result.usage.inputTokens,
3110
+ outputTokens: result.usage.outputTokens,
3111
+ totalTokens: result.usage.inputTokens !== void 0 && result.usage.outputTokens !== void 0 ? result.usage.inputTokens + result.usage.outputTokens : void 0
3112
+ },
3113
+ rawCall: { rawPrompt: null, rawSettings: {} },
3114
+ rawResponse: { headers: {} },
3115
+ request: { body: JSON.stringify({}) },
3116
+ response: {
3117
+ id: `gemini_${Date.now()}`,
3118
+ timestamp: /* @__PURE__ */ new Date(),
3119
+ modelId: this.modelId
3120
+ },
3121
+ warnings: []
3122
+ };
3123
+ }
3124
+ async doStream(options) {
3125
+ return this.client.doStream(this.modelId, options);
3126
+ }
3127
+ };
3128
+ var ClaudeLanguageModel = class {
3129
+ specificationVersion = "v2";
3130
+ modelId;
3131
+ provider = "claude";
3132
+ client;
3133
+ _override;
3134
+ constructor(modelId, config, override) {
3135
+ this.modelId = modelId;
3136
+ this.client = new ClaudeClient(config);
3137
+ this._override = override;
3138
+ }
3139
+ get supportsStructuredOutputs() {
3140
+ return true;
3141
+ }
3142
+ get supportedUrls() {
3143
+ return {};
3144
+ }
3145
+ get defaultObjectGenerationMode() {
3146
+ return "tool";
3147
+ }
3148
+ async doGenerate(options) {
3149
+ const result = await this.client.doGenerate(this.modelId, options);
3150
+ return {
3151
+ content: result.content,
3152
+ finishReason: result.finishReason,
3153
+ usage: {
3154
+ inputTokens: result.usage.inputTokens,
3155
+ outputTokens: result.usage.outputTokens,
3156
+ totalTokens: result.usage.inputTokens !== void 0 && result.usage.outputTokens !== void 0 ? result.usage.inputTokens + result.usage.outputTokens : void 0
3157
+ },
3158
+ rawCall: { rawPrompt: null, rawSettings: {} },
3159
+ rawResponse: { headers: {} },
3160
+ request: { body: JSON.stringify({}) },
3161
+ response: {
3162
+ id: `claude_${Date.now()}`,
3163
+ timestamp: /* @__PURE__ */ new Date(),
3164
+ modelId: this.modelId
3165
+ },
3166
+ warnings: []
3167
+ };
3168
+ }
3169
+ async doStream(options) {
3170
+ return this.client.doStream(this.modelId, options);
3171
+ }
3172
+ };
3173
+ function createApiAdapter(apiType, modelId, config, override) {
3174
+ switch (apiType) {
3175
+ case "gemini":
3176
+ return new GeminiLanguageModel(modelId, config, override);
3177
+ case "claude":
3178
+ return new ClaudeLanguageModel(modelId, config, override);
3179
+ case "openai":
3180
+ default:
3181
+ return void 0;
3182
+ }
3183
+ }
3184
+
2160
3185
  // src/index.ts
2161
3186
  var modelCache = /* @__PURE__ */ new WeakMap();
2162
3187
  function mergeWithConfig(options, config) {
@@ -2203,8 +3228,19 @@ function createOai2lm(options = {}) {
2203
3228
  try {
2204
3229
  let getOverride2 = function(modelId) {
2205
3230
  return findModelOverride(modelId, mergedOptions.modelOverrides);
3231
+ }, createModel2 = function(modelId) {
3232
+ const override = getOverride2(modelId);
3233
+ const apiType = override?.apiType;
3234
+ if (apiType && apiType !== "openai") {
3235
+ const adapter = createApiAdapter(apiType, modelId, apiConfig, override);
3236
+ if (adapter) {
3237
+ return wrapWithEnhancements(adapter, modelId, override);
3238
+ }
3239
+ }
3240
+ const baseModel = baseProvider.languageModel(modelId);
3241
+ return wrapWithEnhancements(baseModel, modelId, override);
2206
3242
  };
2207
- var getOverride = getOverride2;
3243
+ var getOverride = getOverride2, createModel = createModel2;
2208
3244
  const config = options.useConfigFile !== false ? loadConfig() : void 0;
2209
3245
  const mergedOptions = mergeWithConfig(options, config);
2210
3246
  if (!mergedOptions.baseURL) {
@@ -2270,20 +3306,19 @@ function createOai2lm(options = {}) {
2270
3306
  }
2271
3307
  return cache;
2272
3308
  }
3309
+ const apiConfig = {
3310
+ baseURL,
3311
+ apiKey: mergedOptions.apiKey || "",
3312
+ headers: mergedOptions.headers
3313
+ };
2273
3314
  const provider = function(modelId) {
2274
- const baseModel = baseProvider(modelId);
2275
- const override = getOverride2(modelId);
2276
- return wrapWithEnhancements(baseModel, modelId, override);
3315
+ return createModel2(modelId);
2277
3316
  };
2278
3317
  provider.languageModel = (modelId) => {
2279
- const baseModel = baseProvider.languageModel(modelId);
2280
- const override = getOverride2(modelId);
2281
- return wrapWithEnhancements(baseModel, modelId, override);
3318
+ return createModel2(modelId);
2282
3319
  };
2283
3320
  provider.chatModel = (modelId) => {
2284
- const baseModel = baseProvider.chatModel(modelId);
2285
- const override = getOverride2(modelId);
2286
- return wrapWithEnhancements(baseModel, modelId, override);
3321
+ return createModel2(modelId);
2287
3322
  };
2288
3323
  provider.completionModel = (modelId) => baseProvider.completionModel(modelId);
2289
3324
  provider.textEmbeddingModel = (modelId) => baseProvider.textEmbeddingModel(modelId);
@@ -2308,7 +3343,10 @@ function createOai2lm(options = {}) {
2308
3343
  var createOpenAICompatible = createOai2lm;
2309
3344
  var index_default = createOai2lm;
2310
3345
  export {
3346
+ ClaudeLanguageModel,
2311
3347
  EnhancedLanguageModel,
3348
+ GeminiLanguageModel,
3349
+ createApiAdapter,
2312
3350
  createOai2lm,
2313
3351
  createOpenAICompatible,
2314
3352
  index_default as default,