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.
- package/LICENSE +661 -0
- package/README.md +465 -0
- package/config/devos.config.json +186 -0
- package/config/hardware.json +9 -0
- package/config/model-selection.json +7 -0
- package/config/setup-complete.json +20 -0
- package/dist/api/routes/computerUse.js +112 -0
- package/dist/api/server.js +6870 -0
- package/dist/bin/npx-init.js +71 -0
- package/dist/coordination/commandGate.js +115 -0
- package/dist/coordination/livePulse.js +127 -0
- package/dist/core/agentLoop.js +2718 -0
- package/dist/core/agentShield.js +231 -0
- package/dist/core/aidenIdentity.js +215 -0
- package/dist/core/aidenPersonality.js +166 -0
- package/dist/core/aidenSdk.js +374 -0
- package/dist/core/asyncTasks.js +82 -0
- package/dist/core/auditTrail.js +61 -0
- package/dist/core/auxiliaryClient.js +114 -0
- package/dist/core/bgLLM.js +108 -0
- package/dist/core/bm25.js +68 -0
- package/dist/core/callbackSystem.js +64 -0
- package/dist/core/channels/adapter.js +6 -0
- package/dist/core/channels/discord.js +173 -0
- package/dist/core/channels/email.js +253 -0
- package/dist/core/channels/imessage.js +164 -0
- package/dist/core/channels/manager.js +96 -0
- package/dist/core/channels/signal.js +140 -0
- package/dist/core/channels/slack.js +139 -0
- package/dist/core/channels/twilio.js +144 -0
- package/dist/core/channels/webhook.js +186 -0
- package/dist/core/channels/whatsapp.js +185 -0
- package/dist/core/clarifyBus.js +75 -0
- package/dist/core/codeInterpreter.js +82 -0
- package/dist/core/computerControl.js +439 -0
- package/dist/core/conversationMemory.js +334 -0
- package/dist/core/costTracker.js +221 -0
- package/dist/core/cronManager.js +217 -0
- package/dist/core/deepKB.js +77 -0
- package/dist/core/doctor.js +279 -0
- package/dist/core/dreamEngine.js +334 -0
- package/dist/core/entityGraph.js +169 -0
- package/dist/core/eventBus.js +16 -0
- package/dist/core/evolutionAnalyzer.js +153 -0
- package/dist/core/executionLoop.js +309 -0
- package/dist/core/executor.js +224 -0
- package/dist/core/failureAnalyzer.js +166 -0
- package/dist/core/fastPathExpansion.js +82 -0
- package/dist/core/faultEngine.js +106 -0
- package/dist/core/featureGates.js +70 -0
- package/dist/core/fileIngestion.js +113 -0
- package/dist/core/gateway.js +97 -0
- package/dist/core/goalTracker.js +75 -0
- package/dist/core/growthEngine.js +168 -0
- package/dist/core/hardwareDetector.js +98 -0
- package/dist/core/hooks.js +45 -0
- package/dist/core/httpKeepalive.js +46 -0
- package/dist/core/hybridSearch.js +101 -0
- package/dist/core/importers.js +164 -0
- package/dist/core/instinctSystem.js +223 -0
- package/dist/core/knowledgeBase.js +351 -0
- package/dist/core/learningMemory.js +121 -0
- package/dist/core/lessonsBrowser.js +125 -0
- package/dist/core/licenseManager.js +399 -0
- package/dist/core/logBuffer.js +85 -0
- package/dist/core/machineId.js +87 -0
- package/dist/core/mcpClient.js +442 -0
- package/dist/core/memoryDistiller.js +165 -0
- package/dist/core/memoryExtractor.js +212 -0
- package/dist/core/memoryIds.js +213 -0
- package/dist/core/memoryPreamble.js +113 -0
- package/dist/core/memoryQuery.js +136 -0
- package/dist/core/memoryRecall.js +140 -0
- package/dist/core/memoryStrategy.js +201 -0
- package/dist/core/messageValidator.js +85 -0
- package/dist/core/modelDiscovery.js +108 -0
- package/dist/core/modelRouter.js +118 -0
- package/dist/core/morningBriefing.js +203 -0
- package/dist/core/multiGoalValidator.js +51 -0
- package/dist/core/parallelExecutor.js +43 -0
- package/dist/core/passiveSkillObserver.js +204 -0
- package/dist/core/paths.js +57 -0
- package/dist/core/patternDetector.js +83 -0
- package/dist/core/planResponseRepair.js +64 -0
- package/dist/core/planTool.js +111 -0
- package/dist/core/playwrightBridge.js +356 -0
- package/dist/core/pluginSystem.js +121 -0
- package/dist/core/privateMode.js +85 -0
- package/dist/core/reactLoop.js +156 -0
- package/dist/core/recipeEngine.js +166 -0
- package/dist/core/responseCache.js +128 -0
- package/dist/core/runSandbox.js +132 -0
- package/dist/core/sandboxRunner.js +200 -0
- package/dist/core/scheduler.js +543 -0
- package/dist/core/secretScanner.js +49 -0
- package/dist/core/semanticMemory.js +223 -0
- package/dist/core/sessionMemory.js +259 -0
- package/dist/core/sessionRouter.js +91 -0
- package/dist/core/sessionSearch.js +163 -0
- package/dist/core/setupWizard.js +225 -0
- package/dist/core/skillImporter.js +303 -0
- package/dist/core/skillLibrary.js +144 -0
- package/dist/core/skillLoader.js +471 -0
- package/dist/core/skillTeacher.js +352 -0
- package/dist/core/skillValidator.js +210 -0
- package/dist/core/skillWriter.js +384 -0
- package/dist/core/slashAsTool.js +226 -0
- package/dist/core/spawnManager.js +197 -0
- package/dist/core/statusVerbs.js +43 -0
- package/dist/core/swarmManager.js +109 -0
- package/dist/core/taskQueue.js +119 -0
- package/dist/core/taskRecovery.js +128 -0
- package/dist/core/taskState.js +168 -0
- package/dist/core/telegramBot.js +152 -0
- package/dist/core/todoManager.js +70 -0
- package/dist/core/toolNameRepair.js +71 -0
- package/dist/core/toolRegistry.js +2730 -0
- package/dist/core/tools/calendarTool.js +98 -0
- package/dist/core/tools/companyFilingsTool.js +98 -0
- package/dist/core/tools/gmailTool.js +87 -0
- package/dist/core/tools/marketDataTool.js +135 -0
- package/dist/core/tools/socialResearchTool.js +121 -0
- package/dist/core/truthCheck.js +57 -0
- package/dist/core/updateChecker.js +74 -0
- package/dist/core/userCognitionProfile.js +238 -0
- package/dist/core/userProfile.js +341 -0
- package/dist/core/version.js +5 -0
- package/dist/core/visionAnalyze.js +161 -0
- package/dist/core/voice/audio.js +187 -0
- package/dist/core/voice/stt.js +226 -0
- package/dist/core/voice/tts.js +310 -0
- package/dist/core/voiceInput.js +118 -0
- package/dist/core/voiceOutput.js +130 -0
- package/dist/core/webSearch.js +326 -0
- package/dist/core/workflowTracker.js +72 -0
- package/dist/core/workspaceMemory.js +54 -0
- package/dist/core/youtubeTranscript.js +224 -0
- package/dist/integrations/computerUse/apiRegistry.js +113 -0
- package/dist/integrations/computerUse/screenAgent.js +203 -0
- package/dist/integrations/computerUse/visionLoop.js +296 -0
- package/dist/memory/memoryLayers.js +143 -0
- package/dist/providers/boa.js +93 -0
- package/dist/providers/cerebras.js +70 -0
- package/dist/providers/custom.js +89 -0
- package/dist/providers/gemini.js +82 -0
- package/dist/providers/groq.js +92 -0
- package/dist/providers/index.js +149 -0
- package/dist/providers/nvidia.js +70 -0
- package/dist/providers/ollama.js +99 -0
- package/dist/providers/openrouter.js +74 -0
- package/dist/providers/router.js +497 -0
- package/dist/providers/types.js +6 -0
- package/dist/security/browserVault.js +129 -0
- package/dist/security/dataGuard.js +89 -0
- package/dist/tools/eonetTool.js +72 -0
- package/dist/types/computerUse.js +2 -0
- package/dist/types/executor.js +2 -0
- package/dist-bundle/cli.js +357859 -0
- 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();
|