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,168 @@
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.taskStateManager = exports.TaskStateManager = void 0;
11
+ // core/taskState.ts — Persistent step-level task state.
12
+ // Enables crash recovery, idempotent execution, and token budgeting.
13
+ const fs_1 = __importDefault(require("fs"));
14
+ const path_1 = __importDefault(require("path"));
15
+ const TASKS_DIR = path_1.default.join(process.cwd(), 'workspace', 'tasks');
16
+ // ── TaskStateManager ───────────────────────────────────────────
17
+ class TaskStateManager {
18
+ create(taskId, goal, totalSteps, planId) {
19
+ const state = {
20
+ id: taskId,
21
+ goal,
22
+ planId,
23
+ status: 'running',
24
+ currentStep: 0,
25
+ totalSteps,
26
+ steps: [],
27
+ tokenUsage: 0,
28
+ tokenLimit: 50000,
29
+ createdAt: Date.now(),
30
+ updatedAt: Date.now(),
31
+ };
32
+ this.save(state);
33
+ return state;
34
+ }
35
+ load(taskId) {
36
+ try {
37
+ const statePath = path_1.default.join(TASKS_DIR, taskId, 'state.json');
38
+ if (!fs_1.default.existsSync(statePath))
39
+ return null;
40
+ return JSON.parse(fs_1.default.readFileSync(statePath, 'utf-8'));
41
+ }
42
+ catch {
43
+ return null;
44
+ }
45
+ }
46
+ save(state) {
47
+ try {
48
+ const taskDir = path_1.default.join(TASKS_DIR, state.id);
49
+ fs_1.default.mkdirSync(taskDir, { recursive: true });
50
+ state.updatedAt = Date.now();
51
+ // Atomic write — temp file then rename, avoids corruption on crash
52
+ const statePath = path_1.default.join(taskDir, 'state.json');
53
+ const tempPath = path_1.default.join(taskDir, 'state.tmp.json');
54
+ fs_1.default.writeFileSync(tempPath, JSON.stringify(state, null, 2));
55
+ fs_1.default.renameSync(tempPath, statePath);
56
+ }
57
+ catch (e) {
58
+ console.error(`[TaskState] Save failed for ${state.id}: ${e.message}`);
59
+ }
60
+ }
61
+ startStep(state, index, tool, input) {
62
+ const existing = state.steps.find(s => s.index === index);
63
+ if (!existing) {
64
+ state.steps.push({ index, tool, input, status: 'pending' });
65
+ }
66
+ state.currentStep = index;
67
+ this.save(state);
68
+ }
69
+ // NEVER overwrite a completed step — idempotency guard
70
+ completeStep(state, index, output, duration) {
71
+ const step = state.steps.find(s => s.index === index);
72
+ if (step && step.status === 'completed') {
73
+ console.log(`[TaskState] Step ${index} already completed — skipping overwrite`);
74
+ return;
75
+ }
76
+ if (step) {
77
+ step.status = 'completed';
78
+ step.output = output.slice(0, 2000); // cap stored output
79
+ step.duration = duration;
80
+ step.completedAt = Date.now();
81
+ }
82
+ // Estimate token usage — chars/4 is a reasonable approximation
83
+ state.tokenUsage += Math.ceil(output.length / 4);
84
+ this.save(state);
85
+ }
86
+ failStep(state, index, error) {
87
+ const step = state.steps.find(s => s.index === index);
88
+ if (step) {
89
+ step.status = 'failed';
90
+ step.error = error;
91
+ step.completedAt = Date.now();
92
+ }
93
+ this.save(state);
94
+ }
95
+ complete(state) {
96
+ state.status = 'completed';
97
+ state.completedAt = Date.now();
98
+ this.save(state);
99
+ }
100
+ fail(state, error) {
101
+ state.status = 'failed';
102
+ state.error = error;
103
+ state.completedAt = Date.now();
104
+ this.save(state);
105
+ }
106
+ isStepCompleted(state, index) {
107
+ const step = state.steps.find(s => s.index === index);
108
+ return step?.status === 'completed';
109
+ }
110
+ isOverBudget(state) {
111
+ return state.tokenUsage >= state.tokenLimit;
112
+ }
113
+ // Find the first incomplete step index — used to find resume point after crash
114
+ getResumePoint(state) {
115
+ for (let i = 0; i < state.totalSteps; i++) {
116
+ const step = state.steps.find(s => s.index === i);
117
+ if (!step || step.status !== 'completed')
118
+ return i;
119
+ }
120
+ return state.totalSteps; // all steps done
121
+ }
122
+ getRunningTasks() {
123
+ const running = [];
124
+ try {
125
+ if (!fs_1.default.existsSync(TASKS_DIR))
126
+ return [];
127
+ const dirs = fs_1.default.readdirSync(TASKS_DIR).filter(d => d.startsWith('task_'));
128
+ for (const dir of dirs) {
129
+ const state = this.load(dir);
130
+ if (state && state.status === 'running')
131
+ running.push(state);
132
+ }
133
+ }
134
+ catch { }
135
+ return running;
136
+ }
137
+ listAll() {
138
+ try {
139
+ if (!fs_1.default.existsSync(TASKS_DIR))
140
+ return [];
141
+ return fs_1.default.readdirSync(TASKS_DIR)
142
+ .filter(d => d.startsWith('task_'))
143
+ .sort().reverse().slice(0, 20)
144
+ .map(dir => {
145
+ const state = this.load(dir);
146
+ if (!state)
147
+ return null;
148
+ return {
149
+ id: state.id,
150
+ goal: state.goal.slice(0, 80),
151
+ status: state.status,
152
+ currentStep: state.currentStep,
153
+ totalSteps: state.totalSteps,
154
+ tokenUsage: state.tokenUsage,
155
+ tokenLimit: state.tokenLimit,
156
+ createdAt: state.createdAt,
157
+ updatedAt: state.updatedAt,
158
+ };
159
+ })
160
+ .filter(Boolean);
161
+ }
162
+ catch {
163
+ return [];
164
+ }
165
+ }
166
+ }
167
+ exports.TaskStateManager = TaskStateManager;
168
+ exports.taskStateManager = new TaskStateManager();
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.TelegramBot = void 0;
8
+ exports.registerTelegramCallbacks = registerTelegramCallbacks;
9
+ // core/telegramBot.ts — Telegram bot integration for Aiden.
10
+ // Uses native fetch (Node 18+). No external dependencies.
11
+ const callbackSystem_1 = require("./callbackSystem");
12
+ // ── TelegramBot ────────────────────────────────────────────────
13
+ class TelegramBot {
14
+ constructor(config) {
15
+ this.offset = 0;
16
+ this.polling = false;
17
+ this.token = config.botToken;
18
+ this.baseUrl = `https://api.telegram.org/bot${this.token}`;
19
+ this.allowedChats = new Set(config.allowedChatIds);
20
+ }
21
+ // ── Send a message (auto-chunks at 4000 chars) ──────────────
22
+ async sendMessage(chatId, text) {
23
+ const chunks = this.chunkMessage(text, 4000);
24
+ for (const chunk of chunks) {
25
+ try {
26
+ await fetch(`${this.baseUrl}/sendMessage`, {
27
+ method: 'POST',
28
+ headers: { 'Content-Type': 'application/json' },
29
+ body: JSON.stringify({
30
+ chat_id: chatId,
31
+ text: chunk,
32
+ parse_mode: 'Markdown',
33
+ }),
34
+ });
35
+ }
36
+ catch (e) {
37
+ console.error('[Telegram] sendMessage error:', e.message);
38
+ }
39
+ }
40
+ }
41
+ // ── Show typing indicator ───────────────────────────────────
42
+ async sendTyping(chatId) {
43
+ try {
44
+ await fetch(`${this.baseUrl}/sendChatAction`, {
45
+ method: 'POST',
46
+ headers: { 'Content-Type': 'application/json' },
47
+ body: JSON.stringify({ chat_id: chatId, action: 'typing' }),
48
+ });
49
+ }
50
+ catch { }
51
+ }
52
+ // ── Long-poll for updates ───────────────────────────────────
53
+ async poll() {
54
+ try {
55
+ const response = await fetch(`${this.baseUrl}/getUpdates?offset=${this.offset}&timeout=30`);
56
+ const data = await response.json();
57
+ if (data.ok && data.result.length > 0) {
58
+ this.offset = data.result[data.result.length - 1].update_id + 1;
59
+ return data.result;
60
+ }
61
+ }
62
+ catch (error) {
63
+ console.error('[Telegram] Poll error:', error.message);
64
+ }
65
+ return [];
66
+ }
67
+ // ── Main polling loop ───────────────────────────────────────
68
+ async startPolling(onMessage) {
69
+ if (this.polling)
70
+ return;
71
+ this.polling = true;
72
+ console.log('[Telegram] Bot started polling');
73
+ while (this.polling) {
74
+ const updates = await this.poll();
75
+ for (const update of updates) {
76
+ if (!update.message?.text)
77
+ continue;
78
+ const chatId = String(update.message.chat.id);
79
+ const text = update.message.text;
80
+ // Security: only respond to allowed chat IDs
81
+ // If allowedChatIds is empty, respond to everyone (first-time setup)
82
+ if (this.allowedChats.size > 0 && !this.allowedChats.has(chatId)) {
83
+ console.log(`[Telegram] Ignored message from unauthorized chat: ${chatId}`);
84
+ await this.sendMessage(chatId, '⚠️ Unauthorized. Add your chat ID to Aiden Settings → Channels → Telegram.');
85
+ continue;
86
+ }
87
+ console.log(`[Telegram] Message from ${chatId}: ${text.substring(0, 50)}`);
88
+ await this.sendTyping(chatId);
89
+ try {
90
+ const response = await onMessage(chatId, text);
91
+ await this.sendMessage(chatId, response);
92
+ }
93
+ catch (error) {
94
+ console.error('[Telegram] Error processing message:', error.message);
95
+ await this.sendMessage(chatId, '❌ Something went wrong processing your message. Try again.');
96
+ }
97
+ }
98
+ }
99
+ }
100
+ // ── Stop polling ────────────────────────────────────────────
101
+ stop() {
102
+ this.polling = false;
103
+ console.log('[Telegram] Bot stopped');
104
+ }
105
+ // ── Chunk long messages ─────────────────────────────────────
106
+ chunkMessage(text, maxLength) {
107
+ if (text.length <= maxLength)
108
+ return [text];
109
+ const chunks = [];
110
+ let remaining = text;
111
+ while (remaining.length > 0) {
112
+ if (remaining.length <= maxLength) {
113
+ chunks.push(remaining);
114
+ break;
115
+ }
116
+ // Prefer splitting at a newline
117
+ let splitAt = remaining.lastIndexOf('\n', maxLength);
118
+ if (splitAt < maxLength * 0.5) {
119
+ // No good newline — try a space
120
+ splitAt = remaining.lastIndexOf(' ', maxLength);
121
+ }
122
+ if (splitAt < maxLength * 0.5) {
123
+ // No good split point — hard cut
124
+ splitAt = maxLength;
125
+ }
126
+ chunks.push(remaining.substring(0, splitAt));
127
+ remaining = remaining.substring(splitAt).trim();
128
+ }
129
+ return chunks;
130
+ }
131
+ }
132
+ exports.TelegramBot = TelegramBot;
133
+ // ── Callback integration ──────────────────────────────────────────────────────
134
+ /**
135
+ * Register a persistent callback subscriber that sends a typing indicator to
136
+ * the relevant Telegram chat whenever a tool starts executing in any session
137
+ * that originated from Telegram.
138
+ *
139
+ * The gateway routes Telegram messages with sessionId `telegram_telegram_{chatId}`,
140
+ * so we extract the chatId from that pattern and call sendTyping().
141
+ *
142
+ * @returns An unsubscribe function — call it when the bot is stopped.
143
+ */
144
+ function registerTelegramCallbacks(bot) {
145
+ return callbackSystem_1.callbacks.on('tool_start', async (payload) => {
146
+ const prefix = 'telegram_telegram_';
147
+ if (payload.sessionId.startsWith(prefix)) {
148
+ const chatId = payload.sessionId.slice(prefix.length);
149
+ await bot.sendTyping(chatId);
150
+ }
151
+ });
152
+ }
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ //
7
+ // core/todoManager.ts — Per-session in-memory task list.
8
+ //
9
+ // Intentionally ephemeral: todos reset on process restart.
10
+ // Use aiden.todo.* or the /todo CLI command to manage items.
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.addTodo = addTodo;
13
+ exports.completeTodo = completeTodo;
14
+ exports.removeTodo = removeTodo;
15
+ exports.clearTodos = clearTodos;
16
+ exports.listTodos = listTodos;
17
+ exports.getTodo = getTodo;
18
+ exports.formatTodoList = formatTodoList;
19
+ let todos = [];
20
+ let seq = 1;
21
+ // ── CRUD ──────────────────────────────────────────────────────────────────────
22
+ function addTodo(text, priority = 'normal') {
23
+ const item = {
24
+ id: String(seq++),
25
+ text: text.trim(),
26
+ done: false,
27
+ priority,
28
+ createdAt: new Date().toISOString(),
29
+ };
30
+ todos.push(item);
31
+ return item;
32
+ }
33
+ function completeTodo(id) {
34
+ const item = todos.find(t => t.id === id);
35
+ if (!item)
36
+ return null;
37
+ item.done = true;
38
+ item.doneAt = new Date().toISOString();
39
+ return item;
40
+ }
41
+ function removeTodo(id) {
42
+ const before = todos.length;
43
+ todos = todos.filter(t => t.id !== id);
44
+ return todos.length < before;
45
+ }
46
+ function clearTodos() {
47
+ const count = todos.length;
48
+ todos = [];
49
+ return count;
50
+ }
51
+ function listTodos(filter = 'all') {
52
+ if (filter === 'done')
53
+ return todos.filter(t => t.done);
54
+ if (filter === 'pending')
55
+ return todos.filter(t => !t.done);
56
+ return [...todos];
57
+ }
58
+ function getTodo(id) {
59
+ return todos.find(t => t.id === id);
60
+ }
61
+ // ── Formatting helper ─────────────────────────────────────────────────────────
62
+ function formatTodoList(items) {
63
+ if (!items.length)
64
+ return 'No items.';
65
+ return items.map(t => {
66
+ const status = t.done ? '✓' : '○';
67
+ const pri = t.priority !== 'normal' ? ` [${t.priority}]` : '';
68
+ return `[${t.id}] ${status}${pri} ${t.text}`;
69
+ }).join('\n');
70
+ }
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.lev = lev;
8
+ exports.normalize = normalize;
9
+ exports.repairToolName = repairToolName;
10
+ // ── Levenshtein distance ──────────────────────────────────────────────────────
11
+ function lev(a, b) {
12
+ const m = a.length;
13
+ const n = b.length;
14
+ const dp = Array.from({ length: m + 1 }, (_, i) => Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)));
15
+ for (let i = 1; i <= m; i++) {
16
+ for (let j = 1; j <= n; j++) {
17
+ dp[i][j] = a[i - 1] === b[j - 1]
18
+ ? dp[i - 1][j - 1]
19
+ : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
20
+ }
21
+ }
22
+ return dp[m][n];
23
+ }
24
+ // ── Normalization ─────────────────────────────────────────────────────────────
25
+ // Strip common hallucination suffixes/patterns that LLMs append to tool names.
26
+ const SUFFIX_PATTERNS = [
27
+ /_\d+$/, // web_search_1, file_write_2
28
+ /\.(exec|run|call|tool)$/i, // file_write.exec
29
+ /_(exec|run|call|tool|v\d+)$/i, // shell_exec_run, web_search_v2
30
+ ];
31
+ const CAMEL_TO_SNAKE_RE = /([A-Z])/g;
32
+ function normalize(name) {
33
+ let s = name.trim();
34
+ // camelCase → snake_case: getStocks → get_stocks, deepResearch → deep_research
35
+ s = s.replace(CAMEL_TO_SNAKE_RE, '_$1').toLowerCase().replace(/^_/, '');
36
+ // strip known hallucination suffixes
37
+ for (const pattern of SUFFIX_PATTERNS) {
38
+ s = s.replace(pattern, '');
39
+ }
40
+ return s;
41
+ }
42
+ // ── Main export ───────────────────────────────────────────────────────────────
43
+ /**
44
+ * Try to map a hallucinated/corrupted tool name to the closest valid tool.
45
+ *
46
+ * @param name - The tool name the LLM produced
47
+ * @param validTools - Authoritative list of valid tool names
48
+ * @returns A RepairResult if a match within threshold was found; null otherwise
49
+ */
50
+ function repairToolName(name, validTools) {
51
+ if (validTools.includes(name))
52
+ return null; // already valid — nothing to do
53
+ const normalized = normalize(name);
54
+ // Exact match after normalization (e.g. getStocks → get_stocks)
55
+ if (validTools.includes(normalized)) {
56
+ return { original: name, repaired: normalized, distance: 0 };
57
+ }
58
+ // Fuzzy match: find the closest valid tool within the edit-distance threshold
59
+ // Threshold scales with name length: max(2, floor(len * 0.3))
60
+ const threshold = Math.max(2, Math.floor(normalized.length * 0.3));
61
+ let best = null;
62
+ for (const valid of validTools) {
63
+ const d = lev(normalized, valid);
64
+ if (d <= threshold && (!best || d < best.distance)) {
65
+ best = { repaired: valid, distance: d };
66
+ }
67
+ }
68
+ if (!best)
69
+ return null;
70
+ return { original: name, repaired: best.repaired, distance: best.distance };
71
+ }