gencode-ai 0.1.3 → 0.3.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 (260) hide show
  1. package/README.md +2 -1
  2. package/dist/agent/agent.d.ts +44 -2
  3. package/dist/agent/agent.d.ts.map +1 -1
  4. package/dist/agent/agent.js +130 -11
  5. package/dist/agent/agent.js.map +1 -1
  6. package/dist/agent/types.d.ts +11 -1
  7. package/dist/agent/types.d.ts.map +1 -1
  8. package/dist/checkpointing/checkpoint-manager.d.ts +87 -0
  9. package/dist/checkpointing/checkpoint-manager.d.ts.map +1 -0
  10. package/dist/checkpointing/checkpoint-manager.js +281 -0
  11. package/dist/checkpointing/checkpoint-manager.js.map +1 -0
  12. package/dist/checkpointing/index.d.ts +29 -0
  13. package/dist/checkpointing/index.d.ts.map +1 -0
  14. package/dist/checkpointing/index.js +29 -0
  15. package/dist/checkpointing/index.js.map +1 -0
  16. package/dist/checkpointing/types.d.ts +98 -0
  17. package/dist/checkpointing/types.d.ts.map +1 -0
  18. package/dist/checkpointing/types.js +7 -0
  19. package/dist/checkpointing/types.js.map +1 -0
  20. package/dist/cli/components/App.d.ts.map +1 -1
  21. package/dist/cli/components/App.js +171 -14
  22. package/dist/cli/components/App.js.map +1 -1
  23. package/dist/cli/components/CommandSuggestions.d.ts.map +1 -1
  24. package/dist/cli/components/CommandSuggestions.js +5 -0
  25. package/dist/cli/components/CommandSuggestions.js.map +1 -1
  26. package/dist/cli/components/Messages.d.ts +7 -1
  27. package/dist/cli/components/Messages.d.ts.map +1 -1
  28. package/dist/cli/components/Messages.js +12 -3
  29. package/dist/cli/components/Messages.js.map +1 -1
  30. package/dist/cli/components/ModeIndicator.d.ts +42 -0
  31. package/dist/cli/components/ModeIndicator.d.ts.map +1 -0
  32. package/dist/cli/components/ModeIndicator.js +52 -0
  33. package/dist/cli/components/ModeIndicator.js.map +1 -0
  34. package/dist/cli/components/ModelSelector.d.ts +4 -3
  35. package/dist/cli/components/ModelSelector.d.ts.map +1 -1
  36. package/dist/cli/components/ModelSelector.js +54 -37
  37. package/dist/cli/components/ModelSelector.js.map +1 -1
  38. package/dist/cli/components/PlanApproval.d.ts +36 -0
  39. package/dist/cli/components/PlanApproval.d.ts.map +1 -0
  40. package/dist/cli/components/PlanApproval.js +154 -0
  41. package/dist/cli/components/PlanApproval.js.map +1 -0
  42. package/dist/cli/components/ProviderManager.d.ts +2 -2
  43. package/dist/cli/components/ProviderManager.d.ts.map +1 -1
  44. package/dist/cli/components/ProviderManager.js +137 -156
  45. package/dist/cli/components/ProviderManager.js.map +1 -1
  46. package/dist/cli/components/theme.d.ts +2 -0
  47. package/dist/cli/components/theme.d.ts.map +1 -1
  48. package/dist/cli/components/theme.js +3 -0
  49. package/dist/cli/components/theme.js.map +1 -1
  50. package/dist/cli/index.js +30 -13
  51. package/dist/cli/index.js.map +1 -1
  52. package/dist/config/index.d.ts +2 -2
  53. package/dist/config/index.d.ts.map +1 -1
  54. package/dist/config/index.js +1 -1
  55. package/dist/config/index.js.map +1 -1
  56. package/dist/config/levels.d.ts +5 -5
  57. package/dist/config/levels.d.ts.map +1 -1
  58. package/dist/config/levels.js +20 -20
  59. package/dist/config/levels.js.map +1 -1
  60. package/dist/config/merger.js +1 -1
  61. package/dist/config/merger.js.map +1 -1
  62. package/dist/config/providers-config.d.ts +8 -5
  63. package/dist/config/providers-config.d.ts.map +1 -1
  64. package/dist/config/providers-config.js +19 -22
  65. package/dist/config/providers-config.js.map +1 -1
  66. package/dist/config/test-utils.d.ts +2 -2
  67. package/dist/config/test-utils.d.ts.map +1 -1
  68. package/dist/config/test-utils.js +4 -4
  69. package/dist/config/test-utils.js.map +1 -1
  70. package/dist/config/types.d.ts +23 -17
  71. package/dist/config/types.d.ts.map +1 -1
  72. package/dist/config/types.js +14 -14
  73. package/dist/config/types.js.map +1 -1
  74. package/dist/index.d.ts +1 -0
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +2 -0
  77. package/dist/index.js.map +1 -1
  78. package/dist/memory/memory-manager.d.ts +25 -12
  79. package/dist/memory/memory-manager.d.ts.map +1 -1
  80. package/dist/memory/memory-manager.js +241 -112
  81. package/dist/memory/memory-manager.js.map +1 -1
  82. package/dist/memory/test-utils.d.ts +1 -1
  83. package/dist/memory/test-utils.d.ts.map +1 -1
  84. package/dist/memory/test-utils.js +3 -3
  85. package/dist/memory/test-utils.js.map +1 -1
  86. package/dist/memory/types.d.ts +20 -10
  87. package/dist/memory/types.d.ts.map +1 -1
  88. package/dist/memory/types.js +13 -13
  89. package/dist/memory/types.js.map +1 -1
  90. package/dist/migration/migrate.d.ts +24 -0
  91. package/dist/migration/migrate.d.ts.map +1 -0
  92. package/dist/migration/migrate.js +164 -0
  93. package/dist/migration/migrate.js.map +1 -0
  94. package/dist/permissions/persistence.d.ts +2 -2
  95. package/dist/permissions/persistence.js +4 -4
  96. package/dist/permissions/persistence.js.map +1 -1
  97. package/dist/planning/index.d.ts +13 -0
  98. package/dist/planning/index.d.ts.map +1 -0
  99. package/dist/planning/index.js +15 -0
  100. package/dist/planning/index.js.map +1 -0
  101. package/dist/planning/plan-file.d.ts +59 -0
  102. package/dist/planning/plan-file.d.ts.map +1 -0
  103. package/dist/planning/plan-file.js +278 -0
  104. package/dist/planning/plan-file.js.map +1 -0
  105. package/dist/planning/state.d.ts +127 -0
  106. package/dist/planning/state.d.ts.map +1 -0
  107. package/dist/planning/state.js +261 -0
  108. package/dist/planning/state.js.map +1 -0
  109. package/dist/planning/tools/enter-plan-mode.d.ts +25 -0
  110. package/dist/planning/tools/enter-plan-mode.d.ts.map +1 -0
  111. package/dist/planning/tools/enter-plan-mode.js +98 -0
  112. package/dist/planning/tools/enter-plan-mode.js.map +1 -0
  113. package/dist/planning/tools/exit-plan-mode.d.ts +24 -0
  114. package/dist/planning/tools/exit-plan-mode.d.ts.map +1 -0
  115. package/dist/planning/tools/exit-plan-mode.js +149 -0
  116. package/dist/planning/tools/exit-plan-mode.js.map +1 -0
  117. package/dist/planning/types.d.ts +100 -0
  118. package/dist/planning/types.d.ts.map +1 -0
  119. package/dist/planning/types.js +28 -0
  120. package/dist/planning/types.js.map +1 -0
  121. package/dist/pricing/calculator.d.ts +21 -0
  122. package/dist/pricing/calculator.d.ts.map +1 -0
  123. package/dist/pricing/calculator.js +59 -0
  124. package/dist/pricing/calculator.js.map +1 -0
  125. package/dist/pricing/index.d.ts +7 -0
  126. package/dist/pricing/index.d.ts.map +1 -0
  127. package/dist/pricing/index.js +7 -0
  128. package/dist/pricing/index.js.map +1 -0
  129. package/dist/pricing/models.d.ts +20 -0
  130. package/dist/pricing/models.d.ts.map +1 -0
  131. package/dist/pricing/models.js +322 -0
  132. package/dist/pricing/models.js.map +1 -0
  133. package/dist/pricing/types.d.ts +30 -0
  134. package/dist/pricing/types.d.ts.map +1 -0
  135. package/dist/pricing/types.js +5 -0
  136. package/dist/pricing/types.js.map +1 -0
  137. package/dist/prompts/index.d.ts +5 -4
  138. package/dist/prompts/index.d.ts.map +1 -1
  139. package/dist/prompts/index.js +11 -8
  140. package/dist/prompts/index.js.map +1 -1
  141. package/dist/providers/anthropic.d.ts +2 -1
  142. package/dist/providers/anthropic.d.ts.map +1 -1
  143. package/dist/providers/anthropic.js +24 -10
  144. package/dist/providers/anthropic.js.map +1 -1
  145. package/dist/providers/gemini.d.ts +2 -1
  146. package/dist/providers/gemini.d.ts.map +1 -1
  147. package/dist/providers/gemini.js +28 -14
  148. package/dist/providers/gemini.js.map +1 -1
  149. package/dist/providers/index.d.ts +20 -10
  150. package/dist/providers/index.d.ts.map +1 -1
  151. package/dist/providers/index.js +48 -24
  152. package/dist/providers/index.js.map +1 -1
  153. package/dist/providers/openai.d.ts +2 -1
  154. package/dist/providers/openai.d.ts.map +1 -1
  155. package/dist/providers/openai.js +19 -8
  156. package/dist/providers/openai.js.map +1 -1
  157. package/dist/providers/registry.d.ts +48 -34
  158. package/dist/providers/registry.d.ts.map +1 -1
  159. package/dist/providers/registry.js +72 -88
  160. package/dist/providers/registry.js.map +1 -1
  161. package/dist/providers/store.d.ts +43 -17
  162. package/dist/providers/store.d.ts.map +1 -1
  163. package/dist/providers/store.js +112 -19
  164. package/dist/providers/store.js.map +1 -1
  165. package/dist/providers/types.d.ts +25 -0
  166. package/dist/providers/types.d.ts.map +1 -1
  167. package/dist/providers/vertex-ai.d.ts +15 -7
  168. package/dist/providers/vertex-ai.d.ts.map +1 -1
  169. package/dist/providers/vertex-ai.js +63 -23
  170. package/dist/providers/vertex-ai.js.map +1 -1
  171. package/dist/session/manager.d.ts +4 -0
  172. package/dist/session/manager.d.ts.map +1 -1
  173. package/dist/session/manager.js +8 -0
  174. package/dist/session/manager.js.map +1 -1
  175. package/dist/session/types.js +1 -1
  176. package/dist/session/types.js.map +1 -1
  177. package/dist/tools/index.d.ts +7 -1
  178. package/dist/tools/index.d.ts.map +1 -1
  179. package/dist/tools/index.js +7 -0
  180. package/dist/tools/index.js.map +1 -1
  181. package/dist/tools/registry.d.ts +13 -0
  182. package/dist/tools/registry.d.ts.map +1 -1
  183. package/dist/tools/registry.js +79 -2
  184. package/dist/tools/registry.js.map +1 -1
  185. package/docs/config-system-comparison.md +50 -50
  186. package/docs/cost-tracking-comparison.md +904 -0
  187. package/docs/memory-system.md +124 -31
  188. package/docs/operating-modes.md +96 -0
  189. package/docs/permissions.md +2 -2
  190. package/docs/proposals/0006-memory-system.md +4 -4
  191. package/docs/proposals/0008-checkpointing.md +109 -2
  192. package/docs/proposals/0011-custom-commands.md +2 -1
  193. package/docs/proposals/0021-skills-system.md +2 -1
  194. package/docs/proposals/0023-permission-enhancements.md +2 -2
  195. package/docs/proposals/0025-cost-tracking.md +60 -2
  196. package/docs/proposals/0033-enterprise-deployment.md +1 -1
  197. package/docs/proposals/0041-configuration-system.md +17 -19
  198. package/docs/proposals/0042-prompt-optimization.md +17 -9
  199. package/docs/proposals/README.md +6 -6
  200. package/docs/providers.md +94 -9
  201. package/examples/test-checkpointing.ts +121 -0
  202. package/examples/test-cost-tracking.ts +77 -0
  203. package/examples/test-interrupt-cleanup.ts +94 -0
  204. package/package.json +3 -2
  205. package/scripts/migrate.ts +449 -0
  206. package/src/agent/agent.ts +161 -12
  207. package/src/agent/types.ts +11 -1
  208. package/src/checkpointing/checkpoint-manager.ts +327 -0
  209. package/src/checkpointing/index.ts +45 -0
  210. package/src/checkpointing/types.ts +104 -0
  211. package/src/cli/components/App.tsx +221 -13
  212. package/src/cli/components/CommandSuggestions.tsx +5 -0
  213. package/src/cli/components/Messages.tsx +24 -5
  214. package/src/cli/components/ModeIndicator.tsx +174 -0
  215. package/src/cli/components/ModelSelector.tsx +62 -43
  216. package/src/cli/components/PlanApproval.tsx +327 -0
  217. package/src/cli/components/ProviderManager.tsx +278 -323
  218. package/src/cli/components/theme.ts +3 -0
  219. package/src/cli/index.tsx +36 -17
  220. package/src/config/index.ts +5 -3
  221. package/src/config/levels.test.ts +22 -22
  222. package/src/config/levels.ts +22 -22
  223. package/src/config/loader.test.ts +14 -14
  224. package/src/config/manager.test.ts +19 -19
  225. package/src/config/merger.test.ts +23 -23
  226. package/src/config/merger.ts +1 -1
  227. package/src/config/providers-config.ts +23 -21
  228. package/src/config/test-utils.ts +6 -6
  229. package/src/config/types.ts +30 -20
  230. package/src/index.ts +15 -0
  231. package/src/memory/memory-manager.test.ts +242 -24
  232. package/src/memory/memory-manager.ts +270 -141
  233. package/src/memory/test-utils.ts +4 -4
  234. package/src/memory/types.ts +28 -17
  235. package/src/permissions/persistence.ts +4 -4
  236. package/src/planning/index.ts +53 -0
  237. package/src/planning/plan-file.ts +326 -0
  238. package/src/planning/state.ts +305 -0
  239. package/src/planning/tools/enter-plan-mode.ts +111 -0
  240. package/src/planning/tools/exit-plan-mode.ts +170 -0
  241. package/src/planning/types.ts +150 -0
  242. package/src/pricing/calculator.ts +71 -0
  243. package/src/pricing/index.ts +7 -0
  244. package/src/pricing/models.ts +334 -0
  245. package/src/pricing/types.ts +32 -0
  246. package/src/prompts/index.ts +13 -9
  247. package/src/providers/anthropic.ts +30 -10
  248. package/src/providers/gemini.ts +34 -14
  249. package/src/providers/index.ts +76 -33
  250. package/src/providers/openai.ts +26 -8
  251. package/src/providers/registry.ts +116 -111
  252. package/src/providers/store.ts +130 -28
  253. package/src/providers/types.ts +36 -1
  254. package/src/providers/vertex-ai.ts +70 -23
  255. package/src/session/manager.ts +9 -0
  256. package/src/session/types.ts +1 -1
  257. package/src/tools/index.ts +8 -0
  258. package/src/tools/registry.ts +95 -2
  259. package/.gencode/settings.local.json +0 -7
  260. package/CLAUDE.md +0 -86
