opencode-top 3.1.2 → 3.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.
- package/bin/octop.js +2 -9
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +22432 -0
- package/dist/cli.js.map +1 -0
- package/dist/cli.mjs +22570 -0
- package/dist/core/agents.d.ts +11 -0
- package/dist/core/agents.d.ts.map +1 -0
- package/dist/core/agents.js +58 -0
- package/dist/core/agents.js.map +1 -0
- package/dist/core/session.d.ts +19 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +261 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/types.d.ts +140 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +29 -0
- package/dist/core/types.js.map +1 -0
- package/dist/data/pricing.d.ts +4 -0
- package/dist/data/pricing.d.ts.map +1 -0
- package/dist/data/pricing.js +76 -0
- package/dist/data/pricing.js.map +1 -0
- package/dist/data/sqlite.d.ts +5 -0
- package/dist/data/sqlite.d.ts.map +1 -0
- package/dist/data/sqlite.js +222 -0
- package/dist/data/sqlite.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/{src/index.ts → dist/index.js} +1 -0
- package/dist/index.js.map +1 -0
- package/dist/ui/App.d.ts +6 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +101 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/components/AgentChainGraph.d.ts +9 -0
- package/dist/ui/components/AgentChainGraph.d.ts.map +1 -0
- package/dist/ui/components/AgentChainGraph.js +41 -0
- package/dist/ui/components/AgentChainGraph.js.map +1 -0
- package/dist/ui/components/AgentTree.d.ts +13 -0
- package/dist/ui/components/AgentTree.d.ts.map +1 -0
- package/dist/ui/components/AgentTree.js +50 -0
- package/dist/ui/components/AgentTree.js.map +1 -0
- package/dist/ui/components/DetailsPanel.d.ts +9 -0
- package/dist/ui/components/DetailsPanel.d.ts.map +1 -0
- package/dist/ui/components/DetailsPanel.js +82 -0
- package/dist/ui/components/DetailsPanel.js.map +1 -0
- package/dist/ui/components/MessagesPanel.d.ts +12 -0
- package/dist/ui/components/MessagesPanel.d.ts.map +1 -0
- package/dist/ui/components/MessagesPanel.js +107 -0
- package/dist/ui/components/MessagesPanel.js.map +1 -0
- package/dist/ui/components/SparkLine.d.ts +10 -0
- package/dist/ui/components/SparkLine.d.ts.map +1 -0
- package/dist/ui/components/SparkLine.js +12 -0
- package/dist/ui/components/SparkLine.js.map +1 -0
- package/dist/ui/components/StatusBar.d.ts +9 -0
- package/dist/ui/components/StatusBar.d.ts.map +1 -0
- package/dist/ui/components/StatusBar.js +9 -0
- package/dist/ui/components/StatusBar.js.map +1 -0
- package/dist/ui/components/TabBar.d.ts +10 -0
- package/dist/ui/components/TabBar.d.ts.map +1 -0
- package/dist/ui/components/TabBar.js +17 -0
- package/dist/ui/components/TabBar.js.map +1 -0
- package/dist/ui/screens/OverviewScreen.d.ts +12 -0
- package/dist/ui/screens/OverviewScreen.d.ts.map +1 -0
- package/dist/ui/screens/OverviewScreen.js +94 -0
- package/dist/ui/screens/OverviewScreen.js.map +1 -0
- package/dist/ui/screens/SessionsScreen.d.ts +12 -0
- package/dist/ui/screens/SessionsScreen.d.ts.map +1 -0
- package/dist/ui/screens/SessionsScreen.js +98 -0
- package/dist/ui/screens/SessionsScreen.js.map +1 -0
- package/dist/ui/screens/TimelineScreen.d.ts +11 -0
- package/dist/ui/screens/TimelineScreen.d.ts.map +1 -0
- package/dist/ui/screens/TimelineScreen.js +128 -0
- package/dist/ui/screens/TimelineScreen.js.map +1 -0
- package/dist/ui/screens/ToolsScreen.d.ts +12 -0
- package/dist/ui/screens/ToolsScreen.d.ts.map +1 -0
- package/dist/ui/screens/ToolsScreen.js +113 -0
- package/dist/ui/screens/ToolsScreen.js.map +1 -0
- package/dist/ui/theme.d.ts +21 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +21 -0
- package/dist/ui/theme.js.map +1 -0
- package/package.json +2 -1
- package/bin/octop.mjs +0 -13
- package/src/cli.ts +0 -60
- package/src/core/agents.ts +0 -78
- package/src/core/session.ts +0 -315
- package/src/core/types.ts +0 -156
- package/src/data/pricing.ts +0 -82
- package/src/data/sqlite.ts +0 -347
- package/src/ui/App.tsx +0 -154
- package/src/ui/components/AgentChainGraph.tsx +0 -95
- package/src/ui/components/AgentTree.tsx +0 -101
- package/src/ui/components/DetailsPanel.tsx +0 -211
- package/src/ui/components/MessagesPanel.tsx +0 -323
- package/src/ui/components/SparkLine.tsx +0 -18
- package/src/ui/components/StatusBar.tsx +0 -24
- package/src/ui/components/TabBar.tsx +0 -42
- package/src/ui/screens/OverviewScreen.tsx +0 -327
- package/src/ui/screens/SessionsScreen.tsx +0 -168
- package/src/ui/screens/TimelineScreen.tsx +0 -222
- package/src/ui/screens/ToolsScreen.tsx +0 -260
- package/src/ui/theme.ts +0 -21
package/src/core/session.ts
DELETED
|
@@ -1,315 +0,0 @@
|
|
|
1
|
-
import Decimal from "decimal.js";
|
|
2
|
-
import { TokenUsage } from "./types";
|
|
3
|
-
import type { Session, Workflow, ToolUsage, ModelPricing, OverviewStats } from "./types";
|
|
4
|
-
import type { MessagePart } from "./types";
|
|
5
|
-
|
|
6
|
-
export function getSessionTokens(session: Session): TokenUsage {
|
|
7
|
-
return session.interactions.reduce((acc, i) => acc.add(i.tokens), new TokenUsage());
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function getSessionCost(session: Session, pricing: Map<string, ModelPricing>): Decimal {
|
|
11
|
-
return session.interactions.reduce((acc, i) => {
|
|
12
|
-
const p = pricing.get(i.modelId);
|
|
13
|
-
if (!p) return acc;
|
|
14
|
-
return acc.plus(i.tokens.calculateCost(p));
|
|
15
|
-
}, new Decimal(0));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function getSessionCostSingle(session: Session, pricing: ModelPricing): Decimal {
|
|
19
|
-
return session.interactions.reduce((acc, i) => {
|
|
20
|
-
return acc.plus(i.tokens.calculateCost(pricing));
|
|
21
|
-
}, new Decimal(0));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function getSessionDuration(session: Session): number {
|
|
25
|
-
const interactions = session.interactions;
|
|
26
|
-
if (interactions.length === 0) return 0;
|
|
27
|
-
|
|
28
|
-
// Use real time.completed when available
|
|
29
|
-
const times: number[] = [];
|
|
30
|
-
for (const i of interactions) {
|
|
31
|
-
if (i.time.created !== null) times.push(i.time.created);
|
|
32
|
-
if (i.time.completed !== null) times.push(i.time.completed);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (times.length === 0) return 0;
|
|
36
|
-
return Math.max(...times) - Math.min(...times);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function getWorkflowTokens(workflow: Workflow): TokenUsage {
|
|
40
|
-
const main = getSessionTokens(workflow.mainSession);
|
|
41
|
-
const subs = workflow.subAgentSessions.reduce(
|
|
42
|
-
(acc, s) => acc.add(getSessionTokens(s)),
|
|
43
|
-
new TokenUsage()
|
|
44
|
-
);
|
|
45
|
-
return main.add(subs);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function getWorkflowCost(workflow: Workflow, pricing: Map<string, ModelPricing>): Decimal {
|
|
49
|
-
const main = getSessionCost(workflow.mainSession, pricing);
|
|
50
|
-
const subs = workflow.subAgentSessions.reduce(
|
|
51
|
-
(acc, s) => acc.plus(getSessionCost(s, pricing)),
|
|
52
|
-
new Decimal(0)
|
|
53
|
-
);
|
|
54
|
-
return main.plus(subs);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function getWorkflowCostSingle(workflow: Workflow, pricing: ModelPricing): Decimal {
|
|
58
|
-
const main = getSessionCostSingle(workflow.mainSession, pricing);
|
|
59
|
-
const subs = workflow.subAgentSessions.reduce(
|
|
60
|
-
(acc, s) => acc.plus(getSessionCostSingle(s, pricing)),
|
|
61
|
-
new Decimal(0)
|
|
62
|
-
);
|
|
63
|
-
return main.plus(subs);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function getToolUsage(session: Session): ToolUsage[] {
|
|
67
|
-
const tools = new Map<
|
|
68
|
-
string,
|
|
69
|
-
{ calls: number; successes: number; failures: number; totalDurationMs: number; recentErrors: string[] }
|
|
70
|
-
>();
|
|
71
|
-
|
|
72
|
-
for (const interaction of session.interactions) {
|
|
73
|
-
for (const part of interaction.parts) {
|
|
74
|
-
if (part.type !== "tool") continue;
|
|
75
|
-
|
|
76
|
-
const existing = tools.get(part.toolName) ?? {
|
|
77
|
-
calls: 0,
|
|
78
|
-
successes: 0,
|
|
79
|
-
failures: 0,
|
|
80
|
-
totalDurationMs: 0,
|
|
81
|
-
recentErrors: [],
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
existing.calls++;
|
|
85
|
-
if (part.status === "completed") {
|
|
86
|
-
existing.successes++;
|
|
87
|
-
} else if (part.status === "error") {
|
|
88
|
-
existing.failures++;
|
|
89
|
-
// Keep last 3 errors
|
|
90
|
-
if (existing.recentErrors.length < 3) {
|
|
91
|
-
existing.recentErrors.push(part.output?.slice(0, 200) ?? "unknown error");
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const durationMs = part.timeEnd > 0 && part.timeStart > 0 ? part.timeEnd - part.timeStart : 0;
|
|
96
|
-
existing.totalDurationMs += durationMs;
|
|
97
|
-
|
|
98
|
-
tools.set(part.toolName, existing);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return Array.from(tools.entries()).map(([name, stats]) => ({
|
|
103
|
-
name,
|
|
104
|
-
calls: stats.calls,
|
|
105
|
-
successes: stats.successes,
|
|
106
|
-
failures: stats.failures,
|
|
107
|
-
totalDurationMs: stats.totalDurationMs,
|
|
108
|
-
avgDurationMs: stats.calls > 0 ? stats.totalDurationMs / stats.calls : 0,
|
|
109
|
-
recentErrors: stats.recentErrors,
|
|
110
|
-
}));
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export function getWorkflowToolUsage(workflow: Workflow): ToolUsage[] {
|
|
114
|
-
const allSessions = [workflow.mainSession, ...workflow.subAgentSessions];
|
|
115
|
-
const merged = new Map<
|
|
116
|
-
string,
|
|
117
|
-
{ calls: number; successes: number; failures: number; totalDurationMs: number; recentErrors: string[] }
|
|
118
|
-
>();
|
|
119
|
-
|
|
120
|
-
for (const session of allSessions) {
|
|
121
|
-
const usage = getToolUsage(session);
|
|
122
|
-
for (const tool of usage) {
|
|
123
|
-
const existing = merged.get(tool.name) ?? {
|
|
124
|
-
calls: 0,
|
|
125
|
-
successes: 0,
|
|
126
|
-
failures: 0,
|
|
127
|
-
totalDurationMs: 0,
|
|
128
|
-
recentErrors: [],
|
|
129
|
-
};
|
|
130
|
-
existing.calls += tool.calls;
|
|
131
|
-
existing.successes += tool.successes;
|
|
132
|
-
existing.failures += tool.failures;
|
|
133
|
-
existing.totalDurationMs += tool.totalDurationMs;
|
|
134
|
-
for (const err of tool.recentErrors) {
|
|
135
|
-
if (existing.recentErrors.length < 3) existing.recentErrors.push(err);
|
|
136
|
-
}
|
|
137
|
-
merged.set(tool.name, existing);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return Array.from(merged.entries()).map(([name, stats]) => ({
|
|
142
|
-
name,
|
|
143
|
-
calls: stats.calls,
|
|
144
|
-
successes: stats.successes,
|
|
145
|
-
failures: stats.failures,
|
|
146
|
-
totalDurationMs: stats.totalDurationMs,
|
|
147
|
-
avgDurationMs: stats.calls > 0 ? stats.totalDurationMs / stats.calls : 0,
|
|
148
|
-
recentErrors: stats.recentErrors,
|
|
149
|
-
}));
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export function getOutputRate(session: Session): number {
|
|
153
|
-
const rates = session.interactions
|
|
154
|
-
.map((i) => i.outputRate)
|
|
155
|
-
.filter((r) => r > 0)
|
|
156
|
-
.sort((a, b) => a - b);
|
|
157
|
-
|
|
158
|
-
if (rates.length === 0) return 0;
|
|
159
|
-
|
|
160
|
-
const mid = Math.floor(rates.length / 2);
|
|
161
|
-
return rates.length % 2 !== 0 ? rates[mid] : (rates[mid - 1] + rates[mid]) / 2;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
export function computeOverviewStats(
|
|
165
|
-
workflows: Workflow[],
|
|
166
|
-
pricing: Map<string, ModelPricing>
|
|
167
|
-
): OverviewStats {
|
|
168
|
-
const totalTokens = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, reasoning: 0 };
|
|
169
|
-
let totalCost = new Decimal(0);
|
|
170
|
-
const modelBreakdown = new Map<string, { cost: Decimal; tokens: number; calls: number }>();
|
|
171
|
-
const projectBreakdown = new Map<string, { cost: Decimal; sessions: number }>();
|
|
172
|
-
const agentBreakdown = new Map<string, { cost: Decimal; calls: number }>();
|
|
173
|
-
const agentToolErrors = new Map<string, { calls: number; errors: number }>();
|
|
174
|
-
const toolCallCounts = new Map<string, { calls: number; errors: number; totalDurationMs: number }>();
|
|
175
|
-
const weeklyTokenMap = new Map<string, number>();
|
|
176
|
-
const weeklySessionMap = new Map<string, number>();
|
|
177
|
-
const hourlyActivity = new Array(24).fill(0);
|
|
178
|
-
|
|
179
|
-
const now = Date.now();
|
|
180
|
-
const sevenDaysAgo = now - 7 * 86_400_000;
|
|
181
|
-
|
|
182
|
-
for (const workflow of workflows) {
|
|
183
|
-
const allSessions = [workflow.mainSession, ...workflow.subAgentSessions];
|
|
184
|
-
|
|
185
|
-
for (const session of allSessions) {
|
|
186
|
-
const projName = session.projectName ?? "Unknown";
|
|
187
|
-
const projEntry = projectBreakdown.get(projName) ?? { cost: new Decimal(0), sessions: 0 };
|
|
188
|
-
projEntry.sessions++;
|
|
189
|
-
|
|
190
|
-
// Weekly session count
|
|
191
|
-
const sessionTs = session.timeCreated;
|
|
192
|
-
if (sessionTs && sessionTs >= sevenDaysAgo) {
|
|
193
|
-
const day = new Date(sessionTs).toISOString().slice(5, 10); // MM-DD
|
|
194
|
-
weeklySessionMap.set(day, (weeklySessionMap.get(day) ?? 0) + 1);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
for (const interaction of session.interactions) {
|
|
198
|
-
const p = pricing.get(interaction.modelId);
|
|
199
|
-
const cost = p ? interaction.tokens.calculateCost(p) : new Decimal(0);
|
|
200
|
-
|
|
201
|
-
totalCost = totalCost.plus(cost);
|
|
202
|
-
projEntry.cost = projEntry.cost.plus(cost);
|
|
203
|
-
|
|
204
|
-
totalTokens.input += interaction.tokens.input;
|
|
205
|
-
totalTokens.output += interaction.tokens.output;
|
|
206
|
-
totalTokens.cacheRead += interaction.tokens.cacheRead;
|
|
207
|
-
totalTokens.cacheWrite += interaction.tokens.cacheWrite;
|
|
208
|
-
totalTokens.reasoning += interaction.tokens.reasoning;
|
|
209
|
-
|
|
210
|
-
// Model breakdown
|
|
211
|
-
const modelEntry = modelBreakdown.get(interaction.modelId) ?? {
|
|
212
|
-
cost: new Decimal(0),
|
|
213
|
-
tokens: 0,
|
|
214
|
-
calls: 0,
|
|
215
|
-
};
|
|
216
|
-
modelEntry.cost = modelEntry.cost.plus(cost);
|
|
217
|
-
modelEntry.tokens += interaction.tokens.total;
|
|
218
|
-
modelEntry.calls++;
|
|
219
|
-
modelBreakdown.set(interaction.modelId, modelEntry);
|
|
220
|
-
|
|
221
|
-
// Agent breakdown
|
|
222
|
-
const agentKey = interaction.agent ?? "main";
|
|
223
|
-
const agentEntry = agentBreakdown.get(agentKey) ?? { cost: new Decimal(0), calls: 0 };
|
|
224
|
-
agentEntry.cost = agentEntry.cost.plus(cost);
|
|
225
|
-
agentEntry.calls++;
|
|
226
|
-
agentBreakdown.set(agentKey, agentEntry);
|
|
227
|
-
|
|
228
|
-
// Hourly activity
|
|
229
|
-
const ts = interaction.time.created;
|
|
230
|
-
if (ts) {
|
|
231
|
-
hourlyActivity[new Date(ts).getHours()]++;
|
|
232
|
-
|
|
233
|
-
// Weekly token trend
|
|
234
|
-
if (ts >= sevenDaysAgo) {
|
|
235
|
-
const day = new Date(ts).toISOString().slice(5, 10);
|
|
236
|
-
weeklyTokenMap.set(day, (weeklyTokenMap.get(day) ?? 0) + interaction.tokens.total);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Tool stats: per-tool call counts and agent tool errors
|
|
241
|
-
for (const part of interaction.parts) {
|
|
242
|
-
if (part.type !== "tool") continue;
|
|
243
|
-
|
|
244
|
-
const isError = part.status === "error";
|
|
245
|
-
const dur = part.timeEnd > 0 && part.timeStart > 0 ? part.timeEnd - part.timeStart : 0;
|
|
246
|
-
|
|
247
|
-
// Tool call counts
|
|
248
|
-
const toolEntry = toolCallCounts.get(part.toolName) ?? { calls: 0, errors: 0, totalDurationMs: 0 };
|
|
249
|
-
toolEntry.calls++;
|
|
250
|
-
if (isError) toolEntry.errors++;
|
|
251
|
-
toolEntry.totalDurationMs += dur;
|
|
252
|
-
toolCallCounts.set(part.toolName, toolEntry);
|
|
253
|
-
|
|
254
|
-
// Agent tool errors
|
|
255
|
-
const agentToolEntry = agentToolErrors.get(agentKey) ?? { calls: 0, errors: 0 };
|
|
256
|
-
agentToolEntry.calls++;
|
|
257
|
-
if (isError) agentToolEntry.errors++;
|
|
258
|
-
agentToolErrors.set(agentKey, agentToolEntry);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
projectBreakdown.set(projName, projEntry);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Build 7-day arrays (last 7 days, MM-DD labels)
|
|
267
|
-
const today = new Date();
|
|
268
|
-
const weeklyTokens: { date: string; tokens: number }[] = [];
|
|
269
|
-
const weeklySessions: { date: string; sessions: number }[] = [];
|
|
270
|
-
for (let i = 6; i >= 0; i--) {
|
|
271
|
-
const d = new Date(today);
|
|
272
|
-
d.setDate(d.getDate() - i);
|
|
273
|
-
const day = d.toISOString().slice(5, 10);
|
|
274
|
-
weeklyTokens.push({ date: day, tokens: weeklyTokenMap.get(day) ?? 0 });
|
|
275
|
-
weeklySessions.push({ date: day, sessions: weeklySessionMap.get(day) ?? 0 });
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return {
|
|
279
|
-
totalCost,
|
|
280
|
-
totalTokens: new TokenUsage(
|
|
281
|
-
totalTokens.input,
|
|
282
|
-
totalTokens.output,
|
|
283
|
-
totalTokens.cacheRead,
|
|
284
|
-
totalTokens.cacheWrite,
|
|
285
|
-
totalTokens.reasoning
|
|
286
|
-
),
|
|
287
|
-
modelBreakdown,
|
|
288
|
-
projectBreakdown,
|
|
289
|
-
agentBreakdown,
|
|
290
|
-
agentToolErrors,
|
|
291
|
-
toolCallCounts,
|
|
292
|
-
weeklyTokens,
|
|
293
|
-
weeklySessions,
|
|
294
|
-
hourlyActivity,
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/** Build spark series (8 levels) from numeric array */
|
|
299
|
-
export function buildSparkSeries(values: number[]): string {
|
|
300
|
-
if (values.length === 0) return "";
|
|
301
|
-
const max = Math.max(...values);
|
|
302
|
-
if (max === 0) return "▁".repeat(values.length);
|
|
303
|
-
const chars = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
|
|
304
|
-
return values
|
|
305
|
-
.map((v) => {
|
|
306
|
-
const idx = Math.min(7, Math.floor((v / max) * 8));
|
|
307
|
-
return chars[idx];
|
|
308
|
-
})
|
|
309
|
-
.join("");
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/** All parts across all interactions in a session */
|
|
313
|
-
export function getAllParts(session: Session): MessagePart[] {
|
|
314
|
-
return session.interactions.flatMap((i) => i.parts);
|
|
315
|
-
}
|
package/src/core/types.ts
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import Decimal from "decimal.js";
|
|
2
|
-
|
|
3
|
-
export class TokenUsage {
|
|
4
|
-
constructor(
|
|
5
|
-
readonly input: number = 0,
|
|
6
|
-
readonly output: number = 0,
|
|
7
|
-
readonly cacheRead: number = 0,
|
|
8
|
-
readonly cacheWrite: number = 0,
|
|
9
|
-
readonly reasoning: number = 0
|
|
10
|
-
) {}
|
|
11
|
-
|
|
12
|
-
get total(): number {
|
|
13
|
-
return this.input + this.output + this.cacheRead + this.cacheWrite;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
add(other: TokenUsage): TokenUsage {
|
|
17
|
-
return new TokenUsage(
|
|
18
|
-
this.input + other.input,
|
|
19
|
-
this.output + other.output,
|
|
20
|
-
this.cacheRead + other.cacheRead,
|
|
21
|
-
this.cacheWrite + other.cacheWrite,
|
|
22
|
-
this.reasoning + other.reasoning
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
calculateCost(pricing: ModelPricing): Decimal {
|
|
27
|
-
const inputCost = new Decimal(this.input).mul(pricing.input).div(1_000_000);
|
|
28
|
-
const outputCost = new Decimal(this.output).mul(pricing.output).div(1_000_000);
|
|
29
|
-
const cacheReadCost = new Decimal(this.cacheRead).mul(pricing.cacheRead).div(1_000_000);
|
|
30
|
-
const cacheWriteCost = new Decimal(this.cacheWrite).mul(pricing.cacheWrite).div(1_000_000);
|
|
31
|
-
return inputCost.plus(outputCost).plus(cacheReadCost).plus(cacheWriteCost);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export interface TimeData {
|
|
36
|
-
created: number | null;
|
|
37
|
-
completed: number | null;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Part types from the `part` table
|
|
41
|
-
export type MessagePart =
|
|
42
|
-
| {
|
|
43
|
-
type: "text";
|
|
44
|
-
text: string;
|
|
45
|
-
timeStart: number;
|
|
46
|
-
timeEnd: number;
|
|
47
|
-
}
|
|
48
|
-
| {
|
|
49
|
-
type: "tool";
|
|
50
|
-
callId: string;
|
|
51
|
-
toolName: string;
|
|
52
|
-
status: "completed" | "pending" | "error";
|
|
53
|
-
input: Record<string, unknown>;
|
|
54
|
-
output: string;
|
|
55
|
-
title: string | null;
|
|
56
|
-
exitCode: number | null;
|
|
57
|
-
truncated: boolean;
|
|
58
|
-
timeStart: number;
|
|
59
|
-
timeEnd: number;
|
|
60
|
-
}
|
|
61
|
-
| {
|
|
62
|
-
type: "reasoning";
|
|
63
|
-
text: string;
|
|
64
|
-
timeStart: number;
|
|
65
|
-
timeEnd: number;
|
|
66
|
-
}
|
|
67
|
-
| {
|
|
68
|
-
type: "patch";
|
|
69
|
-
hash: string;
|
|
70
|
-
files: string[];
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export interface Interaction {
|
|
74
|
-
id: string;
|
|
75
|
-
sessionId: string;
|
|
76
|
-
modelId: string;
|
|
77
|
-
providerId: string | null;
|
|
78
|
-
role: "assistant" | "user";
|
|
79
|
-
tokens: TokenUsage;
|
|
80
|
-
time: TimeData;
|
|
81
|
-
agent: string | null;
|
|
82
|
-
finishReason: string | null;
|
|
83
|
-
outputRate: number;
|
|
84
|
-
parts: MessagePart[];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface Session {
|
|
88
|
-
id: string;
|
|
89
|
-
parentId: string | null;
|
|
90
|
-
projectId: string | null;
|
|
91
|
-
projectName: string | null;
|
|
92
|
-
title: string | null;
|
|
93
|
-
timeCreated: number | null;
|
|
94
|
-
timeArchived: number | null;
|
|
95
|
-
interactions: Interaction[];
|
|
96
|
-
source: "sqlite" | "files";
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export interface AgentNode {
|
|
100
|
-
session: Session;
|
|
101
|
-
children: AgentNode[];
|
|
102
|
-
depth: number;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export interface FlatNode {
|
|
106
|
-
id: string;
|
|
107
|
-
session: Session;
|
|
108
|
-
workflowIndex: number;
|
|
109
|
-
depth: number;
|
|
110
|
-
hasChildren: boolean;
|
|
111
|
-
agentNode: AgentNode;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export interface Workflow {
|
|
115
|
-
id: string;
|
|
116
|
-
mainSession: Session;
|
|
117
|
-
subAgentSessions: Session[];
|
|
118
|
-
agentTree: AgentNode;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export interface ModelPricing {
|
|
122
|
-
input: Decimal;
|
|
123
|
-
output: Decimal;
|
|
124
|
-
cacheRead: Decimal;
|
|
125
|
-
cacheWrite: Decimal;
|
|
126
|
-
contextWindow: number;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export interface ToolUsage {
|
|
130
|
-
name: string;
|
|
131
|
-
calls: number;
|
|
132
|
-
successes: number;
|
|
133
|
-
failures: number;
|
|
134
|
-
totalDurationMs: number;
|
|
135
|
-
avgDurationMs: number;
|
|
136
|
-
recentErrors: string[];
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export interface OverviewStats {
|
|
140
|
-
totalCost: Decimal;
|
|
141
|
-
totalTokens: TokenUsage;
|
|
142
|
-
modelBreakdown: Map<string, { cost: Decimal; tokens: number; calls: number }>;
|
|
143
|
-
projectBreakdown: Map<string, { cost: Decimal; sessions: number }>;
|
|
144
|
-
agentBreakdown: Map<string, { cost: Decimal; calls: number }>;
|
|
145
|
-
agentToolErrors: Map<string, { calls: number; errors: number }>;
|
|
146
|
-
toolCallCounts: Map<string, { calls: number; errors: number; totalDurationMs: number }>;
|
|
147
|
-
// 7-day daily data
|
|
148
|
-
weeklyTokens: { date: string; tokens: number }[];
|
|
149
|
-
weeklySessions: { date: string; sessions: number }[];
|
|
150
|
-
// 24-hour activity pattern (interactions per hour, all-time)
|
|
151
|
-
hourlyActivity: number[];
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export type ScreenId = "sessions" | "tools" | "overview";
|
|
155
|
-
|
|
156
|
-
export type { Decimal };
|
package/src/data/pricing.ts
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import Decimal from "decimal.js";
|
|
2
|
-
import type { ModelPricing } from "../core/types";
|
|
3
|
-
|
|
4
|
-
const DEFAULT_PRICING: ModelPricing = {
|
|
5
|
-
input: new Decimal(0),
|
|
6
|
-
output: new Decimal(0),
|
|
7
|
-
cacheRead: new Decimal(0),
|
|
8
|
-
cacheWrite: new Decimal(0),
|
|
9
|
-
contextWindow: 128000,
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const KNOWN_PRICING: Record<string, Partial<ModelPricing>> = {
|
|
13
|
-
"claude-sonnet-4-20250514": {
|
|
14
|
-
input: new Decimal(3),
|
|
15
|
-
output: new Decimal(15),
|
|
16
|
-
cacheRead: new Decimal(0.3),
|
|
17
|
-
cacheWrite: new Decimal(3.75),
|
|
18
|
-
contextWindow: 200000,
|
|
19
|
-
},
|
|
20
|
-
"claude-3-5-sonnet-20241022": {
|
|
21
|
-
input: new Decimal(3),
|
|
22
|
-
output: new Decimal(15),
|
|
23
|
-
cacheRead: new Decimal(0.3),
|
|
24
|
-
cacheWrite: new Decimal(3.75),
|
|
25
|
-
contextWindow: 200000,
|
|
26
|
-
},
|
|
27
|
-
"claude-3-5-sonnet-20240620": {
|
|
28
|
-
input: new Decimal(3),
|
|
29
|
-
output: new Decimal(15),
|
|
30
|
-
cacheRead: new Decimal(0.3),
|
|
31
|
-
cacheWrite: new Decimal(3.75),
|
|
32
|
-
contextWindow: 200000,
|
|
33
|
-
},
|
|
34
|
-
"claude-3-5-haiku-20241022": {
|
|
35
|
-
input: new Decimal(1),
|
|
36
|
-
output: new Decimal(5),
|
|
37
|
-
cacheRead: new Decimal(0.1),
|
|
38
|
-
cacheWrite: new Decimal(1.25),
|
|
39
|
-
contextWindow: 200000,
|
|
40
|
-
},
|
|
41
|
-
"claude-3-haiku-20240307": {
|
|
42
|
-
input: new Decimal(0.25),
|
|
43
|
-
output: new Decimal(1.25),
|
|
44
|
-
cacheRead: new Decimal(0.03),
|
|
45
|
-
cacheWrite: new Decimal(0.3),
|
|
46
|
-
contextWindow: 200000,
|
|
47
|
-
},
|
|
48
|
-
"claude-3-opus-20240229": {
|
|
49
|
-
input: new Decimal(15),
|
|
50
|
-
output: new Decimal(75),
|
|
51
|
-
cacheRead: new Decimal(1.5),
|
|
52
|
-
cacheWrite: new Decimal(18.75),
|
|
53
|
-
contextWindow: 200000,
|
|
54
|
-
},
|
|
55
|
-
"claude-opus-4-20250514": {
|
|
56
|
-
input: new Decimal(15),
|
|
57
|
-
output: new Decimal(75),
|
|
58
|
-
cacheRead: new Decimal(1.5),
|
|
59
|
-
cacheWrite: new Decimal(18.75),
|
|
60
|
-
contextWindow: 200000,
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export function getPricing(modelId: string): ModelPricing {
|
|
65
|
-
const normalized = modelId.toLowerCase();
|
|
66
|
-
|
|
67
|
-
for (const [key, pricing] of Object.entries(KNOWN_PRICING)) {
|
|
68
|
-
if (normalized.includes(key.toLowerCase()) || key.toLowerCase().includes(normalized)) {
|
|
69
|
-
return { ...DEFAULT_PRICING, ...pricing };
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return DEFAULT_PRICING;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function getAllPricing(): Map<string, ModelPricing> {
|
|
77
|
-
const result = new Map<string, ModelPricing>();
|
|
78
|
-
for (const [key, pricing] of Object.entries(KNOWN_PRICING)) {
|
|
79
|
-
result.set(key.toLowerCase(), { ...DEFAULT_PRICING, ...pricing });
|
|
80
|
-
}
|
|
81
|
-
return result;
|
|
82
|
-
}
|