gencode-ai 0.1.3 → 0.2.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 (151) hide show
  1. package/README.md +2 -1
  2. package/dist/agent/agent.d.ts +35 -0
  3. package/dist/agent/agent.d.ts.map +1 -1
  4. package/dist/agent/agent.js +93 -3
  5. package/dist/agent/agent.js.map +1 -1
  6. package/dist/agent/types.d.ts +6 -0
  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 +157 -6
  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 +11 -2
  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/PlanApproval.d.ts +36 -0
  35. package/dist/cli/components/PlanApproval.d.ts.map +1 -0
  36. package/dist/cli/components/PlanApproval.js +154 -0
  37. package/dist/cli/components/PlanApproval.js.map +1 -0
  38. package/dist/cli/components/theme.d.ts +2 -0
  39. package/dist/cli/components/theme.d.ts.map +1 -1
  40. package/dist/cli/components/theme.js +3 -0
  41. package/dist/cli/components/theme.js.map +1 -1
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +2 -0
  45. package/dist/index.js.map +1 -1
  46. package/dist/planning/index.d.ts +13 -0
  47. package/dist/planning/index.d.ts.map +1 -0
  48. package/dist/planning/index.js +15 -0
  49. package/dist/planning/index.js.map +1 -0
  50. package/dist/planning/plan-file.d.ts +59 -0
  51. package/dist/planning/plan-file.d.ts.map +1 -0
  52. package/dist/planning/plan-file.js +278 -0
  53. package/dist/planning/plan-file.js.map +1 -0
  54. package/dist/planning/state.d.ts +127 -0
  55. package/dist/planning/state.d.ts.map +1 -0
  56. package/dist/planning/state.js +261 -0
  57. package/dist/planning/state.js.map +1 -0
  58. package/dist/planning/tools/enter-plan-mode.d.ts +25 -0
  59. package/dist/planning/tools/enter-plan-mode.d.ts.map +1 -0
  60. package/dist/planning/tools/enter-plan-mode.js +98 -0
  61. package/dist/planning/tools/enter-plan-mode.js.map +1 -0
  62. package/dist/planning/tools/exit-plan-mode.d.ts +24 -0
  63. package/dist/planning/tools/exit-plan-mode.d.ts.map +1 -0
  64. package/dist/planning/tools/exit-plan-mode.js +149 -0
  65. package/dist/planning/tools/exit-plan-mode.js.map +1 -0
  66. package/dist/planning/types.d.ts +100 -0
  67. package/dist/planning/types.d.ts.map +1 -0
  68. package/dist/planning/types.js +28 -0
  69. package/dist/planning/types.js.map +1 -0
  70. package/dist/pricing/calculator.d.ts +21 -0
  71. package/dist/pricing/calculator.d.ts.map +1 -0
  72. package/dist/pricing/calculator.js +59 -0
  73. package/dist/pricing/calculator.js.map +1 -0
  74. package/dist/pricing/index.d.ts +7 -0
  75. package/dist/pricing/index.d.ts.map +1 -0
  76. package/dist/pricing/index.js +7 -0
  77. package/dist/pricing/index.js.map +1 -0
  78. package/dist/pricing/models.d.ts +20 -0
  79. package/dist/pricing/models.d.ts.map +1 -0
  80. package/dist/pricing/models.js +322 -0
  81. package/dist/pricing/models.js.map +1 -0
  82. package/dist/pricing/types.d.ts +30 -0
  83. package/dist/pricing/types.d.ts.map +1 -0
  84. package/dist/pricing/types.js +5 -0
  85. package/dist/pricing/types.js.map +1 -0
  86. package/dist/providers/anthropic.d.ts.map +1 -1
  87. package/dist/providers/anthropic.js +17 -10
  88. package/dist/providers/anthropic.js.map +1 -1
  89. package/dist/providers/gemini.d.ts.map +1 -1
  90. package/dist/providers/gemini.js +21 -14
  91. package/dist/providers/gemini.js.map +1 -1
  92. package/dist/providers/openai.d.ts.map +1 -1
  93. package/dist/providers/openai.js +12 -8
  94. package/dist/providers/openai.js.map +1 -1
  95. package/dist/providers/types.d.ts +2 -0
  96. package/dist/providers/types.d.ts.map +1 -1
  97. package/dist/providers/vertex-ai.d.ts.map +1 -1
  98. package/dist/providers/vertex-ai.js +17 -10
  99. package/dist/providers/vertex-ai.js.map +1 -1
  100. package/dist/session/manager.d.ts +4 -0
  101. package/dist/session/manager.d.ts.map +1 -1
  102. package/dist/session/manager.js +8 -0
  103. package/dist/session/manager.js.map +1 -1
  104. package/dist/tools/index.d.ts +7 -1
  105. package/dist/tools/index.d.ts.map +1 -1
  106. package/dist/tools/index.js +7 -0
  107. package/dist/tools/index.js.map +1 -1
  108. package/dist/tools/registry.d.ts +13 -0
  109. package/dist/tools/registry.d.ts.map +1 -1
  110. package/dist/tools/registry.js +79 -2
  111. package/dist/tools/registry.js.map +1 -1
  112. package/docs/cost-tracking-comparison.md +904 -0
  113. package/docs/operating-modes.md +96 -0
  114. package/docs/proposals/0025-cost-tracking.md +60 -2
  115. package/docs/proposals/README.md +1 -1
  116. package/examples/test-checkpointing.ts +121 -0
  117. package/examples/test-cost-tracking.ts +77 -0
  118. package/examples/test-interrupt-cleanup.ts +94 -0
  119. package/package.json +1 -1
  120. package/src/agent/agent.ts +110 -3
  121. package/src/agent/types.ts +6 -0
  122. package/src/checkpointing/checkpoint-manager.ts +327 -0
  123. package/src/checkpointing/index.ts +45 -0
  124. package/src/checkpointing/types.ts +104 -0
  125. package/src/cli/components/App.tsx +204 -5
  126. package/src/cli/components/CommandSuggestions.tsx +5 -0
  127. package/src/cli/components/Messages.tsx +23 -4
  128. package/src/cli/components/ModeIndicator.tsx +174 -0
  129. package/src/cli/components/PlanApproval.tsx +327 -0
  130. package/src/cli/components/theme.ts +3 -0
  131. package/src/index.ts +15 -0
  132. package/src/planning/index.ts +53 -0
  133. package/src/planning/plan-file.ts +326 -0
  134. package/src/planning/state.ts +305 -0
  135. package/src/planning/tools/enter-plan-mode.ts +111 -0
  136. package/src/planning/tools/exit-plan-mode.ts +170 -0
  137. package/src/planning/types.ts +150 -0
  138. package/src/pricing/calculator.ts +71 -0
  139. package/src/pricing/index.ts +7 -0
  140. package/src/pricing/models.ts +334 -0
  141. package/src/pricing/types.ts +32 -0
  142. package/src/providers/anthropic.ts +21 -10
  143. package/src/providers/gemini.ts +25 -14
  144. package/src/providers/openai.ts +17 -8
  145. package/src/providers/types.ts +3 -0
  146. package/src/providers/vertex-ai.ts +21 -10
  147. package/src/session/manager.ts +9 -0
  148. package/src/tools/index.ts +8 -0
  149. package/src/tools/registry.ts +95 -2
  150. package/.gencode/settings.local.json +0 -7
  151. package/CLAUDE.md +0 -86