@@ -4,8 +4,10 @@
4
4
  */
5
5
 
6
6
  import Anthropic from '@anthropic-ai/sdk';
7
+ import { calculateCost } from '../pricing/calculator.js';
7
8
  import type {
8
9
  LLMProvider,
10
+ ProviderClassMeta,
9
11
  CompletionOptions,
10
12
  CompletionResponse,
11
13
  StreamChunk,
@@ -22,6 +24,14 @@ type AnthropicTool = Anthropic.Tool;
22
24
  type AnthropicContent = Anthropic.ContentBlockParam;
23
25
 
24
26
  export class AnthropicProvider implements LLMProvider {
27
+ static readonly meta: ProviderClassMeta = {
28
+ provider: 'anthropic',
29
+ authMethod: 'api_key',
30
+ envVars: ['ANTHROPIC_API_KEY'],
31
+ displayName: 'Direct API',
32
+ description: 'Direct API access',
33
+ };
34
+
25
35
  readonly name = 'anthropic';
26
36
  private client: Anthropic;
27
37
 
@@ -45,7 +55,7 @@ export class AnthropicProvider implements LLMProvider {
45
55
  temperature: options.temperature,
46
56
  });
47
57
 
48
- return this.convertResponse(response);
58
+ return this.convertResponse(response, options.model);
49
59
  }
