@probeo/anymodel 0.4.0 → 0.5.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/cli.js CHANGED
@@ -485,6 +485,25 @@ var Router = class {
485
485
  }
486
486
  };
487
487
 
488
+ // src/utils/fetch-with-timeout.ts
489
+ var _defaultTimeout = 12e4;
490
+ var _flexTimeout = 6e5;
491
+ function setDefaultTimeout(ms) {
492
+ _defaultTimeout = ms;
493
+ }
494
+ function getFlexTimeout() {
495
+ return _flexTimeout;
496
+ }
497
+ function fetchWithTimeout(url, init, timeoutMs) {
498
+ const ms = timeoutMs ?? _defaultTimeout;
499
+ const signal = AbortSignal.timeout(ms);
500
+ if (init?.signal) {
501
+ const combined = AbortSignal.any([signal, init.signal]);
502
+ return fetch(url, { ...init, signal: combined });
503
+ }
504
+ return fetch(url, { ...init, signal });
505
+ }
506
+
488
507
  // src/providers/openai.ts
489
508
  var OPENAI_API_BASE = "https://api.openai.com/v1";
490
509
  var SUPPORTED_PARAMS = /* @__PURE__ */ new Set([
@@ -502,19 +521,20 @@ var SUPPORTED_PARAMS = /* @__PURE__ */ new Set([
502
521
  "tools",
503
522
  "tool_choice",
504
523
  "user",
505
- "logit_bias"
524
+ "logit_bias",
525
+ "service_tier"
506
526
  ]);
507
527
  function createOpenAIAdapter(apiKey, baseURL) {
508
528
  const base = baseURL || OPENAI_API_BASE;
509
- async function makeRequest(path2, body, method = "POST") {
510
- const res = await fetch(`${base}${path2}`, {
529
+ async function makeRequest(path2, body, method = "POST", timeoutMs) {
530
+ const res = await fetchWithTimeout(`${base}${path2}`, {
511
531
  method,
512
532
  headers: {
513
533
  "Content-Type": "application/json",
514
534
  "Authorization": `Bearer ${apiKey}`
515
535
  },
516
536
  body: body ? JSON.stringify(body) : void 0
517
- });
537
+ }, timeoutMs);
518
538
  if (!res.ok) {
519
539
  let errorBody;
520
540
  try {
@@ -562,6 +582,7 @@ function createOpenAIAdapter(apiKey, baseURL) {
562
582
  if (request.tools !== void 0) body.tools = request.tools;
563
583
  if (request.tool_choice !== void 0) body.tool_choice = request.tool_choice;
564
584
  if (request.user !== void 0) body.user = request.user;
585
+ if (request.service_tier !== void 0) body.service_tier = request.service_tier;
565
586
  return body;
566
587
  }
567
588
  const adapter = {
@@ -663,13 +684,15 @@ function createOpenAIAdapter(apiKey, baseURL) {
663
684
  },
664
685
  async sendRequest(request) {
665
686
  const body = buildRequestBody(request);
666
- const res = await makeRequest("/chat/completions", body);
687
+ const timeout = request.service_tier === "flex" ? getFlexTimeout() : void 0;
688
+ const res = await makeRequest("/chat/completions", body, "POST", timeout);
667
689
  const json = await res.json();
668
690
  return adapter.translateResponse(json);
669
691
  },
670
692
  async sendStreamingRequest(request) {
671
693
  const body = buildRequestBody({ ...request, stream: true });
672
- const res = await makeRequest("/chat/completions", body);
694
+ const timeout = request.service_tier === "flex" ? getFlexTimeout() : void 0;
695
+ const res = await makeRequest("/chat/completions", body, "POST", timeout);
673
696
  if (!res.body) {
674
697
  throw new AnyModelError(502, "No response body for streaming request", {
675
698
  provider_name: "openai"
@@ -716,7 +739,7 @@ var FALLBACK_MODELS = [
716
739
  ];
717
740
  function createAnthropicAdapter(apiKey) {
718
741
  async function makeRequest(path2, body, stream = false) {
719
- const res = await fetch(`${ANTHROPIC_API_BASE}${path2}`, {
742
+ const res = await fetchWithTimeout(`${ANTHROPIC_API_BASE}${path2}`, {
720
743
  method: "POST",
721
744
  headers: {
722
745
  "Content-Type": "application/json",
@@ -973,7 +996,7 @@ ${body.system}` : jsonInstruction;
973
996
  },
974
997
  async listModels() {
975
998
  try {
976
- const res = await fetch(`${ANTHROPIC_API_BASE}/models`, {
999
+ const res = await fetchWithTimeout(`${ANTHROPIC_API_BASE}/models`, {
977
1000
  method: "GET",
978
1001
  headers: {
979
1002
  "x-api-key": apiKey,
@@ -1258,7 +1281,7 @@ function createGoogleAdapter(apiKey) {
1258
1281
  },
1259
1282
  async listModels() {
1260
1283
  try {
1261
- const res = await fetch(`${GEMINI_API_BASE}/models?key=${apiKey}`);
1284
+ const res = await fetchWithTimeout(`${GEMINI_API_BASE}/models?key=${apiKey}`);
1262
1285
  if (!res.ok) return FALLBACK_MODELS2;
1263
1286
  const data = await res.json();
1264
1287
  const models = data.models || [];
@@ -1293,12 +1316,12 @@ function createGoogleAdapter(apiKey) {
1293
1316
  return SUPPORTED_PARAMS3.has(param);
1294
1317
  },
1295
1318
  supportsBatch() {
1296
- return false;
1319
+ return true;
1297
1320
  },
1298
1321
  async sendRequest(request) {
1299
1322
  const body = translateRequest(request);
1300
1323
  const url = getModelEndpoint(request.model, false);
1301
- const res = await fetch(url, {
1324
+ const res = await fetchWithTimeout(url, {
1302
1325
  method: "POST",
1303
1326
  headers: { "Content-Type": "application/json" },
1304
1327
  body: JSON.stringify(body)
@@ -1321,7 +1344,7 @@ function createGoogleAdapter(apiKey) {
1321
1344
  async sendStreamingRequest(request) {
1322
1345
  const body = translateRequest(request);
1323
1346
  const url = getModelEndpoint(request.model, true);
1324
- const res = await fetch(url, {
1347
+ const res = await fetchWithTimeout(url, {
1325
1348
  method: "POST",
1326
1349
  headers: { "Content-Type": "application/json" },
1327
1350
  body: JSON.stringify(body)
@@ -1371,7 +1394,7 @@ var MODELS = [
1371
1394
  ];
1372
1395
  function createPerplexityAdapter(apiKey) {
1373
1396
  async function makeRequest(path2, body, method = "POST") {
1374
- const res = await fetch(`${PERPLEXITY_API_BASE}${path2}`, {
1397
+ const res = await fetchWithTimeout(`${PERPLEXITY_API_BASE}${path2}`, {
1375
1398
  method,
1376
1399
  headers: {
1377
1400
  "Content-Type": "application/json",
@@ -2243,6 +2266,51 @@ var BatchManager = class {
2243
2266
  }
2244
2267
  };
2245
2268
 
2269
+ // src/utils/token-estimate.ts
2270
+ var CHARS_PER_TOKEN2 = 4;
2271
+ var MODEL_LIMITS = [
2272
+ // OpenAI
2273
+ { pattern: "gpt-4o-mini", limit: { contextLength: 128e3, maxCompletionTokens: 16384 } },
2274
+ { pattern: "gpt-4o", limit: { contextLength: 128e3, maxCompletionTokens: 16384 } },
2275
+ { pattern: "gpt-4-turbo", limit: { contextLength: 128e3, maxCompletionTokens: 4096 } },
2276
+ { pattern: "gpt-3.5-turbo", limit: { contextLength: 16385, maxCompletionTokens: 4096 } },
2277
+ { pattern: "o1", limit: { contextLength: 2e5, maxCompletionTokens: 1e5 } },
2278
+ { pattern: "o3", limit: { contextLength: 2e5, maxCompletionTokens: 1e5 } },
2279
+ { pattern: "o4-mini", limit: { contextLength: 2e5, maxCompletionTokens: 1e5 } },
2280
+ // Anthropic
2281
+ { pattern: "claude-opus-4", limit: { contextLength: 2e5, maxCompletionTokens: 32768 } },
2282
+ { pattern: "claude-sonnet-4", limit: { contextLength: 2e5, maxCompletionTokens: 16384 } },
2283
+ { pattern: "claude-haiku-4", limit: { contextLength: 2e5, maxCompletionTokens: 8192 } },
2284
+ { pattern: "claude-3.5-sonnet", limit: { contextLength: 2e5, maxCompletionTokens: 8192 } },
2285
+ { pattern: "claude-3-opus", limit: { contextLength: 2e5, maxCompletionTokens: 4096 } },
2286
+ // Google
2287
+ { pattern: "gemini-2.5-pro", limit: { contextLength: 1048576, maxCompletionTokens: 65536 } },
2288
+ { pattern: "gemini-2.5-flash", limit: { contextLength: 1048576, maxCompletionTokens: 65536 } },
2289
+ { pattern: "gemini-2.0-flash", limit: { contextLength: 1048576, maxCompletionTokens: 65536 } },
2290
+ { pattern: "gemini-1.5-pro", limit: { contextLength: 2097152, maxCompletionTokens: 8192 } },
2291
+ { pattern: "gemini-1.5-flash", limit: { contextLength: 1048576, maxCompletionTokens: 8192 } }
2292
+ ];
2293
+ var DEFAULT_LIMIT = { contextLength: 128e3, maxCompletionTokens: 4096 };
2294
+ function getModelLimits(model) {
2295
+ const bare = model.includes("/") ? model.slice(model.indexOf("/") + 1) : model;
2296
+ for (const entry of MODEL_LIMITS) {
2297
+ if (bare.startsWith(entry.pattern) || bare.includes(entry.pattern)) {
2298
+ return entry.limit;
2299
+ }
2300
+ }
2301
+ return DEFAULT_LIMIT;
2302
+ }
2303
+ function resolveMaxTokens(model, messages, userMaxTokens) {
2304
+ if (userMaxTokens !== void 0) return userMaxTokens;
2305
+ const inputChars = JSON.stringify(messages).length;
2306
+ const estimatedInput = Math.ceil(inputChars / CHARS_PER_TOKEN2);
2307
+ const estimatedWithMargin = Math.ceil(estimatedInput * 1.05);
2308
+ const limits = getModelLimits(model);
2309
+ const available = limits.contextLength - estimatedWithMargin;
2310
+ const result = Math.min(limits.maxCompletionTokens, available);
2311
+ return Math.max(1, result);
2312
+ }
2313
+
2246
2314
  // src/providers/openai-batch.ts
2247
2315
  var OPENAI_API_BASE2 = "https://api.openai.com/v1";
2248
2316
  function createOpenAIBatchAdapter(apiKey) {
@@ -2257,7 +2325,7 @@ function createOpenAIBatchAdapter(apiKey) {
2257
2325
  headers["Content-Type"] = "application/json";
2258
2326
  fetchBody = JSON.stringify(options.body);
2259
2327
  }
2260
- const res = await fetch(`${OPENAI_API_BASE2}${path2}`, {
2328
+ const res = await fetchWithTimeout(`${OPENAI_API_BASE2}${path2}`, {
2261
2329
  method: options.method || "GET",
2262
2330
  headers,
2263
2331
  body: fetchBody
@@ -2283,7 +2351,7 @@ function createOpenAIBatchAdapter(apiKey) {
2283
2351
  model,
2284
2352
  messages: req.messages
2285
2353
  };
2286
- if (req.max_tokens !== void 0) body.max_tokens = req.max_tokens;
2354
+ body.max_tokens = req.max_tokens !== void 0 ? req.max_tokens : resolveMaxTokens(model, req.messages);
2287
2355
  if (req.temperature !== void 0) body.temperature = req.temperature;
2288
2356
  if (req.top_p !== void 0) body.top_p = req.top_p;
2289
2357
  if (req.stop !== void 0) body.stop = req.stop;
@@ -2442,7 +2510,7 @@ function createAnthropicBatchAdapter(apiKey) {
2442
2510
  "anthropic-version": ANTHROPIC_VERSION2,
2443
2511
  "Content-Type": "application/json"
2444
2512
  };
2445
- const res = await fetch(`${ANTHROPIC_API_BASE2}${path2}`, {
2513
+ const res = await fetchWithTimeout(`${ANTHROPIC_API_BASE2}${path2}`, {
2446
2514
  method: options.method || "GET",
2447
2515
  headers,
2448
2516
  body: options.body ? JSON.stringify(options.body) : void 0
@@ -2465,7 +2533,7 @@ function createAnthropicBatchAdapter(apiKey) {
2465
2533
  function translateToAnthropicParams(model, req) {
2466
2534
  const params = {
2467
2535
  model,
2468
- max_tokens: req.max_tokens || DEFAULT_MAX_TOKENS2
2536
+ max_tokens: resolveMaxTokens(model, req.messages, req.max_tokens || DEFAULT_MAX_TOKENS2)
2469
2537
  };
2470
2538
  const systemMessages = req.messages.filter((m) => m.role === "system");
2471
2539
  const nonSystemMessages = req.messages.filter((m) => m.role !== "system");
@@ -2639,6 +2707,284 @@ ${params.system}` : jsonInstruction;
2639
2707
  };
2640
2708
  }
2641
2709
 
2710
+ // src/providers/google-batch.ts
2711
+ var GEMINI_API_BASE2 = "https://generativelanguage.googleapis.com/v1beta";
2712
+ function createGoogleBatchAdapter(apiKey) {
2713
+ async function apiRequest(path2, options = {}) {
2714
+ const headers = {
2715
+ "Content-Type": "application/json",
2716
+ "x-goog-api-key": apiKey
2717
+ };
2718
+ const res = await fetchWithTimeout(`${GEMINI_API_BASE2}${path2}`, {
2719
+ method: options.method || "GET",
2720
+ headers,
2721
+ body: options.body ? JSON.stringify(options.body) : void 0
2722
+ });
2723
+ if (!res.ok) {
2724
+ let errorBody;
2725
+ try {
2726
+ errorBody = await res.json();
2727
+ } catch {
2728
+ errorBody = { message: res.statusText };
2729
+ }
2730
+ const msg = errorBody?.error?.message || errorBody?.message || res.statusText;
2731
+ throw new AnyModelError(res.status >= 500 ? 502 : res.status, msg, {
2732
+ provider_name: "google",
2733
+ raw: errorBody
2734
+ });
2735
+ }
2736
+ return res;
2737
+ }
2738
+ function translateRequestToGemini(model, req) {
2739
+ const body = {};
2740
+ const systemMessages = req.messages.filter((m) => m.role === "system");
2741
+ const nonSystemMessages = req.messages.filter((m) => m.role !== "system");
2742
+ if (systemMessages.length > 0) {
2743
+ body.systemInstruction = {
2744
+ parts: [{ text: systemMessages.map((m) => typeof m.content === "string" ? m.content : "").join("\n") }]
2745
+ };
2746
+ }
2747
+ body.contents = nonSystemMessages.map((m) => ({
2748
+ role: m.role === "assistant" ? "model" : "user",
2749
+ parts: typeof m.content === "string" ? [{ text: m.content }] : Array.isArray(m.content) ? m.content.map((p) => p.type === "text" ? { text: p.text } : { text: "" }) : [{ text: "" }]
2750
+ }));
2751
+ const generationConfig = {};
2752
+ if (req.temperature !== void 0) generationConfig.temperature = req.temperature;
2753
+ generationConfig.maxOutputTokens = req.max_tokens !== void 0 ? req.max_tokens : resolveMaxTokens(model, req.messages);
2754
+ if (req.top_p !== void 0) generationConfig.topP = req.top_p;
2755
+ if (req.top_k !== void 0) generationConfig.topK = req.top_k;
2756
+ if (req.stop !== void 0) {
2757
+ generationConfig.stopSequences = Array.isArray(req.stop) ? req.stop : [req.stop];
2758
+ }
2759
+ if (req.response_format) {
2760
+ if (req.response_format.type === "json_object") {
2761
+ generationConfig.responseMimeType = "application/json";
2762
+ } else if (req.response_format.type === "json_schema") {
2763
+ generationConfig.responseMimeType = "application/json";
2764
+ generationConfig.responseSchema = req.response_format.json_schema?.schema;
2765
+ }
2766
+ }
2767
+ if (Object.keys(generationConfig).length > 0) {
2768
+ body.generationConfig = generationConfig;
2769
+ }
2770
+ if (req.tools && req.tools.length > 0) {
2771
+ body.tools = [{
2772
+ functionDeclarations: req.tools.map((t) => ({
2773
+ name: t.function.name,
2774
+ description: t.function.description || "",
2775
+ parameters: t.function.parameters || {}
2776
+ }))
2777
+ }];
2778
+ if (req.tool_choice) {
2779
+ if (req.tool_choice === "auto") {
2780
+ body.toolConfig = { functionCallingConfig: { mode: "AUTO" } };
2781
+ } else if (req.tool_choice === "required") {
2782
+ body.toolConfig = { functionCallingConfig: { mode: "ANY" } };
2783
+ } else if (req.tool_choice === "none") {
2784
+ body.toolConfig = { functionCallingConfig: { mode: "NONE" } };
2785
+ } else if (typeof req.tool_choice === "object") {
2786
+ body.toolConfig = {
2787
+ functionCallingConfig: {
2788
+ mode: "ANY",
2789
+ allowedFunctionNames: [req.tool_choice.function.name]
2790
+ }
2791
+ };
2792
+ }
2793
+ }
2794
+ }
2795
+ return body;
2796
+ }
2797
+ function mapFinishReason(reason) {
2798
+ switch (reason) {
2799
+ case "STOP":
2800
+ return "stop";
2801
+ case "MAX_TOKENS":
2802
+ return "length";
2803
+ case "SAFETY":
2804
+ return "content_filter";
2805
+ case "RECITATION":
2806
+ return "content_filter";
2807
+ default:
2808
+ return "stop";
2809
+ }
2810
+ }
2811
+ function translateGeminiResponse(response, model) {
2812
+ const candidate = response.candidates?.[0];
2813
+ let content = "";
2814
+ const toolCalls = [];
2815
+ for (const part of candidate?.content?.parts || []) {
2816
+ if (part.text) {
2817
+ content += part.text;
2818
+ } else if (part.functionCall) {
2819
+ toolCalls.push({
2820
+ id: generateId("call"),
2821
+ type: "function",
2822
+ function: {
2823
+ name: part.functionCall.name,
2824
+ arguments: JSON.stringify(part.functionCall.args || {})
2825
+ }
2826
+ });
2827
+ }
2828
+ }
2829
+ const message = { role: "assistant", content };
2830
+ if (toolCalls.length > 0) {
2831
+ message.tool_calls = toolCalls;
2832
+ }
2833
+ const finishReason = toolCalls.length > 0 ? "tool_calls" : mapFinishReason(candidate?.finishReason || "STOP");
2834
+ return {
2835
+ id: generateId(),
2836
+ object: "chat.completion",
2837
+ created: Math.floor(Date.now() / 1e3),
2838
+ model: `google/${model}`,
2839
+ choices: [{ index: 0, message, finish_reason: finishReason }],
2840
+ usage: {
2841
+ prompt_tokens: response.usageMetadata?.promptTokenCount || 0,
2842
+ completion_tokens: response.usageMetadata?.candidatesTokenCount || 0,
2843
+ total_tokens: response.usageMetadata?.totalTokenCount || 0
2844
+ }
2845
+ };
2846
+ }
2847
+ function mapBatchState(state) {
2848
+ switch (state) {
2849
+ case "JOB_STATE_PENDING":
2850
+ return "pending";
2851
+ case "JOB_STATE_RUNNING":
2852
+ return "processing";
2853
+ case "JOB_STATE_SUCCEEDED":
2854
+ return "completed";
2855
+ case "JOB_STATE_FAILED":
2856
+ return "failed";
2857
+ case "JOB_STATE_CANCELLED":
2858
+ return "cancelled";
2859
+ case "JOB_STATE_EXPIRED":
2860
+ return "failed";
2861
+ default:
2862
+ return "pending";
2863
+ }
2864
+ }
2865
+ return {
2866
+ async createBatch(model, requests, _options) {
2867
+ const batchRequests = requests.map((req) => ({
2868
+ request: translateRequestToGemini(model, req),
2869
+ metadata: { key: req.custom_id }
2870
+ }));
2871
+ const res = await apiRequest(`/models/${model}:batchGenerateContent`, {
2872
+ method: "POST",
2873
+ body: {
2874
+ batch: {
2875
+ display_name: `anymodel-batch-${Date.now()}`,
2876
+ input_config: {
2877
+ requests: {
2878
+ requests: batchRequests
2879
+ }
2880
+ }
2881
+ }
2882
+ }
2883
+ });
2884
+ const data = await res.json();
2885
+ const batchName = data.name || data.batch?.name;
2886
+ if (!batchName) {
2887
+ throw new AnyModelError(502, "No batch name in Google response", {
2888
+ provider_name: "google",
2889
+ raw: data
2890
+ });
2891
+ }
2892
+ return {
2893
+ providerBatchId: batchName,
2894
+ metadata: {
2895
+ model,
2896
+ total_requests: requests.length
2897
+ }
2898
+ };
2899
+ },
2900
+ async pollBatch(providerBatchId) {
2901
+ const res = await apiRequest(`/${providerBatchId}`);
2902
+ const data = await res.json();
2903
+ const state = data.state || "JOB_STATE_PENDING";
2904
+ const status = mapBatchState(state);
2905
+ const totalCount = data.totalCount || data.metadata?.total_requests || 0;
2906
+ const successCount = data.succeededCount || 0;
2907
+ const failedCount = data.failedCount || 0;
2908
+ return {
2909
+ status,
2910
+ total: totalCount || successCount + failedCount,
2911
+ completed: successCount,
2912
+ failed: failedCount
2913
+ };
2914
+ },
2915
+ async getBatchResults(providerBatchId) {
2916
+ const batchRes = await apiRequest(`/${providerBatchId}`);
2917
+ const batchData = await batchRes.json();
2918
+ const results = [];
2919
+ const model = batchData.metadata?.model || "unknown";
2920
+ if (batchData.response?.inlinedResponses) {
2921
+ for (const item of batchData.response.inlinedResponses) {
2922
+ const customId = item.metadata?.key || `request-${results.length}`;
2923
+ if (item.response) {
2924
+ results.push({
2925
+ custom_id: customId,
2926
+ status: "success",
2927
+ response: translateGeminiResponse(item.response, model),
2928
+ error: null
2929
+ });
2930
+ } else if (item.error) {
2931
+ results.push({
2932
+ custom_id: customId,
2933
+ status: "error",
2934
+ response: null,
2935
+ error: {
2936
+ code: item.error.code || 500,
2937
+ message: item.error.message || "Batch item failed"
2938
+ }
2939
+ });
2940
+ }
2941
+ }
2942
+ return results;
2943
+ }
2944
+ const responsesFile = batchData.response?.responsesFileName || batchData.outputConfig?.file_name;
2945
+ if (responsesFile) {
2946
+ const downloadUrl = `${GEMINI_API_BASE2}/${responsesFile}:download?alt=media`;
2947
+ const fileRes = await fetchWithTimeout(downloadUrl, {
2948
+ headers: { "x-goog-api-key": apiKey }
2949
+ });
2950
+ if (!fileRes.ok) {
2951
+ throw new AnyModelError(502, "Failed to download batch results file", {
2952
+ provider_name: "google"
2953
+ });
2954
+ }
2955
+ const text = await fileRes.text();
2956
+ for (const line of text.trim().split("\n")) {
2957
+ if (!line) continue;
2958
+ const item = JSON.parse(line);
2959
+ const customId = item.key || item.metadata?.key || `request-${results.length}`;
2960
+ if (item.response) {
2961
+ results.push({
2962
+ custom_id: customId,
2963
+ status: "success",
2964
+ response: translateGeminiResponse(item.response, model),
2965
+ error: null
2966
+ });
2967
+ } else if (item.error) {
2968
+ results.push({
2969
+ custom_id: customId,
2970
+ status: "error",
2971
+ response: null,
2972
+ error: {
2973
+ code: item.error.code || 500,
2974
+ message: item.error.message || "Batch item failed"
2975
+ }
2976
+ });
2977
+ }
2978
+ }
2979
+ }
2980
+ return results;
2981
+ },
2982
+ async cancelBatch(providerBatchId) {
2983
+ await apiRequest(`/${providerBatchId}:cancel`, { method: "POST" });
2984
+ }
2985
+ };
2986
+ }
2987
+
2642
2988
  // src/client.ts
2643
2989
  var AnyModel = class {
2644
2990
  registry;
@@ -2654,6 +3000,7 @@ var AnyModel = class {
2654
3000
  constructor(config = {}) {
2655
3001
  this.config = resolveConfig(config);
2656
3002
  this.registry = new ProviderRegistry();
3003
+ setDefaultTimeout((this.config.defaults?.timeout ?? 120) * 1e3);
2657
3004
  if (this.config.io) {
2658
3005
  configureFsIO(this.config.io);
2659
3006
  }
@@ -2774,6 +3121,10 @@ var AnyModel = class {
2774
3121
  if (anthropicKey) {
2775
3122
  this.batchManager.registerBatchAdapter("anthropic", createAnthropicBatchAdapter(anthropicKey));
2776
3123
  }
3124
+ const googleKey = config.google?.apiKey || process.env.GOOGLE_API_KEY;
3125
+ if (googleKey) {
3126
+ this.batchManager.registerBatchAdapter("google", createGoogleBatchAdapter(googleKey));
3127
+ }
2777
3128
  }
2778
3129
  applyDefaults(request) {
2779
3130
  const defaults = this.config.defaults;