@@ -0,0 +1,334 @@
1
+ /**
2
+ * Model pricing database
3
+ * Prices are per 1M tokens in USD
4
+ * Updated: January 2025
5
+ */
6
+
7
+ import { ModelPricing } from './types.js';
8
+
9
+ /**
10
+ * Pricing data for all supported models
11
+ * Source: Official provider pricing pages as of January 2025
12
+ */
13
+ export const MODEL_PRICING: ModelPricing[] = [
14
+ // Anthropic Claude Models
15
+ {
16
+ provider: 'anthropic',
17
+ model: 'claude-opus-4-5',
18
+ inputPer1M: 15.0,
19
+ outputPer1M: 75.0,
20
+ effectiveDate: '2025-01-01',
21
+ },
22
+ {
23
+ provider: 'anthropic',
24
+ model: 'claude-opus-4',
25
+ inputPer1M: 15.0,
26
+ outputPer1M: 75.0,
27
+ effectiveDate: '2024-11-01',
28
+ },
29
+ {
30
+ provider: 'anthropic',
31
+ model: 'claude-sonnet-4-5',
32
+ inputPer1M: 3.0,
33
+ outputPer1M: 15.0,
34
+ effectiveDate: '2025-01-01',
35
+ },
36
+ {
37
+ provider: 'anthropic',
38
+ model: 'claude-sonnet-4',
39
+ inputPer1M: 3.0,
40
+ outputPer1M: 15.0,
41
+ effectiveDate: '2024-10-22',
42
+ },
43
+ {
44
+ provider: 'anthropic',
45
+ model: 'claude-3-5-sonnet-20241022',
46
+ inputPer1M: 3.0,
47
+ outputPer1M: 15.0,
48
+ effectiveDate: '2024-10-22',
49
+ },
50
+ {
51
+ provider: 'anthropic',
52
+ model: 'claude-3-5-sonnet-20240620',
53
+ inputPer1M: 3.0,
54
+ outputPer1M: 15.0,
55
+ effectiveDate: '2024-06-20',
56
+ },
57
+ {
58
+ provider: 'anthropic',
59
+ model: 'claude-haiku-3-5',
60
+ inputPer1M: 0.8,
61
+ outputPer1M: 4.0,
62
+ effectiveDate: '2024-11-01',
63
+ },
64
+ {
65
+ provider: 'anthropic',
66
+ model: 'claude-3-5-haiku-20241022',
67
+ inputPer1M: 0.8,
68
+ outputPer1M: 4.0,
69
+ effectiveDate: '2024-10-22',
70
+ },
71
+ {
72
+ provider: 'anthropic',
73
+ model: 'claude-3-haiku-20240307',
74
+ inputPer1M: 0.25,
75
+ outputPer1M: 1.25,
76
+ effectiveDate: '2024-03-07',
77
+ },
78
+ {
79
+ provider: 'anthropic',
80
+ model: 'claude-3-opus-20240229',
81
+ inputPer1M: 15.0,
82
+ outputPer1M: 75.0,
83
+ effectiveDate: '2024-02-29',
84
+ },
85
+
86
+ // OpenAI Models
87
+ {
88
+ provider: 'openai',
89
+ model: 'gpt-4o',
90
+ inputPer1M: 2.5,
91
+ outputPer1M: 10.0,
92
+ effectiveDate: '2024-08-06',
93
+ },
94
+ {
95
+ provider: 'openai',
96
+ model: 'gpt-4o-2024-11-20',
97
+ inputPer1M: 2.5,
98
+ outputPer1M: 10.0,
99
+ effectiveDate: '2024-11-20',
100
+ },
101
+ {
102
+ provider: 'openai',
103
+ model: 'gpt-4o-2024-08-06',
104
+ inputPer1M: 2.5,
105
+ outputPer1M: 10.0,
106
+ effectiveDate: '2024-08-06',
107
+ },
108
+ {
109
+ provider: 'openai',
110
+ model: 'gpt-4o-2024-05-13',
111
+ inputPer1M: 5.0,
112
+ outputPer1M: 15.0,
113
+ effectiveDate: '2024-05-13',
114
+ },
115
+ {
116
+ provider: 'openai',
117
+ model: 'gpt-4o-mini',
118
+ inputPer1M: 0.15,
119
+ outputPer1M: 0.6,
120
+ effectiveDate: '2024-07-18',
121
+ },
122
+ {
123
+ provider: 'openai',
124
+ model: 'gpt-4o-mini-2024-07-18',
125
+ inputPer1M: 0.15,
126
+ outputPer1M: 0.6,
127
+ effectiveDate: '2024-07-18',
128
+ },
129
+ {
130
+ provider: 'openai',
131
+ model: 'gpt-4-turbo',
132
+ inputPer1M: 10.0,
133
+ outputPer1M: 30.0,
134
+ effectiveDate: '2024-04-09',
135
+ },
136
+ {
137
+ provider: 'openai',
138
+ model: 'gpt-4-turbo-2024-04-09',
139
+ inputPer1M: 10.0,
140
+ outputPer1M: 30.0,
141
+ effectiveDate: '2024-04-09',
142
+ },
143
+ {
144
+ provider: 'openai',
145
+ model: 'gpt-4',
146
+ inputPer1M: 30.0,
147
+ outputPer1M: 60.0,
148
+ effectiveDate: '2023-03-14',
149
+ },
150
+ {
151
+ provider: 'openai',
152
+ model: 'gpt-3.5-turbo',
153
+ inputPer1M: 0.5,
154
+ outputPer1M: 1.5,
155
+ effectiveDate: '2023-11-06',
156
+ },
157
+ {
158
+ provider: 'openai',
159
+ model: 'o1',
160
+ inputPer1M: 15.0,
161
+ outputPer1M: 60.0,
162
+ effectiveDate: '2024-12-17',
163
+ },
164
+ {
165
+ provider: 'openai',
166
+ model: 'o1-2024-12-17',
167
+ inputPer1M: 15.0,
168
+ outputPer1M: 60.0,
169
+ effectiveDate: '2024-12-17',
170
+ },
171
+ {
172
+ provider: 'openai',
173
+ model: 'o1-preview',
174
+ inputPer1M: 15.0,
175
+ outputPer1M: 60.0,
176
+ effectiveDate: '2024-09-12',
177
+ },
178
+ {
179
+ provider: 'openai',
180
+ model: 'o1-preview-2024-09-12',
181
+ inputPer1M: 15.0,
182
+ outputPer1M: 60.0,
183
+ effectiveDate: '2024-09-12',
184
+ },
185
+ {
186
+ provider: 'openai',
187
+ model: 'o1-mini',
188
+ inputPer1M: 3.0,
189
+ outputPer1M: 12.0,
190
+ effectiveDate: '2024-09-12',
191
+ },
192
+ {
193
+ provider: 'openai',
194
+ model: 'o1-mini-2024-09-12',
195
+ inputPer1M: 3.0,
196
+ outputPer1M: 12.0,
197
+ effectiveDate: '2024-09-12',
198
+ },
199
+
200
+ // Google Gemini Models
201
+ {
202
+ provider: 'gemini',
203
+ model: 'gemini-2.0-flash-exp',
204
+ inputPer1M: 0.0,
205
+ outputPer1M: 0.0,
206
+ effectiveDate: '2024-12-11',
207
+ },
208
+ {
209
+ provider: 'gemini',
210
+ model: 'gemini-2.0-flash',
211
+ inputPer1M: 0.075,
212
+ outputPer1M: 0.3,
213
+ effectiveDate: '2025-01-01',
214
+ },
215
+ {
216
+ provider: 'gemini',
217
+ model: 'gemini-exp-1206',
218
+ inputPer1M: 0.0,
219
+ outputPer1M: 0.0,
220
+ effectiveDate: '2024-12-06',
221
+ },
222
+ {
223
+ provider: 'gemini',
224
+ model: 'gemini-1.5-pro',
225
+ inputPer1M: 1.25,
226
+ outputPer1M: 5.0,
227
+ effectiveDate: '2024-05-14',
228
+ },
229
+ {
230
+ provider: 'gemini',
231
+ model: 'gemini-1.5-pro-002',
232
+ inputPer1M: 1.25,
233
+ outputPer1M: 5.0,
234
+ effectiveDate: '2024-09-24',
235
+ },
236
+ {
237
+ provider: 'gemini',
238
+ model: 'gemini-1.5-flash',
239
+ inputPer1M: 0.075,
240
+ outputPer1M: 0.3,
241
+ effectiveDate: '2024-05-14',
242
+ },
243
+ {
244
+ provider: 'gemini',
245
+ model: 'gemini-1.5-flash-002',
246
+ inputPer1M: 0.075,
247
+ outputPer1M: 0.3,
248
+ effectiveDate: '2024-09-24',
249
+ },
250
+ {
251
+ provider: 'gemini',
252
+ model: 'gemini-1.5-flash-8b',
253
+ inputPer1M: 0.0375,
254
+ outputPer1M: 0.15,
255
+ effectiveDate: '2024-10-03',
256
+ },
257
+
258
+ // Google Vertex AI (same pricing as Gemini)
259
+ {
260
+ provider: 'vertex-ai',
261
+ model: 'gemini-2.0-flash-exp',
262
+ inputPer1M: 0.0,
263
+ outputPer1M: 0.0,
264
+ effectiveDate: '2024-12-11',
265
+ },
266
+ {
267
+ provider: 'vertex-ai',
268
+ model: 'gemini-2.0-flash',
269
+ inputPer1M: 0.075,
270
+ outputPer1M: 0.3,
271
+ effectiveDate: '2025-01-01',
272
+ },
273
+ {
274
+ provider: 'vertex-ai',
275
+ model: 'gemini-exp-1206',
276
+ inputPer1M: 0.0,
277
+ outputPer1M: 0.0,
278
+ effectiveDate: '2024-12-06',
279
+ },
280
+ {
281
+ provider: 'vertex-ai',
282
+ model: 'gemini-1.5-pro',
283
+ inputPer1M: 1.25,
284
+ outputPer1M: 5.0,
285
+ effectiveDate: '2024-05-14',
286
+ },
287
+ {
288
+ provider: 'vertex-ai',
289
+ model: 'gemini-1.5-pro-002',
290
+ inputPer1M: 1.25,
291
+ outputPer1M: 5.0,
292
+ effectiveDate: '2024-09-24',
293
+ },
294
+ {
295
+ provider: 'vertex-ai',
296
+ model: 'gemini-1.5-flash',
297
+ inputPer1M: 0.075,
298
+ outputPer1M: 0.3,
299
+ effectiveDate: '2024-05-14',
300
+ },
301
+ {
302
+ provider: 'vertex-ai',
303
+ model: 'gemini-1.5-flash-002',
304
+ inputPer1M: 0.075,
305
+ outputPer1M: 0.3,
306
+ effectiveDate: '2024-09-24',
307
+ },
308
+ {
309
+ provider: 'vertex-ai',
310
+ model: 'gemini-1.5-flash-8b',
311
+ inputPer1M: 0.0375,
312
+ outputPer1M: 0.15,
313
+ effectiveDate: '2024-10-03',
314
+ },
315
+ ];
316
+
317
+ /**
318
+ * Get pricing for a specific model
319
+ */
320
+ export function getModelPricing(
321
+ provider: string,
322
+ model: string
323
+ ): ModelPricing | undefined {
324
+ return MODEL_PRICING.find(
325
+ (p) => p.provider === provider && p.model === model
326
+ );
327
+ }
328
+
329
+ /**
330
+ * Get all pricing for a provider
331
+ */
332
+ export function getProviderPricing(provider: string): ModelPricing[] {
333
+ return MODEL_PRICING.filter((p) => p.provider === provider);
334
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Pricing and cost tracking types
3
+ */
4
+
5
+ /**
6
+ * Token usage information
7
+ */
8
+ export interface TokenUsage {
9
+ inputTokens: number;
10
+ outputTokens: number;
11
+ }
12
+
13
+ /**
14
+ * Cost estimate in USD
15
+ */
16
+ export interface CostEstimate {
17
+ inputCost: number;
18
+ outputCost: number;
19
+ totalCost: number;
20
+ currency: string; // 'USD'
21
+ }
22
+
23
+ /**
24
+ * Model pricing per 1M tokens (USD)
25
+ */
26
+ export interface ModelPricing {
27
+ provider: string;
28
+ model: string;
29
+ inputPer1M: number; // USD per 1M input tokens
30
+ outputPer1M: number; // USD per 1M output tokens
31
+ effectiveDate?: string; // When this pricing became effective
32
+ }
@@ -4,6 +4,7 @@
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,
9
10
  CompletionOptions,
@@ -45,7 +46,7 @@ export class AnthropicProvider implements LLMProvider {
45
46
  temperature: options.temperature,
46
47
  });
