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,85 @@
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.setSessionPrivate = setSessionPrivate;
8
+ exports.clearSessionPrivate = clearSessionPrivate;
9
+ exports.toggleSessionPrivate = toggleSessionPrivate;
10
+ exports.isSessionPrivate = isSessionPrivate;
11
+ exports.markNextTurnPrivate = markNextTurnPrivate;
12
+ exports.isCurrentTurnPrivate = isCurrentTurnPrivate;
13
+ exports.clearTurnPrivate = clearTurnPrivate;
14
+ // core/privateMode.ts — Phase 5: Per-turn and per-session memory opacity toggle.
15
+ //
16
+ // When private mode is active for a session, all memory writes are suppressed:
17
+ // - memoryLayers.write()
18
+ // - sessionMemory.addExchange()
19
+ // - memoryExtractor.extractFromSession()
20
+ // - conversationMemory.addAssistantMessage() (skipped at call site)
21
+ //
22
+ // Two granularities:
23
+ // Session-level — ALL turns in the session are private until explicitly toggled off.
24
+ // Turn-level — Only the NEXT turn is private; flag auto-clears after that turn.
25
+ //
26
+ // Usage (server.ts):
27
+ // if (!isCurrentTurnPrivate(sessionId)) {
28
+ // sessionMemory.addExchange(...)
29
+ // memoryLayers.write(...)
30
+ // }
31
+ // clearTurnPrivate(sessionId) // always call after turn completes
32
+ //
33
+ // Usage (CLI, /private command):
34
+ // const nowPrivate = toggleSessionPrivate(sessionId)
35
+ // console.log(nowPrivate ? '🔒 Private mode ON' : '🔓 Private mode OFF')
36
+ // ── State ─────────────────────────────────────────────────────────────────────
37
+ /** Sessions where every turn is private until explicitly cleared. */
38
+ const sessionPrivate = new Set();
39
+ /** Sessions where only the NEXT single turn is private (auto-clears). */
40
+ const nextTurnPrivate = new Set();
41
+ // ── Session-level API ─────────────────────────────────────────────────────────
42
+ /** Mark all future turns in `sessionId` as private. */
43
+ function setSessionPrivate(sessionId) {
44
+ sessionPrivate.add(sessionId);
45
+ }
46
+ /** Remove session-level private flag (turns private mode off for the session). */
47
+ function clearSessionPrivate(sessionId) {
48
+ sessionPrivate.delete(sessionId);
49
+ }
50
+ /**
51
+ * Toggle session-level private mode.
52
+ * @returns true when private mode is now ON, false when now OFF.
53
+ */
54
+ function toggleSessionPrivate(sessionId) {
55
+ if (sessionPrivate.has(sessionId)) {
56
+ sessionPrivate.delete(sessionId);
57
+ return false;
58
+ }
59
+ sessionPrivate.add(sessionId);
60
+ return true;
61
+ }
62
+ /** True when the entire session is set to private. */
63
+ function isSessionPrivate(sessionId) {
64
+ return sessionPrivate.has(sessionId);
65
+ }
66
+ // ── Turn-level API ────────────────────────────────────────────────────────────
67
+ /** Mark only the NEXT turn for `sessionId` as private. Auto-clears after that turn. */
68
+ function markNextTurnPrivate(sessionId) {
69
+ nextTurnPrivate.add(sessionId);
70
+ }
71
+ /**
72
+ * Returns true when the current turn should suppress all memory writes.
73
+ * Checks both session-level and turn-level flags.
74
+ */
75
+ function isCurrentTurnPrivate(sessionId) {
76
+ return sessionPrivate.has(sessionId) || nextTurnPrivate.has(sessionId);
77
+ }
78
+ /**
79
+ * Clear the one-turn private flag for `sessionId`.
80
+ * Call this after every turn completes, regardless of private state —
81
+ * it is a no-op when the flag is not set.
82
+ */
83
+ function clearTurnPrivate(sessionId) {
84
+ nextTurnPrivate.delete(sessionId);
85
+ }
@@ -0,0 +1,156 @@
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.runReActLoop = runReActLoop;
8
+ // core/reactLoop.ts — ReAct (Reasoning + Acting) agent loop.
9
+ // Iterates: Thought → Action → Observation until FINISH or maxIterations.
10
+ const agentLoop_1 = require("./agentLoop");
11
+ const toolRegistry_1 = require("./toolRegistry");
12
+ const livePulse_1 = require("../coordination/livePulse");
13
+ // ── ReAct system prompt ────────────────────────────────────────
14
+ const REACT_SYSTEM = `You are DevOS ReAct agent. You solve goals iteratively using a Thought→Action→Observation loop.
15
+
16
+ At each step, output ONLY valid JSON with this shape:
17
+ {
18
+ "reasoning": "what you're thinking",
19
+ "action": "tool_name or FINISH",
20
+ "actionInput": { ...tool args },
21
+ "finalAnswer": "only when action is FINISH — the complete answer"
22
+ }
23
+
24
+ Available tools:
25
+ - web_search { "query": "..." }
26
+ - fetch_url { "url": "https://..." }
27
+ - file_read { "path": "..." }
28
+ - file_write { "path": "...", "content": "..." }
29
+ - run_python { "script": "..." }
30
+ - run_node { "code": "..." }
31
+ - shell_exec { "command": "..." }
32
+ - system_info {}
33
+ - deep_research { "topic": "..." }
34
+ - get_stocks { "market": "NSE", "type": "gainers" }
35
+
36
+ Rules:
37
+ 1. Think step-by-step. Use observations from previous steps.
38
+ 2. When you have enough information to answer, set action to FINISH and provide finalAnswer.
39
+ 3. Output ONLY valid JSON — no markdown, no prose outside the JSON.
40
+ 4. If a tool fails, adapt your approach in the next thought.`;
41
+ // ── Parse LLM output to Thought ────────────────────────────────
42
+ function parseThought(raw) {
43
+ try {
44
+ const cleaned = raw
45
+ .replace(/```json\s*/g, '')
46
+ .replace(/```\s*/g, '')
47
+ .trim();
48
+ const match = cleaned.match(/\{[\s\S]*\}/);
49
+ if (!match)
50
+ return null;
51
+ const parsed = JSON.parse(match[0]);
52
+ return {
53
+ reasoning: String(parsed.reasoning || ''),
54
+ action: String(parsed.action || 'FINISH'),
55
+ actionInput: parsed.actionInput && typeof parsed.actionInput === 'object'
56
+ ? parsed.actionInput
57
+ : {},
58
+ finalAnswer: parsed.finalAnswer ? String(parsed.finalAnswer) : undefined,
59
+ };
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ }
65
+ // ── Build context string from prior steps ──────────────────────
66
+ function buildContext(goal, steps) {
67
+ let ctx = `Goal: ${goal}\n\n`;
68
+ for (let i = 0; i < steps.length; i++) {
69
+ const s = steps[i];
70
+ ctx += `Step ${i + 1}:\n`;
71
+ ctx += ` Thought: ${s.thought.reasoning}\n`;
72
+ ctx += ` Action: ${s.thought.action}(${JSON.stringify(s.thought.actionInput)})\n`;
73
+ ctx += ` Observation: ${s.observation.success ? 'OK' : 'ERROR'} — ${s.observation.result.slice(0, 400)}\n\n`;
74
+ }
75
+ ctx += 'What is your next thought and action? Output JSON only.';
76
+ return ctx;
77
+ }
78
+ // ── Main ReAct loop ────────────────────────────────────────────
79
+ async function runReActLoop(goal, apiKey, model, provider, onStep, maxIterations = 5) {
80
+ const steps = [];
81
+ let answer = '';
82
+ livePulse_1.livePulse.act('ReAct', `Starting: ${goal.slice(0, 60)}`);
83
+ for (let iter = 0; iter < maxIterations; iter++) {
84
+ // Build prompt from system + accumulated context
85
+ const contextPrompt = `${REACT_SYSTEM}\n\n${buildContext(goal, steps)}`;
86
+ // Call LLM
87
+ let raw = '';
88
+ try {
89
+ raw = await (0, agentLoop_1.callLLM)(contextPrompt, apiKey, model, provider);
90
+ }
91
+ catch (e) {
92
+ console.warn(`[ReAct] LLM call failed at iter ${iter}: ${e.message}`);
93
+ break;
94
+ }
95
+ if (!raw || raw.trim().length === 0) {
96
+ console.warn(`[ReAct] Empty LLM response at iter ${iter}`);
97
+ break;
98
+ }
99
+ // Parse thought
100
+ const thought = parseThought(raw);
101
+ if (!thought) {
102
+ console.warn(`[ReAct] Could not parse thought at iter ${iter}: ${raw.slice(0, 100)}`);
103
+ break;
104
+ }
105
+ livePulse_1.livePulse.act('ReAct', `Iter ${iter + 1}: ${thought.action}`);
106
+ // FINISH — return final answer
107
+ if (thought.action === 'FINISH') {
108
+ answer = thought.finalAnswer || thought.reasoning || 'Done.';
109
+ // Record a terminal step with a synthetic observation
110
+ const terminalStep = {
111
+ thought,
112
+ observation: { tool: 'FINISH', result: answer, success: true },
113
+ };
114
+ steps.push(terminalStep);
115
+ onStep(terminalStep);
116
+ break;
117
+ }
118
+ // Execute the tool
119
+ let toolResult = '';
120
+ let toolSuccess = false;
121
+ try {
122
+ const result = await (0, toolRegistry_1.executeTool)(thought.action, thought.actionInput);
123
+ toolResult = typeof result.output === 'string'
124
+ ? result.output
125
+ : JSON.stringify(result.output || result);
126
+ toolSuccess = result.success !== false;
127
+ }
128
+ catch (e) {
129
+ toolResult = `Tool error: ${e.message}`;
130
+ toolSuccess = false;
131
+ }
132
+ const step = {
133
+ thought,
134
+ observation: {
135
+ tool: thought.action,
136
+ result: toolResult,
137
+ success: toolSuccess,
138
+ },
139
+ };
140
+ steps.push(step);
141
+ onStep(step);
142
+ console.log(`[ReAct] Iter ${iter + 1}: ${thought.action} → ${toolSuccess ? 'OK' : 'ERR'} (${toolResult.slice(0, 80)})`);
143
+ }
144
+ // If loop exhausted without FINISH, summarise what was gathered
145
+ if (!answer && steps.length > 0) {
146
+ const lastObs = steps[steps.length - 1].observation;
147
+ answer = lastObs.success
148
+ ? lastObs.result.slice(0, 800)
149
+ : `Could not complete the goal after ${steps.length} steps. Last error: ${lastObs.result.slice(0, 200)}`;
150
+ }
151
+ if (!answer) {
152
+ answer = 'I was unable to complete the task.';
153
+ }
154
+ livePulse_1.livePulse.done('ReAct', `Finished in ${steps.length} step(s)`);
155
+ return { answer, steps };
156
+ }
@@ -0,0 +1,166 @@
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.loadAllRecipes = loadAllRecipes;
11
+ exports.executeRecipe = executeRecipe;
12
+ exports.matchRecipe = matchRecipe;
13
+ // core/recipeEngine.ts — YAML workflow definitions with typed
14
+ // params, explicit tool chains, conditions, and retry logic.
15
+ const fs_1 = __importDefault(require("fs"));
16
+ const path_1 = __importDefault(require("path"));
17
+ const js_yaml_1 = __importDefault(require("js-yaml"));
18
+ const toolRegistry_1 = require("./toolRegistry");
19
+ // ── Loader ────────────────────────────────────────────────────
20
+ function loadRecipe(filePath) {
21
+ try {
22
+ const content = fs_1.default.readFileSync(filePath, 'utf8');
23
+ const recipe = js_yaml_1.default.load(content);
24
+ if (!recipe.name || !recipe.steps || recipe.steps.length === 0) {
25
+ console.log(`[Recipe] Invalid recipe: ${filePath} — missing name or steps`);
26
+ return null;
27
+ }
28
+ return recipe;
29
+ }
30
+ catch {
31
+ console.log(`[Recipe] Failed to parse: ${filePath}`);
32
+ return null;
33
+ }
34
+ }
35
+ function loadAllRecipes() {
36
+ const recipeDirs = [
37
+ path_1.default.join(process.cwd(), 'workspace', 'recipes'),
38
+ path_1.default.join(process.cwd(), 'recipes'),
39
+ ];
40
+ const recipes = [];
41
+ for (const dir of recipeDirs) {
42
+ if (!fs_1.default.existsSync(dir))
43
+ continue;
44
+ const files = fs_1.default.readdirSync(dir).filter(f => f.endsWith('.yaml') || f.endsWith('.yml'));
45
+ for (const file of files) {
46
+ const recipe = loadRecipe(path_1.default.join(dir, file));
47
+ if (recipe)
48
+ recipes.push(recipe);
49
+ }
50
+ }
51
+ if (recipes.length > 0) {
52
+ console.log(`[Recipe] Loaded ${recipes.length} recipes`);
53
+ }
54
+ return recipes;
55
+ }
56
+ // ── Template resolution ───────────────────────────────────────
57
+ function resolveTemplate(template, params, stepResults) {
58
+ return template.replace(/\{\{(\w+\.[\w.]+)\}\}/g, (match, dotPath) => {
59
+ const parts = dotPath.split('.');
60
+ if (parts[0] === 'params') {
61
+ return String(params[parts[1]] ?? match);
62
+ }
63
+ if (parts[0] === 'steps') {
64
+ const stepResult = stepResults[parts[1]];
65
+ if (stepResult && parts[2]) {
66
+ return String(stepResult[parts[2]] ?? stepResult.output ?? match);
67
+ }
68
+ return String(stepResult?.output ?? match);
69
+ }
70
+ return match;
71
+ });
72
+ }
73
+ function resolveArgs(args, params, stepResults) {
74
+ const resolved = {};
75
+ for (const [key, value] of Object.entries(args)) {
76
+ resolved[key] = typeof value === 'string'
77
+ ? resolveTemplate(value, params, stepResults)
78
+ : value;
79
+ }
80
+ return resolved;
81
+ }
82
+ // ── Condition evaluator ───────────────────────────────────────
83
+ function evaluateCondition(condition, stepResults) {
84
+ try {
85
+ const resolved = condition.replace(/steps\.(\w+)\.(\w+)/g, (_full, stepId, prop) => {
86
+ const result = stepResults[stepId];
87
+ if (!result)
88
+ return 'undefined';
89
+ return JSON.stringify(result[prop] ?? result.output);
90
+ });
91
+ // eslint-disable-next-line no-new-func
92
+ return new Function(`return ${resolved}`)();
93
+ }
94
+ catch {
95
+ return true; // default to true if condition can't be evaluated
96
+ }
97
+ }
98
+ // ── Executor ──────────────────────────────────────────────────
99
+ async function executeRecipe(recipe, params) {
100
+ console.log(`[Recipe] Executing: ${recipe.name}`);
101
+ // Apply defaults for missing optional params
102
+ for (const [name, def] of Object.entries(recipe.params || {})) {
103
+ if (!(name in params) && 'default' in def) {
104
+ params[name] = def.default;
105
+ }
106
+ }
107
+ const stepResults = {};
108
+ for (const step of recipe.steps) {
109
+ // Evaluate condition gate
110
+ if (step.condition) {
111
+ try {
112
+ if (!evaluateCondition(step.condition, stepResults)) {
113
+ console.log(`[Recipe] Skipping ${step.id}: condition not met`);
114
+ stepResults[step.id] = { skipped: true };
115
+ continue;
116
+ }
117
+ }
118
+ catch { }
119
+ }
120
+ const resolvedArgs = resolveArgs(step.args || {}, params, stepResults);
121
+ console.log(`[Recipe] Step ${step.id}: ${step.tool}`);
122
+ const maxAttempts = step.retries ?? 1;
123
+ let result = null;
124
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
125
+ try {
126
+ result = await (0, toolRegistry_1.executeTool)(step.tool, resolvedArgs);
127
+ if (result?.success)
128
+ break;
129
+ }
130
+ catch (err) {
131
+ if (attempt === maxAttempts - 1) {
132
+ if (step.onFail === 'abort') {
133
+ return { success: false, output: `Recipe aborted at step ${step.id}: ${err}` };
134
+ }
135
+ // 'skip' or no onFail — mark skipped and continue
136
+ result = { skipped: true, error: String(err), output: '' };
137
+ }
138
+ }
139
+ }
140
+ stepResults[step.id] = result;
141
+ }
142
+ const output = resolveTemplate(recipe.output || '', params, stepResults);
143
+ return { success: true, output };
144
+ }
145
+ function matchRecipe(message, recipes) {
146
+ for (const recipe of recipes) {
147
+ for (const trigger of (recipe.trigger || [])) {
148
+ // Extract param names from {{param}} placeholders
149
+ const paramNames = (trigger.match(/\{\{(\w+)\}\}/g) || [])
150
+ .map(p => p.replace(/[{}]/g, ''));
151
+ // Build a regex by replacing {{param}} with capture groups
152
+ const escaped = trigger.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
153
+ const pattern = escaped.replace(/\\\{\\\{(\w+)\\\}\\\}/g, '(.+)');
154
+ const match = message.match(new RegExp(`^${pattern}$`, 'i'));
155
+ if (match) {
156
+ console.log(`[Recipe] Matched: ${recipe.name} via trigger: "${trigger}"`);
157
+ const params = {};
158
+ paramNames.forEach((name, i) => {
159
+ params[name] = match[i + 1]?.trim();
160
+ });
161
+ return { recipe, params };
162
+ }
163
+ }
164
+ }
165
+ return null;
166
+ }
@@ -0,0 +1,128 @@
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.responseCache = exports.ResponseCache = void 0;
11
+ // core/responseCache.ts — TTL-based response cache for tool results.
12
+ // Tools with defined TTLs get their outputs cached and reused within
13
+ // the TTL window. Side-effectful tools (file_write, shell_exec, etc.)
14
+ // are explicitly excluded via NO_CACHE_TOOLS.
15
+ const fs_1 = __importDefault(require("fs"));
16
+ const path_1 = __importDefault(require("path"));
17
+ const crypto_1 = __importDefault(require("crypto"));
18
+ const CACHE_PATH = path_1.default.join(process.cwd(), 'workspace', 'cache', 'response-cache.json');
19
+ // TTL per tool type (milliseconds)
20
+ const TOOL_TTL = {
21
+ system_info: 30 * 1000, // 30 seconds — hardware changes rarely
22
+ get_market_data: 5 * 60 * 1000, // 5 minutes — prices update frequently
23
+ get_company_info: 60 * 60 * 1000, // 1 hour — fundamentals change slowly
24
+ get_stocks: 5 * 60 * 1000, // 5 minutes
25
+ social_research: 30 * 60 * 1000, // 30 minutes
26
+ web_search: 10 * 60 * 1000, // 10 minutes
27
+ fetch_url: 15 * 60 * 1000, // 15 minutes
28
+ fetch_page: 15 * 60 * 1000, // 15 minutes
29
+ };
30
+ // Tools that should NEVER be cached (side-effectful or time-sensitive)
31
+ const NO_CACHE_TOOLS = new Set([
32
+ 'file_write', 'file_read', 'shell_exec', 'run_python',
33
+ 'run_node', 'screenshot', 'notify', 'open_browser',
34
+ 'browser_click', 'browser_type', 'mouse_click', 'keyboard_type',
35
+ 'code_interpreter_python', 'code_interpreter_node',
36
+ ]);
37
+ class ResponseCache {
38
+ constructor() {
39
+ this.cache = new Map();
40
+ this.load();
41
+ // Cleanup expired entries every 5 minutes
42
+ setInterval(() => this.cleanup(), 5 * 60 * 1000);
43
+ }
44
+ // ── Key hashing ───────────────────────────────────────────────
45
+ hashKey(tool, input) {
46
+ const str = `${tool}:${JSON.stringify(input, Object.keys(input).sort())}`;
47
+ return crypto_1.default.createHash('md5').update(str).digest('hex');
48
+ }
49
+ // ── Cache read ────────────────────────────────────────────────
50
+ get(tool, input) {
51
+ if (NO_CACHE_TOOLS.has(tool))
52
+ return null;
53
+ const key = this.hashKey(tool, input);
54
+ const entry = this.cache.get(key);
55
+ if (!entry)
56
+ return null;
57
+ if (Date.now() > entry.expiresAt) {
58
+ this.cache.delete(key);
59
+ return null;
60
+ }
61
+ entry.hitCount++;
62
+ console.log(`[Cache] HIT: ${tool} (hits: ${entry.hitCount})`);
63
+ return entry.output;
64
+ }
65
+ // ── Cache write ───────────────────────────────────────────────
66
+ set(tool, input, output) {
67
+ if (NO_CACHE_TOOLS.has(tool))
68
+ return;
69
+ const ttl = TOOL_TTL[tool];
70
+ if (!ttl)
71
+ return; // Only cache tools with a defined TTL
72
+ const key = this.hashKey(tool, input);
73
+ this.cache.set(key, {
74
+ key,
75
+ output,
76
+ tool,
77
+ input,
78
+ createdAt: Date.now(),
79
+ expiresAt: Date.now() + ttl,
80
+ hitCount: 0,
81
+ });
82
+ this.save();
83
+ }
84
+ // ── Stats ─────────────────────────────────────────────────────
85
+ getStats() {
86
+ const tools = {};
87
+ let totalHits = 0;
88
+ for (const entry of this.cache.values()) {
89
+ tools[entry.tool] = (tools[entry.tool] || 0) + 1;
90
+ totalHits += entry.hitCount;
91
+ }
92
+ return { totalEntries: this.cache.size, totalHits, tools };
93
+ }
94
+ // ── Clear all ─────────────────────────────────────────────────
95
+ clear() {
96
+ this.cache.clear();
97
+ this.save();
98
+ }
99
+ // ── Expired entry cleanup ─────────────────────────────────────
100
+ cleanup() {
101
+ const now = Date.now();
102
+ for (const [key, entry] of this.cache) {
103
+ if (now > entry.expiresAt)
104
+ this.cache.delete(key);
105
+ }
106
+ this.save();
107
+ }
108
+ // ── Persistence ───────────────────────────────────────────────
109
+ load() {
110
+ try {
111
+ if (!fs_1.default.existsSync(CACHE_PATH))
112
+ return;
113
+ const data = JSON.parse(fs_1.default.readFileSync(CACHE_PATH, 'utf-8'));
114
+ this.cache = new Map(Object.entries(data));
115
+ this.cleanup(); // Remove expired entries on load
116
+ }
117
+ catch { }
118
+ }
119
+ save() {
120
+ try {
121
+ fs_1.default.mkdirSync(path_1.default.dirname(CACHE_PATH), { recursive: true });
122
+ fs_1.default.writeFileSync(CACHE_PATH, JSON.stringify(Object.fromEntries(this.cache), null, 2));
123
+ }
124
+ catch { }
125
+ }
126
+ }
127
+ exports.ResponseCache = ResponseCache;
128
+ exports.responseCache = new ResponseCache();
@@ -0,0 +1,132 @@
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.runInSandbox = runInSandbox;
8
+ // core/runSandbox.ts — Node.js VM-based sandbox for the ▲ run tool.
9
+ //
10
+ // Injects the Aiden SDK (`aiden` namespace) into a fresh VM context.
11
+ // All tool calls are tracked. Timeout and max-tool-call limits enforced.
12
+ // No new dependencies — uses built-in `vm` module only.
13
+ const vm_1 = require("vm");
14
+ const aidenSdk_1 = require("./aidenSdk");
15
+ // ── Sandbox ───────────────────────────────────────────────────────────────────
16
+ const DEFAULT_TIMEOUT = 30000; // 30 s
17
+ const DEFAULT_MAX_TOOL_CALLS = 20;
18
+ async function runInSandbox(code, options = {}) {
19
+ const timeout = options.timeout ?? DEFAULT_TIMEOUT;
20
+ const maxToolCalls = options.maxToolCalls ?? DEFAULT_MAX_TOOL_CALLS;
21
+ const start = Date.now();
22
+ const outputLog = [];
23
+ const toolCalls = [];
24
+ // ── Build SDK runtime with tracking ───────────────────────────────────────
25
+ const sdk = (0, aidenSdk_1.buildSdkRuntime)((toolName, args) => {
26
+ if (toolCalls.length >= maxToolCalls) {
27
+ throw new Error(`Tool call limit exceeded (max ${maxToolCalls}). Aborting.`);
28
+ }
29
+ const callStart = Date.now();
30
+ // We push after the fact — duration set to 0 here, patched in wrapper below
31
+ toolCalls.push({ tool: toolName, args, durationMs: 0 });
32
+ const idx = toolCalls.length - 1;
33
+ // Patch the duration after the call completes (via a post-hook approach)
34
+ const origTime = callStart;
35
+ // We'll update durationMs via the wrapper in makeTrackedSdk
36
+ void origTime; // suppress unused warning; timing done differently below
37
+ void idx;
38
+ });
39
+ // ── Patch SDK to record timing per-call ───────────────────────────────────
40
+ const trackedSdk = patchSdkTiming(sdk, toolCalls, maxToolCalls);
41
+ // ── Sandboxed console ─────────────────────────────────────────────────────
42
+ const sandboxConsole = {
43
+ log: (...a) => outputLog.push(a.map(String).join(' ')),
44
+ warn: (...a) => outputLog.push('[warn] ' + a.map(String).join(' ')),
45
+ error: (...a) => outputLog.push('[error] ' + a.map(String).join(' ')),
46
+ info: (...a) => outputLog.push(a.map(String).join(' ')),
47
+ };
48
+ // ── VM context — minimal globals ─────────────────────────────────────────
49
+ const ctx = (0, vm_1.createContext)({
50
+ aiden: trackedSdk,
51
+ console: sandboxConsole,
52
+ JSON,
53
+ Math,
54
+ Date,
55
+ parseInt,
56
+ parseFloat,
57
+ isNaN,
58
+ isFinite,
59
+ String,
60
+ Number,
61
+ Boolean,
62
+ Array,
63
+ Object,
64
+ Promise,
65
+ setTimeout,
66
+ clearTimeout,
67
+ setInterval,
68
+ clearInterval,
69
+ });
70
+ // ── Wrap user code in async IIFE ─────────────────────────────────────────
71
+ const wrappedCode = `
72
+ (async () => {
73
+ ${code}
74
+ })()
75
+ `;
76
+ try {
77
+ const script = new vm_1.Script(wrappedCode);
78
+ const resultPromise = script.runInContext(ctx, { timeout: Math.min(timeout, 5000) });
79
+ // The script.runInContext timeout only applies to sync execution.
80
+ // For async, we race with a wall-clock timeout.
81
+ const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error(`Sandbox timeout after ${timeout}ms`)), timeout));
82
+ const finalValue = await Promise.race([resultPromise, timeoutPromise]);
83
+ return {
84
+ success: true,
85
+ output: outputLog,
86
+ result: finalValue,
87
+ toolCalls,
88
+ durationMs: Date.now() - start,
89
+ };
90
+ }
91
+ catch (err) {
92
+ return {
93
+ success: false,
94
+ output: outputLog,
95
+ error: err?.message ?? String(err),
96
+ toolCalls,
97
+ durationMs: Date.now() - start,
98
+ };
99
+ }
100
+ }
101
+ // ── Timing patcher ────────────────────────────────────────────────────────────
102
+ /**
103
+ * Walks the SDK object tree and wraps every async function to record
104
+ * actual call duration in the toolCalls array.
105
+ */
106
+ function patchSdkTiming(sdkNode, toolCalls, maxToolCalls) {
107
+ if (typeof sdkNode === 'function') {
108
+ return async (...args) => {
109
+ if (toolCalls.length >= maxToolCalls) {
110
+ throw new Error(`Tool call limit exceeded (max ${maxToolCalls}). Aborting.`);
111
+ }
112
+ const t0 = Date.now();
113
+ try {
114
+ return await sdkNode(...args);
115
+ }
116
+ finally {
117
+ // Find the last entry that was pushed by the inner onToolCall handler
118
+ const last = toolCalls[toolCalls.length - 1];
119
+ if (last)
120
+ last.durationMs = Date.now() - t0;
121
+ }
122
+ };
123
+ }
124
+ if (typeof sdkNode === 'object' && sdkNode !== null) {
125
+ const patched = {};
126
+ for (const [k, v] of Object.entries(sdkNode)) {
127
+ patched[k] = patchSdkTiming(v, toolCalls, maxToolCalls);
128
+ }
129
+ return patched;
130
+ }
131
+ return sdkNode;
132
+ }