50
60
 
51
61
  async *stream(options: CompletionOptions): AsyncGenerator<StreamChunk, void, unknown> {
@@ -94,15 +104,20 @@ export class AnthropicProvider implements LLMProvider {
94
104
  const finalMessage = await stream.finalMessage();
95
105
  const content = this.convertContent(finalMessage.content);
96
106
 
107
+ const usage = {
108
+ inputTokens: finalMessage.usage.input_tokens,
109
+ outputTokens: finalMessage.usage.output_tokens,
110
+ };
111
+
112
+ const cost = calculateCost(this.name, options.model, usage);
113
+
97
114
  yield {
98
115
  type: 'done',
99
116
  response: {
100
117
  content,
101
118
  stopReason: this.convertStopReason(finalMessage.stop_reason),
102
- usage: {
103
- inputTokens: finalMessage.usage.input_tokens,
104
- outputTokens: finalMessage.usage.output_tokens,
105
- },
119
+ usage,
120
+ cost,
106
121
  },
107
122
  };
108
123
  }
@@ -169,14 +184,19 @@ export class AnthropicProvider implements LLMProvider {
169
184
  }));
170
185
  }
171
186
 
172
- private convertResponse(response: Anthropic.Message): CompletionResponse {
187
+ private convertResponse(response: Anthropic.Message, model: string): CompletionResponse {
188
+ const usage = {
189
+ inputTokens: response.usage.input_tokens,
190
+ outputTokens: response.usage.output_tokens,
191
+ };
192
+
193
+ const cost = calculateCost(this.name, model, usage);
194
+
173
195
  return {
174
196
  content: this.convertContent(response.content),
175
197
  stopReason: this.convertStopReason(response.stop_reason),
176
- usage: {
177
- inputTokens: response.usage.input_tokens,
178
- outputTokens: response.usage.output_tokens,
179
- },
198
+ usage,
199
+ cost,
180
200
  };
181
201
  }
182
202
 
@@ -5,8 +5,10 @@
5
5
 
6
6
  import { GoogleGenerativeAI, SchemaType } from '@google/generative-ai';
7
7
  import type { Content, Part, Tool, GenerateContentResult } from '@google/generative-ai';
8
+ import { calculateCost } from '../pricing/calculator.js';
8
9
  import type {
9
10
  LLMProvider,
11
+ ProviderClassMeta,
10
12
  CompletionOptions,
11
13
  CompletionResponse,
12
14
  StreamChunk,
@@ -20,6 +22,14 @@ import type {
20
22
  } from './types.js';
21
23
 
22
24
  export class GeminiProvider implements LLMProvider {
25
+ static readonly meta: ProviderClassMeta = {
26
+ provider: 'gemini',
27
+ authMethod: 'api_key',
28
+ envVars: ['GOOGLE_API_KEY', 'GEMINI_API_KEY'],
29
+ displayName: 'Direct API',
30
+ description: 'Direct API access',
31
+ };
32
+
23
33
  readonly name = 'gemini';
24
34
  private client: GoogleGenerativeAI;
25
35
  private apiKey: string;
@@ -47,7 +57,7 @@ export class GeminiProvider implements LLMProvider {
47
57
  const contents = this.convertMessages(options.messages);
48
58
  const result = await model.generateContent({ contents });
49
59
 
50
- return this.convertResponse(result);
60
+ return this.convertResponse(result, options.model);
51
61
  }
52
62
 
53
63
  async *stream(options: CompletionOptions): AsyncGenerator<StreamChunk, void, unknown> {
@@ -115,17 +125,22 @@ export class GeminiProvider implements LLMProvider {
115
125
  const finalResponse = await result.response;
116
126
  const stopReason = this.getStopReason(finalResponse, functionCalls.length > 0);
117
127
 
128
+ const usage = finalResponse.usageMetadata
129
+ ? {
130
+ inputTokens: finalResponse.usageMetadata.promptTokenCount ?? 0,
131
+ outputTokens: finalResponse.usageMetadata.candidatesTokenCount ?? 0,
132
+ }
133
+ : undefined;
134
+
135
+ const cost = usage ? calculateCost(this.name, options.model, usage) : undefined;
136
+
118
137
  yield {
119
138
  type: 'done',
120
139
  response: {
121
140
  content,
122
141
  stopReason,
123
- usage: finalResponse.usageMetadata
124
- ? {
125
- inputTokens: finalResponse.usageMetadata.promptTokenCount ?? 0,
126
- outputTokens: finalResponse.usageMetadata.candidatesTokenCount ?? 0,
127
- }
128
- : undefined,
142
+ usage,
143
+ cost,
129
144
  },
130
145
  };
131
146
  }
@@ -237,7 +252,7 @@ export class GeminiProvider implements LLMProvider {
237
252
  return result;
238
253
  }
239
254
 
240
- private convertResponse(result: GenerateContentResult): CompletionResponse {
255
+ private convertResponse(result: GenerateContentResult, model: string): CompletionResponse {
241
256
  const response = result.response;
242
257
  const parts = response.candidates?.[0]?.content?.parts ?? [];
243
258
  const content: MessageContent[] = [];
@@ -261,15 +276,20 @@ export class GeminiProvider implements LLMProvider {
261
276
 
262
277
  const hasFunctionCalls = parts.some((p) => 'functionCall' in p);
263
278
 
279
+ const usage = response.usageMetadata
280
+ ? {
281
+ inputTokens: response.usageMetadata.promptTokenCount ?? 0,
282
+ outputTokens: response.usageMetadata.candidatesTokenCount ?? 0,
283
+ }
284
+ : undefined;
285
+
286
+ const cost = usage ? calculateCost(this.name, model, usage) : undefined;
287
+
264
288
  return {
265
289
  content,
266
290
  stopReason: this.getStopReason(response, hasFunctionCalls),
267
- usage: response.usageMetadata
268
- ? {
269
- inputTokens: response.usageMetadata.promptTokenCount ?? 0,
270
- outputTokens: response.usageMetadata.candidatesTokenCount ?? 0,
271
- }
272
- : undefined,
291
+ usage,
292
+ cost,
273
293
  };
274
294
  }
275
295
 
@@ -6,56 +6,80 @@ export * from './types.js';
6
6
  export { OpenAIProvider } from './openai.js';
7
7
  export { AnthropicProvider } from './anthropic.js';
8
8
  export { GeminiProvider } from './gemini.js';
9
- export { VertexAIProvider } from './vertex-ai.js';
9
+ export { AnthropicVertexProvider } from './vertex-ai.js';
10
10
 
11
- import type { LLMProvider, OpenAIConfig, AnthropicConfig, GeminiConfig, VertexAIConfig } from './types.js';
11
+ import type {
12
+ LLMProvider,
13
+ Provider,
14
+ AuthMethod,
15
+ OpenAIConfig,
16
+ AnthropicConfig,
17
+ GeminiConfig,
18
+ VertexAIConfig,
19
+ } from './types.js';
12
20
  import { OpenAIProvider } from './openai.js';
13
21
  import { AnthropicProvider } from './anthropic.js';
14
22
  import { GeminiProvider } from './gemini.js';
15
- import { VertexAIProvider } from './vertex-ai.js';
23
+ import { AnthropicVertexProvider } from './vertex-ai.js';
24
+
25
+ // Legacy type alias for backward compatibility
26
+ /** @deprecated Use Provider instead */
27
+ export type ProviderName = Provider;
16
28
 
17
- export type ProviderName = 'openai' | 'anthropic' | 'gemini' | 'vertex-ai';
18
29
  export type ProviderConfigMap = {
19
30
  openai: OpenAIConfig;
20
31
  anthropic: AnthropicConfig;
21
32
  gemini: GeminiConfig;
22
- 'vertex-ai': VertexAIConfig;
23
33
  };
24
34
 
25
- export interface CreateProviderOptions<T extends ProviderName = ProviderName> {
26
- provider: T;
27
- config?: ProviderConfigMap[T];
35
+ export interface CreateProviderOptions {
36
+ provider: Provider;
37
+ authMethod?: AuthMethod;
38
+ config?: OpenAIConfig | AnthropicConfig | GeminiConfig | VertexAIConfig;
28
39
  }
29
40
 
30
41
  /**
31
- * Create a provider instance by name
42
+ * Create a provider instance by provider and auth method
43
+ * If authMethod is not provided, defaults to 'api_key'
32
44
  */
33
45
  export function createProvider(options: CreateProviderOptions): LLMProvider {
34
- switch (options.provider) {
35
- case 'openai':
36
- return new OpenAIProvider(options.config as OpenAIConfig);
37
- case 'anthropic':
38
- return new AnthropicProvider(options.config as AnthropicConfig);
39
- case 'gemini':
40
- return new GeminiProvider(options.config as GeminiConfig);
41
- case 'vertex-ai':
42
- return new VertexAIProvider(options.config as VertexAIConfig);
43
- default:
44
- throw new Error(`Unknown provider: ${options.provider}`);
46
+ const { provider, authMethod = 'api_key', config } = options;
47
+
48
+ // Map provider + authMethod to the correct implementation
49
+ if (provider === 'anthropic') {
50
+ if (authMethod === 'vertex') {
51
+ return new AnthropicVertexProvider(config as VertexAIConfig);
52
+ } else if (authMethod === 'api_key') {
53
+ return new AnthropicProvider(config as AnthropicConfig);
54
+ }
55
+ throw new Error(`Unsupported auth method for anthropic: ${authMethod}`);
56
+ }
57
+
58
+ if (provider === 'openai') {
59
+ if (authMethod === 'api_key') {
60
+ return new OpenAIProvider(config as OpenAIConfig);
61
+ }
62
+ throw new Error(`Unsupported auth method for openai: ${authMethod}`);
63
+ }
64
+
65
+ if (provider === 'gemini') {
66
+ if (authMethod === 'api_key') {
67
+ return new GeminiProvider(config as GeminiConfig);
68
+ }
69
+ throw new Error(`Unsupported auth method for gemini: ${authMethod}`);
45
70
  }
71
+
72
+ throw new Error(`Unknown provider: ${provider}`);
46
73
  }
47
74
 
48
75
  /**
49
76
  * Infer provider from model name
77
+ * Note: This only returns the provider, not the auth method
78
+ * For Vertex AI models (claude-*@version), this returns 'anthropic'
50
79
  */
51
- export function inferProvider(model: string): ProviderName {
80
+ export function inferProvider(model: string): Provider {
52
81
  const modelLower = model.toLowerCase();
53
82
 
54
- // Vertex AI models (Claude models with @ version suffix like claude-sonnet-4-5@20250929)
55
- if (modelLower.includes('claude') && modelLower.includes('@')) {
56
- return 'vertex-ai';
57
- }
58
-
59
83
  // OpenAI models
60
84
  if (
61
85
  modelLower.includes('gpt') ||
@@ -68,7 +92,7 @@ export function inferProvider(model: string): ProviderName {
68
92
  return 'openai';
69
93
  }
70
94
 
71
- // Anthropic models
95
+ // Anthropic models (including Vertex AI format with @)
72
96
  if (modelLower.includes('claude')) {
73
97
  return 'anthropic';
74
98
  }
@@ -82,10 +106,29 @@ export function inferProvider(model: string): ProviderName {
82
106
  return 'openai';
83
107
  }
84
108
 
109
+ /**
110
+ * Infer auth method from model name
111
+ * Returns undefined if auth method cannot be inferred
112
+ */
113
+ export function inferAuthMethod(model: string): AuthMethod | undefined {
114
+ const modelLower = model.toLowerCase();
115
+
116
+ // Vertex AI models (Claude models with @ version suffix like claude-sonnet-4-5@20250929)
117
+ if (modelLower.includes('claude') && modelLower.includes('@')) {
118
+ return 'vertex';
119
+ }
120
+
121
+ // For other models, we can't reliably infer auth method
122
+ return undefined;
123
+ }
124
+
85
125
  /**
86
126
  * Common model aliases
87
127
  */
88
- export const ModelAliases: Record<string, { provider: ProviderName; model: string }> = {
128
+ export const ModelAliases: Record<
129
+ string,
130
+ { provider: Provider; authMethod?: AuthMethod; model: string }
131
+ > = {
89
132
  // OpenAI
90
133
  'gpt-4o': { provider: 'openai', model: 'gpt-4o' },
91
134
  'gpt-4o-mini': { provider: 'openai', model: 'gpt-4o-mini' },
@@ -94,7 +137,7 @@ export const ModelAliases: Record<string, { provider: ProviderName; model: strin
94
137
  'o1-mini': { provider: 'openai', model: 'o1-mini' },
95
138
  'o3-mini': { provider: 'openai', model: 'o3-mini' },
96
139
 
97
- // Anthropic
140
+ // Anthropic (Direct API)
98
141
  'claude-opus': { provider: 'anthropic', model: 'claude-opus-4-5-20251101' },
99
142
  'claude-sonnet': { provider: 'anthropic', model: 'claude-sonnet-4-20250514' },
100
143
  'claude-haiku': { provider: 'anthropic', model: 'claude-haiku-4-20250514' },
@@ -105,8 +148,8 @@ export const ModelAliases: Record<string, { provider: ProviderName; model: strin
105
148
  'gemini-1.5-pro': { provider: 'gemini', model: 'gemini-1.5-pro' },
106
149
  'gemini-1.5-flash': { provider: 'gemini', model: 'gemini-1.5-flash' },
107
150
 
108
- // Vertex AI (Claude on GCP)
109
- 'vertex-sonnet': { provider: 'vertex-ai', model: 'claude-sonnet-4-5@20250929' },
110
- 'vertex-haiku': { provider: 'vertex-ai', model: 'claude-haiku-4-5@20251001' },
111
- 'vertex-opus': { provider: 'vertex-ai', model: 'claude-opus-4-1@20250805' },
151
+ // Anthropic via Vertex AI
152
+ 'vertex-sonnet': { provider: 'anthropic', authMethod: 'vertex', model: 'claude-sonnet-4-5@20250929' },
153
+ 'vertex-haiku': { provider: 'anthropic', authMethod: 'vertex', model: 'claude-haiku-4-5@20251001' },
154
+ 'vertex-opus': { provider: 'anthropic', authMethod: 'vertex', model: 'claude-opus-4-1@20250805' },
112
155
  };
@@ -4,8 +4,10 @@
4
4
  */
5
5
 
6
6
  import OpenAI from 'openai';
7
+ import { calculateCost } from '../pricing/calculator.js';
7
8
  import type {
8
9
  LLMProvider,
10
+ ProviderClassMeta,
9
11
  CompletionOptions,
10
12
  CompletionResponse,
11
13
  StreamChunk,
@@ -21,6 +23,14 @@ type OpenAIMessage = OpenAI.Chat.Completions.ChatCompletionMessageParam;
21
23
  type OpenAITool = OpenAI.Chat.Completions.ChatCompletionTool;
22
24
 
23
25
  export class OpenAIProvider implements LLMProvider {
26
+ static readonly meta: ProviderClassMeta = {
27
+ provider: 'openai',
28
+ authMethod: 'api_key',
29
+ envVars: ['OPENAI_API_KEY'],
30
+ displayName: 'Direct API',
31
+ description: 'Direct API access',
32
+ };
33
+
24
34
  readonly name = 'openai';
25
35
  private client: OpenAI;
26
36
 
@@ -44,7 +54,7 @@ export class OpenAIProvider implements LLMProvider {
44
54
  temperature: options.temperature,
45
55
  });
46
56
 
47
- return this.convertResponse(response);
57
+ return this.convertResponse(response, options.model);
48
58
  }
49
59
 
50
60
  async *stream(options: CompletionOptions): AsyncGenerator<StreamChunk, void, unknown> {
@@ -195,7 +205,10 @@ export class OpenAIProvider implements LLMProvider {
195
205
  }));
196
206
  }
197
207
 
198
- private convertResponse(response: OpenAI.Chat.Completions.ChatCompletion): CompletionResponse {
208
+ private convertResponse(
209
+ response: OpenAI.Chat.Completions.ChatCompletion,
210
+ model: string
211
+ ): CompletionResponse {
199
212
  const choice = response.choices[0];
200
213
  const content: MessageContent[] = [];
201
214
 
@@ -216,15 +229,20 @@ export class OpenAIProvider implements LLMProvider {
216
229
  }
217
230
  }
218
231
 
232
+ const usage = response.usage
233
+ ? {
234
+ inputTokens: response.usage.prompt_tokens,
235
+ outputTokens: response.usage.completion_tokens,
236
+ }
237
+ : undefined;
238
+
239
+ const cost = usage ? calculateCost(this.name, model, usage) : undefined;
240
+
219
241
  return {
220
242
  content,
221
243
  stopReason: this.convertStopReason(choice.finish_reason),
222
- usage: response.usage
223
- ? {
224
- inputTokens: response.usage.prompt_tokens,
225
- outputTokens: response.usage.completion_tokens,
226
- }
227
- : undefined,
244
+ usage,
245
+ cost,
228
246
  };
229
247
  }
230
248