47
48
 
48
- return this.convertResponse(response);
49
+ return this.convertResponse(response, options.model);
49
50
  }
50
51
 
51
52
  async *stream(options: CompletionOptions): AsyncGenerator<StreamChunk, void, unknown> {
@@ -94,15 +95,20 @@ export class AnthropicProvider implements LLMProvider {
94
95
  const finalMessage = await stream.finalMessage();
95
96
  const content = this.convertContent(finalMessage.content);
96
97
 
98
+ const usage = {
99
+ inputTokens: finalMessage.usage.input_tokens,
100
+ outputTokens: finalMessage.usage.output_tokens,
101
+ };
102
+
103
+ const cost = calculateCost(this.name, options.model, usage);
104
+
97
105
  yield {
98
106
  type: 'done',
99
107
  response: {
100
108
  content,
101
109
  stopReason: this.convertStopReason(finalMessage.stop_reason),
102
- usage: {
103
- inputTokens: finalMessage.usage.input_tokens,
104
- outputTokens: finalMessage.usage.output_tokens,
105
- },
110
+ usage,
111
+ cost,
106
112
  },
107
113
  };
108
114
  }
@@ -169,14 +175,19 @@ export class AnthropicProvider implements LLMProvider {
169
175
  }));
170
176
  }
171
177
 
