@mariozechner/pi-ai 0.49.2 → 0.50.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.
Files changed (108) hide show
  1. package/README.md +32 -22
  2. package/dist/api-registry.d.ts +20 -0
  3. package/dist/api-registry.d.ts.map +1 -0
  4. package/dist/api-registry.js +44 -0
  5. package/dist/api-registry.js.map +1 -0
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +22 -67
  8. package/dist/cli.js.map +1 -1
  9. package/dist/env-api-keys.d.ts +9 -0
  10. package/dist/env-api-keys.d.ts.map +1 -0
  11. package/dist/env-api-keys.js +91 -0
  12. package/dist/env-api-keys.js.map +1 -0
  13. package/dist/index.d.ts +4 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +4 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/models.generated.d.ts +649 -126
  18. package/dist/models.generated.d.ts.map +1 -1
  19. package/dist/models.generated.js +679 -151
  20. package/dist/models.generated.js.map +1 -1
  21. package/dist/providers/amazon-bedrock.d.ts +3 -2
  22. package/dist/providers/amazon-bedrock.d.ts.map +1 -1
  23. package/dist/providers/amazon-bedrock.js +52 -5
  24. package/dist/providers/amazon-bedrock.js.map +1 -1
  25. package/dist/providers/anthropic.d.ts +3 -2
  26. package/dist/providers/anthropic.d.ts.map +1 -1
  27. package/dist/providers/anthropic.js +35 -10
  28. package/dist/providers/anthropic.js.map +1 -1
  29. package/dist/providers/azure-openai-responses.d.ts +15 -0
  30. package/dist/providers/azure-openai-responses.d.ts.map +1 -0
  31. package/dist/providers/azure-openai-responses.js +184 -0
  32. package/dist/providers/azure-openai-responses.js.map +1 -0
  33. package/dist/providers/google-gemini-cli.d.ts +3 -2
  34. package/dist/providers/google-gemini-cli.d.ts.map +1 -1
  35. package/dist/providers/google-gemini-cli.js +69 -1
  36. package/dist/providers/google-gemini-cli.js.map +1 -1
  37. package/dist/providers/google-vertex.d.ts +3 -2
  38. package/dist/providers/google-vertex.d.ts.map +1 -1
  39. package/dist/providers/google-vertex.js +85 -5
  40. package/dist/providers/google-vertex.js.map +1 -1
  41. package/dist/providers/google.d.ts +3 -2
  42. package/dist/providers/google.d.ts.map +1 -1
  43. package/dist/providers/google.js +88 -7
  44. package/dist/providers/google.js.map +1 -1
  45. package/dist/providers/openai-codex-responses.d.ts +3 -2
  46. package/dist/providers/openai-codex-responses.d.ts.map +1 -1
  47. package/dist/providers/openai-codex-responses.js +71 -311
  48. package/dist/providers/openai-codex-responses.js.map +1 -1
  49. package/dist/providers/openai-completions.d.ts +5 -2
  50. package/dist/providers/openai-completions.d.ts.map +1 -1
  51. package/dist/providers/openai-completions.js +84 -43
  52. package/dist/providers/openai-completions.js.map +1 -1
  53. package/dist/providers/openai-responses-shared.d.ts +17 -0
  54. package/dist/providers/openai-responses-shared.d.ts.map +1 -0
  55. package/dist/providers/openai-responses-shared.js +424 -0
  56. package/dist/providers/openai-responses-shared.js.map +1 -0
  57. package/dist/providers/openai-responses.d.ts +3 -2
  58. package/dist/providers/openai-responses.d.ts.map +1 -1
  59. package/dist/providers/openai-responses.js +31 -402
  60. package/dist/providers/openai-responses.js.map +1 -1
  61. package/dist/providers/register-builtins.d.ts +3 -0
  62. package/dist/providers/register-builtins.d.ts.map +1 -0
  63. package/dist/providers/register-builtins.js +63 -0
  64. package/dist/providers/register-builtins.js.map +1 -0
  65. package/dist/providers/simple-options.d.ts +8 -0
  66. package/dist/providers/simple-options.d.ts.map +1 -0
  67. package/dist/providers/simple-options.js +32 -0
  68. package/dist/providers/simple-options.js.map +1 -0
  69. package/dist/stream.d.ts +5 -10
  70. package/dist/stream.d.ts.map +1 -1
  71. package/dist/stream.js +21 -404
  72. package/dist/stream.js.map +1 -1
  73. package/dist/types.d.ts +24 -22
  74. package/dist/types.d.ts.map +1 -1
  75. package/dist/types.js +0 -1
  76. package/dist/types.js.map +1 -1
  77. package/dist/utils/event-stream.d.ts +2 -0
  78. package/dist/utils/event-stream.d.ts.map +1 -1
  79. package/dist/utils/event-stream.js +4 -0
  80. package/dist/utils/event-stream.js.map +1 -1
  81. package/dist/utils/oauth/anthropic.d.ts +2 -1
  82. package/dist/utils/oauth/anthropic.d.ts.map +1 -1
  83. package/dist/utils/oauth/anthropic.js +13 -0
  84. package/dist/utils/oauth/anthropic.js.map +1 -1
  85. package/dist/utils/oauth/github-copilot.d.ts +2 -1
  86. package/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  87. package/dist/utils/oauth/github-copilot.js +25 -0
  88. package/dist/utils/oauth/github-copilot.js.map +1 -1
  89. package/dist/utils/oauth/google-antigravity.d.ts +2 -1
  90. package/dist/utils/oauth/google-antigravity.d.ts.map +1 -1
  91. package/dist/utils/oauth/google-antigravity.js +19 -0
  92. package/dist/utils/oauth/google-antigravity.js.map +1 -1
  93. package/dist/utils/oauth/google-gemini-cli.d.ts +2 -1
  94. package/dist/utils/oauth/google-gemini-cli.d.ts.map +1 -1
  95. package/dist/utils/oauth/google-gemini-cli.js +19 -0
  96. package/dist/utils/oauth/google-gemini-cli.js.map +1 -1
  97. package/dist/utils/oauth/index.d.ts +26 -16
  98. package/dist/utils/oauth/index.d.ts.map +1 -1
  99. package/dist/utils/oauth/index.js +65 -84
  100. package/dist/utils/oauth/index.js.map +1 -1
  101. package/dist/utils/oauth/openai-codex.d.ts +7 -1
  102. package/dist/utils/oauth/openai-codex.d.ts.map +1 -1
  103. package/dist/utils/oauth/openai-codex.js +46 -8
  104. package/dist/utils/oauth/openai-codex.js.map +1 -1
  105. package/dist/utils/oauth/types.d.ts +28 -6
  106. package/dist/utils/oauth/types.d.ts.map +1 -1
  107. package/dist/utils/oauth/types.js.map +1 -1
  108. package/package.json +3 -1
