@hailer/mcp 0.0.1

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 (163) hide show
  1. package/.claude/commands/tool-builder.md +37 -0
  2. package/.claude/commands/ws-pull.md +44 -0
  3. package/.claude/settings.json +8 -0
  4. package/.claude/settings.local.json +49 -0
  5. package/.claude/skills/activity-api/SKILL.md +96 -0
  6. package/.claude/skills/activity-api/references/activity-endpoints.md +845 -0
  7. package/.claude/skills/add-app-member-skill/SKILL.md +977 -0
  8. package/.claude/skills/agent-building/SKILL.md +243 -0
  9. package/.claude/skills/agent-building/references/architecture-patterns.md +446 -0
  10. package/.claude/skills/agent-building/references/code-examples.md +587 -0
  11. package/.claude/skills/agent-building/references/implementation-guide.md +619 -0
  12. package/.claude/skills/app-api/SKILL.md +219 -0
  13. package/.claude/skills/app-api/references/app-endpoints.md +759 -0
  14. package/.claude/skills/building-hailer-apps-skill/SKILL.md +548 -0
  15. package/.claude/skills/create-app-skill/SKILL.md +1101 -0
  16. package/.claude/skills/create-insight-skill/SKILL.md +1317 -0
  17. package/.claude/skills/get-insight-data-skill/SKILL.md +1053 -0
  18. package/.claude/skills/hailer-api/SKILL.md +283 -0
  19. package/.claude/skills/hailer-api/references/activities.md +620 -0
  20. package/.claude/skills/hailer-api/references/authentication.md +216 -0
  21. package/.claude/skills/hailer-api/references/datasets.md +437 -0
  22. package/.claude/skills/hailer-api/references/files.md +301 -0
  23. package/.claude/skills/hailer-api/references/insights.md +469 -0
  24. package/.claude/skills/hailer-api/references/workflows.md +720 -0
  25. package/.claude/skills/hailer-api/references/workspaces-users.md +445 -0
  26. package/.claude/skills/insight-api/SKILL.md +185 -0
  27. package/.claude/skills/insight-api/references/insight-endpoints.md +514 -0
  28. package/.claude/skills/install-workflow-skill/SKILL.md +1056 -0
  29. package/.claude/skills/list-apps-skill/SKILL.md +1010 -0
  30. package/.claude/skills/list-workflows-minimal-skill/SKILL.md +992 -0
  31. package/.claude/skills/local-first-skill/SKILL.md +570 -0
  32. package/.claude/skills/mcp-tools/SKILL.md +419 -0
  33. package/.claude/skills/mcp-tools/references/api-endpoints.md +499 -0
  34. package/.claude/skills/mcp-tools/references/data-structures.md +554 -0
  35. package/.claude/skills/mcp-tools/references/implementation-patterns.md +717 -0
  36. package/.claude/skills/preview-insight-skill/SKILL.md +1290 -0
  37. package/.claude/skills/publish-hailer-app-skill/SKILL.md +453 -0
  38. package/.claude/skills/remove-app-member-skill/SKILL.md +671 -0
  39. package/.claude/skills/remove-app-skill/SKILL.md +985 -0
  40. package/.claude/skills/remove-insight-skill/SKILL.md +1011 -0
  41. package/.claude/skills/remove-workflow-skill/SKILL.md +920 -0
  42. package/.claude/skills/scaffold-hailer-app-skill/SKILL.md +1034 -0
  43. package/.claude/skills/skill-testing/README.md +137 -0
  44. package/.claude/skills/skill-testing/SKILL.md +348 -0
  45. package/.claude/skills/skill-testing/references/test-patterns.md +705 -0
  46. package/.claude/skills/skill-testing/references/testing-guide.md +603 -0
  47. package/.claude/skills/skill-testing/references/validation-checklist.md +537 -0
  48. package/.claude/skills/tool-builder/SKILL.md +328 -0
  49. package/.claude/skills/update-app-skill/SKILL.md +970 -0
  50. package/.claude/skills/update-workflow-field-skill/SKILL.md +1098 -0
  51. package/.env.example +81 -0
  52. package/.mcp.json +13 -0
  53. package/README.md +297 -0
  54. package/dist/app.d.ts +4 -0
  55. package/dist/app.js +74 -0
  56. package/dist/cli.d.ts +3 -0
  57. package/dist/cli.js +5 -0
  58. package/dist/client/adaptive-documentation-bot.d.ts +108 -0
  59. package/dist/client/adaptive-documentation-bot.js +475 -0
  60. package/dist/client/adaptive-documentation-types.d.ts +66 -0
  61. package/dist/client/adaptive-documentation-types.js +9 -0
  62. package/dist/client/agent-activity-bot.d.ts +51 -0
  63. package/dist/client/agent-activity-bot.js +166 -0
  64. package/dist/client/agent-tracker.d.ts +499 -0
  65. package/dist/client/agent-tracker.js +659 -0
  66. package/dist/client/description-updater.d.ts +56 -0
  67. package/dist/client/description-updater.js +259 -0
  68. package/dist/client/log-parser.d.ts +72 -0
  69. package/dist/client/log-parser.js +387 -0
  70. package/dist/client/mcp-client.d.ts +50 -0
  71. package/dist/client/mcp-client.js +532 -0
  72. package/dist/client/message-processor.d.ts +35 -0
  73. package/dist/client/message-processor.js +352 -0
  74. package/dist/client/multi-bot-manager.d.ts +24 -0
  75. package/dist/client/multi-bot-manager.js +74 -0
  76. package/dist/client/providers/anthropic-provider.d.ts +19 -0
  77. package/dist/client/providers/anthropic-provider.js +631 -0
  78. package/dist/client/providers/llm-provider.d.ts +47 -0
  79. package/dist/client/providers/llm-provider.js +367 -0
  80. package/dist/client/providers/openai-provider.d.ts +23 -0
  81. package/dist/client/providers/openai-provider.js +621 -0
  82. package/dist/client/simple-llm-caller.d.ts +19 -0
  83. package/dist/client/simple-llm-caller.js +100 -0
  84. package/dist/client/skill-generator.d.ts +81 -0
  85. package/dist/client/skill-generator.js +386 -0
  86. package/dist/client/test-adaptive-bot.d.ts +9 -0
  87. package/dist/client/test-adaptive-bot.js +82 -0
  88. package/dist/client/token-pricing.d.ts +38 -0
  89. package/dist/client/token-pricing.js +127 -0
  90. package/dist/client/token-tracker.d.ts +232 -0
  91. package/dist/client/token-tracker.js +457 -0
  92. package/dist/client/token-usage-bot.d.ts +53 -0
  93. package/dist/client/token-usage-bot.js +153 -0
  94. package/dist/client/tool-executor.d.ts +69 -0
  95. package/dist/client/tool-executor.js +159 -0
  96. package/dist/client/tool-schema-loader.d.ts +60 -0
  97. package/dist/client/tool-schema-loader.js +178 -0
  98. package/dist/client/types.d.ts +69 -0
  99. package/dist/client/types.js +7 -0
  100. package/dist/config.d.ts +162 -0
  101. package/dist/config.js +296 -0
  102. package/dist/core.d.ts +26 -0
  103. package/dist/core.js +147 -0
  104. package/dist/lib/context-manager.d.ts +111 -0
  105. package/dist/lib/context-manager.js +431 -0
  106. package/dist/lib/logger.d.ts +74 -0
  107. package/dist/lib/logger.js +277 -0
  108. package/dist/lib/materialize.d.ts +3 -0
  109. package/dist/lib/materialize.js +101 -0
  110. package/dist/lib/normalizedName.d.ts +7 -0
  111. package/dist/lib/normalizedName.js +48 -0
  112. package/dist/lib/prompt-length-manager.d.ts +81 -0
  113. package/dist/lib/prompt-length-manager.js +457 -0
  114. package/dist/lib/terminal-prompt.d.ts +9 -0
  115. package/dist/lib/terminal-prompt.js +108 -0
  116. package/dist/mcp/UserContextCache.d.ts +56 -0
  117. package/dist/mcp/UserContextCache.js +163 -0
  118. package/dist/mcp/auth.d.ts +2 -0
  119. package/dist/mcp/auth.js +29 -0
  120. package/dist/mcp/hailer-clients.d.ts +42 -0
  121. package/dist/mcp/hailer-clients.js +246 -0
  122. package/dist/mcp/signal-handler.d.ts +45 -0
  123. package/dist/mcp/signal-handler.js +317 -0
  124. package/dist/mcp/tool-registry.d.ts +100 -0
  125. package/dist/mcp/tool-registry.js +306 -0
  126. package/dist/mcp/tools/activity.d.ts +15 -0
  127. package/dist/mcp/tools/activity.js +955 -0
  128. package/dist/mcp/tools/app.d.ts +20 -0
  129. package/dist/mcp/tools/app.js +1488 -0
  130. package/dist/mcp/tools/discussion.d.ts +19 -0
  131. package/dist/mcp/tools/discussion.js +950 -0
  132. package/dist/mcp/tools/file.d.ts +15 -0
  133. package/dist/mcp/tools/file.js +119 -0
  134. package/dist/mcp/tools/insight.d.ts +17 -0
  135. package/dist/mcp/tools/insight.js +806 -0
  136. package/dist/mcp/tools/skill.d.ts +10 -0
  137. package/dist/mcp/tools/skill.js +279 -0
  138. package/dist/mcp/tools/user.d.ts +10 -0
  139. package/dist/mcp/tools/user.js +108 -0
  140. package/dist/mcp/tools/workflow-template.d.ts +19 -0
  141. package/dist/mcp/tools/workflow-template.js +822 -0
  142. package/dist/mcp/tools/workflow.d.ts +18 -0
  143. package/dist/mcp/tools/workflow.js +1362 -0
  144. package/dist/mcp/utils/api-errors.d.ts +45 -0
  145. package/dist/mcp/utils/api-errors.js +160 -0
  146. package/dist/mcp/utils/data-transformers.d.ts +102 -0
  147. package/dist/mcp/utils/data-transformers.js +194 -0
  148. package/dist/mcp/utils/file-upload.d.ts +33 -0
  149. package/dist/mcp/utils/file-upload.js +148 -0
  150. package/dist/mcp/utils/hailer-api-client.d.ts +120 -0
  151. package/dist/mcp/utils/hailer-api-client.js +323 -0
  152. package/dist/mcp/utils/index.d.ts +13 -0
  153. package/dist/mcp/utils/index.js +39 -0
  154. package/dist/mcp/utils/logger.d.ts +42 -0
  155. package/dist/mcp/utils/logger.js +103 -0
  156. package/dist/mcp/utils/types.d.ts +286 -0
  157. package/dist/mcp/utils/types.js +7 -0
  158. package/dist/mcp/workspace-cache.d.ts +42 -0
  159. package/dist/mcp/workspace-cache.js +97 -0
  160. package/dist/mcp-server.d.ts +42 -0
  161. package/dist/mcp-server.js +280 -0
  162. package/package.json +56 -0
  163. package/tsconfig.json +23 -0