172
- private convertResponse(response: Anthropic.Message): CompletionResponse {
178
+ private convertResponse(response: Anthropic.Message, model: string): CompletionResponse {
179
+ const usage = {
180
+ inputTokens: response.usage.input_tokens,
181
+ outputTokens: response.usage.output_tokens,
182
+ };
183
+
184
+ const cost = calculateCost(this.name, model, usage);
185
+
173
186
  return {
174
187
  content: this.convertContent(response.content),
175
188
  stopReason: this.convertStopReason(response.stop_reason),
176
- usage: {
177
- inputTokens: response.usage.input_tokens,
178
- outputTokens: response.usage.output_tokens,
179
- },
189
+ usage,
190
+ cost,
180
191
  };
181
192
  }
182
193
 
@@ -5,6 +5,7 @@
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,
10
11
  CompletionOptions,
@@ -47,7 +48,7 @@ export class GeminiProvider implements LLMProvider {
47
48
  const contents = this.convertMessages(options.messages);
48
49
  const result = await model.generateContent({ contents });
49
50
 
50
- return this.convertResponse(result);
51
+ return this.convertResponse(result, options.model);
51
52
  }
52
53
 
53
54
  async *stream(options: CompletionOptions): AsyncGenerator<StreamChunk, void, unknown> {
@@ -115,17 +116,22 @@ export class GeminiProvider implements LLMProvider {
115
116
  const finalResponse = await result.response;
116
117
  const stopReason = this.getStopReason(finalResponse, functionCalls.length > 0);
117
118
 
119
+ const usage = finalResponse.usageMetadata
120
+ ? {
121
+ inputTokens: finalResponse.usageMetadata.promptTokenCount ?? 0,
122
+ outputTokens: finalResponse.usageMetadata.candidatesTokenCount ?? 0,
123
+ }
124
+ : undefined;
125
+
126
+ const cost = usage ? calculateCost(this.name, options.model, usage) : undefined;
127
+
118
128
  yield {
119
129
  type: 'done',
120
130
  response: {
121
131
  content,
122
132
  stopReason,
123
- usage: finalResponse.usageMetadata
124
- ? {
125
- inputTokens: finalResponse.usageMetadata.promptTokenCount ?? 0,
126
- outputTokens: finalResponse.usageMetadata.candidatesTokenCount ?? 0,
127
- }
128
- : undefined,
133
+ usage,
134
+ cost,
129
135
  },
130
136
  };
131
137
  }
@@ -237,7 +243,7 @@ export class GeminiProvider implements LLMProvider {
237
243
  return result;
238
244
  }
239
245
 
240
- private convertResponse(result: GenerateContentResult): CompletionResponse {
246
+ private convertResponse(result: GenerateContentResult, model: string): CompletionResponse {
241
247
  const response = result.response;
242
248
  const parts = response.candidates?.[0]?.content?.parts ?? [];
243
249
  const content: MessageContent[] = [];
@@ -261,15 +267,20 @@ export class GeminiProvider implements LLMProvider {
261
267
 
262
268
  const hasFunctionCalls = parts.some((p) => 'functionCall' in p);
263
269
 
270
+ const usage = response.usageMetadata
271
+ ? {
272
+ inputTokens: response.usageMetadata.promptTokenCount ?? 0,
273
+ outputTokens: response.usageMetadata.candidatesTokenCount ?? 0,
274
+ }
275
+ : undefined;
276
+
277
+ const cost = usage ? calculateCost(this.name, model, usage) : undefined;
278
+
264
279
  return {
265
280
  content,
266
281
  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,
282
+ usage,
283
+ cost,
273
284
  };
274
285
  }
275
286
 
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import OpenAI from 'openai';
7
+ import { calculateCost } from '../pricing/calculator.js';
7
8
  import type {
8
9
  LLMProvider,
9
10
  CompletionOptions,
@@ -44,7 +45,7 @@ export class OpenAIProvider implements LLMProvider {
44
45
  temperature: options.temperature,
45
46
  });
46
47
 
47
- return this.convertResponse(response);
48
+ return this.convertResponse(response, options.model);
48
49
  }
49
50
 
50
51
  async *stream(options: CompletionOptions): AsyncGenerator<StreamChunk, void, unknown> {
@@ -195,7 +196,10 @@ export class OpenAIProvider implements LLMProvider {
195
196
  }));
196
197
  }
197
198
 
198
- private convertResponse(response: OpenAI.Chat.Completions.ChatCompletion): CompletionResponse {
199
+ private convertResponse(
200
+ response: OpenAI.Chat.Completions.ChatCompletion,
201
+ model: string
202
+ ): CompletionResponse {
199
203
  const choice = response.choices[0];
200
204
  const content: MessageContent[] = [];
201
205
 
@@ -216,15 +220,20 @@ export class OpenAIProvider implements LLMProvider {
216
220
  }
217
221
  }
218
222
 
223
+ const usage = response.usage
224
+ ? {
225
+ inputTokens: response.usage.prompt_tokens,
226
+ outputTokens: response.usage.completion_tokens,
227
+ }
228
+ : undefined;
229
+
230
+ const cost = usage ? calculateCost(this.name, model, usage) : undefined;
231
+
219
232
  return {
220
233
  content,
221
234
  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,
235
+ usage,
236
+ cost,
228
237
  };
229
238
  }
230
239
 
@@ -3,6 +3,8 @@
3
3
  * Abstracts differences between OpenAI, Anthropic, and Gemini APIs
4
4
  */
5
5
 
6
+ import type { CostEstimate } from '../pricing/types.js';
7
+
6
8
  // ============================================================================
7
9
  // Message Types
8
10
  // ============================================================================
@@ -92,6 +94,7 @@ export interface CompletionResponse {
92
94
  inputTokens: number;
93
95
  outputTokens: number;
94
96
  };
97
+ cost?: CostEstimate;
95
98
  }