@@ -0,0 +1,63 @@
1
+ import { clearApiProviders, registerApiProvider } from "../api-registry.js";
2
+ import { streamBedrock, streamSimpleBedrock } from "./amazon-bedrock.js";
3
+ import { streamAnthropic, streamSimpleAnthropic } from "./anthropic.js";
4
+ import { streamAzureOpenAIResponses, streamSimpleAzureOpenAIResponses } from "./azure-openai-responses.js";
5
+ import { streamGoogle, streamSimpleGoogle } from "./google.js";
6
+ import { streamGoogleGeminiCli, streamSimpleGoogleGeminiCli } from "./google-gemini-cli.js";
7
+ import { streamGoogleVertex, streamSimpleGoogleVertex } from "./google-vertex.js";
8
+ import { streamOpenAICodexResponses, streamSimpleOpenAICodexResponses } from "./openai-codex-responses.js";
9
+ import { streamOpenAICompletions, streamSimpleOpenAICompletions } from "./openai-completions.js";
10
+ import { streamOpenAIResponses, streamSimpleOpenAIResponses } from "./openai-responses.js";
11
+ export function registerBuiltInApiProviders() {
12
+ registerApiProvider({
13
+ api: "anthropic-messages",
14
+ stream: streamAnthropic,
15
+ streamSimple: streamSimpleAnthropic,
16
+ });
17
+ registerApiProvider({
18
+ api: "openai-completions",
19
+ stream: streamOpenAICompletions,
20
+ streamSimple: streamSimpleOpenAICompletions,
21
+ });
22
+ registerApiProvider({
23
+ api: "openai-responses",
24
+ stream: streamOpenAIResponses,
25
+ streamSimple: streamSimpleOpenAIResponses,
26
+ });
27
+ registerApiProvider({
28
+ api: "azure-openai-responses",
29
+ stream: streamAzureOpenAIResponses,
30
+ streamSimple: streamSimpleAzureOpenAIResponses,
31
+ });
32
+ registerApiProvider({
33
+ api: "openai-codex-responses",
34
+ stream: streamOpenAICodexResponses,
35
+ streamSimple: streamSimpleOpenAICodexResponses,
36
+ });
37
+ registerApiProvider({
38
+ api: "google-generative-ai",
39
+ stream: streamGoogle,
40
+ streamSimple: streamSimpleGoogle,
41
+ });
42
+ registerApiProvider({
43
+ api: "google-gemini-cli",
44
+ stream: streamGoogleGeminiCli,
45
+ streamSimple: streamSimpleGoogleGeminiCli,
46
+ });
47
+ registerApiProvider({
48
+ api: "google-vertex",
49
+ stream: streamGoogleVertex,
50
+ streamSimple: streamSimpleGoogleVertex,
51
+ });
52
+ registerApiProvider({
53
+ api: "bedrock-converse-stream",
54
+ stream: streamBedrock,
55
+ streamSimple: streamSimpleBedrock,
56
+ });
57
+ }
58
+ export function resetApiProviders() {
59
+ clearApiProviders();
60
+ registerBuiltInApiProviders();
61
+ }
62
+ registerBuiltInApiProviders();
63
+ //# sourceMappingURL=register-builtins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-builtins.js","sourceRoot":"","sources":["../../src/providers/register-builtins.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,0BAA0B,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAC;AAC3G,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAC5F,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAC;AAC3G,OAAO,EAAE,uBAAuB,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAE,qBAAqB,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAE3F,MAAM,UAAU,2BAA2B,GAAS;IACnD,mBAAmB,CAAC;QACnB,GAAG,EAAE,oBAAoB;QACzB,MAAM,EAAE,eAAe;QACvB,YAAY,EAAE,qBAAqB;KACnC,CAAC,CAAC;IAEH,mBAAmB,CAAC;QACnB,GAAG,EAAE,oBAAoB;QACzB,MAAM,EAAE,uBAAuB;QAC/B,YAAY,EAAE,6BAA6B;KAC3C,CAAC,CAAC;IAEH,mBAAmB,CAAC;QACnB,GAAG,EAAE,kBAAkB;QACvB,MAAM,EAAE,qBAAqB;QAC7B,YAAY,EAAE,2BAA2B;KACzC,CAAC,CAAC;IAEH,mBAAmB,CAAC;QACnB,GAAG,EAAE,wBAAwB;QAC7B,MAAM,EAAE,0BAA0B;QAClC,YAAY,EAAE,gCAAgC;KAC9C,CAAC,CAAC;IAEH,mBAAmB,CAAC;QACnB,GAAG,EAAE,wBAAwB;QAC7B,MAAM,EAAE,0BAA0B;QAClC,YAAY,EAAE,gCAAgC;KAC9C,CAAC,CAAC;IAEH,mBAAmB,CAAC;QACnB,GAAG,EAAE,sBAAsB;QAC3B,MAAM,EAAE,YAAY;QACpB,YAAY,EAAE,kBAAkB;KAChC,CAAC,CAAC;IAEH,mBAAmB,CAAC;QACnB,GAAG,EAAE,mBAAmB;QACxB,MAAM,EAAE,qBAAqB;QAC7B,YAAY,EAAE,2BAA2B;KACzC,CAAC,CAAC;IAEH,mBAAmB,CAAC;QACnB,GAAG,EAAE,eAAe;QACpB,MAAM,EAAE,kBAAkB;QAC1B,YAAY,EAAE,wBAAwB;KACtC,CAAC,CAAC;IAEH,mBAAmB,CAAC;QACnB,GAAG,EAAE,yBAAyB;QAC9B,MAAM,EAAE,aAAa;QACrB,YAAY,EAAE,mBAAmB;KACjC,CAAC,CAAC;AAAA,CACH;AAED,MAAM,UAAU,iBAAiB,GAAS;IACzC,iBAAiB,EAAE,CAAC;IACpB,2BAA2B,EAAE,CAAC;AAAA,CAC9B;AAED,2BAA2B,EAAE,CAAC","sourcesContent":["import { clearApiProviders, registerApiProvider } from \"../api-registry.js\";\nimport { streamBedrock, streamSimpleBedrock } from \"./amazon-bedrock.js\";\nimport { streamAnthropic, streamSimpleAnthropic } from \"./anthropic.js\";\nimport { streamAzureOpenAIResponses, streamSimpleAzureOpenAIResponses } from \"./azure-openai-responses.js\";\nimport { streamGoogle, streamSimpleGoogle } from \"./google.js\";\nimport { streamGoogleGeminiCli, streamSimpleGoogleGeminiCli } from \"./google-gemini-cli.js\";\nimport { streamGoogleVertex, streamSimpleGoogleVertex } from \"./google-vertex.js\";\nimport { streamOpenAICodexResponses, streamSimpleOpenAICodexResponses } from \"./openai-codex-responses.js\";\nimport { streamOpenAICompletions, streamSimpleOpenAICompletions } from \"./openai-completions.js\";\nimport { streamOpenAIResponses, streamSimpleOpenAIResponses } from \"./openai-responses.js\";\n\nexport function registerBuiltInApiProviders(): void {\n\tregisterApiProvider({\n\t\tapi: \"anthropic-messages\",\n\t\tstream: streamAnthropic,\n\t\tstreamSimple: streamSimpleAnthropic,\n\t});\n\n\tregisterApiProvider({\n\t\tapi: \"openai-completions\",\n\t\tstream: streamOpenAICompletions,\n\t\tstreamSimple: streamSimpleOpenAICompletions,\n\t});\n\n\tregisterApiProvider({\n\t\tapi: \"openai-responses\",\n\t\tstream: streamOpenAIResponses,\n\t\tstreamSimple: streamSimpleOpenAIResponses,\n\t});\n\n\tregisterApiProvider({\n\t\tapi: \"azure-openai-responses\",\n\t\tstream: streamAzureOpenAIResponses,\n\t\tstreamSimple: streamSimpleAzureOpenAIResponses,\n\t});\n\n\tregisterApiProvider({\n\t\tapi: \"openai-codex-responses\",\n\t\tstream: streamOpenAICodexResponses,\n\t\tstreamSimple: streamSimpleOpenAICodexResponses,\n\t});\n\n\tregisterApiProvider({\n\t\tapi: \"google-generative-ai\",\n\t\tstream: streamGoogle,\n\t\tstreamSimple: streamSimpleGoogle,\n\t});\n\n\tregisterApiProvider({\n\t\tapi: \"google-gemini-cli\",\n\t\tstream: streamGoogleGeminiCli,\n\t\tstreamSimple: streamSimpleGoogleGeminiCli,\n\t});\n\n\tregisterApiProvider({\n\t\tapi: \"google-vertex\",\n\t\tstream: streamGoogleVertex,\n\t\tstreamSimple: streamSimpleGoogleVertex,\n\t});\n\n\tregisterApiProvider({\n\t\tapi: \"bedrock-converse-stream\",\n\t\tstream: streamBedrock,\n\t\tstreamSimple: streamSimpleBedrock,\n\t});\n}\n\nexport function resetApiProviders(): void {\n\tclearApiProviders();\n\tregisterBuiltInApiProviders();\n}\n\nregisterBuiltInApiProviders();\n"]}
@@ -0,0 +1,8 @@
1
+ import type { Api, Model, SimpleStreamOptions, StreamOptions, ThinkingBudgets, ThinkingLevel } from "../types.js";
2
+ export declare function buildBaseOptions(model: Model<Api>, options?: SimpleStreamOptions, apiKey?: string): StreamOptions;
3
+ export declare function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, "xhigh"> | undefined;
4
+ export declare function adjustMaxTokensForThinking(baseMaxTokens: number, modelMaxTokens: number, reasoningLevel: ThinkingLevel, customBudgets?: ThinkingBudgets): {
5
+ maxTokens: number;
6
+ thinkingBudget: number;
7
+ };
8
+ //# sourceMappingURL=simple-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-options.d.ts","sourceRoot":"","sources":["../../src/providers/simple-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,mBAAmB,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAElH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,mBAAmB,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,aAAa,CAUjH;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,GAAG,SAAS,CAE7G;AAED,wBAAgB,0BAA0B,CACzC,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,aAAa,EAC7B,aAAa,CAAC,EAAE,eAAe,GAC7B;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAmB/C","sourcesContent":["import type { Api, Model, SimpleStreamOptions, StreamOptions, ThinkingBudgets, ThinkingLevel } from \"../types.js\";\n\nexport function buildBaseOptions(model: Model<Api>, options?: SimpleStreamOptions, apiKey?: string): StreamOptions {\n\treturn {\n\t\ttemperature: options?.temperature,\n\t\tmaxTokens: options?.maxTokens || Math.min(model.maxTokens, 32000),\n\t\tsignal: options?.signal,\n\t\tapiKey: apiKey || options?.apiKey,\n\t\tsessionId: options?.sessionId,\n\t\theaders: options?.headers,\n\t\tonPayload: options?.onPayload,\n\t};\n}\n\nexport function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, \"xhigh\"> | undefined {\n\treturn effort === \"xhigh\" ? \"high\" : effort;\n}\n\nexport function adjustMaxTokensForThinking(\n\tbaseMaxTokens: number,\n\tmodelMaxTokens: number,\n\treasoningLevel: ThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): { maxTokens: number; thinkingBudget: number } {\n\tconst defaultBudgets: ThinkingBudgets = {\n\t\tminimal: 1024,\n\t\tlow: 2048,\n\t\tmedium: 8192,\n\t\thigh: 16384,\n\t};\n\tconst budgets = { ...defaultBudgets, ...customBudgets };\n\n\tconst minOutputTokens = 1024;\n\tconst level = clampReasoning(reasoningLevel)!;\n\tlet thinkingBudget = budgets[level]!;\n\tconst maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n\n\tif (maxTokens <= thinkingBudget) {\n\t\tthinkingBudget = Math.max(0, maxTokens - minOutputTokens);\n\t}\n\n\treturn { maxTokens, thinkingBudget };\n}\n"]}
@@ -0,0 +1,32 @@
1
+ export function buildBaseOptions(model, options, apiKey) {
2
+ return {
3
+ temperature: options?.temperature,
4
+ maxTokens: options?.maxTokens || Math.min(model.maxTokens, 32000),
5
+ signal: options?.signal,
6
+ apiKey: apiKey || options?.apiKey,
7
+ sessionId: options?.sessionId,
8
+ headers: options?.headers,
9
+ onPayload: options?.onPayload,
10
+ };
11
+ }
12
+ export function clampReasoning(effort) {
13
+ return effort === "xhigh" ? "high" : effort;
14
+ }
15
+ export function adjustMaxTokensForThinking(baseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) {
16
+ const defaultBudgets = {
17
+ minimal: 1024,
18
+ low: 2048,
19
+ medium: 8192,
20
+ high: 16384,
21
+ };
22
+ const budgets = { ...defaultBudgets, ...customBudgets };
23
+ const minOutputTokens = 1024;
24
+ const level = clampReasoning(reasoningLevel);
25
+ let thinkingBudget = budgets[level];
26
+ const maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
27
+ if (maxTokens <= thinkingBudget) {
28
+ thinkingBudget = Math.max(0, maxTokens - minOutputTokens);
29
+ }
30
+ return { maxTokens, thinkingBudget };
31
+ }
32
+ //# sourceMappingURL=simple-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simple-options.js","sourceRoot":"","sources":["../../src/providers/simple-options.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gBAAgB,CAAC,KAAiB,EAAE,OAA6B,EAAE,MAAe,EAAiB;IAClH,OAAO;QACN,WAAW,EAAE,OAAO,EAAE,WAAW;QACjC,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC;QACjE,MAAM,EAAE,OAAO,EAAE,MAAM;QACvB,MAAM,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM;QACjC,SAAS,EAAE,OAAO,EAAE,SAAS;QAC7B,OAAO,EAAE,OAAO,EAAE,OAAO;QACzB,SAAS,EAAE,OAAO,EAAE,SAAS;KAC7B,CAAC;AAAA,CACF;AAED,MAAM,UAAU,cAAc,CAAC,MAAiC,EAA+C;IAC9G,OAAO,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;AAAA,CAC5C;AAED,MAAM,UAAU,0BAA0B,CACzC,aAAqB,EACrB,cAAsB,EACtB,cAA6B,EAC7B,aAA+B,EACiB;IAChD,MAAM,cAAc,GAAoB;QACvC,OAAO,EAAE,IAAI;QACb,GAAG,EAAE,IAAI;QACT,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,KAAK;KACX,CAAC;IACF,MAAM,OAAO,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,aAAa,EAAE,CAAC;IAExD,MAAM,eAAe,GAAG,IAAI,CAAC;IAC7B,MAAM,KAAK,GAAG,cAAc,CAAC,cAAc,CAAE,CAAC;IAC9C,IAAI,cAAc,GAAG,OAAO,CAAC,KAAK,CAAE,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,GAAG,cAAc,EAAE,cAAc,CAAC,CAAC;IAE3E,IAAI,SAAS,IAAI,cAAc,EAAE,CAAC;QACjC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,eAAe,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;AAAA,CACrC","sourcesContent":["import type { Api, Model, SimpleStreamOptions, StreamOptions, ThinkingBudgets, ThinkingLevel } from \"../types.js\";\n\nexport function buildBaseOptions(model: Model<Api>, options?: SimpleStreamOptions, apiKey?: string): StreamOptions {\n\treturn {\n\t\ttemperature: options?.temperature,\n\t\tmaxTokens: options?.maxTokens || Math.min(model.maxTokens, 32000),\n\t\tsignal: options?.signal,\n\t\tapiKey: apiKey || options?.apiKey,\n\t\tsessionId: options?.sessionId,\n\t\theaders: options?.headers,\n\t\tonPayload: options?.onPayload,\n\t};\n}\n\nexport function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, \"xhigh\"> | undefined {\n\treturn effort === \"xhigh\" ? \"high\" : effort;\n}\n\nexport function adjustMaxTokensForThinking(\n\tbaseMaxTokens: number,\n\tmodelMaxTokens: number,\n\treasoningLevel: ThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): { maxTokens: number; thinkingBudget: number } {\n\tconst defaultBudgets: ThinkingBudgets = {\n\t\tminimal: 1024,\n\t\tlow: 2048,\n\t\tmedium: 8192,\n\t\thigh: 16384,\n\t};\n\tconst budgets = { ...defaultBudgets, ...customBudgets };\n\n\tconst minOutputTokens = 1024;\n\tconst level = clampReasoning(reasoningLevel)!;\n\tlet thinkingBudget = budgets[level]!;\n\tconst maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n\n\tif (maxTokens <= thinkingBudget) {\n\t\tthinkingBudget = Math.max(0, maxTokens - minOutputTokens);\n\t}\n\n\treturn { maxTokens, thinkingBudget };\n}\n"]}
package/dist/stream.d.ts CHANGED
@@ -1,13 +1,8 @@
1
- import type { Api, AssistantMessage, AssistantMessageEventStream, Context, KnownProvider, Model, OptionsForApi, SimpleStreamOptions } from "./types.js";
2
- /**
3
- * Get API key for provider from known environment variables, e.g. OPENAI_API_KEY.
4
- *
5
- * Will not return API keys for providers that require OAuth tokens.
6
- */
7
- export declare function getEnvApiKey(provider: KnownProvider): string | undefined;
8
- export declare function getEnvApiKey(provider: string): string | undefined;
9
- export declare function stream<TApi extends Api>(model: Model<TApi>, context: Context, options?: OptionsForApi<TApi>): AssistantMessageEventStream;
10
- export declare function complete<TApi extends Api>(model: Model<TApi>, context: Context, options?: OptionsForApi<TApi>): Promise<AssistantMessage>;
1
+ import "./providers/register-builtins.js";
2
+ import type { Api, AssistantMessage, AssistantMessageEventStream, Context, Model, ProviderStreamOptions, SimpleStreamOptions } from "./types.js";
3
+ export { getEnvApiKey } from "./env-api-keys.js";
4
+ export declare function stream<TApi extends Api>(model: Model<TApi>, context: Context, options?: ProviderStreamOptions): AssistantMessageEventStream;
5
+ export declare function complete<TApi extends Api>(model: Model<TApi>, context: Context, options?: ProviderStreamOptions): Promise<AssistantMessage>;
11
6
  export declare function streamSimple<TApi extends Api>(model: Model<TApi>, context: Context, options?: SimpleStreamOptions): AssistantMessageEventStream;
