aiden-runtime 3.16.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 (159) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +465 -0
  3. package/config/devos.config.json +186 -0
  4. package/config/hardware.json +9 -0
  5. package/config/model-selection.json +7 -0
  6. package/config/setup-complete.json +20 -0
  7. package/dist/api/routes/computerUse.js +112 -0
  8. package/dist/api/server.js +6870 -0
  9. package/dist/bin/npx-init.js +71 -0
  10. package/dist/coordination/commandGate.js +115 -0
  11. package/dist/coordination/livePulse.js +127 -0
  12. package/dist/core/agentLoop.js +2718 -0
  13. package/dist/core/agentShield.js +231 -0
  14. package/dist/core/aidenIdentity.js +215 -0
  15. package/dist/core/aidenPersonality.js +166 -0
  16. package/dist/core/aidenSdk.js +374 -0
  17. package/dist/core/asyncTasks.js +82 -0
  18. package/dist/core/auditTrail.js +61 -0
  19. package/dist/core/auxiliaryClient.js +114 -0
  20. package/dist/core/bgLLM.js +108 -0
  21. package/dist/core/bm25.js +68 -0
  22. package/dist/core/callbackSystem.js +64 -0
  23. package/dist/core/channels/adapter.js +6 -0
  24. package/dist/core/channels/discord.js +173 -0
  25. package/dist/core/channels/email.js +253 -0
  26. package/dist/core/channels/imessage.js +164 -0
  27. package/dist/core/channels/manager.js +96 -0
  28. package/dist/core/channels/signal.js +140 -0
  29. package/dist/core/channels/slack.js +139 -0
  30. package/dist/core/channels/twilio.js +144 -0
  31. package/dist/core/channels/webhook.js +186 -0
  32. package/dist/core/channels/whatsapp.js +185 -0
  33. package/dist/core/clarifyBus.js +75 -0
  34. package/dist/core/codeInterpreter.js +82 -0
  35. package/dist/core/computerControl.js +439 -0
  36. package/dist/core/conversationMemory.js +334 -0
  37. package/dist/core/costTracker.js +221 -0
  38. package/dist/core/cronManager.js +217 -0
  39. package/dist/core/deepKB.js +77 -0
  40. package/dist/core/doctor.js +279 -0
  41. package/dist/core/dreamEngine.js +334 -0
  42. package/dist/core/entityGraph.js +169 -0
  43. package/dist/core/eventBus.js +16 -0
  44. package/dist/core/evolutionAnalyzer.js +153 -0
  45. package/dist/core/executionLoop.js +309 -0
  46. package/dist/core/executor.js +224 -0
  47. package/dist/core/failureAnalyzer.js +166 -0
  48. package/dist/core/fastPathExpansion.js +82 -0
  49. package/dist/core/faultEngine.js +106 -0
  50. package/dist/core/featureGates.js +70 -0
  51. package/dist/core/fileIngestion.js +113 -0
  52. package/dist/core/gateway.js +97 -0
  53. package/dist/core/goalTracker.js +75 -0
  54. package/dist/core/growthEngine.js +168 -0
  55. package/dist/core/hardwareDetector.js +98 -0
  56. package/dist/core/hooks.js +45 -0
  57. package/dist/core/httpKeepalive.js +46 -0
  58. package/dist/core/hybridSearch.js +101 -0
  59. package/dist/core/importers.js +164 -0
  60. package/dist/core/instinctSystem.js +223 -0
  61. package/dist/core/knowledgeBase.js +351 -0
  62. package/dist/core/learningMemory.js +121 -0
  63. package/dist/core/lessonsBrowser.js +125 -0
  64. package/dist/core/licenseManager.js +399 -0
  65. package/dist/core/logBuffer.js +85 -0
  66. package/dist/core/machineId.js +87 -0
  67. package/dist/core/mcpClient.js +442 -0
  68. package/dist/core/memoryDistiller.js +165 -0
  69. package/dist/core/memoryExtractor.js +212 -0
  70. package/dist/core/memoryIds.js +213 -0
  71. package/dist/core/memoryPreamble.js +113 -0
  72. package/dist/core/memoryQuery.js +136 -0
  73. package/dist/core/memoryRecall.js +140 -0
  74. package/dist/core/memoryStrategy.js +201 -0
  75. package/dist/core/messageValidator.js +85 -0
  76. package/dist/core/modelDiscovery.js +108 -0
  77. package/dist/core/modelRouter.js +118 -0
  78. package/dist/core/morningBriefing.js +203 -0
  79. package/dist/core/multiGoalValidator.js +51 -0
  80. package/dist/core/parallelExecutor.js +43 -0
  81. package/dist/core/passiveSkillObserver.js +204 -0
  82. package/dist/core/paths.js +57 -0
  83. package/dist/core/patternDetector.js +83 -0
  84. package/dist/core/planResponseRepair.js +64 -0
  85. package/dist/core/planTool.js +111 -0
  86. package/dist/core/playwrightBridge.js +356 -0
  87. package/dist/core/pluginSystem.js +121 -0
  88. package/dist/core/privateMode.js +85 -0
  89. package/dist/core/reactLoop.js +156 -0
  90. package/dist/core/recipeEngine.js +166 -0
  91. package/dist/core/responseCache.js +128 -0
  92. package/dist/core/runSandbox.js +132 -0
  93. package/dist/core/sandboxRunner.js +200 -0
  94. package/dist/core/scheduler.js +543 -0
  95. package/dist/core/secretScanner.js +49 -0
  96. package/dist/core/semanticMemory.js +223 -0
  97. package/dist/core/sessionMemory.js +259 -0
  98. package/dist/core/sessionRouter.js +91 -0
  99. package/dist/core/sessionSearch.js +163 -0
  100. package/dist/core/setupWizard.js +225 -0
  101. package/dist/core/skillImporter.js +303 -0
  102. package/dist/core/skillLibrary.js +144 -0
  103. package/dist/core/skillLoader.js +471 -0
  104. package/dist/core/skillTeacher.js +352 -0
  105. package/dist/core/skillValidator.js +210 -0
  106. package/dist/core/skillWriter.js +384 -0
  107. package/dist/core/slashAsTool.js +226 -0
  108. package/dist/core/spawnManager.js +197 -0
  109. package/dist/core/statusVerbs.js +43 -0
  110. package/dist/core/swarmManager.js +109 -0
  111. package/dist/core/taskQueue.js +119 -0
  112. package/dist/core/taskRecovery.js +128 -0
  113. package/dist/core/taskState.js +168 -0
  114. package/dist/core/telegramBot.js +152 -0
  115. package/dist/core/todoManager.js +70 -0
  116. package/dist/core/toolNameRepair.js +71 -0
  117. package/dist/core/toolRegistry.js +2730 -0
  118. package/dist/core/tools/calendarTool.js +98 -0
  119. package/dist/core/tools/companyFilingsTool.js +98 -0
  120. package/dist/core/tools/gmailTool.js +87 -0
  121. package/dist/core/tools/marketDataTool.js +135 -0
  122. package/dist/core/tools/socialResearchTool.js +121 -0
  123. package/dist/core/truthCheck.js +57 -0
  124. package/dist/core/updateChecker.js +74 -0
  125. package/dist/core/userCognitionProfile.js +238 -0
  126. package/dist/core/userProfile.js +341 -0
  127. package/dist/core/version.js +5 -0
  128. package/dist/core/visionAnalyze.js +161 -0
  129. package/dist/core/voice/audio.js +187 -0
  130. package/dist/core/voice/stt.js +226 -0
  131. package/dist/core/voice/tts.js +310 -0
  132. package/dist/core/voiceInput.js +118 -0
  133. package/dist/core/voiceOutput.js +130 -0
  134. package/dist/core/webSearch.js +326 -0
  135. package/dist/core/workflowTracker.js +72 -0
  136. package/dist/core/workspaceMemory.js +54 -0
  137. package/dist/core/youtubeTranscript.js +224 -0
  138. package/dist/integrations/computerUse/apiRegistry.js +113 -0
  139. package/dist/integrations/computerUse/screenAgent.js +203 -0
  140. package/dist/integrations/computerUse/visionLoop.js +296 -0
  141. package/dist/memory/memoryLayers.js +143 -0
  142. package/dist/providers/boa.js +93 -0
  143. package/dist/providers/cerebras.js +70 -0
  144. package/dist/providers/custom.js +89 -0
  145. package/dist/providers/gemini.js +82 -0
  146. package/dist/providers/groq.js +92 -0
  147. package/dist/providers/index.js +149 -0
  148. package/dist/providers/nvidia.js +70 -0
  149. package/dist/providers/ollama.js +99 -0
  150. package/dist/providers/openrouter.js +74 -0
  151. package/dist/providers/router.js +497 -0
  152. package/dist/providers/types.js +6 -0
  153. package/dist/security/browserVault.js +129 -0
  154. package/dist/security/dataGuard.js +89 -0
  155. package/dist/tools/eonetTool.js +72 -0
  156. package/dist/types/computerUse.js +2 -0
  157. package/dist/types/executor.js +2 -0
  158. package/dist-bundle/cli.js +357859 -0
  159. package/package.json +256 -0