96
99
 
97
100
  // ============================================================================
@@ -9,6 +9,7 @@
9
9
  */
10
10
 
11
11
  import { GoogleAuth } from 'google-auth-library';
12
+ import { calculateCost } from '../pricing/calculator.js';
12
13
  import type {
13
14
  LLMProvider,
14
15
  CompletionOptions,
@@ -210,7 +211,7 @@ export class VertexAIProvider implements LLMProvider {
210
211
  }
211
212
 
212
213
  const data = (await response.json()) as VertexAIResponse;
213
- return this.convertResponse(data);
214
+ return this.convertResponse(data, options.model);
214
215
  }
215
216
 
216
217
  async *stream(options: CompletionOptions): AsyncGenerator<StreamChunk, void, unknown> {
@@ -337,15 +338,20 @@ export class VertexAIProvider implements LLMProvider {
337
338
  // Build final response
338
339
  const content = this.buildFinalContent(contentBlocks, toolInputBuffers);
339
340
 
341
+ const usage = {
342
+ inputTokens,
343
+ outputTokens,
344
+ };
345
+
346
+ const cost = calculateCost(this.name, options.model, usage);
347
+
340
348
  yield {
341
349
  type: 'done',
342
350
  response: {
343
351
  content,
344
352
  stopReason,
345
- usage: {
346
- inputTokens,
347
- outputTokens,
348
- },
353
+ usage,
354
+ cost,
349
355
  },
350
356
  };
351
357
  }
@@ -449,14 +455,19 @@ export class VertexAIProvider implements LLMProvider {
449
455
  }));