12
7
  export declare function completeSimple<TApi extends Api>(model: Model<TApi>, context: Context, options?: SimpleStreamOptions): Promise<AssistantMessage>;
13
8
  //# sourceMappingURL=stream.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EACX,GAAG,EACH,gBAAgB,EAChB,2BAA2B,EAC3B,OAAO,EACP,aAAa,EACb,KAAK,EACL,aAAa,EACb,mBAAmB,EAGnB,MAAM,YAAY,CAAC;AAoBpB;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC;AAC1E,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AA+DnE,wBAAgB,MAAM,CAAC,IAAI,SAAS,GAAG,EACtC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,GAC3B,2BAA2B,CA6C7B;AAED,wBAAsB,QAAQ,CAAC,IAAI,SAAS,GAAG,EAC9C,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,aAAa,CAAC,IAAI,CAAC,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAG3B;AAED,wBAAgB,YAAY,CAAC,IAAI,SAAS,GAAG,EAC5C,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC3B,2BAA2B,CAkB7B;AAED,wBAAsB,cAAc,CAAC,IAAI,SAAS,GAAG,EACpD,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAG3B","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { supportsXhigh } from \"./models.js\";\nimport { type BedrockOptions, streamBedrock } from \"./providers/amazon-bedrock.js\";\nimport { type AnthropicOptions, streamAnthropic } from \"./providers/anthropic.js\";\nimport { type GoogleOptions, streamGoogle } from \"./providers/google.js\";\nimport {\n\ttype GoogleGeminiCliOptions,\n\ttype GoogleThinkingLevel,\n\tstreamGoogleGeminiCli,\n} from \"./providers/google-gemini-cli.js\";\nimport { type GoogleVertexOptions, streamGoogleVertex } from \"./providers/google-vertex.js\";\nimport { type OpenAICodexResponsesOptions, streamOpenAICodexResponses } from \"./providers/openai-codex-responses.js\";\nimport { type OpenAICompletionsOptions, streamOpenAICompletions } from \"./providers/openai-completions.js\";\nimport { type OpenAIResponsesOptions, streamOpenAIResponses } from \"./providers/openai-responses.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tAssistantMessageEventStream,\n\tContext,\n\tKnownProvider,\n\tModel,\n\tOptionsForApi,\n\tSimpleStreamOptions,\n\tThinkingBudgets,\n\tThinkingLevel,\n} from \"./types.js\";\n\nlet cachedVertexAdcCredentialsExists: boolean | null = null;\n\nfunction hasVertexAdcCredentials(): boolean {\n\tif (cachedVertexAdcCredentialsExists === null) {\n\t\t// Check GOOGLE_APPLICATION_CREDENTIALS env var first (standard way)\n\t\tconst gacPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;\n\t\tif (gacPath) {\n\t\t\tcachedVertexAdcCredentialsExists = existsSync(gacPath);\n\t\t} else {\n\t\t\t// Fall back to default ADC path (lazy evaluation)\n\t\t\tcachedVertexAdcCredentialsExists = existsSync(\n\t\t\t\tjoin(homedir(), \".config\", \"gcloud\", \"application_default_credentials.json\"),\n\t\t\t);\n\t\t}\n\t}\n\treturn cachedVertexAdcCredentialsExists;\n}\n\n/**\n * Get API key for provider from known environment variables, e.g. OPENAI_API_KEY.\n *\n * Will not return API keys for providers that require OAuth tokens.\n */\nexport function getEnvApiKey(provider: KnownProvider): string | undefined;\nexport function getEnvApiKey(provider: string): string | undefined;\nexport function getEnvApiKey(provider: any): string | undefined {\n\t// Fall back to environment variables\n\tif (provider === \"github-copilot\") {\n\t\treturn process.env.COPILOT_GITHUB_TOKEN || process.env.GH_TOKEN || process.env.GITHUB_TOKEN;\n\t}\n\n\t// ANTHROPIC_OAUTH_TOKEN takes precedence over ANTHROPIC_API_KEY\n\tif (provider === \"anthropic\") {\n\t\treturn process.env.ANTHROPIC_OAUTH_TOKEN || process.env.ANTHROPIC_API_KEY;\n\t}\n\n\t// Vertex AI uses Application Default Credentials, not API keys.\n\t// Auth is configured via `gcloud auth application-default login`.\n\tif (provider === \"google-vertex\") {\n\t\tconst hasCredentials = hasVertexAdcCredentials();\n\t\tconst hasProject = !!(process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT);\n\t\tconst hasLocation = !!process.env.GOOGLE_CLOUD_LOCATION;\n\n\t\tif (hasCredentials && hasProject && hasLocation) {\n\t\t\treturn \"<authenticated>\";\n\t\t}\n\t}\n\n\tif (provider === \"amazon-bedrock\") {\n\t\t// Amazon Bedrock supports multiple credential sources:\n\t\t// 1. AWS_PROFILE - named profile from ~/.aws/credentials\n\t\t// 2. AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY - standard IAM keys\n\t\t// 3. AWS_BEARER_TOKEN_BEDROCK - Bedrock API keys (bearer token)\n\t\t// 4. AWS_CONTAINER_CREDENTIALS_RELATIVE_URI - ECS task roles\n\t\t// 5. AWS_CONTAINER_CREDENTIALS_FULL_URI - ECS task roles (full URI)\n\t\t// 6. AWS_WEB_IDENTITY_TOKEN_FILE - IRSA (IAM Roles for Service Accounts)\n\t\tif (\n\t\t\tprocess.env.AWS_PROFILE ||\n\t\t\t(process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) ||\n\t\t\tprocess.env.AWS_BEARER_TOKEN_BEDROCK ||\n\t\t\tprocess.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ||\n\t\t\tprocess.env.AWS_CONTAINER_CREDENTIALS_FULL_URI ||\n\t\t\tprocess.env.AWS_WEB_IDENTITY_TOKEN_FILE\n\t\t) {\n\t\t\treturn \"<authenticated>\";\n\t\t}\n\t}\n\n\tconst envMap: Record<string, string> = {\n\t\topenai: \"OPENAI_API_KEY\",\n\t\tgoogle: \"GEMINI_API_KEY\",\n\t\tgroq: \"GROQ_API_KEY\",\n\t\tcerebras: \"CEREBRAS_API_KEY\",\n\t\txai: \"XAI_API_KEY\",\n\t\topenrouter: \"OPENROUTER_API_KEY\",\n\t\t\"vercel-ai-gateway\": \"AI_GATEWAY_API_KEY\",\n\t\tzai: \"ZAI_API_KEY\",\n\t\tmistral: \"MISTRAL_API_KEY\",\n\t\tminimax: \"MINIMAX_API_KEY\",\n\t\t\"minimax-cn\": \"MINIMAX_CN_API_KEY\",\n\t\topencode: \"OPENCODE_API_KEY\",\n\t};\n\n\tconst envVar = envMap[provider];\n\treturn envVar ? process.env[envVar] : undefined;\n}\n\nexport function stream<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: OptionsForApi<TApi>,\n): AssistantMessageEventStream {\n\t// Vertex AI uses Application Default Credentials, not API keys\n\tif (model.api === \"google-vertex\") {\n\t\treturn streamGoogleVertex(model as Model<\"google-vertex\">, context, options as GoogleVertexOptions);\n\t} else if (model.api === \"bedrock-converse-stream\") {\n\t\t// Bedrock doesn't have any API keys instead it sources credentials from standard AWS env variables or from given AWS profile.\n\t\treturn streamBedrock(model as Model<\"bedrock-converse-stream\">, context, (options || {}) as BedrockOptions);\n\t}\n\n\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider);\n\tif (!apiKey) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\tconst providerOptions = { ...options, apiKey };\n\n\tconst api: Api = model.api;\n\tswitch (api) {\n\t\tcase \"anthropic-messages\":\n\t\t\treturn streamAnthropic(model as Model<\"anthropic-messages\">, context, providerOptions);\n\n\t\tcase \"openai-completions\":\n\t\t\treturn streamOpenAICompletions(model as Model<\"openai-completions\">, context, providerOptions as any);\n\n\t\tcase \"openai-responses\":\n\t\t\treturn streamOpenAIResponses(model as Model<\"openai-responses\">, context, providerOptions as any);\n\n\t\tcase \"openai-codex-responses\":\n\t\t\treturn streamOpenAICodexResponses(model as Model<\"openai-codex-responses\">, context, providerOptions as any);\n\n\t\tcase \"google-generative-ai\":\n\t\t\treturn streamGoogle(model as Model<\"google-generative-ai\">, context, providerOptions);\n\n\t\tcase \"google-gemini-cli\":\n\t\t\treturn streamGoogleGeminiCli(\n\t\t\t\tmodel as Model<\"google-gemini-cli\">,\n\t\t\t\tcontext,\n\t\t\t\tproviderOptions as GoogleGeminiCliOptions,\n\t\t\t);\n\n\t\tdefault: {\n\t\t\t// This should never be reached if all Api cases are handled\n\t\t\tconst _exhaustive: never = api;\n\t\t\tthrow new Error(`Unhandled API: ${_exhaustive}`);\n\t\t}\n\t}\n}\n\nexport async function complete<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: OptionsForApi<TApi>,\n): Promise<AssistantMessage> {\n\tconst s = stream(model, context, options);\n\treturn s.result();\n}\n\nexport function streamSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream {\n\t// Vertex AI uses Application Default Credentials, not API keys\n\tif (model.api === \"google-vertex\") {\n\t\tconst providerOptions = mapOptionsForApi(model, options, undefined);\n\t\treturn stream(model, context, providerOptions);\n\t} else if (model.api === \"bedrock-converse-stream\") {\n\t\t// Bedrock doesn't have any API keys instead it sources credentials from standard AWS env variables or from given AWS profile.\n\t\tconst providerOptions = mapOptionsForApi(model, options, undefined);\n\t\treturn stream(model, context, providerOptions);\n\t}\n\n\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider);\n\tif (!apiKey) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\n\tconst providerOptions = mapOptionsForApi(model, options, apiKey);\n\treturn stream(model, context, providerOptions);\n}\n\nexport async function completeSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = streamSimple(model, context, options);\n\treturn s.result();\n}\n\nfunction mapOptionsForApi<TApi extends Api>(\n\tmodel: Model<TApi>,\n\toptions?: SimpleStreamOptions,\n\tapiKey?: string,\n): OptionsForApi<TApi> {\n\tconst base = {\n\t\ttemperature: options?.temperature,\n\t\tmaxTokens: options?.maxTokens || Math.min(model.maxTokens, 32000),\n\t\tsignal: options?.signal,\n\t\tapiKey: apiKey || options?.apiKey,\n\t\tsessionId: options?.sessionId,\n\t};\n\n\t// Helper to clamp xhigh to high for providers that don't support it\n\tconst clampReasoning = (effort: ThinkingLevel | undefined) => (effort === \"xhigh\" ? \"high\" : effort);\n\n\t/**\n\t * Adjust maxTokens to account for thinking budget.\n\t * APIs like Anthropic and Bedrock require max_tokens > thinking.budget_tokens.\n\t * Returns { adjustedMaxTokens, adjustedThinkingBudget }\n\t */\n\tconst adjustMaxTokensForThinking = (\n\t\tbaseMaxTokens: number,\n\t\tmodelMaxTokens: number,\n\t\treasoningLevel: ThinkingLevel,\n\t\tcustomBudgets?: ThinkingBudgets,\n\t): { maxTokens: number; thinkingBudget: number } => {\n\t\tconst defaultBudgets: ThinkingBudgets = {\n\t\t\tminimal: 1024,\n\t\t\tlow: 2048,\n\t\t\tmedium: 8192,\n\t\t\thigh: 16384,\n\t\t};\n\t\tconst budgets = { ...defaultBudgets, ...customBudgets };\n\n\t\tconst minOutputTokens = 1024;\n\t\tconst level = clampReasoning(reasoningLevel)!;\n\t\tlet thinkingBudget = budgets[level]!;\n\t\t// Caller's maxTokens is the desired output; add thinking budget on top, capped at model limit\n\t\tconst maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);\n\n\t\t// If not enough room for thinking + output, reduce thinking budget\n\t\tif (maxTokens <= thinkingBudget) {\n\t\t\tthinkingBudget = Math.max(0, maxTokens - minOutputTokens);\n\t\t}\n\n\t\treturn { maxTokens, thinkingBudget };\n\t};\n\n\tswitch (model.api) {\n\t\tcase \"anthropic-messages\": {\n\t\t\t// Explicitly disable thinking when reasoning is not specified\n\t\t\tif (!options?.reasoning) {\n\t\t\t\treturn { ...base, thinkingEnabled: false } satisfies AnthropicOptions;\n\t\t\t}\n\n\t\t\t// Claude requires max_tokens > thinking.budget_tokens\n\t\t\t// So we need to ensure maxTokens accounts for both thinking and output\n\t\t\tconst adjusted = adjustMaxTokensForThinking(\n\t\t\t\tbase.maxTokens || 0,\n\t\t\t\tmodel.maxTokens,\n\t\t\t\toptions.reasoning,\n\t\t\t\toptions?.thinkingBudgets,\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tmaxTokens: adjusted.maxTokens,\n\t\t\t\tthinkingEnabled: true,\n\t\t\t\tthinkingBudgetTokens: adjusted.thinkingBudget,\n\t\t\t} satisfies AnthropicOptions;\n\t\t}\n\n\t\tcase \"bedrock-converse-stream\": {\n\t\t\t// Explicitly disable thinking when reasoning is not specified\n\t\t\tif (!options?.reasoning) {\n\t\t\t\treturn { ...base, reasoning: undefined } satisfies BedrockOptions;\n\t\t\t}\n\n\t\t\t// Claude requires max_tokens > thinking.budget_tokens (same as Anthropic direct API)\n\t\t\t// So we need to ensure maxTokens accounts for both thinking and output\n\t\t\tif (model.id.includes(\"anthropic.claude\") || model.id.includes(\"anthropic/claude\")) {\n\t\t\t\tconst adjusted = adjustMaxTokensForThinking(\n\t\t\t\t\tbase.maxTokens || 0,\n\t\t\t\t\tmodel.maxTokens,\n\t\t\t\t\toptions.reasoning,\n\t\t\t\t\toptions?.thinkingBudgets,\n\t\t\t\t);\n\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\tmaxTokens: adjusted.maxTokens,\n\t\t\t\t\treasoning: options.reasoning,\n\t\t\t\t\tthinkingBudgets: {\n\t\t\t\t\t\t...(options?.thinkingBudgets || {}),\n\t\t\t\t\t\t[clampReasoning(options.reasoning)!]: adjusted.thinkingBudget,\n\t\t\t\t\t},\n\t\t\t\t} satisfies BedrockOptions;\n\t\t\t}\n\n\t\t\t// Non-Claude models - pass through\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\treasoning: options?.reasoning,\n\t\t\t\tthinkingBudgets: options?.thinkingBudgets,\n\t\t\t} satisfies BedrockOptions;\n\t\t}\n\n\t\tcase \"openai-completions\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\treasoningEffort: supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning),\n\t\t\t} satisfies OpenAICompletionsOptions;\n\n\t\tcase \"openai-responses\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\treasoningEffort: supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning),\n\t\t\t} satisfies OpenAIResponsesOptions;\n\n\t\tcase \"openai-codex-responses\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\treasoningEffort: supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning),\n\t\t\t} satisfies OpenAICodexResponsesOptions;\n\n\t\tcase \"google-generative-ai\": {\n\t\t\t// Explicitly disable thinking when reasoning is not specified\n\t\t\t// This is needed because Gemini has \"dynamic thinking\" enabled by default\n\t\t\tif (!options?.reasoning) {\n\t\t\t\treturn { ...base, thinking: { enabled: false } } satisfies GoogleOptions;\n\t\t\t}\n\n\t\t\tconst googleModel = model as Model<\"google-generative-ai\">;\n\t\t\tconst effort = clampReasoning(options.reasoning)!;\n\n\t\t\t// Gemini 3 models use thinkingLevel exclusively instead of thinkingBudget.\n\t\t\t// https://ai.google.dev/gemini-api/docs/thinking#set-budget\n\t\t\tif (isGemini3ProModel(googleModel) || isGemini3FlashModel(googleModel)) {\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\tthinking: {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tlevel: getGemini3ThinkingLevel(effort, googleModel),\n\t\t\t\t\t},\n\t\t\t\t} satisfies GoogleOptions;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tthinking: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tbudgetTokens: getGoogleBudget(googleModel, effort, options?.thinkingBudgets),\n\t\t\t\t},\n\t\t\t} satisfies GoogleOptions;\n\t\t}\n\n\t\tcase \"google-gemini-cli\": {\n\t\t\tif (!options?.reasoning) {\n\t\t\t\treturn { ...base, thinking: { enabled: false } } satisfies GoogleGeminiCliOptions;\n\t\t\t}\n\n\t\t\tconst effort = clampReasoning(options.reasoning)!;\n\n\t\t\t// Gemini 3 models use thinkingLevel instead of thinkingBudget\n\t\t\tif (model.id.includes(\"3-pro\") || model.id.includes(\"3-flash\")) {\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\tthinking: {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tlevel: getGeminiCliThinkingLevel(effort, model.id),\n\t\t\t\t\t},\n\t\t\t\t} satisfies GoogleGeminiCliOptions;\n\t\t\t}\n\n\t\t\t// Models using thinkingBudget (Gemini 2.x, Claude via Antigravity)\n\t\t\t// Claude requires max_tokens > thinking.budget_tokens\n\t\t\t// So we need to ensure maxTokens accounts for both thinking and output\n\t\t\tconst defaultBudgets: ThinkingBudgets = {\n\t\t\t\tminimal: 1024,\n\t\t\t\tlow: 2048,\n\t\t\t\tmedium: 8192,\n\t\t\t\thigh: 16384,\n\t\t\t};\n\t\t\tconst budgets = { ...defaultBudgets, ...options?.thinkingBudgets };\n\n\t\t\tconst minOutputTokens = 1024;\n\t\t\tlet thinkingBudget = budgets[effort]!;\n\t\t\t// Caller's maxTokens is the desired output; add thinking budget on top, capped at model limit\n\t\t\tconst maxTokens = Math.min((base.maxTokens || 0) + thinkingBudget, model.maxTokens);\n\n\t\t\t// If not enough room for thinking + output, reduce thinking budget\n\t\t\tif (maxTokens <= thinkingBudget) {\n\t\t\t\tthinkingBudget = Math.max(0, maxTokens - minOutputTokens);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tmaxTokens,\n\t\t\t\tthinking: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tbudgetTokens: thinkingBudget,\n\t\t\t\t},\n\t\t\t} satisfies GoogleGeminiCliOptions;\n\t\t}\n\n\t\tcase \"google-vertex\": {\n\t\t\t// Explicitly disable thinking when reasoning is not specified\n\t\t\tif (!options?.reasoning) {\n\t\t\t\treturn { ...base, thinking: { enabled: false } } satisfies GoogleVertexOptions;\n\t\t\t}\n\n\t\t\tconst vertexModel = model as Model<\"google-vertex\">;\n\t\t\tconst effort = clampReasoning(options.reasoning)!;\n\t\t\tconst geminiModel = vertexModel as unknown as Model<\"google-generative-ai\">;\n\n\t\t\tif (isGemini3ProModel(geminiModel) || isGemini3FlashModel(geminiModel)) {\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\tthinking: {\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\tlevel: getGemini3ThinkingLevel(effort, geminiModel),\n\t\t\t\t\t},\n\t\t\t\t} satisfies GoogleVertexOptions;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tthinking: {\n\t\t\t\t\tenabled: true,\n\t\t\t\t\tbudgetTokens: getGoogleBudget(geminiModel, effort, options?.thinkingBudgets),\n\t\t\t\t},\n\t\t\t} satisfies GoogleVertexOptions;\n\t\t}\n\n\t\tdefault: {\n\t\t\t// Exhaustiveness check\n\t\t\tconst _exhaustive: never = model.api;\n\t\t\tthrow new Error(`Unhandled API in mapOptionsForApi: ${_exhaustive}`);\n\t\t}\n\t}\n}\n\ntype ClampedThinkingLevel = Exclude<ThinkingLevel, \"xhigh\">;\n\nfunction isGemini3ProModel(model: Model<\"google-generative-ai\">): boolean {\n\t// Covers gemini-3-pro, gemini-3-pro-preview, and possible other prefixed ids in the future\n\treturn model.id.includes(\"3-pro\");\n}\n\nfunction isGemini3FlashModel(model: Model<\"google-generative-ai\">): boolean {\n\t// Covers gemini-3-flash, gemini-3-flash-preview, and possible other prefixed ids in the future\n\treturn model.id.includes(\"3-flash\");\n}\n\nfunction getGemini3ThinkingLevel(\n\teffort: ClampedThinkingLevel,\n\tmodel: Model<\"google-generative-ai\">,\n): GoogleThinkingLevel {\n\tif (isGemini3ProModel(model)) {\n\t\t// Gemini 3 Pro only supports LOW/HIGH (for now)\n\t\tswitch (effort) {\n\t\t\tcase \"minimal\":\n\t\t\tcase \"low\":\n\t\t\t\treturn \"LOW\";\n\t\t\tcase \"medium\":\n\t\t\tcase \"high\":\n\t\t\t\treturn \"HIGH\";\n\t\t}\n\t}\n\t// Gemini 3 Flash supports all four levels\n\tswitch (effort) {\n\t\tcase \"minimal\":\n\t\t\treturn \"MINIMAL\";\n\t\tcase \"low\":\n\t\t\treturn \"LOW\";\n\t\tcase \"medium\":\n\t\t\treturn \"MEDIUM\";\n\t\tcase \"high\":\n\t\t\treturn \"HIGH\";\n\t}\n}\n\nfunction getGeminiCliThinkingLevel(effort: ClampedThinkingLevel, modelId: string): GoogleThinkingLevel {\n\tif (modelId.includes(\"3-pro\")) {\n\t\t// Gemini 3 Pro only supports LOW/HIGH (for now)\n\t\tswitch (effort) {\n\t\t\tcase \"minimal\":\n\t\t\tcase \"low\":\n\t\t\t\treturn \"LOW\";\n\t\t\tcase \"medium\":\n\t\t\tcase \"high\":\n\t\t\t\treturn \"HIGH\";\n\t\t}\n\t}\n\t// Gemini 3 Flash supports all four levels\n\tswitch (effort) {\n\t\tcase \"minimal\":\n\t\t\treturn \"MINIMAL\";\n\t\tcase \"low\":\n\t\t\treturn \"LOW\";\n\t\tcase \"medium\":\n\t\t\treturn \"MEDIUM\";\n\t\tcase \"high\":\n\t\t\treturn \"HIGH\";\n\t}\n}\n\nfunction getGoogleBudget(\n\tmodel: Model<\"google-generative-ai\">,\n\teffort: ClampedThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): number {\n\t// Custom budgets take precedence if provided for this level\n\tif (customBudgets?.[effort] !== undefined) {\n\t\treturn customBudgets[effort]!;\n\t}\n\n\t// See https://ai.google.dev/gemini-api/docs/thinking#set-budget\n\tif (model.id.includes(\"2.5-pro\")) {\n\t\tconst budgets: Record<ClampedThinkingLevel, number> = {\n\t\t\tminimal: 128,\n\t\t\tlow: 2048,\n\t\t\tmedium: 8192,\n\t\t\thigh: 32768,\n\t\t};\n\t\treturn budgets[effort];\n\t}\n\n\tif (model.id.includes(\"2.5-flash\")) {\n\t\t// Covers 2.5-flash-lite as well\n\t\tconst budgets: Record<ClampedThinkingLevel, number> = {\n\t\t\tminimal: 128,\n\t\t\tlow: 2048,\n\t\t\tmedium: 8192,\n\t\t\thigh: 24576,\n\t\t};\n\t\treturn budgets[effort];\n\t}\n\n\t// Unknown model - use dynamic\n\treturn -1;\n}\n"]}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,kCAAkC,CAAC;AAG1C,OAAO,KAAK,EACX,GAAG,EACH,gBAAgB,EAChB,2BAA2B,EAC3B,OAAO,EACP,KAAK,EACL,qBAAqB,EACrB,mBAAmB,EAEnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAmBjD,wBAAgB,MAAM,CAAC,IAAI,SAAS,GAAG,EACtC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,qBAAqB,GAC7B,2BAA2B,CAG7B;AAED,wBAAsB,QAAQ,CAAC,IAAI,SAAS,GAAG,EAC9C,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CAG3B;AAED,wBAAgB,YAAY,CAAC,IAAI,SAAS,GAAG,EAC5C,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC3B,2BAA2B,CAG7B;AAED,wBAAsB,cAAc,CAAC,IAAI,SAAS,GAAG,EACpD,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAG3B","sourcesContent":["import \"./providers/register-builtins.js\";\n\nimport { getApiProvider } from \"./api-registry.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tAssistantMessageEventStream,\n\tContext,\n\tModel,\n\tProviderStreamOptions,\n\tSimpleStreamOptions,\n\tStreamOptions,\n} from \"./types.js\";\n\nexport { getEnvApiKey } from \"./env-api-keys.js\";\n\n// Set up http proxy according to env variables for `fetch` based SDKs in Node.js.\n// Bun has builtin support for this.\nif (typeof process !== \"undefined\" && process.versions?.node) {\n\timport(\"undici\").then((m) => {\n\t\tconst { EnvHttpProxyAgent, setGlobalDispatcher } = m;\n\t\tsetGlobalDispatcher(new EnvHttpProxyAgent());\n\t});\n}\n\nfunction resolveApiProvider(api: Api) {\n\tconst provider = getApiProvider(api);\n\tif (!provider) {\n\t\tthrow new Error(`No API provider registered for api: ${api}`);\n\t}\n\treturn provider;\n}\n\nexport function stream<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: ProviderStreamOptions,\n): AssistantMessageEventStream {\n\tconst provider = resolveApiProvider(model.api);\n\treturn provider.stream(model, context, options as StreamOptions);\n}\n\nexport async function complete<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: ProviderStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = stream(model, context, options);\n\treturn s.result();\n}\n\nexport function streamSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream {\n\tconst provider = resolveApiProvider(model.api);\n\treturn provider.streamSimple(model, context, options);\n}\n\nexport async function completeSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = streamSimple(model, context, options);\n\treturn s.result();\n}\n"]}