@@ -0,0 +1,334 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.conversationMemory = exports.ConversationMemory = void 0;
11
+ // core/conversationMemory.ts — Multi-session cross-session conversation memory.
12
+ // Each browser tab gets its own session. Facts and semantic memory are shared
13
+ // across sessions; exchange history is per-session.
14
+ const fs_1 = __importDefault(require("fs"));
15
+ const path_1 = __importDefault(require("path"));
16
+ const semanticMemory_1 = require("./semanticMemory");
17
+ const entityGraph_1 = require("./entityGraph");
18
+ const secretScanner_1 = require("./secretScanner");
19
+ const MEMORY_PATH = path_1.default.join(process.cwd(), 'workspace', 'conversation.json');
20
+ // ── ConversationMemory ─────────────────────────────────────────
21
+ class ConversationMemory {
22
+ constructor() {
23
+ this.sessionId = 'default';
24
+ this.allSessions = {};
25
+ this.state = this.load();
26
+ }
27
+ // ── Persistence ──────────────────────────────────────────────
28
+ load() {
29
+ try {
30
+ if (fs_1.default.existsSync(MEMORY_PATH)) {
31
+ const raw = fs_1.default.readFileSync(MEMORY_PATH, 'utf-8');
32
+ const parsed = JSON.parse(raw);
33
+ // Backward-compatibility: old format was a single ConversationState
34
+ // (has .exchanges array at top level). Migrate into multi-session map.
35
+ if (Array.isArray(parsed.exchanges)) {
36
+ const legacy = parsed;
37
+ this.allSessions = { [legacy.sessionId || 'default']: legacy };
38
+ }
39
+ else {
40
+ this.allSessions = parsed;
41
+ }
42
+ }
43
+ }
44
+ catch { }
45
+ return this.allSessions[this.sessionId] || this.freshState();
46
+ }
47
+ freshState() {
48
+ return {
49
+ exchanges: [],
50
+ facts: {
51
+ lastFilesCreated: [],
52
+ lastSearchQueries: [],
53
+ lastToolsUsed: [],
54
+ mentionedEntities: [],
55
+ preferredPaths: [],
56
+ },
57
+ sessionId: this.sessionId,
58
+ updatedAt: Date.now(),
59
+ };
60
+ }
61
+ save() {
62
+ try {
63
+ const dir = path_1.default.dirname(MEMORY_PATH);
64
+ fs_1.default.mkdirSync(dir, { recursive: true });
65
+ this.state.updatedAt = Date.now();
66
+ this.allSessions[this.sessionId] = this.state;
67
+ const tmp = MEMORY_PATH + '.tmp';
68
+ fs_1.default.writeFileSync(tmp, JSON.stringify(this.allSessions, null, 2));
69
+ fs_1.default.renameSync(tmp, MEMORY_PATH);
70
+ }
71
+ catch (e) {
72
+ console.error('[ConversationMemory] Save failed:', e.message);
73
+ }
74
+ }
75
+ // ── Session management ────────────────────────────────────────
76
+ setSession(sessionId) {
77
+ if (sessionId === this.sessionId)
78
+ return;
79
+ this.sessionId = sessionId;
80
+ // Load (or create fresh) state for this session
81
+ this.state = this.allSessions[sessionId] || this.freshState();
82
+ }
83
+ getSessions() {
84
+ return Object.keys(this.allSessions);
85
+ }
86
+ getSessionsSummary() {
87
+ return Object.entries(this.allSessions)
88
+ .map(([id, state]) => {
89
+ const firstMsg = state.exchanges.find(e => e.userMessage);
90
+ return {
91
+ id,
92
+ title: firstMsg ? firstMsg.userMessage.slice(0, 40) : 'Untitled',
93
+ timestamp: state.updatedAt,
94
+ messageCount: state.exchanges.length,
95
+ preview: firstMsg ? firstMsg.userMessage.slice(0, 80) : '',
96
+ };
97
+ })
98
+ .filter(s => s.messageCount > 0)
99
+ .sort((a, b) => b.timestamp - a.timestamp)
100
+ .slice(0, 30);
101
+ }
102
+ // Pull key facts from ALL sessions — useful for cross-session context
103
+ getCrossSessionFacts() {
104
+ const allFacts = [];
105
+ Object.values(this.allSessions).forEach(session => {
106
+ const f = session.facts;
107
+ if (f.lastFilesCreated?.length) {
108
+ allFacts.push(`Created: ${f.lastFilesCreated[f.lastFilesCreated.length - 1]}`);
109
+ }
110
+ if (f.lastSearchQueries?.length) {
111
+ allFacts.push(`Searched: "${f.lastSearchQueries[f.lastSearchQueries.length - 1]}"`);
112
+ }
113
+ if (f.mentionedEntities?.length) {
114
+ allFacts.push(`Topics: ${f.mentionedEntities.slice(0, 3).join(', ')}`);
115
+ }
116
+ });
117
+ return [...new Set(allFacts)].slice(0, 10).join('\n');
118
+ }
119
+ // ── Add messages ─────────────────────────────────────────────
120
+ addUserMessage(message) {
121
+ const resolved = this.resolveReferences(message);
122
+ // Sprint 22: redact secrets before persisting to semantic memory
123
+ const safeResolved = (0, secretScanner_1.scanAndRedact)(resolved);
124
+ semanticMemory_1.semanticMemory.add(safeResolved, 'exchange', ['user']);
125
+ return resolved; // return original (unredacted) for in-process use
126
+ }
127
+ addAssistantMessage(reply, metadata = {}) {
128
+ // Sprint 22: redact secrets before writing to disk
129
+ const safeReply = (0, secretScanner_1.scanAndRedact)(reply);
130
+ const lastExchange = this.state.exchanges[this.state.exchanges.length - 1];
131
+ if (lastExchange && !lastExchange.aiReply) {
132
+ lastExchange.aiReply = safeReply.slice(0, 2000);
133
+ lastExchange.toolsUsed = metadata.toolsUsed || [];
134
+ lastExchange.filesCreated = metadata.filesCreated || [];
135
+ lastExchange.searchQueries = metadata.searchQueries || [];
136
+ lastExchange.planId = metadata.planId;
137
+ }
138
+ else {
139
+ const ex = {
140
+ id: `ex_${Date.now()}`,
141
+ userMessage: '',
142
+ aiReply: safeReply.slice(0, 2000),
143
+ timestamp: Date.now(),
144
+ toolsUsed: metadata.toolsUsed || [],
145
+ filesCreated: metadata.filesCreated || [],
146
+ searchQueries: metadata.searchQueries || [],
147
+ planId: metadata.planId,
148
+ };
149
+ this.state.exchanges.push(ex);
150
+ }
151
+ // Keep only last 20 exchanges per session
152
+ if (this.state.exchanges.length > 20) {
153
+ this.state.exchanges = this.state.exchanges.slice(-20);
154
+ }
155
+ this.save();
156
+ // Index into shared semantic memory (using redacted copy)
157
+ semanticMemory_1.semanticMemory.add(safeReply.slice(0, 500), 'exchange', ['assistant']);
158
+ // Auto-extract entities and build graph from this exchange
159
+ entityGraph_1.entityGraph.extractAndAdd(safeReply, {
160
+ files: metadata?.filesCreated,
161
+ tools: metadata?.toolsUsed,
162
+ searchQuery: metadata?.searchQueries?.[0],
163
+ });
164
+ }
165
+ // Called at the start of processing each user message — records the user turn
166
+ recordUserTurn(resolvedMessage) {
167
+ // Sprint 22: redact secrets before writing to disk
168
+ const safeMessage = (0, secretScanner_1.scanAndRedact)(resolvedMessage);
169
+ const ex = {
170
+ id: `ex_${Date.now()}`,
171
+ userMessage: safeMessage.slice(0, 500),
172
+ aiReply: '', // filled in by addAssistantMessage
173
+ timestamp: Date.now(),
174
+ toolsUsed: [],
175
+ filesCreated: [],
176
+ searchQueries: [],
177
+ };
178
+ this.state.exchanges.push(ex);
179
+ this.save();
180
+ }
181
+ // ── Update facts from execution ───────────────────────────────
182
+ updateFromExecution(toolsUsed, filesCreated, searchQueries, planId) {
183
+ const facts = this.state.facts;
184
+ if (toolsUsed.length)
185
+ facts.lastToolsUsed = toolsUsed;
186
+ if (filesCreated.length)
187
+ facts.lastFilesCreated = filesCreated;
188
+ if (searchQueries.length)
189
+ facts.lastSearchQueries = searchQueries;
190
+ if (planId)
191
+ facts.lastPlanId = planId;
192
+ for (const f of filesCreated) {
193
+ if (!facts.preferredPaths.includes(f))
194
+ facts.preferredPaths.push(f);
195
+ }
196
+ if (facts.preferredPaths.length > 10) {
197
+ facts.preferredPaths = facts.preferredPaths.slice(-10);
198
+ }
199
+ for (const q of searchQueries) {
200
+ const matches = q.match(/\b[A-Z][a-zA-Z]{2,}\b/g) || [];
201
+ for (const m of matches) {
202
+ if (!facts.mentionedEntities.includes(m))
203
+ facts.mentionedEntities.push(m);
204
+ }
205
+ }
206
+ if (facts.mentionedEntities.length > 30) {
207
+ facts.mentionedEntities = facts.mentionedEntities.slice(-30);
208
+ }
209
+ this.save();
210
+ }
211
+ // ── Reference resolution ─────────────────────────────────────
212
+ resolveReferences(message) {
213
+ const facts = this.state.facts;
214
+ let resolved = message;
215
+ // Only replace "the file"/"that file" if NOT followed by an explicit file path
216
+ if (/\b(that file|the file|that document|that report|that script)\b(?!\s+[/\\]|\s+[A-Z]:)/i.test(resolved)) {
217
+ const lastFile = facts.lastFilesCreated[facts.lastFilesCreated.length - 1];
218
+ if (lastFile) {
219
+ resolved = resolved.replace(/\b(that file|the file|that document|that report|that script)\b(?!\s+[/\\]|\s+[A-Z]:)/gi, lastFile);
220
+ }
221
+ }
222
+ if (/\b(that search|those results|the results|that query)\b/i.test(resolved)) {
223
+ const lastQuery = facts.lastSearchQueries[facts.lastSearchQueries.length - 1];
224
+ if (lastQuery) {
225
+ resolved = resolved.replace(/\b(that search|those results|the results|that query)\b/gi, `"${lastQuery}"`);
226
+ }
227
+ }
228
+ return resolved;
229
+ }
230
+ // ── Context building for planner ─────────────────────────────
231
+ buildContext() {
232
+ const facts = this.state.facts;
233
+ const allExchanges = this.state.exchanges;
234
+ const recent = allExchanges.slice(-6);
235
+ const older = allExchanges.slice(0, -6);
236
+ const lastUserMsg = recent.filter(e => e.userMessage).slice(-1)[0]?.userMessage || '';
237
+ const lines = [];
238
+ // ── Key facts (files, searches, tools) ─────────────────────
239
+ if (facts.lastFilesCreated.length > 0) {
240
+ lines.push(`Recently created files: ${facts.lastFilesCreated.join(', ')}`);
241
+ }
242
+ if (facts.lastSearchQueries.length > 0) {
243
+ lines.push(`Recent searches: ${facts.lastSearchQueries.join(', ')}`);
244
+ }
245
+ if (facts.lastToolsUsed.length > 0) {
246
+ lines.push(`Last tools used: ${facts.lastToolsUsed.join(', ')}`);
247
+ }
248
+ if (facts.mentionedEntities.length > 0) {
249
+ lines.push(`Topics discussed: ${facts.mentionedEntities.slice(-10).join(', ')}`);
250
+ }
251
+ if (facts.preferredPaths.length > 0) {
252
+ lines.push(`User file paths: ${facts.preferredPaths.slice(-5).join(', ')}`);
253
+ }
254
+ // ── Older exchange compression ──────────────────────────────
255
+ // Exchanges beyond the last 6 are compressed to key facts only
256
+ if (older.length > 0) {
257
+ const olderFacts = older
258
+ .slice(-10) // max 10 older items to scan
259
+ .map(ex => {
260
+ const parts = [];
261
+ const src = [ex.userMessage || '', ex.aiReply || ''].join(' ');
262
+ // Extract file paths
263
+ const filePaths = src.match(/[A-Za-z]:\\[^\s"']+\.[a-z]{1,5}/g) || [];
264
+ parts.push(...filePaths.slice(0, 2));
265
+ // Extract URLs
266
+ const urls = src.match(/https?:\/\/[^\s"']+/g) || [];
267
+ parts.push(...urls.slice(0, 1));
268
+ // If nothing specific, use truncated user message
269
+ if (parts.length === 0 && ex.userMessage) {
270
+ parts.push(ex.userMessage.slice(0, 60));
271
+ }
272
+ return parts.join(', ');
273
+ })
274
+ .filter(Boolean);
275
+ if (olderFacts.length > 0) {
276
+ lines.push('');
277
+ lines.push(`Earlier this session: ${olderFacts.join(' | ')}`);
278
+ }
279
+ }
280
+ // ── Cross-session context ───────────────────────────────────
281
+ const crossSession = this.getCrossSessionFacts();
282
+ if (crossSession) {
283
+ lines.push('');
284
+ lines.push('CROSS-SESSION CONTEXT:');
285
+ crossSession.split('\n').forEach(l => lines.push(` ${l}`));
286
+ }
287
+ // ── Recent exchanges (verbatim, last 6) ─────────────────────
288
+ if (recent.length > 0) {
289
+ lines.push('');
290
+ lines.push('Recent exchanges:');
291
+ for (const ex of recent) {
292
+ if (ex.userMessage)
293
+ lines.push(` User: ${ex.userMessage.slice(0, 150)}`);
294
+ if (ex.aiReply)
295
+ lines.push(` Aiden: ${ex.aiReply.slice(0, 100)}`);
296
+ }
297
+ }
298
+ // ── Semantic memory — similar past exchanges ────────────────
299
+ if (lastUserMsg) {
300
+ const semanticMatches = semanticMemory_1.semanticMemory.searchText(lastUserMsg, 3);
301
+ if (semanticMatches.length > 0) {
302
+ lines.push('');
303
+ lines.push('SEMANTIC MEMORY (similar past exchanges):');
304
+ semanticMatches.forEach(m => lines.push(`- ${m.slice(0, 120)}`));
305
+ }
306
+ }
307
+ // ── Entity graph context ────────────────────────────────────
308
+ const graphContext = entityGraph_1.entityGraph.buildContextString(lastUserMsg);
309
+ if (graphContext) {
310
+ lines.push('');
311
+ lines.push(graphContext);
312
+ }
313
+ // Hard cap at 1200 chars to keep planner prompts lean
314
+ return lines.join('\n').slice(0, 1200);
315
+ }
316
+ // ── Accessors ─────────────────────────────────────────────────
317
+ /** Return the full ConversationState for a given session ID, or null if unknown. */
318
+ getSession(sessionId) {
319
+ return this.allSessions[sessionId] ?? null;
320
+ }
321
+ getRecentHistory() {
322
+ return this.state.exchanges.slice(-10);
323
+ }
324
+ getFacts() {
325
+ return this.state.facts;
326
+ }
327
+ // ── Clear (current session only) ──────────────────────────────
328
+ clear() {
329
+ this.state = this.freshState();
330
+ this.save();
331
+ }
332
+ }
333
+ exports.ConversationMemory = ConversationMemory;
334
+ exports.conversationMemory = new ConversationMemory();
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.costTracker = void 0;
44
+ // core/costTracker.ts — Token usage and cost tracking for every LLM call.
45
+ // Hooked into callLLM in agentLoop.ts.
46
+ // Background (system) costs are tracked separately from user budget.
47
+ const fs_1 = __importDefault(require("fs"));
48
+ const path_1 = __importDefault(require("path"));
49
+ const eventBus_1 = require("./eventBus");
50
+ // ── Pricing (per million tokens) ─────────────────────────────
51
+ const PRICING = {
52
+ 'groq': { input: 0, output: 0 },
53
+ 'gemini': { input: 0, output: 0 },
54
+ 'cerebras': { input: 0, output: 0 },
55
+ 'openrouter': { input: 0.14, output: 0.28 },
56
+ 'ollama': { input: 0, output: 0 },
57
+ 'nvidia': { input: 0, output: 0 },
58
+ 'cloudflare': { input: 0, output: 0 },
59
+ 'github': { input: 0, output: 0 },
60
+ };
61
+ // ── Paths ─────────────────────────────────────────────────────
62
+ const COST_DIR = path_1.default.join(process.cwd(), 'workspace', 'cost');
63
+ // ── CostTracker ───────────────────────────────────────────────
64
+ class CostTracker {
65
+ constructor() {
66
+ this.todayRecords = [];
67
+ this.lastDate = '';
68
+ this.budgetEnforced = false;
69
+ try {
70
+ fs_1.default.mkdirSync(COST_DIR, { recursive: true });
71
+ }
72
+ catch { }
73
+ this.refreshDay();
74
+ }
75
+ // ── Day management ─────────────────────────────────────────
76
+ dateKey() {
77
+ return new Date().toISOString().slice(0, 10);
78
+ }
79
+ logPath() {
80
+ return path_1.default.join(COST_DIR, `${this.dateKey()}.jsonl`);
81
+ }
82
+ refreshDay() {
83
+ const today = this.dateKey();
84
+ if (today === this.lastDate)
85
+ return;
86
+ this.lastDate = today;
87
+ this.budgetEnforced = false;
88
+ const p = this.logPath();
89
+ if (!fs_1.default.existsSync(p)) {
90
+ this.todayRecords = [];
91
+ return;
92
+ }
93
+ try {
94
+ this.todayRecords = fs_1.default.readFileSync(p, 'utf-8')
95
+ .trim().split('\n').filter(Boolean)
96
+ .map(l => { try {
97
+ return JSON.parse(l);
98
+ }
99
+ catch {
100
+ return null;
101
+ } })
102
+ .filter((r) => r !== null);
103
+ }
104
+ catch {
105
+ this.todayRecords = [];
106
+ }
107
+ }
108
+ // ── Main tracking call ─────────────────────────────────────
109
+ trackUsage(provider, model, inputTokens, outputTokens, traceId, isSystem = false) {
110
+ this.refreshDay();
111
+ const pricing = PRICING[provider] ?? { input: 0, output: 0 };
112
+ const costUSD = (inputTokens * pricing.input + outputTokens * pricing.output) / 1000000;
113
+ const record = {
114
+ ts: Date.now(),
115
+ provider,
116
+ model,
117
+ inputTokens,
118
+ outputTokens,
119
+ costUSD,
120
+ traceId,
121
+ isSystem,
122
+ };
123
+ this.todayRecords.push(record);
124
+ try {
125
+ fs_1.default.appendFileSync(this.logPath(), JSON.stringify(record) + '\n');
126
+ }
127
+ catch (e) {
128
+ console.error('[CostTracker] Write failed:', e.message);
129
+ }
130
+ // Budget enforcement — only for user calls, only trigger once per day
131
+ if (!isSystem && !this.budgetEnforced) {
132
+ const userTotal = this.getDailyUserCost();
133
+ const budget = this.getDailyBudget();
134
+ if (userTotal >= budget) {
135
+ this.budgetEnforced = true;
136
+ this.enforceBudgetCap(userTotal, budget);
137
+ }
138
+ }
139
+ // Emit event for dashboard
140
+ try {
141
+ eventBus_1.eventBus.emit('cost_update', this.getDailySummary());
142
+ }
143
+ catch { }
144
+ }
145
+ // ── Accessors ──────────────────────────────────────────────
146
+ getDailyBudget() {
147
+ try {
148
+ const cfgPath = path_1.default.join(process.cwd(), 'config', 'devos.config.json');
149
+ const raw = JSON.parse(fs_1.default.readFileSync(cfgPath, 'utf-8'));
150
+ return typeof raw.dailyBudgetUSD === 'number' ? raw.dailyBudgetUSD : 5.00;
151
+ }
152
+ catch {
153
+ return 5.00;
154
+ }
155
+ }
156
+ getDailyUserCost() {
157
+ this.refreshDay();
158
+ return this.todayRecords
159
+ .filter(r => !r.isSystem)
160
+ .reduce((s, r) => s + r.costUSD, 0);
161
+ }
162
+ getDailySystemCost() {
163
+ this.refreshDay();
164
+ return this.todayRecords
165
+ .filter(r => r.isSystem)
166
+ .reduce((s, r) => s + r.costUSD, 0);
167
+ }
168
+ getDailySummary() {
169
+ this.refreshDay();
170
+ const byProvider = {};
171
+ let totalUSD = 0, systemUSD = 0, userUSD = 0;
172
+ for (const r of this.todayRecords) {
173
+ byProvider[r.provider] = (byProvider[r.provider] ?? 0) + r.costUSD;
174
+ totalUSD += r.costUSD;
175
+ if (r.isSystem)
176
+ systemUSD += r.costUSD;
177
+ else
178
+ userUSD += r.costUSD;
179
+ }
180
+ return {
181
+ date: this.dateKey(),
182
+ totalUSD,
183
+ systemUSD,
184
+ userUSD,
185
+ byProvider,
186
+ };
187
+ }
188
+ getTraceTotal(traceId) {
189
+ this.refreshDay();
190
+ return this.todayRecords
191
+ .filter(r => r.traceId === traceId)
192
+ .reduce((s, r) => s + r.costUSD, 0);
193
+ }
194
+ formatUserCost() {
195
+ const usd = this.getDailyUserCost();
196
+ return `$${usd.toFixed(2)} today`;
197
+ }
198
+ // ── Budget enforcement ─────────────────────────────────────
199
+ enforceBudgetCap(userTotal, budget) {
200
+ console.warn(`[CostTracker] Daily budget cap $${budget} reached ($${userTotal.toFixed(4)} used) — switching to Ollama`);
201
+ // Switch routing to Ollama-only
202
+ try {
203
+ const configPath = path_1.default.join(process.cwd(), 'config', 'devos.config.json');
204
+ const raw = JSON.parse(fs_1.default.readFileSync(configPath, 'utf-8'));
205
+ raw.routing = { ...raw.routing, mode: 'manual' };
206
+ raw.model = { ...raw.model, active: 'ollama' };
207
+ fs_1.default.writeFileSync(configPath, JSON.stringify(raw, null, 2));
208
+ }
209
+ catch (e) {
210
+ console.error('[CostTracker] Failed to switch to Ollama:', e.message);
211
+ }
212
+ // Desktop notification — fire-and-forget
213
+ Promise.resolve().then(() => __importStar(require('./toolRegistry'))).then(({ executeTool }) => {
214
+ executeTool('notify', {
215
+ message: `DevOS daily budget cap ($${budget}) reached. Switched to Ollama to prevent overspending.`,
216
+ }).catch(() => { });
217
+ }).catch(() => { });
218
+ }
219
+ }
220
+ // ── Singleton ──────────────────────────────────────────────────
221
+ exports.costTracker = new CostTracker();