450
456
  }
451
457
 
452
- private convertResponse(response: VertexAIResponse): CompletionResponse {
458
+ private convertResponse(response: VertexAIResponse, model: string): CompletionResponse {
459
+ const usage = {
460
+ inputTokens: response.usage.input_tokens,
461
+ outputTokens: response.usage.output_tokens,
462
+ };
463
+
464
+ const cost = calculateCost(this.name, model, usage);
465
+
453
466
  return {
454
467
  content: this.convertContent(response.content),
455
468
  stopReason: this.convertStopReason(response.stop_reason),
456
- usage: {
457
- inputTokens: response.usage.input_tokens,
458
- outputTokens: response.usage.output_tokens,
459
- },
469
+ usage,
470
+ cost,
460
471
  };
461
472
  }
462
473
 
@@ -326,6 +326,15 @@ export class SessionManager {
326
326
  }
327
327
  }
328
328
 
329
+ /**
330
+ * Remove the last message from current session
331
+ */
332
+ removeLastMessage(): void {
333
+ if (this.currentSession && this.currentSession.messages.length > 0) {
334
+ this.currentSession.messages.pop();
335
+ }
336
+ }
337
+
329
338
  /**
330
339
  * Export session to JSON
331
340
  */
@@ -28,6 +28,9 @@ export type {
28
28
  AskUserQuestionResult,
29
29
  } from './builtin/ask-user.js';