package/dist/stream.js CHANGED
@@ -1,418 +1,35 @@
1
- import { existsSync } from "node:fs";
2
- import { homedir } from "node:os";
3
- import { join } from "node:path";
4
- import { supportsXhigh } from "./models.js";
5
- import { streamBedrock } from "./providers/amazon-bedrock.js";
6
- import { streamAnthropic } from "./providers/anthropic.js";
7
- import { streamGoogle } from "./providers/google.js";
8
- import { streamGoogleGeminiCli, } from "./providers/google-gemini-cli.js";
9
- import { streamGoogleVertex } from "./providers/google-vertex.js";
10
- import { streamOpenAICodexResponses } from "./providers/openai-codex-responses.js";
11
- import { streamOpenAICompletions } from "./providers/openai-completions.js";
12
- import { streamOpenAIResponses } from "./providers/openai-responses.js";
13
- let cachedVertexAdcCredentialsExists = null;
14
- function hasVertexAdcCredentials() {
15
- if (cachedVertexAdcCredentialsExists === null) {
16
- // Check GOOGLE_APPLICATION_CREDENTIALS env var first (standard way)
17
- const gacPath = process.env.GOOGLE_APPLICATION_CREDENTIALS;
18
- if (gacPath) {
19
- cachedVertexAdcCredentialsExists = existsSync(gacPath);
20
- }
21
- else {
22
- // Fall back to default ADC path (lazy evaluation)
23
- cachedVertexAdcCredentialsExists = existsSync(join(homedir(), ".config", "gcloud", "application_default_credentials.json"));
24
- }
25
- }
26
- return cachedVertexAdcCredentialsExists;
27
- }
28
- export function getEnvApiKey(provider) {
29
- // Fall back to environment variables
30
- if (provider === "github-copilot") {
31
- return process.env.COPILOT_GITHUB_TOKEN || process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
32
- }
33
- // ANTHROPIC_OAUTH_TOKEN takes precedence over ANTHROPIC_API_KEY
34
- if (provider === "anthropic") {
35
- return process.env.ANTHROPIC_OAUTH_TOKEN || process.env.ANTHROPIC_API_KEY;
36
- }
37
- // Vertex AI uses Application Default Credentials, not API keys.
38
- // Auth is configured via `gcloud auth application-default login`.
39
- if (provider === "google-vertex") {
40
- const hasCredentials = hasVertexAdcCredentials();
41
- const hasProject = !!(process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT);
42
- const hasLocation = !!process.env.GOOGLE_CLOUD_LOCATION;
43
- if (hasCredentials && hasProject && hasLocation) {
44
- return "<authenticated>";
45
- }
46
- }
47
- if (provider === "amazon-bedrock") {
48
- // Amazon Bedrock supports multiple credential sources:
49
- // 1. AWS_PROFILE - named profile from ~/.aws/credentials
50
- // 2. AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY - standard IAM keys
51
- // 3. AWS_BEARER_TOKEN_BEDROCK - Bedrock API keys (bearer token)
52
- // 4. AWS_CONTAINER_CREDENTIALS_RELATIVE_URI - ECS task roles
53
- // 5. AWS_CONTAINER_CREDENTIALS_FULL_URI - ECS task roles (full URI)
54
- // 6. AWS_WEB_IDENTITY_TOKEN_FILE - IRSA (IAM Roles for Service Accounts)
55
- if (process.env.AWS_PROFILE ||
56
- (process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) ||
57
- process.env.AWS_BEARER_TOKEN_BEDROCK ||
58
- process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI ||
59
- process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI ||
60
- process.env.AWS_WEB_IDENTITY_TOKEN_FILE) {
61
- return "<authenticated>";
62
- }
63
- }
64
- const envMap = {
65
- openai: "OPENAI_API_KEY",
66
- google: "GEMINI_API_KEY",
67
- groq: "GROQ_API_KEY",
68
- cerebras: "CEREBRAS_API_KEY",
69
- xai: "XAI_API_KEY",
70
- openrouter: "OPENROUTER_API_KEY",
71
- "vercel-ai-gateway": "AI_GATEWAY_API_KEY",
72
- zai: "ZAI_API_KEY",
73
- mistral: "MISTRAL_API_KEY",
74
- minimax: "MINIMAX_API_KEY",
75
- "minimax-cn": "MINIMAX_CN_API_KEY",
76
- opencode: "OPENCODE_API_KEY",
77
- };
78
- const envVar = envMap[provider];
79
- return envVar ? process.env[envVar] : undefined;
1
+ import "./providers/register-builtins.js";
2
+ import { getApiProvider } from "./api-registry.js";
3
+ export { getEnvApiKey } from "./env-api-keys.js";
4
+ // Set up http proxy according to env variables for `fetch` based SDKs in Node.js.
5
+ // Bun has builtin support for this.
6
+ if (typeof process !== "undefined" && process.versions?.node) {
7
+ import("undici").then((m) => {
8
+ const { EnvHttpProxyAgent, setGlobalDispatcher } = m;
9
+ setGlobalDispatcher(new EnvHttpProxyAgent());
10
+ });
11
+ }
12
+ function resolveApiProvider(api) {
13
+ const provider = getApiProvider(api);
14
+ if (!provider) {
15
+ throw new Error(`No API provider registered for api: ${api}`);
16
+ }
17
+ return provider;
80
18
  }
81
19
  export function stream(model, context, options) {
82
- // Vertex AI uses Application Default Credentials, not API keys
83
- if (model.api === "google-vertex") {
84
- return streamGoogleVertex(model, context, options);
85
- }
86
- else if (model.api === "bedrock-converse-stream") {
87
- // Bedrock doesn't have any API keys instead it sources credentials from standard AWS env variables or from given AWS profile.
88
- return streamBedrock(model, context, (options || {}));
89
- }
90
- const apiKey = options?.apiKey || getEnvApiKey(model.provider);
91
- if (!apiKey) {
92
- throw new Error(`No API key for provider: ${model.provider}`);
93
- }
94
- const providerOptions = { ...options, apiKey };
95
- const api = model.api;
96
- switch (api) {
97
- case "anthropic-messages":
98
- return streamAnthropic(model, context, providerOptions);
99
- case "openai-completions":
100
- return streamOpenAICompletions(model, context, providerOptions);
101
- case "openai-responses":
102
- return streamOpenAIResponses(model, context, providerOptions);
103
- case "openai-codex-responses":
104
- return streamOpenAICodexResponses(model, context, providerOptions);
105
- case "google-generative-ai":
106
- return streamGoogle(model, context, providerOptions);
107
- case "google-gemini-cli":
108
- return streamGoogleGeminiCli(model, context, providerOptions);
109
- default: {
110
- // This should never be reached if all Api cases are handled
111
- const _exhaustive = api;
112
- throw new Error(`Unhandled API: ${_exhaustive}`);
113
- }
114
- }
20
+ const provider = resolveApiProvider(model.api);
21
+ return provider.stream(model, context, options);
115
22
  }
116
23
  export async function complete(model, context, options) {
117
24
  const s = stream(model, context, options);
118
25
  return s.result();
119
26
  }
120
27
  export function streamSimple(model, context, options) {
121
- // Vertex AI uses Application Default Credentials, not API keys
122
- if (model.api === "google-vertex") {
123
- const providerOptions = mapOptionsForApi(model, options, undefined);
124
- return stream(model, context, providerOptions);
125
- }
126
- else if (model.api === "bedrock-converse-stream") {
127
- // Bedrock doesn't have any API keys instead it sources credentials from standard AWS env variables or from given AWS profile.
128
- const providerOptions = mapOptionsForApi(model, options, undefined);
129
- return stream(model, context, providerOptions);
130
- }
131
- const apiKey = options?.apiKey || getEnvApiKey(model.provider);
132
- if (!apiKey) {
133
- throw new Error(`No API key for provider: ${model.provider}`);
134
- }
135
- const providerOptions = mapOptionsForApi(model, options, apiKey);
136
- return stream(model, context, providerOptions);
28
+ const provider = resolveApiProvider(model.api);
29
+ return provider.streamSimple(model, context, options);
137
30
  }
138
31
  export async function completeSimple(model, context, options) {
139
32
  const s = streamSimple(model, context, options);
140
33
  return s.result();
141
34
  }
142
- function mapOptionsForApi(model, options, apiKey) {
143
- const base = {
144
- temperature: options?.temperature,
145
- maxTokens: options?.maxTokens || Math.min(model.maxTokens, 32000),
146
- signal: options?.signal,
147
- apiKey: apiKey || options?.apiKey,
148
- sessionId: options?.sessionId,
149
- };
150
- // Helper to clamp xhigh to high for providers that don't support it
151
- const clampReasoning = (effort) => (effort === "xhigh" ? "high" : effort);
152
- /**
153
- * Adjust maxTokens to account for thinking budget.
154
- * APIs like Anthropic and Bedrock require max_tokens > thinking.budget_tokens.
155
- * Returns { adjustedMaxTokens, adjustedThinkingBudget }
156
- */
157
- const adjustMaxTokensForThinking = (baseMaxTokens, modelMaxTokens, reasoningLevel, customBudgets) => {
158
- const defaultBudgets = {
159
- minimal: 1024,
160
- low: 2048,
161
- medium: 8192,
162
- high: 16384,
163
- };
164
- const budgets = { ...defaultBudgets, ...customBudgets };
165
- const minOutputTokens = 1024;
166
- const level = clampReasoning(reasoningLevel);
167
- let thinkingBudget = budgets[level];
168
- // Caller's maxTokens is the desired output; add thinking budget on top, capped at model limit
169
- const maxTokens = Math.min(baseMaxTokens + thinkingBudget, modelMaxTokens);
170
- // If not enough room for thinking + output, reduce thinking budget
171
- if (maxTokens <= thinkingBudget) {
172
- thinkingBudget = Math.max(0, maxTokens - minOutputTokens);
173
- }
174
- return { maxTokens, thinkingBudget };
175
- };
176
- switch (model.api) {
177
- case "anthropic-messages": {
178
- // Explicitly disable thinking when reasoning is not specified
179
- if (!options?.reasoning) {
180
- return { ...base, thinkingEnabled: false };
181
- }
182
- // Claude requires max_tokens > thinking.budget_tokens
183
- // So we need to ensure maxTokens accounts for both thinking and output
184
- const adjusted = adjustMaxTokensForThinking(base.maxTokens || 0, model.maxTokens, options.reasoning, options?.thinkingBudgets);
185
- return {
186
- ...base,
187
- maxTokens: adjusted.maxTokens,
188
- thinkingEnabled: true,
189
- thinkingBudgetTokens: adjusted.thinkingBudget,
190
- };
191
- }
192
- case "bedrock-converse-stream": {
193
- // Explicitly disable thinking when reasoning is not specified
194
- if (!options?.reasoning) {
195
- return { ...base, reasoning: undefined };
196
- }
197
- // Claude requires max_tokens > thinking.budget_tokens (same as Anthropic direct API)
198
- // So we need to ensure maxTokens accounts for both thinking and output
199
- if (model.id.includes("anthropic.claude") || model.id.includes("anthropic/claude")) {
200
- const adjusted = adjustMaxTokensForThinking(base.maxTokens || 0, model.maxTokens, options.reasoning, options?.thinkingBudgets);
201
- return {
202
- ...base,
203
- maxTokens: adjusted.maxTokens,
204
- reasoning: options.reasoning,
205
- thinkingBudgets: {
206
- ...(options?.thinkingBudgets || {}),
207
- [clampReasoning(options.reasoning)]: adjusted.thinkingBudget,
208
- },
209
- };
210
- }
211
- // Non-Claude models - pass through
212
- return {
213
- ...base,
214
- reasoning: options?.reasoning,
215
- thinkingBudgets: options?.thinkingBudgets,
216
- };
217
- }
218
- case "openai-completions":
219
- return {
220
- ...base,
221
- reasoningEffort: supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning),
222
- };
223
- case "openai-responses":
224
- return {
225
- ...base,
226
- reasoningEffort: supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning),
227
- };
228
- case "openai-codex-responses":
229
- return {
230
- ...base,
231
- reasoningEffort: supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning),
232
- };
233
- case "google-generative-ai": {
234
- // Explicitly disable thinking when reasoning is not specified
235
- // This is needed because Gemini has "dynamic thinking" enabled by default
236
- if (!options?.reasoning) {
237
- return { ...base, thinking: { enabled: false } };
238
- }
239
- const googleModel = model;
240
- const effort = clampReasoning(options.reasoning);
241
- // Gemini 3 models use thinkingLevel exclusively instead of thinkingBudget.
242
- // https://ai.google.dev/gemini-api/docs/thinking#set-budget
243
- if (isGemini3ProModel(googleModel) || isGemini3FlashModel(googleModel)) {
244
- return {
245
- ...base,
246
- thinking: {
247
- enabled: true,
248
- level: getGemini3ThinkingLevel(effort, googleModel),
249
- },
250
- };
251
- }
252
- return {
253
- ...base,
254
- thinking: {
255
- enabled: true,
256
- budgetTokens: getGoogleBudget(googleModel, effort, options?.thinkingBudgets),
257
- },
258
- };
259
- }
260
- case "google-gemini-cli": {
261
- if (!options?.reasoning) {
262
- return { ...base, thinking: { enabled: false } };
263
- }
264
- const effort = clampReasoning(options.reasoning);
265
- // Gemini 3 models use thinkingLevel instead of thinkingBudget
266
- if (model.id.includes("3-pro") || model.id.includes("3-flash")) {
267
- return {
268
- ...base,
269
- thinking: {
270
- enabled: true,
271
- level: getGeminiCliThinkingLevel(effort, model.id),
272
- },
273
- };
274
- }
275
- // Models using thinkingBudget (Gemini 2.x, Claude via Antigravity)
276
- // Claude requires max_tokens > thinking.budget_tokens
277
- // So we need to ensure maxTokens accounts for both thinking and output
278
- const defaultBudgets = {
279
- minimal: 1024,
280
- low: 2048,
281
- medium: 8192,
282
- high: 16384,
283
- };
284
- const budgets = { ...defaultBudgets, ...options?.thinkingBudgets };
285
- const minOutputTokens = 1024;
286
- let thinkingBudget = budgets[effort];
287
- // Caller's maxTokens is the desired output; add thinking budget on top, capped at model limit
288
- const maxTokens = Math.min((base.maxTokens || 0) + thinkingBudget, model.maxTokens);
289
- // If not enough room for thinking + output, reduce thinking budget
290
- if (maxTokens <= thinkingBudget) {
291
- thinkingBudget = Math.max(0, maxTokens - minOutputTokens);
292
- }
293
- return {
294
- ...base,
295
- maxTokens,
296
- thinking: {
297
- enabled: true,
298
- budgetTokens: thinkingBudget,
299
- },
300
- };
301
- }
302
- case "google-vertex": {
303
- // Explicitly disable thinking when reasoning is not specified
304
- if (!options?.reasoning) {
305
- return { ...base, thinking: { enabled: false } };
306
- }
307
- const vertexModel = model;
308
- const effort = clampReasoning(options.reasoning);
309
- const geminiModel = vertexModel;
310
- if (isGemini3ProModel(geminiModel) || isGemini3FlashModel(geminiModel)) {
311
- return {
312
- ...base,
313
- thinking: {
314
- enabled: true,
315
- level: getGemini3ThinkingLevel(effort, geminiModel),
316
- },
317
- };
318
- }
319
- return {
320
- ...base,
321
- thinking: {
322
- enabled: true,
323
- budgetTokens: getGoogleBudget(geminiModel, effort, options?.thinkingBudgets),
324
- },
325
- };
326
- }
327
- default: {
328
- // Exhaustiveness check
329
- const _exhaustive = model.api;
330
- throw new Error(`Unhandled API in mapOptionsForApi: ${_exhaustive}`);
331
- }
332
- }
333
- }
334
- function isGemini3ProModel(model) {
335
- // Covers gemini-3-pro, gemini-3-pro-preview, and possible other prefixed ids in the future
336
- return model.id.includes("3-pro");
337
- }
338
- function isGemini3FlashModel(model) {
339
- // Covers gemini-3-flash, gemini-3-flash-preview, and possible other prefixed ids in the future
340
- return model.id.includes("3-flash");
341
- }
342
- function getGemini3ThinkingLevel(effort, model) {
343
- if (isGemini3ProModel(model)) {
344
- // Gemini 3 Pro only supports LOW/HIGH (for now)
345
- switch (effort) {
346
- case "minimal":
347
- case "low":
348
- return "LOW";
349
- case "medium":
350
- case "high":
351
- return "HIGH";
352
- }
353
- }
354
- // Gemini 3 Flash supports all four levels
355
- switch (effort) {
356
- case "minimal":
357
- return "MINIMAL";
358
- case "low":
359
- return "LOW";
360
- case "medium":
361
- return "MEDIUM";
362
- case "high":
363
- return "HIGH";
364
- }
365
- }
366
- function getGeminiCliThinkingLevel(effort, modelId) {
367
- if (modelId.includes("3-pro")) {
368
- // Gemini 3 Pro only supports LOW/HIGH (for now)
369
- switch (effort) {
370
- case "minimal":
371
- case "low":
372
- return "LOW";
373
- case "medium":
374
- case "high":
375
- return "HIGH";
376
- }
377
- }
378
- // Gemini 3 Flash supports all four levels
379
- switch (effort) {
380
- case "minimal":
381
- return "MINIMAL";
382
- case "low":
383
- return "LOW";
384
- case "medium":
385
- return "MEDIUM";
386
- case "high":
387
- return "HIGH";
388
- }
389
- }
390
- function getGoogleBudget(model, effort, customBudgets) {
391
- // Custom budgets take precedence if provided for this level
392
- if (customBudgets?.[effort] !== undefined) {
393
- return customBudgets[effort];
394
- }
395
- // See https://ai.google.dev/gemini-api/docs/thinking#set-budget
396
- if (model.id.includes("2.5-pro")) {
397
- const budgets = {
398
- minimal: 128,
399
- low: 2048,
400
- medium: 8192,
401
- high: 32768,
402
- };
403
- return budgets[effort];
404
- }
405
- if (model.id.includes("2.5-flash")) {
406
- // Covers 2.5-flash-lite as well
407
- const budgets = {
408
- minimal: 128,
409
- low: 2048,
410
- medium: 8192,
411
- high: 24576,
412
- };
413
- return budgets[effort];
414
- }
415
- // Unknown model - use dynamic
416
- return -1;
417
- }
418
35
  //# sourceMappingURL=stream.js.map