@@ -0,0 +1,457 @@
1
+ "use strict";
2
+ /**
3
+ * Token Usage Tracker
4
+ *
5
+ * Dedicated tracking system for token usage and costs across all bots.
6
+ * Optimized for both human readability and LLM analysis.
7
+ *
8
+ * Use Cases:
9
+ * - Monitor per-bot token budgets
10
+ * - Identify expensive tools/operations
11
+ * - Feed data to optimizer agents
12
+ * - Generate cost reports
13
+ */
14
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ var desc = Object.getOwnPropertyDescriptor(m, k);
17
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
+ desc = { enumerable: true, get: function() { return m[k]; } };
19
+ }
20
+ Object.defineProperty(o, k2, desc);
21
+ }) : (function(o, m, k, k2) {
22
+ if (k2 === undefined) k2 = k;
23
+ o[k2] = m[k];
24
+ }));
25
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
27
+ }) : function(o, v) {
28
+ o["default"] = v;
29
+ });
30
+ var __importStar = (this && this.__importStar) || (function () {
31
+ var ownKeys = function(o) {
32
+ ownKeys = Object.getOwnPropertyNames || function (o) {
33
+ var ar = [];
34
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
35
+ return ar;
36
+ };
37
+ return ownKeys(o);
38
+ };
39
+ return function (mod) {
40
+ if (mod && mod.__esModule) return mod;
41
+ var result = {};
42
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
43
+ __setModuleDefault(result, mod);
44
+ return result;
45
+ };
46
+ })();
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ exports.TokenTracker = void 0;
49
+ exports.createTokenTracker = createTokenTracker;
50
+ const logger_1 = require("../lib/logger");
51
+ const fs = __importStar(require("fs"));
52
+ const path = __importStar(require("path"));
53
+ /**
54
+ * Token Usage Tracker
55
+ *
56
+ * Tracks token usage across all bots and tools for cost optimization.
57
+ * Data is stored in a structured format for easy analysis by humans and agents.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const tracker = new TokenTracker();
62
+ *
63
+ * // Log bot activity
64
+ * tracker.logUsage({
65
+ * botId: 'bot_sales_789',
66
+ * botName: 'Sales Bot',
67
+ * provider: 'anthropic',
68
+ * conversationId: 'disc_123',
69
+ * toolsCalled: ['list_activities', 'create_activity'],
70
+ * tokens: {
71
+ * input: 24567,
72
+ * output: 412,
73
+ * total: 24979,
74
+ * cacheRead: 22000,
75
+ * cost: 0.038
76
+ * },
77
+ * duration: 2450,
78
+ * success: true
79
+ * });
80
+ *
81
+ * // Query for analyzer agent
82
+ * const botUsage = tracker.getBotUsage('bot_sales_789');
83
+ * const expensiveTools = tracker.getMostExpensiveTools(5);
84
+ * ```
85
+ */
86
+ class TokenTracker {
87
+ logger;
88
+ dataFilePath;
89
+ data;
90
+ maxRecentEvents = 100;
91
+ maxDailySummaries = 90; // Keep 90 days
92
+ constructor(logger, logDir = 'logs') {
93
+ this.logger = logger || (0, logger_1.createLogger)({ component: 'token-tracker' });
94
+ this.dataFilePath = path.join(logDir, 'token-usage.json');
95
+ // Initialize or load existing data
96
+ this.data = this.loadData();
97
+ this.logger.info('Token tracker initialized', {
98
+ dataFile: this.dataFilePath,
99
+ totalBots: this.data.summary.totalBots,
100
+ totalCost: this.data.summary.totalCost,
101
+ });
102
+ }
103
+ /**
104
+ * Load existing data or initialize new structure
105
+ */
106
+ loadData() {
107
+ try {
108
+ if (fs.existsSync(this.dataFilePath)) {
109
+ const fileContent = fs.readFileSync(this.dataFilePath, 'utf8');
110
+ const data = JSON.parse(fileContent);
111
+ this.logger.info('Loaded existing token usage data', {
112
+ totalCost: data.summary.totalCost,
113
+ totalConversations: data.summary.totalConversations,
114
+ });
115
+ return data;
116
+ }
117
+ }
118
+ catch (error) {
119
+ this.logger.error('Failed to load token usage data, initializing new', error);
120
+ }
121
+ // Initialize new data structure
122
+ return {
123
+ summary: {
124
+ totalCost: 0,
125
+ totalTokens: 0,
126
+ totalConversations: 0,
127
+ totalBots: 0,
128
+ totalTools: 0,
129
+ mostExpensiveBot: null,
130
+ mostExpensiveTool: null,
131
+ period: {
132
+ start: new Date().toISOString().split('T')[0],
133
+ end: new Date().toISOString().split('T')[0],
134
+ },
135
+ lastUpdated: new Date().toISOString(),
136
+ },
137
+ bots: {},
138
+ tools: {},
139
+ dailySummaries: [],
140
+ recentEvents: [],
141
+ };
142
+ }
143
+ /**
144
+ * Save data to disk
145
+ */
146
+ saveData() {
147
+ try {
148
+ // Ensure directory exists
149
+ const dir = path.dirname(this.dataFilePath);
150
+ if (!fs.existsSync(dir)) {
151
+ fs.mkdirSync(dir, { recursive: true });
152
+ }
153
+ // Update last updated timestamp
154
+ this.data.summary.lastUpdated = new Date().toISOString();
155
+ // Write with pretty formatting for human readability
156
+ fs.writeFileSync(this.dataFilePath, JSON.stringify(this.data, null, 2), 'utf8');
157
+ }
158
+ catch (error) {
159
+ this.logger.error('Failed to save token usage data', error);
160
+ }
161
+ }
162
+ /**
163
+ * Log a token usage event from a bot interaction
164
+ */
165
+ logUsage(event) {
166
+ const fullEvent = {
167
+ ...event,
168
+ timestamp: new Date().toISOString(),
169
+ };
170
+ try {
171
+ // Add to recent events (with rotation)
172
+ this.data.recentEvents.push(fullEvent);
173
+ if (this.data.recentEvents.length > this.maxRecentEvents) {
174
+ this.data.recentEvents.shift();
175
+ }
176
+ // Update bot statistics
177
+ this.updateBotStats(fullEvent);
178
+ // Update tool statistics
179
+ this.updateToolStats(fullEvent);
180
+ // Update daily summary
181
+ this.updateDailySummary(fullEvent);
182
+ // Update global summary
183
+ this.updateGlobalSummary(fullEvent);
184
+ // Save to disk
185
+ this.saveData();
186
+ this.logger.info('Token usage logged', {
187
+ botId: event.botId,
188
+ cost: event.tokens.cost,
189
+ tokens: event.tokens.total,
190
+ tools: event.toolsCalled.length,
191
+ });
192
+ }
193
+ catch (error) {
194
+ this.logger.error('Failed to log token usage', error, {
195
+ botId: event.botId,
196
+ });
197
+ }
198
+ }
199
+ /**
200
+ * Update per-bot statistics
201
+ */
202
+ updateBotStats(event) {
203
+ const { botId, botName, tokens, toolsCalled } = event;
204
+ if (!this.data.bots[botId]) {
205
+ // Initialize new bot
206
+ this.data.bots[botId] = {
207
+ botId,
208
+ botName,
209
+ totalCost: 0,
210
+ totalTokens: 0,
211
+ conversations: 0,
212
+ averageCostPerConversation: 0,
213
+ averageTokensPerConversation: 0,
214
+ tools: {},
215
+ firstSeen: event.timestamp,
216
+ lastSeen: event.timestamp,
217
+ };
218
+ this.data.summary.totalBots++;
219
+ }
220
+ const bot = this.data.bots[botId];
221
+ // Update totals
222
+ bot.totalCost += tokens.cost;
223
+ bot.totalTokens += tokens.total;
224
+ bot.conversations++;
225
+ bot.lastSeen = event.timestamp;
226
+ // Update averages
227
+ bot.averageCostPerConversation = bot.totalCost / bot.conversations;
228
+ bot.averageTokensPerConversation = bot.totalTokens / bot.conversations;
229
+ // Update cache efficiency (if applicable)
230
+ if (tokens.cacheRead !== undefined || tokens.cacheCreation !== undefined) {
231
+ if (!bot.cacheEfficiency) {
232
+ bot.cacheEfficiency = {
233
+ totalCacheRead: 0,
234
+ totalCacheCreation: 0,
235
+ savingsPercent: 0,
236
+ };
237
+ }
238
+ bot.cacheEfficiency.totalCacheRead += tokens.cacheRead || 0;
239
+ bot.cacheEfficiency.totalCacheCreation += tokens.cacheCreation || 0;
240
+ const totalInput = bot.totalTokens;
241
+ const cacheReads = bot.cacheEfficiency.totalCacheRead;
242
+ bot.cacheEfficiency.savingsPercent = totalInput > 0
243
+ ? Math.round((cacheReads / totalInput) * 100)
244
+ : 0;
245
+ }
246
+ // Update per-tool stats within this bot
247
+ for (const toolName of toolsCalled) {
248
+ if (!bot.tools[toolName]) {
249
+ bot.tools[toolName] = {
250
+ calls: 0,
251
+ tokens: 0,
252
+ cost: 0,
253
+ };
254
+ }
255
+ const toolStat = bot.tools[toolName];
256
+ toolStat.calls++;
257
+ // Distribute tokens/cost evenly across tools (approximation)
258
+ toolStat.tokens += Math.round(tokens.total / toolsCalled.length);
259
+ toolStat.cost += tokens.cost / toolsCalled.length;
260
+ }
261
+ }
262
+ /**
263
+ * Update per-tool statistics
264
+ */
265
+ updateToolStats(event) {
266
+ const { botId, tokens, toolsCalled } = event;
267
+ for (const toolName of toolsCalled) {
268
+ if (!this.data.tools[toolName]) {
269
+ this.data.tools[toolName] = {
270
+ toolName,
271
+ totalCost: 0,
272
+ totalTokens: 0,
273
+ calls: 0,
274
+ averageCostPerCall: 0,
275
+ averageTokensPerCall: 0,
276
+ usedByBots: [],
277
+ };
278
+ this.data.summary.totalTools++;
279
+ }
280
+ const tool = this.data.tools[toolName];
281
+ // Update totals (distribute evenly across tools)
282
+ tool.calls++;
283
+ tool.totalTokens += Math.round(tokens.total / toolsCalled.length);
284
+ tool.totalCost += tokens.cost / toolsCalled.length;
285
+ // Update averages
286
+ tool.averageCostPerCall = tool.totalCost / tool.calls;
287
+ tool.averageTokensPerCall = tool.totalTokens / tool.calls;
288
+ // Track which bots use this tool
289
+ if (!tool.usedByBots.includes(botId)) {
290
+ tool.usedByBots.push(botId);
291
+ }
292
+ }
293
+ }
294
+ /**
295
+ * Update daily summary
296
+ */
297
+ updateDailySummary(event) {
298
+ const date = event.timestamp.split('T')[0]; // YYYY-MM-DD
299
+ let daily = this.data.dailySummaries.find(d => d.date === date);
300
+ if (!daily) {
301
+ daily = {
302
+ date,
303
+ cost: 0,
304
+ tokens: 0,
305
+ conversations: 0,
306
+ uniqueBots: 0,
307
+ topBot: '',
308
+ topTool: '',
309
+ };
310
+ this.data.dailySummaries.push(daily);
311
+ // Sort by date and trim old entries
312
+ this.data.dailySummaries.sort((a, b) => a.date.localeCompare(b.date));
313
+ if (this.data.dailySummaries.length > this.maxDailySummaries) {
314
+ this.data.dailySummaries.shift();
315
+ }
316
+ }
317
+ daily.cost += event.tokens.cost;
318
+ daily.tokens += event.tokens.total;
319
+ daily.conversations++;
320
+ // Update period range
321
+ if (date < this.data.summary.period.start) {
322
+ this.data.summary.period.start = date;
323
+ }
324
+ if (date > this.data.summary.period.end) {
325
+ this.data.summary.period.end = date;
326
+ }
327
+ }
328
+ /**
329
+ * Update global summary statistics
330
+ */
331
+ updateGlobalSummary(event) {
332
+ this.data.summary.totalCost += event.tokens.cost;
333
+ this.data.summary.totalTokens += event.tokens.total;
334
+ this.data.summary.totalConversations++;
335
+ // Find most expensive bot
336
+ let maxBotCost = 0;
337
+ let maxBotId = null;
338
+ for (const [botId, bot] of Object.entries(this.data.bots)) {
339
+ if (bot.totalCost > maxBotCost) {
340
+ maxBotCost = bot.totalCost;
341
+ maxBotId = botId;
342
+ }
343
+ }
344
+ this.data.summary.mostExpensiveBot = maxBotId;
345
+ // Find most expensive tool
346
+ let maxToolCost = 0;
347
+ let maxToolName = null;
348
+ for (const [toolName, tool] of Object.entries(this.data.tools)) {
349
+ if (tool.totalCost > maxToolCost) {
350
+ maxToolCost = tool.totalCost;
351
+ maxToolName = toolName;
352
+ }
353
+ }
354
+ this.data.summary.mostExpensiveTool = maxToolName;
355
+ }
356
+ /**
357
+ * Get usage statistics for a specific bot
358
+ * Useful for analyzer agents to investigate specific bots
359
+ */
360
+ getBotUsage(botId) {
361
+ return this.data.bots[botId] || null;
362
+ }
363
+ /**
364
+ * Get usage statistics for a specific tool
365
+ */
366
+ getToolUsage(toolName) {
367
+ return this.data.tools[toolName] || null;
368
+ }
369
+ /**
370
+ * Get N most expensive bots
371
+ */
372
+ getMostExpensiveBots(limit = 5) {
373
+ return Object.values(this.data.bots)
374
+ .sort((a, b) => b.totalCost - a.totalCost)
375
+ .slice(0, limit);
376
+ }
377
+ /**
378
+ * Get N most expensive tools
379
+ */
380
+ getMostExpensiveTools(limit = 5) {
381
+ return Object.values(this.data.tools)
382
+ .sort((a, b) => b.totalCost - a.totalCost)
383
+ .slice(0, limit);
384
+ }
385
+ /**
386
+ * Get daily summaries for a date range
387
+ */
388
+ getDailySummaries(startDate, endDate) {
389
+ let summaries = this.data.dailySummaries;
390
+ if (startDate) {
391
+ summaries = summaries.filter(s => s.date >= startDate);
392
+ }
393
+ if (endDate) {
394
+ summaries = summaries.filter(s => s.date <= endDate);
395
+ }
396
+ return summaries;
397
+ }
398
+ /**
399
+ * Get full data dump for analyzer agents
400
+ * This gives the agent complete context
401
+ */
402
+ getFullData() {
403
+ return this.data;
404
+ }
405
+ /**
406
+ * Get summary statistics
407
+ */
408
+ getSummary() {
409
+ return this.data.summary;
410
+ }
411
+ /**
412
+ * Generate human-readable report
413
+ */
414
+ generateReport() {
415
+ const { summary, bots, tools } = this.data;
416
+ const report = `
417
+ Token Usage Report
418
+ ==================
419
+ Period: ${summary.period.start} to ${summary.period.end}
420
+ Last Updated: ${summary.lastUpdated}
421
+
422
+ OVERALL SUMMARY
423
+ ---------------
424
+ Total Cost: $${summary.totalCost.toFixed(2)}
425
+ Total Tokens: ${summary.totalTokens.toLocaleString()}
426
+ Total Conversations: ${summary.totalConversations}
427
+ Active Bots: ${summary.totalBots}
428
+ Tools Used: ${summary.totalTools}
429
+
430
+ TOP CONSUMERS
431
+ -------------
432
+ Most Expensive Bot: ${summary.mostExpensiveBot || 'N/A'}
433
+ Most Expensive Tool: ${summary.mostExpensiveTool || 'N/A'}
434
+
435
+ TOP 5 BOTS BY COST
436
+ ------------------
437
+ ${this.getMostExpensiveBots(5).map((bot, i) => `${i + 1}. ${bot.botName || bot.botId}: $${bot.totalCost.toFixed(2)} (${bot.conversations} conversations)`).join('\n')}
438
+
439
+ TOP 5 TOOLS BY COST
440
+ -------------------
441
+ ${this.getMostExpensiveTools(5).map((tool, i) => `${i + 1}. ${tool.toolName}: $${tool.totalCost.toFixed(2)} (${tool.calls} calls)`).join('\n')}
442
+
443
+ RECENT DAILY USAGE
444
+ ------------------
445
+ ${this.data.dailySummaries.slice(-7).map(day => `${day.date}: $${day.cost.toFixed(2)} (${day.conversations} conversations)`).join('\n')}
446
+ `;
447
+ return report;
448
+ }
449
+ }
450
+ exports.TokenTracker = TokenTracker;
451
+ /**
452
+ * Factory function to create a new TokenTracker instance
453
+ */
454
+ function createTokenTracker(logger, logDir) {
455
+ return new TokenTracker(logger, logDir);
456
+ }
457
+ //# sourceMappingURL=token-tracker.js.map
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Token Usage Bot
3
+ *
4
+ * Monitors token usage and posts summaries to discussions.
5
+ * Can respond to queries about token costs and usage details.
6
+ */
7
+ import { TokenTracker } from './token-tracker';
8
+ import { AgentTracker } from './agent-tracker';
9
+ export interface TokenUsageBotConfig {
10
+ enabled: boolean;
11
+ postSummaryAfterConversation: boolean;
12
+ minCostThreshold?: number;
13
+ }
14
+ export declare class TokenUsageBot {
15
+ private tokenTracker;
16
+ private agentTracker;
17
+ private config;
18
+ private lastPostedConversation;
19
+ constructor(tokenTracker: TokenTracker, agentTracker: AgentTracker, config: TokenUsageBotConfig);
20
+ /**
21
+ * Generate a summary message for the last conversation in a discussion
22
+ */
23
+ generateSummary(discussionId: string, conversationCost: number, conversationTokens: number): Promise<string>;
24
+ /**
25
+ * Format a concise summary message
26
+ */
27
+ private formatSummaryMessage;
28
+ /**
29
+ * Generate detailed token usage report
30
+ */
31
+ generateDetailedReport(discussionId?: string): string;
32
+ /**
33
+ * Check if message is asking for token details
34
+ */
35
+ isTokenQuery(messageContent: string): boolean;
36
+ /**
37
+ * Should post summary after this conversation?
38
+ */
39
+ shouldPostSummary(discussionId: string, cost: number): boolean;
40
+ /**
41
+ * Mark that we posted a summary for this discussion
42
+ */
43
+ markPosted(discussionId: string): void;
44
+ /**
45
+ * Get token tracker instance
46
+ */
47
+ getTokenTracker(): TokenTracker;
48
+ }
49
+ /**
50
+ * Factory function to create TokenUsageBot
51
+ */
52
+ export declare function createTokenUsageBot(tokenTracker: TokenTracker, agentTracker: AgentTracker, config: TokenUsageBotConfig): TokenUsageBot;
53
+ //# sourceMappingURL=token-usage-bot.d.ts.map
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ /**
3
+ * Token Usage Bot
4
+ *
5
+ * Monitors token usage and posts summaries to discussions.
6
+ * Can respond to queries about token costs and usage details.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.TokenUsageBot = void 0;
10
+ exports.createTokenUsageBot = createTokenUsageBot;
11
+ const logger_1 = require("../lib/logger");
12
+ const logger = (0, logger_1.createLogger)({ component: 'token-usage-bot' });
13
+ class TokenUsageBot {
14
+ tokenTracker;
15
+ agentTracker;
16
+ config;
17
+ lastPostedConversation = new Map(); // discussionId -> timestamp
18
+ constructor(tokenTracker, agentTracker, config) {
19
+ this.tokenTracker = tokenTracker;
20
+ this.agentTracker = agentTracker;
21
+ this.config = {
22
+ minCostThreshold: 0.01,
23
+ ...config
24
+ };
25
+ if (this.config.enabled) {
26
+ logger.info('Token Usage Bot initialized', {
27
+ postSummaries: this.config.postSummaryAfterConversation,
28
+ minThreshold: this.config.minCostThreshold
29
+ });
30
+ }
31
+ }
32
+ /**
33
+ * Generate a summary message for the last conversation in a discussion
34
+ */
35
+ async generateSummary(discussionId, conversationCost, conversationTokens) {
36
+ const summary = this.tokenTracker.getSummary();
37
+ const recentEvents = this.tokenTracker.getFullData().recentEvents.filter(e => e.conversationId === discussionId);
38
+ if (recentEvents.length === 0) {
39
+ return `💰 **Token Usage Summary**\n\nNo recent token data available for this conversation.`;
40
+ }
41
+ // Get the most recent event for this discussion
42
+ const lastEvent = recentEvents[recentEvents.length - 1];
43
+ return this.formatSummaryMessage(lastEvent, conversationCost, conversationTokens);
44
+ }
45
+ /**
46
+ * Format a concise summary message
47
+ */
48
+ formatSummaryMessage(event, cost, tokens) {
49
+ const cacheInfo = event.tokens.cacheRead > 0
50
+ ? ` (${event.tokens.cacheRead.toLocaleString()} cached)`
51
+ : '';
52
+ return `💰 **Token Usage**
53
+ Cost: $${cost.toFixed(4)} | Tokens: ${tokens.toLocaleString()}${cacheInfo}
54
+ Tools: ${event.toolsCalled.length > 0 ? event.toolsCalled.join(', ') : 'none'}`;
55
+ }
56
+ /**
57
+ * Generate detailed token usage report
58
+ */
59
+ generateDetailedReport(discussionId) {
60
+ const summary = this.tokenTracker.getSummary();
61
+ const data = this.tokenTracker.getFullData();
62
+ let report = `📊 **Detailed Token Usage Report**\n\n`;
63
+ if (discussionId) {
64
+ // Filter for specific discussion
65
+ const discussionEvents = data.recentEvents.filter(e => e.conversationId === discussionId);
66
+ const discussionCost = discussionEvents.reduce((sum, e) => sum + e.tokens.cost, 0);
67
+ const discussionTokens = discussionEvents.reduce((sum, e) => sum + e.tokens.total, 0);
68
+ report += `**This Conversation:**\n`;
69
+ report += `- Total Cost: $${discussionCost.toFixed(4)}\n`;
70
+ report += `- Total Tokens: ${discussionTokens.toLocaleString()}\n`;
71
+ report += `- Messages: ${discussionEvents.length}\n`;
72
+ report += `- Avg per message: $${(discussionCost / discussionEvents.length).toFixed(4)}\n\n`;
73
+ // Show last 5 events
74
+ report += `**Recent Messages:**\n`;
75
+ discussionEvents.slice(-5).forEach((event, i) => {
76
+ report += `${i + 1}. $${event.tokens.cost.toFixed(4)} - ${event.tokens.total.toLocaleString()} tokens`;
77
+ if (event.toolsCalled.length > 0) {
78
+ report += ` - Tools: ${event.toolsCalled.slice(0, 3).join(', ')}`;
79
+ if (event.toolsCalled.length > 3)
80
+ report += `...`;
81
+ }
82
+ report += `\n`;
83
+ });
84
+ report += `\n`;
85
+ }
86
+ // Overall stats
87
+ report += `**Overall Stats:**\n`;
88
+ report += `- Total Cost: $${summary.totalCost.toFixed(2)}\n`;
89
+ report += `- Total Tokens: ${summary.totalTokens.toLocaleString()}\n`;
90
+ report += `- Total Conversations: ${summary.totalConversations}\n`;
91
+ report += `- Avg per conversation: $${(summary.totalCost / summary.totalConversations).toFixed(4)}\n\n`;
92
+ // Top tools
93
+ const topTools = this.tokenTracker.getMostExpensiveTools(5);
94
+ if (topTools.length > 0) {
95
+ report += `**Most Expensive Tools:**\n`;
96
+ topTools.forEach((tool, i) => {
97
+ report += `${i + 1}. ${tool.toolName}: $${tool.totalCost.toFixed(4)} (${tool.calls} calls)\n`;
98
+ });
99
+ }
100
+ return report;
101
+ }
102
+ /**
103
+ * Check if message is asking for token details
104
+ */
105
+ isTokenQuery(messageContent) {
106
+ const lower = messageContent.toLowerCase();
107
+ return (lower.includes('token') && (lower.includes('usage') ||
108
+ lower.includes('cost') ||
109
+ lower.includes('price') ||
110
+ lower.includes('detail') ||
111
+ lower.includes('report') ||
112
+ lower.includes('how much') ||
113
+ lower.includes('expensive')));
114
+ }
115
+ /**
116
+ * Should post summary after this conversation?
117
+ */
118
+ shouldPostSummary(discussionId, cost) {
119
+ if (!this.config.enabled || !this.config.postSummaryAfterConversation) {
120
+ return false;
121
+ }
122
+ // Check cost threshold
123
+ if (cost < (this.config.minCostThreshold || 0)) {
124
+ return false;
125
+ }
126
+ // Debounce: Don't post if we posted recently (within 30 seconds)
127
+ const lastPosted = this.lastPostedConversation.get(discussionId);
128
+ if (lastPosted && Date.now() - lastPosted < 30000) {
129
+ return false;
130
+ }
131
+ return true;
132
+ }
133
+ /**
134
+ * Mark that we posted a summary for this discussion
135
+ */
136
+ markPosted(discussionId) {
137
+ this.lastPostedConversation.set(discussionId, Date.now());
138
+ }
139
+ /**
140
+ * Get token tracker instance
141
+ */
142
+ getTokenTracker() {
143
+ return this.tokenTracker;
144
+ }
145
+ }
146
+ exports.TokenUsageBot = TokenUsageBot;
147
+ /**
148
+ * Factory function to create TokenUsageBot
149
+ */
150
+ function createTokenUsageBot(tokenTracker, agentTracker, config) {
151
+ return new TokenUsageBot(tokenTracker, agentTracker, config);
152
+ }
153
+ //# sourceMappingURL=token-usage-bot.js.map