30
30
 
31
+ // Plan mode tools
32
+ export { enterPlanModeTool, exitPlanModeTool } from '../planning/index.js';
33
+
31
34
  import { ToolRegistry } from './registry.js';
32
35
  import { readTool } from './builtin/read.js';
33
36
  import { writeTool } from './builtin/write.js';
@@ -39,6 +42,7 @@ import { webfetchTool } from './builtin/webfetch.js';
39
42
  import { websearchTool } from './builtin/websearch.js';
40
43
  import { todowriteTool } from './builtin/todowrite.js';
41
44
  import { askUserQuestionTool } from './builtin/ask-user.js';
45
+ import { enterPlanModeTool, exitPlanModeTool } from '../planning/index.js';
42
46
 
43
47
  /**
44
48
  * Create a registry with all built-in tools
@@ -56,6 +60,8 @@ export function createDefaultRegistry(): ToolRegistry {
56
60
  websearchTool,
57
61
  todowriteTool,
58
62
  askUserQuestionTool,
63
+ enterPlanModeTool,
64
+ exitPlanModeTool,
59
65
  ]);
60
66
  return registry;
61
67
  }
@@ -74,4 +80,6 @@ export const builtinTools = [
74
80
  websearchTool,
75
81
  todowriteTool,
76
82
  askUserQuestionTool,
83
+ enterPlanModeTool,
84
+ exitPlanModeTool,
77
85
  ];