gencode-ai 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +11 -0
- package/CLAUDE.md +70 -0
- package/LICENSE +21 -0
- package/README.md +117 -0
- package/dist/agent/agent.d.ts +84 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +233 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/index.d.ts +6 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +6 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/types.d.ts +47 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +5 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/cli/components/App.d.ts +14 -0
- package/dist/cli/components/App.d.ts.map +1 -0
- package/dist/cli/components/App.js +395 -0
- package/dist/cli/components/App.js.map +1 -0
- package/dist/cli/components/CommandSuggestions.d.ts +13 -0
- package/dist/cli/components/CommandSuggestions.d.ts.map +1 -0
- package/dist/cli/components/CommandSuggestions.js +32 -0
- package/dist/cli/components/CommandSuggestions.js.map +1 -0
- package/dist/cli/components/Header.d.ts +9 -0
- package/dist/cli/components/Header.d.ts.map +1 -0
- package/dist/cli/components/Header.js +13 -0
- package/dist/cli/components/Header.js.map +1 -0
- package/dist/cli/components/Input.d.ts +13 -0
- package/dist/cli/components/Input.d.ts.map +1 -0
- package/dist/cli/components/Input.js +27 -0
- package/dist/cli/components/Input.js.map +1 -0
- package/dist/cli/components/Logo.d.ts +2 -0
- package/dist/cli/components/Logo.d.ts.map +1 -0
- package/dist/cli/components/Logo.js +8 -0
- package/dist/cli/components/Logo.js.map +1 -0
- package/dist/cli/components/Messages.d.ts +37 -0
- package/dist/cli/components/Messages.d.ts.map +1 -0
- package/dist/cli/components/Messages.js +106 -0
- package/dist/cli/components/Messages.js.map +1 -0
- package/dist/cli/components/ModelSelector.d.ts +13 -0
- package/dist/cli/components/ModelSelector.d.ts.map +1 -0
- package/dist/cli/components/ModelSelector.js +72 -0
- package/dist/cli/components/ModelSelector.js.map +1 -0
- package/dist/cli/components/Spinner.d.ts +12 -0
- package/dist/cli/components/Spinner.d.ts.map +1 -0
- package/dist/cli/components/Spinner.js +45 -0
- package/dist/cli/components/Spinner.js.map +1 -0
- package/dist/cli/components/index.d.ts +12 -0
- package/dist/cli/components/index.d.ts.map +1 -0
- package/dist/cli/components/index.js +12 -0
- package/dist/cli/components/index.js.map +1 -0
- package/dist/cli/components/theme.d.ts +31 -0
- package/dist/cli/components/theme.d.ts.map +1 -0
- package/dist/cli/components/theme.js +36 -0
- package/dist/cli/components/theme.js.map +1 -0
- package/dist/cli/index-legacy.d.ts +7 -0
- package/dist/cli/index-legacy.d.ts.map +1 -0
- package/dist/cli/index-legacy.js +431 -0
- package/dist/cli/index-legacy.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +116 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/ink-cli.d.ts +7 -0
- package/dist/cli/ink-cli.d.ts.map +1 -0
- package/dist/cli/ink-cli.js +105 -0
- package/dist/cli/ink-cli.js.map +1 -0
- package/dist/cli/session-picker.d.ts +16 -0
- package/dist/cli/session-picker.d.ts.map +1 -0
- package/dist/cli/session-picker.js +280 -0
- package/dist/cli/session-picker.js.map +1 -0
- package/dist/cli/ui.d.ts +61 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +364 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +6 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/manager.d.ts +31 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +65 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/types.d.ts +22 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +6 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/index.d.ts +10 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +9 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/init.d.ts +20 -0
- package/dist/memory/init.d.ts.map +1 -0
- package/dist/memory/init.js +332 -0
- package/dist/memory/init.js.map +1 -0
- package/dist/memory/manager.d.ts +85 -0
- package/dist/memory/manager.d.ts.map +1 -0
- package/dist/memory/manager.js +234 -0
- package/dist/memory/manager.js.map +1 -0
- package/dist/memory/types.d.ts +74 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +6 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/permissions/index.d.ts +7 -0
- package/dist/permissions/index.d.ts.map +1 -0
- package/dist/permissions/index.js +6 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/permissions/manager.d.ts +32 -0
- package/dist/permissions/manager.d.ts.map +1 -0
- package/dist/permissions/manager.js +79 -0
- package/dist/permissions/manager.js.map +1 -0
- package/dist/permissions/types.d.ts +14 -0
- package/dist/permissions/types.d.ts.map +1 -0
- package/dist/permissions/types.js +17 -0
- package/dist/permissions/types.js.map +1 -0
- package/dist/providers/anthropic.d.ts +20 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +185 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/gemini.d.ts +21 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +241 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/index.d.ts +34 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +72 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai.d.ts +19 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +221 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/types.d.ts +125 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +6 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/session/index.d.ts +6 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +6 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/manager.d.ts +101 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +295 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/session/types.d.ts +39 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +10 -0
- package/dist/session/types.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts +7 -0
- package/dist/tools/builtin/bash.d.ts.map +1 -0
- package/dist/tools/builtin/bash.js +80 -0
- package/dist/tools/builtin/bash.js.map +1 -0
- package/dist/tools/builtin/edit.d.ts +7 -0
- package/dist/tools/builtin/edit.d.ts.map +1 -0
- package/dist/tools/builtin/edit.js +32 -0
- package/dist/tools/builtin/edit.js.map +1 -0
- package/dist/tools/builtin/glob.d.ts +7 -0
- package/dist/tools/builtin/glob.d.ts.map +1 -0
- package/dist/tools/builtin/glob.js +36 -0
- package/dist/tools/builtin/glob.js.map +1 -0
- package/dist/tools/builtin/grep.d.ts +7 -0
- package/dist/tools/builtin/grep.d.ts.map +1 -0
- package/dist/tools/builtin/grep.js +59 -0
- package/dist/tools/builtin/grep.js.map +1 -0
- package/dist/tools/builtin/read.d.ts +7 -0
- package/dist/tools/builtin/read.d.ts.map +1 -0
- package/dist/tools/builtin/read.js +29 -0
- package/dist/tools/builtin/read.js.map +1 -0
- package/dist/tools/builtin/write.d.ts +7 -0
- package/dist/tools/builtin/write.d.ts.map +1 -0
- package/dist/tools/builtin/write.js +24 -0
- package/dist/tools/builtin/write.js.map +1 -0
- package/dist/tools/index.d.ts +38 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +32 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/registry.d.ts +22 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +71 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/types.d.ts +62 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +126 -0
- package/dist/tools/types.js.map +1 -0
- package/docs/README.md +16 -0
- package/docs/proposals/0001-web-fetch-tool.md +293 -0
- package/docs/proposals/0002-web-search-tool.md +306 -0
- package/docs/proposals/0003-task-subagents.md +333 -0
- package/docs/proposals/0004-plan-mode.md +338 -0
- package/docs/proposals/0005-todo-system.md +299 -0
- package/docs/proposals/0006-memory-system.md +539 -0
- package/docs/proposals/0007-context-management.md +429 -0
- package/docs/proposals/0008-checkpointing.md +327 -0
- package/docs/proposals/0009-hooks-system.md +343 -0
- package/docs/proposals/0010-mcp-integration.md +382 -0
- package/docs/proposals/0011-custom-commands.md +374 -0
- package/docs/proposals/0012-ask-user-question.md +317 -0
- package/docs/proposals/0013-multi-edit-tool.md +345 -0
- package/docs/proposals/0014-lsp-tool.md +478 -0
- package/docs/proposals/0015-ls-tool.md +407 -0
- package/docs/proposals/0016-kill-shell-tool.md +455 -0
- package/docs/proposals/0017-background-tasks.md +489 -0
- package/docs/proposals/0018-parallel-tool-execution.md +415 -0
- package/docs/proposals/0019-session-enhancements.md +462 -0
- package/docs/proposals/0020-session-summarization.md +447 -0
- package/docs/proposals/0021-skills-system.md +409 -0
- package/docs/proposals/0022-plugin-system.md +467 -0
- package/docs/proposals/0023-permission-enhancements.md +470 -0
- package/docs/proposals/0024-keyboard-shortcuts.md +443 -0
- package/docs/proposals/0025-cost-tracking.md +447 -0
- package/docs/proposals/0026-git-integration.md +475 -0
- package/docs/proposals/0027-enhanced-read-tool.md +514 -0
- package/docs/proposals/0028-enhanced-bash-tool.md +511 -0
- package/docs/proposals/0029-notebook-edit-tool.md +413 -0
- package/docs/proposals/0030-plugin-marketplace.md +360 -0
- package/docs/proposals/0031-command-suggestions.md +295 -0
- package/docs/proposals/0032-ide-integrations.md +328 -0
- package/docs/proposals/0033-enterprise-deployment.md +221 -0
- package/docs/proposals/0034-sandboxing.md +273 -0
- package/docs/proposals/0035-auto-updater.md +311 -0
- package/docs/proposals/0036-enhanced-glob-tool.md +267 -0
- package/docs/proposals/0037-enhanced-grep-tool.md +360 -0
- package/docs/proposals/0038-interactive-cli-ui.md +373 -0
- package/docs/proposals/0039-streaming-enhancements.md +359 -0
- package/docs/proposals/0040-multi-provider-enhancements.md +369 -0
- package/docs/proposals/README.md +84 -0
- package/docs/proposals/TEMPLATE.md +57 -0
- package/docs/proposals/research/claude-code-research.md +307 -0
- package/examples/agent-demo.ts +115 -0
- package/examples/basic.ts +166 -0
- package/package.json +50 -0
- package/src/agent/agent.ts +276 -0
- package/src/agent/index.ts +6 -0
- package/src/agent/types.ts +62 -0
- package/src/cli/components/App.tsx +565 -0
- package/src/cli/components/CommandSuggestions.tsx +58 -0
- package/src/cli/components/Header.tsx +36 -0
- package/src/cli/components/Input.tsx +60 -0
- package/src/cli/components/Logo.tsx +16 -0
- package/src/cli/components/Messages.tsx +210 -0
- package/src/cli/components/ModelSelector.tsx +135 -0
- package/src/cli/components/Spinner.tsx +72 -0
- package/src/cli/components/index.ts +21 -0
- package/src/cli/components/theme.ts +36 -0
- package/src/cli/index.tsx +136 -0
- package/src/config/index.ts +7 -0
- package/src/config/manager.ts +77 -0
- package/src/config/types.ts +25 -0
- package/src/index.ts +86 -0
- package/src/permissions/index.ts +7 -0
- package/src/permissions/manager.ts +97 -0
- package/src/permissions/types.ts +29 -0
- package/src/providers/anthropic.ts +224 -0
- package/src/providers/gemini.ts +295 -0
- package/src/providers/index.ts +97 -0
- package/src/providers/openai.ts +261 -0
- package/src/providers/types.ts +181 -0
- package/src/session/index.ts +6 -0
- package/src/session/manager.ts +354 -0
- package/src/session/types.ts +49 -0
- package/src/tools/builtin/bash.ts +92 -0
- package/src/tools/builtin/edit.ts +37 -0
- package/src/tools/builtin/glob.ts +42 -0
- package/src/tools/builtin/grep.ts +67 -0
- package/src/tools/builtin/read.ts +34 -0
- package/src/tools/builtin/write.ts +27 -0
- package/src/tools/index.ts +36 -0
- package/src/tools/registry.ts +83 -0
- package/src/tools/types.ts +172 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
# Proposal: Cost Tracking
|
|
2
|
+
|
|
3
|
+
- **Proposal ID**: 0025
|
|
4
|
+
- **Author**: mycode team
|
|
5
|
+
- **Status**: Draft
|
|
6
|
+
- **Created**: 2025-01-15
|
|
7
|
+
- **Updated**: 2025-01-15
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
Implement comprehensive cost tracking for API usage, showing real-time token counts, estimated costs, and cumulative spending. This provides users with visibility and control over their LLM API expenses.
|
|
12
|
+
|
|
13
|
+
## Motivation
|
|
14
|
+
|
|
15
|
+
Currently, mycode provides no cost visibility:
|
|
16
|
+
|
|
17
|
+
1. **Surprise bills**: Users don't know costs until invoice
|
|
18
|
+
2. **No optimization**: Can't identify expensive operations
|
|
19
|
+
3. **No budgets**: Can't set spending limits
|
|
20
|
+
4. **Hidden usage**: Token counts not visible
|
|
21
|
+
5. **No comparison**: Can't compare provider costs
|
|
22
|
+
|
|
23
|
+
Cost tracking enables informed usage decisions.
|
|
24
|
+
|
|
25
|
+
## Claude Code Reference
|
|
26
|
+
|
|
27
|
+
Claude Code displays cost information in the interface:
|
|
28
|
+
|
|
29
|
+
### Observed Features
|
|
30
|
+
- Token count display (input/output)
|
|
31
|
+
- Estimated cost per message
|
|
32
|
+
- Session totals
|
|
33
|
+
- Model-specific pricing
|
|
34
|
+
|
|
35
|
+
### Cost Visibility
|
|
36
|
+
```
|
|
37
|
+
Tokens: 1,234 in / 567 out (~$0.02)
|
|
38
|
+
Session total: 45,678 tokens (~$0.58)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Detailed Design
|
|
42
|
+
|
|
43
|
+
### API Design
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// src/costs/types.ts
|
|
47
|
+
interface TokenUsage {
|
|
48
|
+
inputTokens: number;
|
|
49
|
+
outputTokens: number;
|
|
50
|
+
totalTokens: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface CostEstimate {
|
|
54
|
+
inputCost: number;
|
|
55
|
+
outputCost: number;
|
|
56
|
+
totalCost: number;
|
|
57
|
+
currency: string; // 'USD'
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface MessageCost {
|
|
61
|
+
messageId: string;
|
|
62
|
+
timestamp: Date;
|
|
63
|
+
model: string;
|
|
64
|
+
provider: string;
|
|
65
|
+
tokens: TokenUsage;
|
|
66
|
+
cost: CostEstimate;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface SessionCost {
|
|
70
|
+
sessionId: string;
|
|
71
|
+
messages: MessageCost[];
|
|
72
|
+
totals: {
|
|
73
|
+
tokens: TokenUsage;
|
|
74
|
+
cost: CostEstimate;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface CostConfig {
|
|
79
|
+
displayMode: 'always' | 'summary' | 'never';
|
|
80
|
+
currency: string;
|
|
81
|
+
budgets?: {
|
|
82
|
+
perMessage?: number;
|
|
83
|
+
perSession?: number;
|
|
84
|
+
daily?: number;
|
|
85
|
+
monthly?: number;
|
|
86
|
+
};
|
|
87
|
+
alerts?: {
|
|
88
|
+
threshold: number;
|
|
89
|
+
action: 'warn' | 'confirm' | 'block';
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Provider pricing (per 1M tokens)
|
|
94
|
+
interface ProviderPricing {
|
|
95
|
+
provider: string;
|
|
96
|
+
model: string;
|
|
97
|
+
inputPer1M: number;
|
|
98
|
+
outputPer1M: number;
|
|
99
|
+
effectiveDate: string;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Cost Tracker
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// src/costs/tracker.ts
|
|
107
|
+
class CostTracker {
|
|
108
|
+
private config: CostConfig;
|
|
109
|
+
private pricing: Map<string, ProviderPricing> = new Map();
|
|
110
|
+
private sessionCosts: Map<string, SessionCost> = new Map();
|
|
111
|
+
private dailyTotal: number = 0;
|
|
112
|
+
private monthlyTotal: number = 0;
|
|
113
|
+
|
|
114
|
+
constructor(config?: Partial<CostConfig>) {
|
|
115
|
+
this.config = {
|
|
116
|
+
displayMode: 'always',
|
|
117
|
+
currency: 'USD',
|
|
118
|
+
...config
|
|
119
|
+
};
|
|
120
|
+
this.loadPricing();
|
|
121
|
+
this.loadHistory();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private loadPricing(): void {
|
|
125
|
+
// Current pricing as of 2025
|
|
126
|
+
const defaultPricing: ProviderPricing[] = [
|
|
127
|
+
// Anthropic
|
|
128
|
+
{ provider: 'anthropic', model: 'claude-opus-4-5', inputPer1M: 15, outputPer1M: 75, effectiveDate: '2025-01-01' },
|
|
129
|
+
{ provider: 'anthropic', model: 'claude-sonnet-4', inputPer1M: 3, outputPer1M: 15, effectiveDate: '2025-01-01' },
|
|
130
|
+
{ provider: 'anthropic', model: 'claude-haiku-3-5', inputPer1M: 0.25, outputPer1M: 1.25, effectiveDate: '2025-01-01' },
|
|
131
|
+
|
|
132
|
+
// OpenAI
|
|
133
|
+
{ provider: 'openai', model: 'gpt-4o', inputPer1M: 2.5, outputPer1M: 10, effectiveDate: '2025-01-01' },
|
|
134
|
+
{ provider: 'openai', model: 'gpt-4-turbo', inputPer1M: 10, outputPer1M: 30, effectiveDate: '2025-01-01' },
|
|
135
|
+
{ provider: 'openai', model: 'o1', inputPer1M: 15, outputPer1M: 60, effectiveDate: '2025-01-01' },
|
|
136
|
+
|
|
137
|
+
// Google
|
|
138
|
+
{ provider: 'gemini', model: 'gemini-2.0-flash', inputPer1M: 0.075, outputPer1M: 0.30, effectiveDate: '2025-01-01' },
|
|
139
|
+
{ provider: 'gemini', model: 'gemini-1.5-pro', inputPer1M: 1.25, outputPer1M: 5, effectiveDate: '2025-01-01' },
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
for (const pricing of defaultPricing) {
|
|
143
|
+
this.pricing.set(`${pricing.provider}:${pricing.model}`, pricing);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
recordUsage(
|
|
148
|
+
sessionId: string,
|
|
149
|
+
model: string,
|
|
150
|
+
provider: string,
|
|
151
|
+
tokens: TokenUsage
|
|
152
|
+
): MessageCost {
|
|
153
|
+
const cost = this.calculateCost(provider, model, tokens);
|
|
154
|
+
|
|
155
|
+
const messageCost: MessageCost = {
|
|
156
|
+
messageId: generateId(),
|
|
157
|
+
timestamp: new Date(),
|
|
158
|
+
model,
|
|
159
|
+
provider,
|
|
160
|
+
tokens,
|
|
161
|
+
cost
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Update session costs
|
|
165
|
+
const session = this.sessionCosts.get(sessionId) || {
|
|
166
|
+
sessionId,
|
|
167
|
+
messages: [],
|
|
168
|
+
totals: { tokens: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }, cost: { inputCost: 0, outputCost: 0, totalCost: 0, currency: 'USD' } }
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
session.messages.push(messageCost);
|
|
172
|
+
session.totals.tokens.inputTokens += tokens.inputTokens;
|
|
173
|
+
session.totals.tokens.outputTokens += tokens.outputTokens;
|
|
174
|
+
session.totals.tokens.totalTokens += tokens.totalTokens;
|
|
175
|
+
session.totals.cost.inputCost += cost.inputCost;
|
|
176
|
+
session.totals.cost.outputCost += cost.outputCost;
|
|
177
|
+
session.totals.cost.totalCost += cost.totalCost;
|
|
178
|
+
|
|
179
|
+
this.sessionCosts.set(sessionId, session);
|
|
180
|
+
|
|
181
|
+
// Update daily/monthly
|
|
182
|
+
this.dailyTotal += cost.totalCost;
|
|
183
|
+
this.monthlyTotal += cost.totalCost;
|
|
184
|
+
|
|
185
|
+
// Check budgets
|
|
186
|
+
this.checkBudgets(messageCost);
|
|
187
|
+
|
|
188
|
+
return messageCost;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private calculateCost(
|
|
192
|
+
provider: string,
|
|
193
|
+
model: string,
|
|
194
|
+
tokens: TokenUsage
|
|
195
|
+
): CostEstimate {
|
|
196
|
+
const pricing = this.pricing.get(`${provider}:${model}`);
|
|
197
|
+
|
|
198
|
+
if (!pricing) {
|
|
199
|
+
// Default/unknown pricing
|
|
200
|
+
return {
|
|
201
|
+
inputCost: 0,
|
|
202
|
+
outputCost: 0,
|
|
203
|
+
totalCost: 0,
|
|
204
|
+
currency: 'USD'
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const inputCost = (tokens.inputTokens / 1_000_000) * pricing.inputPer1M;
|
|
209
|
+
const outputCost = (tokens.outputTokens / 1_000_000) * pricing.outputPer1M;
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
inputCost,
|
|
213
|
+
outputCost,
|
|
214
|
+
totalCost: inputCost + outputCost,
|
|
215
|
+
currency: 'USD'
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private checkBudgets(cost: MessageCost): void {
|
|
220
|
+
const budgets = this.config.budgets;
|
|
221
|
+
if (!budgets) return;
|
|
222
|
+
|
|
223
|
+
const alerts = this.config.alerts;
|
|
224
|
+
|
|
225
|
+
if (budgets.perMessage && cost.cost.totalCost > budgets.perMessage) {
|
|
226
|
+
this.handleBudgetAlert('perMessage', cost.cost.totalCost, budgets.perMessage);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (budgets.daily && this.dailyTotal > budgets.daily) {
|
|
230
|
+
this.handleBudgetAlert('daily', this.dailyTotal, budgets.daily);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (budgets.monthly && this.monthlyTotal > budgets.monthly) {
|
|
234
|
+
this.handleBudgetAlert('monthly', this.monthlyTotal, budgets.monthly);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
getSessionCost(sessionId: string): SessionCost | undefined {
|
|
239
|
+
return this.sessionCosts.get(sessionId);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
formatCost(cost: CostEstimate): string {
|
|
243
|
+
if (cost.totalCost < 0.01) {
|
|
244
|
+
return `<$0.01`;
|
|
245
|
+
}
|
|
246
|
+
return `$${cost.totalCost.toFixed(2)}`;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
formatTokens(tokens: TokenUsage): string {
|
|
250
|
+
return `${this.formatNumber(tokens.inputTokens)} in / ${this.formatNumber(tokens.outputTokens)} out`;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private formatNumber(n: number): string {
|
|
254
|
+
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
255
|
+
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;
|
|
256
|
+
return n.toString();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
getReport(period: 'session' | 'day' | 'month'): CostReport {
|
|
260
|
+
// Generate detailed cost report
|
|
261
|
+
return {
|
|
262
|
+
period,
|
|
263
|
+
totalCost: period === 'session' ? this.getCurrentSessionCost() : this.getPeriodCost(period),
|
|
264
|
+
breakdown: this.getBreakdown(period),
|
|
265
|
+
topOperations: this.getTopOperations(period)
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export const costTracker = new CostTracker();
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### Provider Integration
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
// Update to src/providers/types.ts
|
|
277
|
+
interface CompletionResponse {
|
|
278
|
+
content: ContentBlock[];
|
|
279
|
+
stopReason: string;
|
|
280
|
+
usage?: {
|
|
281
|
+
inputTokens: number;
|
|
282
|
+
outputTokens: number;
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Update agent to track costs
|
|
287
|
+
class Agent {
|
|
288
|
+
async *run(messages: Message[]): AsyncGenerator<AgentEvent> {
|
|
289
|
+
// ... existing code ...
|
|
290
|
+
|
|
291
|
+
const response = await this.provider.complete({ messages, tools });
|
|
292
|
+
|
|
293
|
+
// Track cost if usage available
|
|
294
|
+
if (response.usage) {
|
|
295
|
+
const cost = costTracker.recordUsage(
|
|
296
|
+
this.sessionId,
|
|
297
|
+
this.model,
|
|
298
|
+
this.provider.name,
|
|
299
|
+
{
|
|
300
|
+
inputTokens: response.usage.inputTokens,
|
|
301
|
+
outputTokens: response.usage.outputTokens,
|
|
302
|
+
totalTokens: response.usage.inputTokens + response.usage.outputTokens
|
|
303
|
+
}
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
yield { type: 'cost', cost };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### File Changes
|
|
313
|
+
|
|
314
|
+
| File | Action | Description |
|
|
315
|
+
|------|--------|-------------|
|
|
316
|
+
| `src/costs/types.ts` | Create | Type definitions |
|
|
317
|
+
| `src/costs/tracker.ts` | Create | Cost tracking logic |
|
|
318
|
+
| `src/costs/pricing.ts` | Create | Provider pricing data |
|
|
319
|
+
| `src/costs/reports.ts` | Create | Cost reporting |
|
|
320
|
+
| `src/costs/index.ts` | Create | Module exports |
|
|
321
|
+
| `src/agent/agent.ts` | Modify | Track costs |
|
|
322
|
+
| `src/providers/types.ts` | Modify | Add usage to response |
|
|
323
|
+
| `src/cli/ui.ts` | Modify | Display costs |
|
|
324
|
+
|
|
325
|
+
## User Experience
|
|
326
|
+
|
|
327
|
+
### Real-time Display
|
|
328
|
+
```
|
|
329
|
+
┌─ mycode ──────────────────────────────────────────────────┐
|
|
330
|
+
│ Agent: Here's the implementation for the auth module... │
|
|
331
|
+
│ │
|
|
332
|
+
│ [Edit: src/auth.ts] │
|
|
333
|
+
│ [Write: src/auth.test.ts] │
|
|
334
|
+
│ │
|
|
335
|
+
├──────────────────────────────────────────────────────────┤
|
|
336
|
+
│ Tokens: 2.3K in / 1.8K out (~$0.04) Session: $0.23 │
|
|
337
|
+
└──────────────────────────────────────────────────────────┘
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Cost Report
|
|
341
|
+
```
|
|
342
|
+
User: /costs
|
|
343
|
+
|
|
344
|
+
Cost Report - Current Session:
|
|
345
|
+
┌────────────────────────────────────────────────────────────┐
|
|
346
|
+
│ Provider Model Messages Tokens Cost │
|
|
347
|
+
├────────────────────────────────────────────────────────────┤
|
|
348
|
+
│ anthropic claude-sonnet-4 12 45.2K $0.23 │
|
|
349
|
+
│ anthropic claude-haiku 3 8.1K $0.01 │
|
|
350
|
+
├────────────────────────────────────────────────────────────┤
|
|
351
|
+
│ Total 15 53.3K $0.24 │
|
|
352
|
+
└────────────────────────────────────────────────────────────┘
|
|
353
|
+
|
|
354
|
+
Daily: $1.45 / $10.00 budget (14.5%)
|
|
355
|
+
Monthly: $23.67 / $100.00 budget (23.7%)
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Budget Warning
|
|
359
|
+
```
|
|
360
|
+
⚠️ Budget Alert
|
|
361
|
+
Daily spending ($9.50) approaching limit ($10.00).
|
|
362
|
+
Continue? [y/N]
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Compare Providers
|
|
366
|
+
```
|
|
367
|
+
User: /costs compare
|
|
368
|
+
|
|
369
|
+
Cost Comparison for Current Session (53.3K tokens):
|
|
370
|
+
┌────────────────────────────────────────────────────────────┐
|
|
371
|
+
│ Provider Model Input Output Total│
|
|
372
|
+
├────────────────────────────────────────────────────────────┤
|
|
373
|
+
│ gemini gemini-2.0-flash $0.00 $0.01 $0.01 │
|
|
374
|
+
│ anthropic claude-haiku $0.01 $0.05 $0.06 │
|
|
375
|
+
│ openai gpt-4o $0.10 $0.40 $0.50 │
|
|
376
|
+
│ anthropic claude-sonnet $0.13 $0.68 $0.81 │
|
|
377
|
+
│ anthropic claude-opus $0.67 $3.38 $4.05 │
|
|
378
|
+
└────────────────────────────────────────────────────────────┘
|
|
379
|
+
|
|
380
|
+
Current selection: claude-sonnet ($0.24 actual)
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Alternatives Considered
|
|
384
|
+
|
|
385
|
+
### Alternative 1: Provider Dashboard Only
|
|
386
|
+
Rely on provider's usage dashboards.
|
|
387
|
+
|
|
388
|
+
**Pros**: Accurate, authoritative
|
|
389
|
+
**Cons**: Not real-time, not in-context
|
|
390
|
+
**Decision**: Rejected - Need inline visibility
|
|
391
|
+
|
|
392
|
+
### Alternative 2: Token Count Only
|
|
393
|
+
Show tokens without cost estimates.
|
|
394
|
+
|
|
395
|
+
**Pros**: Simpler, always accurate
|
|
396
|
+
**Cons**: Users must calculate costs
|
|
397
|
+
**Decision**: Rejected - Cost is more actionable
|
|
398
|
+
|
|
399
|
+
### Alternative 3: Post-hoc Reports Only
|
|
400
|
+
Only show costs after session ends.
|
|
401
|
+
|
|
402
|
+
**Pros**: Simpler implementation
|
|
403
|
+
**Cons**: No real-time awareness
|
|
404
|
+
**Decision**: Rejected - Real-time is essential
|
|
405
|
+
|
|
406
|
+
## Security Considerations
|
|
407
|
+
|
|
408
|
+
1. **No API Keys in Reports**: Don't expose credentials
|
|
409
|
+
2. **Local Storage**: Cost data stored locally
|
|
410
|
+
3. **Pricing Updates**: Verify pricing source
|
|
411
|
+
4. **Budget Enforcement**: Optional hard limits
|
|
412
|
+
5. **Export Encryption**: Protect exported reports
|
|
413
|
+
|
|
414
|
+
## Testing Strategy
|
|
415
|
+
|
|
416
|
+
1. **Unit Tests**:
|
|
417
|
+
- Cost calculation accuracy
|
|
418
|
+
- Token counting
|
|
419
|
+
- Budget checking
|
|
420
|
+
- Report generation
|
|
421
|
+
|
|
422
|
+
2. **Integration Tests**:
|
|
423
|
+
- Provider usage extraction
|
|
424
|
+
- Real-time updates
|
|
425
|
+
- Multiple sessions
|
|
426
|
+
|
|
427
|
+
3. **Manual Testing**:
|
|
428
|
+
- Various providers
|
|
429
|
+
- Display modes
|
|
430
|
+
- Budget scenarios
|
|
431
|
+
|
|
432
|
+
## Migration Path
|
|
433
|
+
|
|
434
|
+
1. **Phase 1**: Basic token/cost display
|
|
435
|
+
2. **Phase 2**: Session totals
|
|
436
|
+
3. **Phase 3**: Budget system
|
|
437
|
+
4. **Phase 4**: Detailed reports
|
|
438
|
+
5. **Phase 5**: Cost optimization suggestions
|
|
439
|
+
|
|
440
|
+
No breaking changes.
|
|
441
|
+
|
|
442
|
+
## References
|
|
443
|
+
|
|
444
|
+
- [Anthropic Pricing](https://www.anthropic.com/pricing)
|
|
445
|
+
- [OpenAI Pricing](https://openai.com/pricing)
|
|
446
|
+
- [Google AI Pricing](https://ai.google.dev/pricing)
|
|
447
|
+
- [Token Counting Libraries](https://github.com/openai/tiktoken)
|