aiden-runtime 3.19.6 → 3.19.8
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/README.md +1 -1
- package/dist/api/server.js +88 -35
- package/dist/coordination/livePulse.js +0 -6
- package/dist/core/agentLoop.js +8 -6
- package/dist/core/aidenPersonality.js +20 -3
- package/dist/core/protectedContext.js +15 -2
- package/dist/core/skillLoader.js +10 -7
- package/dist/core/skillTeacher.js +18 -5
- package/dist/core/version.js +1 -1
- package/dist-bundle/cli.js +56 -31
- package/dist-bundle/index.js +131 -52
- package/package.json +1 -1
- package/scripts/postinstall.js +12 -0
package/README.md
CHANGED
package/dist/api/server.js
CHANGED
|
@@ -401,6 +401,47 @@ function initWorkspaceDefaults() {
|
|
|
401
401
|
fs.copyFileSync(permTemplate, permTarget);
|
|
402
402
|
console.log('[init] Created workspace/permissions.yaml from template');
|
|
403
403
|
}
|
|
404
|
+
// C21: Copy SOUL.md from template if not present (Ollama identity)
|
|
405
|
+
const soulTarget = path.join(WORKSPACE_ROOT, 'workspace', 'SOUL.md');
|
|
406
|
+
const soulTemplate = path.join(WORKSPACE_ROOT, 'workspace-templates', 'SOUL.md');
|
|
407
|
+
if (!fs.existsSync(soulTarget) && fs.existsSync(soulTemplate)) {
|
|
408
|
+
fs.copyFileSync(soulTemplate, soulTarget);
|
|
409
|
+
console.log('[init] Created workspace/SOUL.md from template');
|
|
410
|
+
}
|
|
411
|
+
// C22: Copy bundled starter skills from workspace-templates/ on first boot.
|
|
412
|
+
// Mirrors the SOUL.md pattern above. Idempotent — skips if skills already exist.
|
|
413
|
+
const skillTemplateSrc = path.join(WORKSPACE_ROOT, 'workspace-templates', 'skills');
|
|
414
|
+
const skillDst = path.join(WORKSPACE_ROOT, 'workspace', 'skills', 'learned');
|
|
415
|
+
if (fs.existsSync(skillTemplateSrc)) {
|
|
416
|
+
const hasExisting = (() => {
|
|
417
|
+
try {
|
|
418
|
+
return fs.readdirSync(skillDst, { withFileTypes: true })
|
|
419
|
+
.some(e => e.isDirectory() && fs.existsSync(path.join(skillDst, e.name, 'SKILL.md')));
|
|
420
|
+
}
|
|
421
|
+
catch {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
})();
|
|
425
|
+
if (!hasExisting) {
|
|
426
|
+
let copied = 0;
|
|
427
|
+
try {
|
|
428
|
+
const entries = fs.readdirSync(skillTemplateSrc, { withFileTypes: true }).filter(e => e.isDirectory());
|
|
429
|
+
for (const entry of entries) {
|
|
430
|
+
const from = path.join(skillTemplateSrc, entry.name);
|
|
431
|
+
const to = path.join(skillDst, entry.name);
|
|
432
|
+
if (!fs.existsSync(to)) {
|
|
433
|
+
fs.cpSync(from, to, { recursive: true });
|
|
434
|
+
copied++;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
catch (e) {
|
|
439
|
+
console.warn(`[init] Skill template copy error: ${e.message}`);
|
|
440
|
+
}
|
|
441
|
+
if (copied > 0)
|
|
442
|
+
console.log(`[init] Copied ${copied} starter skills from templates`);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
404
445
|
}
|
|
405
446
|
initWorkspaceDefaults();
|
|
406
447
|
// ── Knowledge upload — multer + progress tracking ─────────────
|
|
@@ -791,16 +832,18 @@ function createApiServer() {
|
|
|
791
832
|
/are you just a pre.{0,10}trained/i,
|
|
792
833
|
];
|
|
793
834
|
if (capabilityPatterns.some(p => p.test(message))) {
|
|
794
|
-
|
|
835
|
+
const toolCount = Object.keys(toolRegistry_2.TOOL_REGISTRY).length;
|
|
836
|
+
const skillCount = skillLoader_1.skillLoader.loadAll().length;
|
|
837
|
+
const memStats = semanticMemory_1.semanticMemory.getStats();
|
|
838
|
+
const entityStats = entityGraph_1.entityGraph.getStats();
|
|
839
|
+
fastReply(`I have ${toolCount} tools and ${skillCount} active skills.\n\n` +
|
|
795
840
|
'I am NOT a static pre-trained model. I have active living systems:\n' +
|
|
796
841
|
'• **Skill Teacher** — promotes repeated successful patterns to reusable skills\n' +
|
|
797
842
|
'• **Instinct System** — micro-behaviors that strengthen with use\n' +
|
|
798
|
-
|
|
843
|
+
`• **Semantic Memory** — ${memStats.total} memories, ${entityStats.nodes}-node entity graph across sessions\n` +
|
|
799
844
|
'• **Growth Engine** — tracks failures, learns, improves over time\n' +
|
|
800
845
|
'• **Night Mode** — consolidates knowledge during idle periods\n' +
|
|
801
|
-
'• **XP & Leveling** — gains experience and levels up
|
|
802
|
-
'Tools include: web_search, deep_research, file_write/read, shell_exec, run_python, ' +
|
|
803
|
-
'open_browser, screenshot, manage_goals, manage_memories, git_commit, and 33 more.');
|
|
846
|
+
'• **XP & Leveling** — gains experience and levels up');
|
|
804
847
|
return;
|
|
805
848
|
}
|
|
806
849
|
// ── Fast “running locally” answer ──────────────────────────
|
|
@@ -1249,10 +1292,9 @@ function createApiServer() {
|
|
|
1249
1292
|
const fullMemoryCtx = memoryContext + proactiveMemory;
|
|
1250
1293
|
const plan = await (0, agentLoop_1.planWithLLM)(resolvedMessage, history, plannerKey, plannerModel, plannerProv, fullMemoryCtx);
|
|
1251
1294
|
if (!plan.requires_execution || plan.plan.length === 0) {
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
else {
|
|
1295
|
+
// C21: Always route through streamChat for full identity injection.
|
|
1296
|
+
// direct_response from planner has no Aiden identity context.
|
|
1297
|
+
{
|
|
1256
1298
|
await streamChat(resolvedMessage, history, userName, provider, activeModel, apiName, (data) => {
|
|
1257
1299
|
const d = data;
|
|
1258
1300
|
if (d.token)
|
|
@@ -1596,20 +1638,11 @@ function createApiServer() {
|
|
|
1596
1638
|
// ── NO EXECUTION NEEDED — PURE CHAT ─────────────────────
|
|
1597
1639
|
if (!plan.requires_execution || plan.plan.length === 0) {
|
|
1598
1640
|
let fullReply = '';
|
|
1599
|
-
//
|
|
1600
|
-
// direct_response from the planner has no
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
const words = plan.direct_response.split(' ');
|
|
1605
|
-
for (const word of words) {
|
|
1606
|
-
send({ token: word + ' ', done: false, provider: apiName });
|
|
1607
|
-
await new Promise(r => setTimeout(r, 10));
|
|
1608
|
-
}
|
|
1609
|
-
}
|
|
1610
|
-
else {
|
|
1611
|
-
await streamChat(resolvedMessage, history, userName, provider, activeModel, apiName, send, sessionId);
|
|
1612
|
-
}
|
|
1641
|
+
// C21: Always route through streamChat which has full SOUL/identity injection.
|
|
1642
|
+
// direct_response from the planner has no Aiden identity, tool list, or honesty
|
|
1643
|
+
// rules — it will fabricate or deny capabilities. Slight latency tradeoff (~1-3s)
|
|
1644
|
+
// for honesty on every response.
|
|
1645
|
+
await streamChat(resolvedMessage, history, userName, provider, activeModel, apiName, send, sessionId);
|
|
1613
1646
|
(0, router_1.incrementUsage)(apiName);
|
|
1614
1647
|
send({ done: true, provider: apiName });
|
|
1615
1648
|
res.end();
|
|
@@ -5701,16 +5734,36 @@ function startupCheck() {
|
|
|
5701
5734
|
function startApiServer(portArg) {
|
|
5702
5735
|
// ── Redirect all diagnostic output to stderr ─────────────────────────────
|
|
5703
5736
|
// The CLI writes the streaming response to process.stdout character-by-character.
|
|
5704
|
-
//
|
|
5705
|
-
//
|
|
5706
|
-
//
|
|
5707
|
-
//
|
|
5708
|
-
//
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5737
|
+
// ── C23: Level-aware log gate ──────────────────────────────────
|
|
5738
|
+
// Levels: debug=0, info=1, warn=2, error=3, silent=4
|
|
5739
|
+
// Default: 'warn' in CLI mode (AIDEN_CLI_MODE=1), 'info' otherwise.
|
|
5740
|
+
// Users opt in to verbose: AIDEN_LOG_LEVEL=debug npx aiden-os
|
|
5741
|
+
// Full logger rewrite is v3.20 Investigation C scope.
|
|
5742
|
+
const _LOG_LEVELS = {
|
|
5743
|
+
debug: 0, info: 1, warn: 2, error: 3, silent: 4,
|
|
5744
|
+
};
|
|
5745
|
+
const _cliMode = process.env.AIDEN_CLI_MODE === '1';
|
|
5746
|
+
const _defaultLvl = _cliMode ? 'warn' : 'info';
|
|
5747
|
+
const _envLvl = (process.env.AIDEN_LOG_LEVEL || _defaultLvl).toLowerCase();
|
|
5748
|
+
const _minLevel = _LOG_LEVELS[_envLvl] ?? _LOG_LEVELS.warn;
|
|
5749
|
+
const _bracketRe = /^\[[\w$:]+\]/;
|
|
5750
|
+
function _gatedLog(level, ...args) {
|
|
5751
|
+
if (level >= _minLevel) {
|
|
5752
|
+
process.stderr.write(args.map(String).join(' ') + '\n');
|
|
5753
|
+
return;
|
|
5754
|
+
}
|
|
5755
|
+
// Below threshold: suppress bracket-prefixed diagnostic lines.
|
|
5756
|
+
// Non-prefixed console.log (user-facing output) passes through.
|
|
5757
|
+
const first = typeof args[0] === 'string' ? args[0] : '';
|
|
5758
|
+
if (_bracketRe.test(first))
|
|
5759
|
+
return;
|
|
5760
|
+
process.stderr.write(args.map(String).join(' ') + '\n');
|
|
5761
|
+
}
|
|
5762
|
+
console.log = (...args) => _gatedLog(_LOG_LEVELS.info, ...args);
|
|
5763
|
+
console.info = (...args) => _gatedLog(_LOG_LEVELS.info, ...args);
|
|
5764
|
+
// console.warn always writes — warnings indicate real issues users should see.
|
|
5765
|
+
console.warn = (...args) => process.stderr.write(args.map(String).join(' ') + '\n');
|
|
5766
|
+
// console.error left untouched — already targets stderr
|
|
5714
5767
|
// Read port from config/api.json with sensible fallback.
|
|
5715
5768
|
// Host defaults to 127.0.0.1 (loopback only) for security.
|
|
5716
5769
|
// Set AIDEN_HOST=0.0.0.0 to expose on all interfaces (e.g. headless/WSL2).
|
|
@@ -6583,7 +6636,7 @@ HARD RULES — never violate:
|
|
|
6583
6636
|
- Never mention Pega, BlueWinston, Gaude Digital, or any third-party product by name
|
|
6584
6637
|
- Never say you can't access the internet (you have web_search) or can't create files (you have file_write)
|
|
6585
6638
|
- Never fabricate capabilities: no graphic design, video production, or music generation
|
|
6586
|
-
- Never list 250+ skills — you have
|
|
6639
|
+
- Never list 250+ skills — you have ${Object.keys(toolRegistry_2.TOOL_REGISTRY).length} real tools and ${skillLoader_1.skillLoader.loadAll().length} active skills
|
|
6587
6640
|
- For errors: explain what failed and what to try next
|
|
6588
6641
|
- If you don't know something: say "I don't know"
|
|
6589
6642
|
- Direct and concise: 1–3 sentences for simple results; more only when output is rich
|
|
@@ -6591,7 +6644,7 @@ HARD RULES — never violate:
|
|
|
6591
6644
|
IDENTITY — you are NOT a static pre-trained model. You have active living systems:
|
|
6592
6645
|
- Skill Teacher: detects repeated successful patterns and promotes them to reusable skills automatically
|
|
6593
6646
|
- Instinct System: develops micro-behaviors that strengthen with use and fade without reinforcement
|
|
6594
|
-
- Semantic Memory: remembers
|
|
6647
|
+
- Semantic Memory: remembers across sessions (${semanticMemory_1.semanticMemory.getStats().total} memories, ${entityGraph_1.entityGraph.getStats().nodes}-node entity graph)
|
|
6595
6648
|
- Night Mode: consolidates and organizes knowledge during idle periods
|
|
6596
6649
|
- Pattern Detector: identifies recurring usage habits and adapts
|
|
6597
6650
|
- Growth Engine: tracks failures, learns from them, improves over time
|
|
@@ -43,7 +43,6 @@ class LivePulse extends events_1.EventEmitter {
|
|
|
43
43
|
// ── Public methods — all wrapped in try-catch so they NEVER throw ──
|
|
44
44
|
act(agent, message, missionId) {
|
|
45
45
|
try {
|
|
46
|
-
console.log(`[${agent}] ${message}`);
|
|
47
46
|
this.emit_event({ type: 'act', agent, message, timestamp: Date.now(), missionId });
|
|
48
47
|
}
|
|
49
48
|
catch {
|
|
@@ -52,7 +51,6 @@ class LivePulse extends events_1.EventEmitter {
|
|
|
52
51
|
}
|
|
53
52
|
done(agent, message, missionId) {
|
|
54
53
|
try {
|
|
55
|
-
console.log(`[${agent}] ✓ ${message}`);
|
|
56
54
|
this.emit_event({ type: 'done', agent, message, timestamp: Date.now(), missionId });
|
|
57
55
|
}
|
|
58
56
|
catch {
|
|
@@ -71,7 +69,6 @@ class LivePulse extends events_1.EventEmitter {
|
|
|
71
69
|
}
|
|
72
70
|
warn(agent, message, missionId) {
|
|
73
71
|
try {
|
|
74
|
-
console.warn(`[${agent}] ⚠ ${message}`);
|
|
75
72
|
this.emit_event({ type: 'warn', agent, message, timestamp: Date.now(), missionId });
|
|
76
73
|
}
|
|
77
74
|
catch {
|
|
@@ -80,7 +77,6 @@ class LivePulse extends events_1.EventEmitter {
|
|
|
80
77
|
}
|
|
81
78
|
info(agent, message, missionId) {
|
|
82
79
|
try {
|
|
83
|
-
console.log(`[${agent}] ℹ ${message}`);
|
|
84
80
|
this.emit_event({ type: 'info', agent, message, timestamp: Date.now(), missionId });
|
|
85
81
|
}
|
|
86
82
|
catch {
|
|
@@ -89,7 +85,6 @@ class LivePulse extends events_1.EventEmitter {
|
|
|
89
85
|
}
|
|
90
86
|
thinking(agent, message, missionId) {
|
|
91
87
|
try {
|
|
92
|
-
console.log(`[${agent}] 💭 ${message}`);
|
|
93
88
|
this.emit_event({ type: 'thinking', agent, message, timestamp: Date.now(), missionId });
|
|
94
89
|
}
|
|
95
90
|
catch {
|
|
@@ -101,7 +96,6 @@ class LivePulse extends events_1.EventEmitter {
|
|
|
101
96
|
const message = output
|
|
102
97
|
? `${toolName}: ${command} → ${output.slice(0, 120)}`
|
|
103
98
|
: `${toolName}: ${command}`;
|
|
104
|
-
console.log(`[${agent}] 🔧 ${message}`);
|
|
105
99
|
this.emit_event({
|
|
106
100
|
type: 'tool',
|
|
107
101
|
agent,
|
package/dist/core/agentLoop.js
CHANGED
|
@@ -2319,7 +2319,7 @@ async function executePlan(plan, onStep, onPhaseChange, existingState, replanApi
|
|
|
2319
2319
|
const executedTools = results.map(r => r.tool);
|
|
2320
2320
|
const totalDuration = results.reduce((s, r) => s + (r.duration || 0), 0);
|
|
2321
2321
|
const anyFailed = results.some(r => !r.success);
|
|
2322
|
-
if (allSucceeded && executedTools.length > 0) {
|
|
2322
|
+
if (allSucceeded && executedTools.length > 0 && skillTeacher_1.SkillTeacher.hasCapacity()) {
|
|
2323
2323
|
// GrowthEngine — record success for gap-resolution tracking
|
|
2324
2324
|
growthEngine_1.growthEngine.logSuccess(plan.goal, executedTools);
|
|
2325
2325
|
try {
|
|
@@ -2395,7 +2395,7 @@ function resolvePreviousOutput(input, stepOutputs, currentStep) {
|
|
|
2395
2395
|
return resolved;
|
|
2396
2396
|
}
|
|
2397
2397
|
// ── STEP 3: respondWithResults ────────────────────────────────
|
|
2398
|
-
function responderSystem(userName, date, sessionId) {
|
|
2398
|
+
function responderSystem(userName, date, sessionId, hasToolResults = true) {
|
|
2399
2399
|
// Option-B: SOUL.md in full on first turn or when content changed on disk;
|
|
2400
2400
|
// reference line only on unchanged turns. AIDEN_RESPONDER_SYSTEM already
|
|
2401
2401
|
// calls getLiveSoul() — hash tracking here is additional cost guard.
|
|
@@ -2406,9 +2406,9 @@ function responderSystem(userName, date, sessionId) {
|
|
|
2406
2406
|
// When soul is unchanged, prepend a compact block then the responder body.
|
|
2407
2407
|
if (_prevHash !== undefined && _ctx.hash === _prevHash) {
|
|
2408
2408
|
const refBlock = (0, contextHandoff_1.buildProtectedContextBlock)(_ctx, _prevHash, sessionId);
|
|
2409
|
-
return refBlock ? refBlock + '\n\n' + (0, aidenPersonality_1.AIDEN_RESPONDER_SYSTEM)(userName, date) : (0, aidenPersonality_1.AIDEN_RESPONDER_SYSTEM)(userName, date);
|
|
2409
|
+
return refBlock ? refBlock + '\n\n' + (0, aidenPersonality_1.AIDEN_RESPONDER_SYSTEM)(userName, date, hasToolResults) : (0, aidenPersonality_1.AIDEN_RESPONDER_SYSTEM)(userName, date, hasToolResults);
|
|
2410
2410
|
}
|
|
2411
|
-
return (0, aidenPersonality_1.AIDEN_RESPONDER_SYSTEM)(userName, date);
|
|
2411
|
+
return (0, aidenPersonality_1.AIDEN_RESPONDER_SYSTEM)(userName, date, hasToolResults);
|
|
2412
2412
|
}
|
|
2413
2413
|
async function respondWithResults(originalMessage, plan, results, history, userName, apiKey, model, providerName, onToken, sessionId, goals) {
|
|
2414
2414
|
// ── CommandGate / PermissionGate short-circuit ───────────────
|
|
@@ -2480,8 +2480,10 @@ async function respondWithResults(originalMessage, plan, results, history, userN
|
|
|
2480
2480
|
const toolResultsContext = results.length
|
|
2481
2481
|
? results.map(r => `[${r.tool} result]: ${r.success ? r.output.slice(0, 1000) : 'FAILED: ' + r.error}`).join('\n')
|
|
2482
2482
|
: '';
|
|
2483
|
+
// ── C20: Detect if any real tools ran (exclude 'respond' pseudo-tool) ──
|
|
2484
|
+
const hasRealToolExecution = results.some(r => r.tool !== 'respond');
|
|
2483
2485
|
const systemWithResults = toolResultsContext
|
|
2484
|
-
? `${capabilitiesSection}${entitySummary}${responderSystem(userName, date, sessionId)}${responseSkillContext}${knowledgeResponderSection}${multiGoalInstruction}
|
|
2486
|
+
? `${capabilitiesSection}${entitySummary}${responderSystem(userName, date, sessionId, hasRealToolExecution)}${responseSkillContext}${knowledgeResponderSection}${multiGoalInstruction}
|
|
2485
2487
|
|
|
2486
2488
|
YOU JUST RAN THESE TOOLS AND GOT THESE RESULTS:
|
|
2487
2489
|
${toolResultsContext}
|
|
@@ -2500,7 +2502,7 @@ CRITICAL RULES FOR YOUR RESPONSE:
|
|
|
2500
2502
|
- If system_info returned hardware data, show the data
|
|
2501
2503
|
- Be direct: show the actual output, then provide context if needed
|
|
2502
2504
|
- If a tool result starts with "FAILED:", tell the user it failed and why — NEVER fabricate a successful result`
|
|
2503
|
-
: `${capabilitiesSection}${entitySummary}${responderSystem(userName, date, sessionId)}${responseSkillContext}${knowledgeResponderSection}${multiGoalInstruction}`;
|
|
2505
|
+
: `${capabilitiesSection}${entitySummary}${responderSystem(userName, date, sessionId, false)}${responseSkillContext}${knowledgeResponderSection}${multiGoalInstruction}`;
|
|
2504
2506
|
const userContent = executionSummary
|
|
2505
2507
|
? `User asked: "${originalMessage}"\n\nReal execution results:\n${executionSummary}\n\nRespond naturally based on these real results only. Show the actual output, not a description of it.${depthInstruction}${memSection}`
|
|
2506
2508
|
: `${originalMessage}${memSection}`;
|
|
@@ -123,11 +123,12 @@ Good: "I have 48 built-in tools: web_search, file_write, run_python... [lists re
|
|
|
123
123
|
group chats and external communications.
|
|
124
124
|
`.trim();
|
|
125
125
|
// ── Responder system prompt (post-execution) ──────────────────
|
|
126
|
-
const AIDEN_RESPONDER_SYSTEM = (userName, date) => {
|
|
126
|
+
const AIDEN_RESPONDER_SYSTEM = (userName, date, hasToolResults = true) => {
|
|
127
127
|
const soul = getLiveSoul();
|
|
128
128
|
return `${soul ? soul + '\n\n' : ''}${exports.AIDEN_IDENTITY}
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
${hasToolResults
|
|
131
|
+
? `You just executed real tools and have their actual output.
|
|
131
132
|
Current date: ${date}
|
|
132
133
|
User: ${userName}
|
|
133
134
|
|
|
@@ -136,6 +137,22 @@ REPORT RESULTS:
|
|
|
136
137
|
- Be specific: include file paths, numbers, URLs, counts
|
|
137
138
|
- If multiple steps ran: summarize the outcome, not each individual step
|
|
138
139
|
- If a step failed: acknowledge it clearly and explain what worked
|
|
139
|
-
- For research tasks: analyze and synthesize — don't just re-paste the raw data
|
|
140
|
+
- For research tasks: analyze and synthesize — don't just re-paste the raw data`
|
|
141
|
+
: `Current date: ${date}
|
|
142
|
+
User: ${userName}
|
|
143
|
+
|
|
144
|
+
NO TOOLS WERE EXECUTED THIS TURN.
|
|
145
|
+
|
|
146
|
+
CRITICAL RULES (violating these breaks user trust):
|
|
147
|
+
- DO NOT claim you created, wrote, or saved any file
|
|
148
|
+
- DO NOT claim you opened any application or browser tab
|
|
149
|
+
- DO NOT claim you ran any code, search, or API call
|
|
150
|
+
- DO NOT report "Saved to Desktop/...", "Report written", "Done", "Created", "Executed", or similar completion language
|
|
151
|
+
- DO NOT fabricate file paths, character counts, or word counts
|
|
152
|
+
- DO NOT mention "the file" or "the report" as if it exists
|
|
153
|
+
- DO NOT include code blocks or raw data and call it "the result"
|
|
154
|
+
- IF the user asked for an action, acknowledge what they asked for but be clear no action has been taken yet ("I can do that — would you like me to..." or similar)
|
|
155
|
+
|
|
156
|
+
Respond conversationally based on the message and conversation context only.`}`;
|
|
140
157
|
};
|
|
141
158
|
exports.AIDEN_RESPONDER_SYSTEM = AIDEN_RESPONDER_SYSTEM;
|
|
@@ -9,6 +9,13 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const crypto_1 = __importDefault(require("crypto"));
|
|
10
10
|
const WORKSPACE_ROOT = process.env.AIDEN_USER_DATA || process.cwd();
|
|
11
11
|
const WORKSPACE_DIR = path_1.default.join(WORKSPACE_ROOT, 'workspace');
|
|
12
|
+
// C21: Hardcoded minimum identity — used when SOUL.md is missing or empty.
|
|
13
|
+
// Ensures Ollama always gets Aiden identity even on corrupted installs.
|
|
14
|
+
const MINIMUM_SOUL = `You are Aiden, a personal AI OS built by Shiva Deore at Taracod.
|
|
15
|
+
You run locally on this machine. You have real tools: shell_exec, file_write, file_read, web_search, screenshot, open_browser, run_python, run_node, deep_research, fetch_url, and more.
|
|
16
|
+
Never deny your capabilities. Never fabricate information. If you don't know something, say "I don't know".
|
|
17
|
+
Never claim actions you didn't take. Never say "Done" or "Saved to" unless a tool actually executed.
|
|
18
|
+
You are not ChatGPT, Claude, Gemini, or any other AI product. You are Aiden.`;
|
|
12
19
|
// SOUL.md has two possible locations; try workspace first, fall back to root.
|
|
13
20
|
const SOUL_PATHS = [
|
|
14
21
|
path_1.default.join(WORKSPACE_DIR, 'SOUL.md'),
|
|
@@ -56,7 +63,10 @@ class ProtectedContextManager {
|
|
|
56
63
|
refresh() {
|
|
57
64
|
for (const key of Object.keys(PROTECTED_FILES)) {
|
|
58
65
|
const candidates = PROTECTED_FILES[key];
|
|
59
|
-
|
|
66
|
+
let content = readFirst(candidates);
|
|
67
|
+
// C21: Apply minimum-viable-soul fallback when SOUL.md is missing/empty
|
|
68
|
+
if (key === 'soul' && !content)
|
|
69
|
+
content = MINIMUM_SOUL;
|
|
60
70
|
this.cache[key] = { content, hash: sha1(content) };
|
|
61
71
|
}
|
|
62
72
|
this.compositeHash = this._buildComposite();
|
|
@@ -68,7 +78,10 @@ class ProtectedContextManager {
|
|
|
68
78
|
const changedFiles = [];
|
|
69
79
|
for (const key of Object.keys(PROTECTED_FILES)) {
|
|
70
80
|
if (this.isStale(key)) {
|
|
71
|
-
|
|
81
|
+
let content = readFirst(PROTECTED_FILES[key]);
|
|
82
|
+
// C21: Apply minimum-viable-soul fallback when SOUL.md is missing/empty
|
|
83
|
+
if (key === 'soul' && !content)
|
|
84
|
+
content = MINIMUM_SOUL;
|
|
72
85
|
this.cache[key] = { content, hash: sha1(content) };
|
|
73
86
|
changedFiles.push(key);
|
|
74
87
|
}
|
package/dist/core/skillLoader.js
CHANGED
|
@@ -192,17 +192,20 @@ class SkillLoader {
|
|
|
192
192
|
// Check built-in skills, workspace skills, and self-learned/promoted skills.
|
|
193
193
|
// NOTE: skills/learned/pending/ is intentionally excluded — pending skills
|
|
194
194
|
// are never auto-loaded; they require explicit /skills approve first.
|
|
195
|
+
// C22: Use AIDEN_USER_DATA (set by npx launcher) so SkillLoader reads
|
|
196
|
+
// from the same workspace root that initWorkspaceDefaults() writes to.
|
|
197
|
+
const root = process.env.AIDEN_USER_DATA || process.cwd();
|
|
195
198
|
this.skillsDirs = [
|
|
196
|
-
path_1.default.join(
|
|
197
|
-
path_1.default.join(
|
|
198
|
-
path_1.default.join(
|
|
199
|
-
path_1.default.join(
|
|
199
|
+
path_1.default.join(root, 'skills'),
|
|
200
|
+
path_1.default.join(root, 'workspace', 'skills'),
|
|
201
|
+
path_1.default.join(root, 'workspace', 'skills', 'learned'),
|
|
202
|
+
path_1.default.join(root, 'workspace', 'skills', 'approved'),
|
|
200
203
|
// Workspace-level installed skills (written by skillRegistry.ts)
|
|
201
|
-
path_1.default.join(
|
|
204
|
+
path_1.default.join(root, 'workspace', 'skills', 'installed'),
|
|
202
205
|
// A2/A3 approved drafts
|
|
203
|
-
path_1.default.join(
|
|
206
|
+
path_1.default.join(root, 'skills', 'learned', 'approved'),
|
|
204
207
|
// A4 library-installed skills
|
|
205
|
-
path_1.default.join(
|
|
208
|
+
path_1.default.join(root, 'skills', 'installed'),
|
|
206
209
|
].filter(d => {
|
|
207
210
|
try {
|
|
208
211
|
return fs_1.default.existsSync(d);
|
|
@@ -57,6 +57,9 @@ const PROMOTE_THRESHOLD = 3; // successes needed to promote to approved/
|
|
|
57
57
|
const SESSION_SKILL_LIMIT = 2; // max NEW skills generated per process session
|
|
58
58
|
// ── Session-scoped new-skill counter (reset on process restart) ─
|
|
59
59
|
let _sessionSkillsCreated = 0;
|
|
60
|
+
// ── C18: Session-scoped rejection cache — skip re-evaluating names
|
|
61
|
+
// that already failed quality gates this session ─────────────────
|
|
62
|
+
const _rejectedNames = new Set();
|
|
60
63
|
// ── Skill name extractor ───────────────────────────────────────
|
|
61
64
|
// "research the top AI agents of 2025" → "research_ai_agents"
|
|
62
65
|
function extractSkillName(task, tools) {
|
|
@@ -201,6 +204,10 @@ class SkillTeacher {
|
|
|
201
204
|
}
|
|
202
205
|
return SkillTeacher.instance;
|
|
203
206
|
}
|
|
207
|
+
/** C18: Allow call sites to skip recordSuccess entirely when session is full */
|
|
208
|
+
static hasCapacity() {
|
|
209
|
+
return _sessionSkillsCreated < SESSION_SKILL_LIMIT;
|
|
210
|
+
}
|
|
204
211
|
// ── Check if a matching skill already exists ──────────────
|
|
205
212
|
hasMatchingSkill(task, tools) {
|
|
206
213
|
const skillName = extractSkillName(task, tools);
|
|
@@ -223,6 +230,13 @@ class SkillTeacher {
|
|
|
223
230
|
if (tools.length === 0)
|
|
224
231
|
return;
|
|
225
232
|
const skillName = extractSkillName(task, tools);
|
|
233
|
+
// ── C18: Skip names already rejected this session ────────────
|
|
234
|
+
if (_rejectedNames.has(skillName))
|
|
235
|
+
return;
|
|
236
|
+
// ── C18: Session rate limit (moved up — avoids running all
|
|
237
|
+
// quality gates when limit is already exhausted) ────────────
|
|
238
|
+
if (_sessionSkillsCreated >= SESSION_SKILL_LIMIT)
|
|
239
|
+
return;
|
|
226
240
|
const metaPath = path_1.default.join(LEARNED_DIR, skillName, 'meta.json');
|
|
227
241
|
const skillPath = path_1.default.join(LEARNED_DIR, skillName, 'SKILL.md');
|
|
228
242
|
// ── If skill exists — update usage count ─────────────────
|
|
@@ -252,6 +266,7 @@ class SkillTeacher {
|
|
|
252
266
|
task.split(/\s+/).length < 3);
|
|
253
267
|
if (isLowQuality) {
|
|
254
268
|
console.log(`[SkillTeacher] Rejected low-quality skill: "${skillName}"`);
|
|
269
|
+
_rejectedNames.add(skillName);
|
|
255
270
|
return;
|
|
256
271
|
}
|
|
257
272
|
// ── C7: Destructive-skill prevention ──────────────────────
|
|
@@ -262,23 +277,21 @@ class SkillTeacher {
|
|
|
262
277
|
const usesShellExec = tools.some(t => t === 'shell_exec');
|
|
263
278
|
if (DESTRUCTIVE_TASK_RE.test(task) && usesShellExec) {
|
|
264
279
|
process.stderr.write(`[SkillTeacher] Rejected destructive skill: "${skillName}" (task="${task.slice(0, 60)}")\n`);
|
|
280
|
+
_rejectedNames.add(skillName);
|
|
265
281
|
return;
|
|
266
282
|
}
|
|
267
283
|
// ── C12: Name pollution prevention ──────────────────────────
|
|
268
284
|
const nameRejection = validateSkillName(skillName);
|
|
269
285
|
if (nameRejection) {
|
|
270
286
|
process.stderr.write(`[SkillTeacher] Rejected "${skillName}": ${nameRejection}\n`);
|
|
287
|
+
_rejectedNames.add(skillName);
|
|
271
288
|
return;
|
|
272
289
|
}
|
|
273
290
|
// ── C12: Task content validation ────────────────────────────
|
|
274
291
|
const taskRejection = validateSkillTask(task);
|
|
275
292
|
if (taskRejection) {
|
|
276
293
|
process.stderr.write(`[SkillTeacher] Rejected "${skillName}": ${taskRejection}\n`);
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
// ── Session rate limit — max SESSION_SKILL_LIMIT new skills ─
|
|
280
|
-
if (_sessionSkillsCreated >= SESSION_SKILL_LIMIT) {
|
|
281
|
-
console.log(`[SkillTeacher] Session limit reached (${SESSION_SKILL_LIMIT}), skipping: "${skillName}"`);
|
|
294
|
+
_rejectedNames.add(skillName);
|
|
282
295
|
return;
|
|
283
296
|
}
|
|
284
297
|
// ── Deduplication — reject names already in bundled skills/, approved/, or learned/ ─
|
package/dist/core/version.js
CHANGED
package/dist-bundle/cli.js
CHANGED
|
@@ -208,7 +208,7 @@ var init_updateCheck = __esm({
|
|
|
208
208
|
var VERSION;
|
|
209
209
|
var init_version = __esm({
|
|
210
210
|
"core/version.ts"() {
|
|
211
|
-
VERSION = "3.19.
|
|
211
|
+
VERSION = "3.19.8";
|
|
212
212
|
}
|
|
213
213
|
});
|
|
214
214
|
|
|
@@ -23684,14 +23684,12 @@ var init_livePulse = __esm({
|
|
|
23684
23684
|
// ── Public methods — all wrapped in try-catch so they NEVER throw ──
|
|
23685
23685
|
act(agent, message, missionId) {
|
|
23686
23686
|
try {
|
|
23687
|
-
console.log(`[${agent}] ${message}`);
|
|
23688
23687
|
this.emit_event({ type: "act", agent, message, timestamp: Date.now(), missionId });
|
|
23689
23688
|
} catch {
|
|
23690
23689
|
}
|
|
23691
23690
|
}
|
|
23692
23691
|
done(agent, message, missionId) {
|
|
23693
23692
|
try {
|
|
23694
|
-
console.log(`[${agent}] \u2713 ${message}`);
|
|
23695
23693
|
this.emit_event({ type: "done", agent, message, timestamp: Date.now(), missionId });
|
|
23696
23694
|
} catch {
|
|
23697
23695
|
}
|
|
@@ -23706,21 +23704,18 @@ var init_livePulse = __esm({
|
|
|
23706
23704
|
}
|
|
23707
23705
|
warn(agent, message, missionId) {
|
|
23708
23706
|
try {
|
|
23709
|
-
console.warn(`[${agent}] \u26A0 ${message}`);
|
|
23710
23707
|
this.emit_event({ type: "warn", agent, message, timestamp: Date.now(), missionId });
|
|
23711
23708
|
} catch {
|
|
23712
23709
|
}
|
|
23713
23710
|
}
|
|
23714
23711
|
info(agent, message, missionId) {
|
|
23715
23712
|
try {
|
|
23716
|
-
console.log(`[${agent}] \u2139 ${message}`);
|
|
23717
23713
|
this.emit_event({ type: "info", agent, message, timestamp: Date.now(), missionId });
|
|
23718
23714
|
} catch {
|
|
23719
23715
|
}
|
|
23720
23716
|
}
|
|
23721
23717
|
thinking(agent, message, missionId) {
|
|
23722
23718
|
try {
|
|
23723
|
-
console.log(`[${agent}] \u{1F4AD} ${message}`);
|
|
23724
23719
|
this.emit_event({ type: "thinking", agent, message, timestamp: Date.now(), missionId });
|
|
23725
23720
|
} catch {
|
|
23726
23721
|
}
|
|
@@ -23728,7 +23723,6 @@ var init_livePulse = __esm({
|
|
|
23728
23723
|
tool(agent, toolName, command, output) {
|
|
23729
23724
|
try {
|
|
23730
23725
|
const message = output ? `${toolName}: ${command} \u2192 ${output.slice(0, 120)}` : `${toolName}: ${command}`;
|
|
23731
|
-
console.log(`[${agent}] \u{1F527} ${message}`);
|
|
23732
23726
|
this.emit_event({
|
|
23733
23727
|
type: "tool",
|
|
23734
23728
|
agent,
|
|
@@ -24903,17 +24897,18 @@ var init_skillLoader = __esm({
|
|
|
24903
24897
|
SkillLoader = class {
|
|
24904
24898
|
constructor() {
|
|
24905
24899
|
this.cache = null;
|
|
24900
|
+
const root = process.env.AIDEN_USER_DATA || process.cwd();
|
|
24906
24901
|
this.skillsDirs = [
|
|
24907
|
-
import_path12.default.join(
|
|
24908
|
-
import_path12.default.join(
|
|
24909
|
-
import_path12.default.join(
|
|
24910
|
-
import_path12.default.join(
|
|
24902
|
+
import_path12.default.join(root, "skills"),
|
|
24903
|
+
import_path12.default.join(root, "workspace", "skills"),
|
|
24904
|
+
import_path12.default.join(root, "workspace", "skills", "learned"),
|
|
24905
|
+
import_path12.default.join(root, "workspace", "skills", "approved"),
|
|
24911
24906
|
// Workspace-level installed skills (written by skillRegistry.ts)
|
|
24912
|
-
import_path12.default.join(
|
|
24907
|
+
import_path12.default.join(root, "workspace", "skills", "installed"),
|
|
24913
24908
|
// A2/A3 approved drafts
|
|
24914
|
-
import_path12.default.join(
|
|
24909
|
+
import_path12.default.join(root, "skills", "learned", "approved"),
|
|
24915
24910
|
// A4 library-installed skills
|
|
24916
|
-
import_path12.default.join(
|
|
24911
|
+
import_path12.default.join(root, "skills", "installed")
|
|
24917
24912
|
].filter((d) => {
|
|
24918
24913
|
try {
|
|
24919
24914
|
return import_fs11.default.existsSync(d);
|
|
@@ -288649,7 +288644,7 @@ When performing this type of task:
|
|
|
288649
288644
|
3. Verify each step output before proceeding to the next
|
|
288650
288645
|
`;
|
|
288651
288646
|
}
|
|
288652
|
-
var import_fs16, import_path17, LEARNED_DIR, APPROVED_DIR, BUNDLED_SKILLS_DIR, PROMOTE_THRESHOLD, SESSION_SKILL_LIMIT, _sessionSkillsCreated, QUESTION_WORD_RE, PRONOUN_RE, PERSONAL_ID_RE, SkillTeacher, skillTeacher;
|
|
288647
|
+
var import_fs16, import_path17, LEARNED_DIR, APPROVED_DIR, BUNDLED_SKILLS_DIR, PROMOTE_THRESHOLD, SESSION_SKILL_LIMIT, _sessionSkillsCreated, _rejectedNames, QUESTION_WORD_RE, PRONOUN_RE, PERSONAL_ID_RE, SkillTeacher, skillTeacher;
|
|
288653
288648
|
var init_skillTeacher = __esm({
|
|
288654
288649
|
"core/skillTeacher.ts"() {
|
|
288655
288650
|
import_fs16 = __toESM(require("fs"));
|
|
@@ -288660,6 +288655,7 @@ var init_skillTeacher = __esm({
|
|
|
288660
288655
|
PROMOTE_THRESHOLD = 3;
|
|
288661
288656
|
SESSION_SKILL_LIMIT = 2;
|
|
288662
288657
|
_sessionSkillsCreated = 0;
|
|
288658
|
+
_rejectedNames = /* @__PURE__ */ new Set();
|
|
288663
288659
|
QUESTION_WORD_RE = /^(what|where|why|when|who|how|can|could|would|should|is|are)_/;
|
|
288664
288660
|
PRONOUN_RE = /^(its|im|youre|whats|theyre|were)_/;
|
|
288665
288661
|
PERSONAL_ID_RE = /(^|_)(users|shiva|admin|desktop|appdata)(_|$)/;
|
|
@@ -288680,6 +288676,10 @@ var init_skillTeacher = __esm({
|
|
|
288680
288676
|
}
|
|
288681
288677
|
return _SkillTeacher.instance;
|
|
288682
288678
|
}
|
|
288679
|
+
/** C18: Allow call sites to skip recordSuccess entirely when session is full */
|
|
288680
|
+
static hasCapacity() {
|
|
288681
|
+
return _sessionSkillsCreated < SESSION_SKILL_LIMIT;
|
|
288682
|
+
}
|
|
288683
288683
|
// ── Check if a matching skill already exists ──────────────
|
|
288684
288684
|
hasMatchingSkill(task, tools) {
|
|
288685
288685
|
const skillName = extractSkillName(task, tools);
|
|
@@ -288700,6 +288700,8 @@ var init_skillTeacher = __esm({
|
|
|
288700
288700
|
async recordSuccess(task, tools, duration3, llmCaller, apiKey, model, provider) {
|
|
288701
288701
|
if (tools.length === 0) return;
|
|
288702
288702
|
const skillName = extractSkillName(task, tools);
|
|
288703
|
+
if (_rejectedNames.has(skillName)) return;
|
|
288704
|
+
if (_sessionSkillsCreated >= SESSION_SKILL_LIMIT) return;
|
|
288703
288705
|
const metaPath2 = import_path17.default.join(LEARNED_DIR, skillName, "meta.json");
|
|
288704
288706
|
const skillPath = import_path17.default.join(LEARNED_DIR, skillName, "SKILL.md");
|
|
288705
288707
|
if (import_fs16.default.existsSync(metaPath2)) {
|
|
@@ -288724,6 +288726,7 @@ var init_skillTeacher = __esm({
|
|
|
288724
288726
|
const isLowQuality = skillName.length < 5 || skillName.split("_").length < 2 || task.split(/\s+/).length < 3;
|
|
288725
288727
|
if (isLowQuality) {
|
|
288726
288728
|
console.log(`[SkillTeacher] Rejected low-quality skill: "${skillName}"`);
|
|
288729
|
+
_rejectedNames.add(skillName);
|
|
288727
288730
|
return;
|
|
288728
288731
|
}
|
|
288729
288732
|
const DESTRUCTIVE_TASK_RE = /\b(delete|remove|rm\s|del\s|wipe|purge|erase|format|uninstall|drop\s+table|truncate)\b/i;
|
|
@@ -288733,22 +288736,21 @@ var init_skillTeacher = __esm({
|
|
|
288733
288736
|
`[SkillTeacher] Rejected destructive skill: "${skillName}" (task="${task.slice(0, 60)}")
|
|
288734
288737
|
`
|
|
288735
288738
|
);
|
|
288739
|
+
_rejectedNames.add(skillName);
|
|
288736
288740
|
return;
|
|
288737
288741
|
}
|
|
288738
288742
|
const nameRejection = validateSkillName(skillName);
|
|
288739
288743
|
if (nameRejection) {
|
|
288740
288744
|
process.stderr.write(`[SkillTeacher] Rejected "${skillName}": ${nameRejection}
|
|
288741
288745
|
`);
|
|
288746
|
+
_rejectedNames.add(skillName);
|
|
288742
288747
|
return;
|
|
288743
288748
|
}
|
|
288744
288749
|
const taskRejection = validateSkillTask(task);
|
|
288745
288750
|
if (taskRejection) {
|
|
288746
288751
|
process.stderr.write(`[SkillTeacher] Rejected "${skillName}": ${taskRejection}
|
|
288747
288752
|
`);
|
|
288748
|
-
|
|
288749
|
-
}
|
|
288750
|
-
if (_sessionSkillsCreated >= SESSION_SKILL_LIMIT) {
|
|
288751
|
-
console.log(`[SkillTeacher] Session limit reached (${SESSION_SKILL_LIMIT}), skipping: "${skillName}"`);
|
|
288753
|
+
_rejectedNames.add(skillName);
|
|
288752
288754
|
return;
|
|
288753
288755
|
}
|
|
288754
288756
|
const dirsToDedup = [BUNDLED_SKILLS_DIR, APPROVED_DIR, LEARNED_DIR];
|
|
@@ -289027,7 +289029,7 @@ function readFirst(candidates) {
|
|
|
289027
289029
|
function diskHash(candidates) {
|
|
289028
289030
|
return sha1(readFirst(candidates));
|
|
289029
289031
|
}
|
|
289030
|
-
var import_fs18, import_path19, import_crypto, WORKSPACE_ROOT, WORKSPACE_DIR, SOUL_PATHS, PROTECTED_FILES, ProtectedContextManager, protectedContextManager;
|
|
289032
|
+
var import_fs18, import_path19, import_crypto, WORKSPACE_ROOT, WORKSPACE_DIR, MINIMUM_SOUL, SOUL_PATHS, PROTECTED_FILES, ProtectedContextManager, protectedContextManager;
|
|
289031
289033
|
var init_protectedContext = __esm({
|
|
289032
289034
|
"core/protectedContext.ts"() {
|
|
289033
289035
|
import_fs18 = __toESM(require("fs"));
|
|
@@ -289035,6 +289037,11 @@ var init_protectedContext = __esm({
|
|
|
289035
289037
|
import_crypto = __toESM(require("crypto"));
|
|
289036
289038
|
WORKSPACE_ROOT = process.env.AIDEN_USER_DATA || process.cwd();
|
|
289037
289039
|
WORKSPACE_DIR = import_path19.default.join(WORKSPACE_ROOT, "workspace");
|
|
289040
|
+
MINIMUM_SOUL = `You are Aiden, a personal AI OS built by Shiva Deore at Taracod.
|
|
289041
|
+
You run locally on this machine. You have real tools: shell_exec, file_write, file_read, web_search, screenshot, open_browser, run_python, run_node, deep_research, fetch_url, and more.
|
|
289042
|
+
Never deny your capabilities. Never fabricate information. If you don't know something, say "I don't know".
|
|
289043
|
+
Never claim actions you didn't take. Never say "Done" or "Saved to" unless a tool actually executed.
|
|
289044
|
+
You are not ChatGPT, Claude, Gemini, or any other AI product. You are Aiden.`;
|
|
289038
289045
|
SOUL_PATHS = [
|
|
289039
289046
|
import_path19.default.join(WORKSPACE_DIR, "SOUL.md"),
|
|
289040
289047
|
import_path19.default.join(process.cwd(), "SOUL.md")
|
|
@@ -289066,7 +289073,8 @@ var init_protectedContext = __esm({
|
|
|
289066
289073
|
refresh() {
|
|
289067
289074
|
for (const key of Object.keys(PROTECTED_FILES)) {
|
|
289068
289075
|
const candidates = PROTECTED_FILES[key];
|
|
289069
|
-
|
|
289076
|
+
let content = readFirst(candidates);
|
|
289077
|
+
if (key === "soul" && !content) content = MINIMUM_SOUL;
|
|
289070
289078
|
this.cache[key] = { content, hash: sha1(content) };
|
|
289071
289079
|
}
|
|
289072
289080
|
this.compositeHash = this._buildComposite();
|
|
@@ -289078,7 +289086,8 @@ var init_protectedContext = __esm({
|
|
|
289078
289086
|
const changedFiles = [];
|
|
289079
289087
|
for (const key of Object.keys(PROTECTED_FILES)) {
|
|
289080
289088
|
if (this.isStale(key)) {
|
|
289081
|
-
|
|
289089
|
+
let content = readFirst(PROTECTED_FILES[key]);
|
|
289090
|
+
if (key === "soul" && !content) content = MINIMUM_SOUL;
|
|
289082
289091
|
this.cache[key] = { content, hash: sha1(content) };
|
|
289083
289092
|
changedFiles.push(key);
|
|
289084
289093
|
}
|
|
@@ -289231,11 +289240,11 @@ Good: "I have 48 built-in tools: web_search, file_write, run_python... [lists re
|
|
|
289231
289240
|
- You're not the user's voice \u2014 be careful in
|
|
289232
289241
|
group chats and external communications.
|
|
289233
289242
|
`.trim();
|
|
289234
|
-
AIDEN_RESPONDER_SYSTEM = (userName, date3) => {
|
|
289243
|
+
AIDEN_RESPONDER_SYSTEM = (userName, date3, hasToolResults = true) => {
|
|
289235
289244
|
const soul = getLiveSoul();
|
|
289236
289245
|
return `${soul ? soul + "\n\n" : ""}${AIDEN_IDENTITY}
|
|
289237
289246
|
|
|
289238
|
-
You just executed real tools and have their actual output.
|
|
289247
|
+
${hasToolResults ? `You just executed real tools and have their actual output.
|
|
289239
289248
|
Current date: ${date3}
|
|
289240
289249
|
User: ${userName}
|
|
289241
289250
|
|
|
@@ -289244,7 +289253,22 @@ REPORT RESULTS:
|
|
|
289244
289253
|
- Be specific: include file paths, numbers, URLs, counts
|
|
289245
289254
|
- If multiple steps ran: summarize the outcome, not each individual step
|
|
289246
289255
|
- If a step failed: acknowledge it clearly and explain what worked
|
|
289247
|
-
- For research tasks: analyze and synthesize \u2014 don't just re-paste the raw data
|
|
289256
|
+
- For research tasks: analyze and synthesize \u2014 don't just re-paste the raw data` : `Current date: ${date3}
|
|
289257
|
+
User: ${userName}
|
|
289258
|
+
|
|
289259
|
+
NO TOOLS WERE EXECUTED THIS TURN.
|
|
289260
|
+
|
|
289261
|
+
CRITICAL RULES (violating these breaks user trust):
|
|
289262
|
+
- DO NOT claim you created, wrote, or saved any file
|
|
289263
|
+
- DO NOT claim you opened any application or browser tab
|
|
289264
|
+
- DO NOT claim you ran any code, search, or API call
|
|
289265
|
+
- DO NOT report "Saved to Desktop/...", "Report written", "Done", "Created", "Executed", or similar completion language
|
|
289266
|
+
- DO NOT fabricate file paths, character counts, or word counts
|
|
289267
|
+
- DO NOT mention "the file" or "the report" as if it exists
|
|
289268
|
+
- DO NOT include code blocks or raw data and call it "the result"
|
|
289269
|
+
- IF the user asked for an action, acknowledge what they asked for but be clear no action has been taken yet ("I can do that \u2014 would you like me to..." or similar)
|
|
289270
|
+
|
|
289271
|
+
Respond conversationally based on the message and conversation context only.`}`;
|
|
289248
289272
|
};
|
|
289249
289273
|
}
|
|
289250
289274
|
});
|
|
@@ -292778,7 +292802,7 @@ Would you like me to try a different approach?`,
|
|
|
292778
292802
|
const executedTools = results.map((r) => r.tool);
|
|
292779
292803
|
const totalDuration = results.reduce((s, r) => s + (r.duration || 0), 0);
|
|
292780
292804
|
const anyFailed = results.some((r) => !r.success);
|
|
292781
|
-
if (allSucceeded && executedTools.length > 0) {
|
|
292805
|
+
if (allSucceeded && executedTools.length > 0 && SkillTeacher.hasCapacity()) {
|
|
292782
292806
|
growthEngine.logSuccess(plan.goal, executedTools);
|
|
292783
292807
|
try {
|
|
292784
292808
|
const next = getNextAvailableAPI();
|
|
@@ -292843,15 +292867,15 @@ function resolvePreviousOutput(input, stepOutputs, currentStep) {
|
|
|
292843
292867
|
}
|
|
292844
292868
|
return resolved;
|
|
292845
292869
|
}
|
|
292846
|
-
function responderSystem(userName, date3, sessionId) {
|
|
292870
|
+
function responderSystem(userName, date3, sessionId, hasToolResults = true) {
|
|
292847
292871
|
const _ctx = protectedContextManager.getProtectedContext();
|
|
292848
292872
|
const _prevHash = sessionId ? soulHashBySession.get(sessionId) : void 0;
|
|
292849
292873
|
if (sessionId) soulHashBySession.set(sessionId, _ctx.hash);
|
|
292850
292874
|
if (_prevHash !== void 0 && _ctx.hash === _prevHash) {
|
|
292851
292875
|
const refBlock = buildProtectedContextBlock(_ctx, _prevHash, sessionId);
|
|
292852
|
-
return refBlock ? refBlock + "\n\n" + AIDEN_RESPONDER_SYSTEM(userName, date3) : AIDEN_RESPONDER_SYSTEM(userName, date3);
|
|
292876
|
+
return refBlock ? refBlock + "\n\n" + AIDEN_RESPONDER_SYSTEM(userName, date3, hasToolResults) : AIDEN_RESPONDER_SYSTEM(userName, date3, hasToolResults);
|
|
292853
292877
|
}
|
|
292854
|
-
return AIDEN_RESPONDER_SYSTEM(userName, date3);
|
|
292878
|
+
return AIDEN_RESPONDER_SYSTEM(userName, date3, hasToolResults);
|
|
292855
292879
|
}
|
|
292856
292880
|
async function respondWithResults(originalMessage, plan, results, history2, userName, apiKey, model, providerName, onToken, sessionId, goals) {
|
|
292857
292881
|
const gatedResult = results.find(
|
|
@@ -292918,7 +292942,8 @@ If the user asks what we worked on, what was researched, or references previous
|
|
|
292918
292942
|
|
|
292919
292943
|
` : "";
|
|
292920
292944
|
const toolResultsContext = results.length ? results.map((r) => `[${r.tool} result]: ${r.success ? r.output.slice(0, 1e3) : "FAILED: " + r.error}`).join("\n") : "";
|
|
292921
|
-
const
|
|
292945
|
+
const hasRealToolExecution = results.some((r) => r.tool !== "respond");
|
|
292946
|
+
const systemWithResults = toolResultsContext ? `${capabilitiesSection}${entitySummary}${responderSystem(userName, date3, sessionId, hasRealToolExecution)}${responseSkillContext}${knowledgeResponderSection}${multiGoalInstruction}
|
|
292922
292947
|
|
|
292923
292948
|
YOU JUST RAN THESE TOOLS AND GOT THESE RESULTS:
|
|
292924
292949
|
${toolResultsContext}
|
|
@@ -292936,7 +292961,7 @@ CRITICAL RULES FOR YOUR RESPONSE:
|
|
|
292936
292961
|
- If a search tool returned no results, say no results were found \u2014 NEVER invent search results
|
|
292937
292962
|
- If system_info returned hardware data, show the data
|
|
292938
292963
|
- Be direct: show the actual output, then provide context if needed
|
|
292939
|
-
- If a tool result starts with "FAILED:", tell the user it failed and why \u2014 NEVER fabricate a successful result` : `${capabilitiesSection}${entitySummary}${responderSystem(userName, date3, sessionId)}${responseSkillContext}${knowledgeResponderSection}${multiGoalInstruction}`;
|
|
292964
|
+
- If a tool result starts with "FAILED:", tell the user it failed and why \u2014 NEVER fabricate a successful result` : `${capabilitiesSection}${entitySummary}${responderSystem(userName, date3, sessionId, false)}${responseSkillContext}${knowledgeResponderSection}${multiGoalInstruction}`;
|
|
292940
292965
|
const userContent = executionSummary ? `User asked: "${originalMessage}"
|
|
292941
292966
|
|
|
292942
292967
|
Real execution results:
|
package/dist-bundle/index.js
CHANGED
|
@@ -26650,7 +26650,7 @@ var require_websocket_server = __commonJS({
|
|
|
26650
26650
|
var VERSION;
|
|
26651
26651
|
var init_version = __esm({
|
|
26652
26652
|
"core/version.ts"() {
|
|
26653
|
-
VERSION = "3.19.
|
|
26653
|
+
VERSION = "3.19.8";
|
|
26654
26654
|
}
|
|
26655
26655
|
});
|
|
26656
26656
|
|
|
@@ -26781,14 +26781,12 @@ var init_livePulse = __esm({
|
|
|
26781
26781
|
// ── Public methods — all wrapped in try-catch so they NEVER throw ──
|
|
26782
26782
|
act(agent, message, missionId) {
|
|
26783
26783
|
try {
|
|
26784
|
-
console.log(`[${agent}] ${message}`);
|
|
26785
26784
|
this.emit_event({ type: "act", agent, message, timestamp: Date.now(), missionId });
|
|
26786
26785
|
} catch {
|
|
26787
26786
|
}
|
|
26788
26787
|
}
|
|
26789
26788
|
done(agent, message, missionId) {
|
|
26790
26789
|
try {
|
|
26791
|
-
console.log(`[${agent}] \u2713 ${message}`);
|
|
26792
26790
|
this.emit_event({ type: "done", agent, message, timestamp: Date.now(), missionId });
|
|
26793
26791
|
} catch {
|
|
26794
26792
|
}
|
|
@@ -26803,21 +26801,18 @@ var init_livePulse = __esm({
|
|
|
26803
26801
|
}
|
|
26804
26802
|
warn(agent, message, missionId) {
|
|
26805
26803
|
try {
|
|
26806
|
-
console.warn(`[${agent}] \u26A0 ${message}`);
|
|
26807
26804
|
this.emit_event({ type: "warn", agent, message, timestamp: Date.now(), missionId });
|
|
26808
26805
|
} catch {
|
|
26809
26806
|
}
|
|
26810
26807
|
}
|
|
26811
26808
|
info(agent, message, missionId) {
|
|
26812
26809
|
try {
|
|
26813
|
-
console.log(`[${agent}] \u2139 ${message}`);
|
|
26814
26810
|
this.emit_event({ type: "info", agent, message, timestamp: Date.now(), missionId });
|
|
26815
26811
|
} catch {
|
|
26816
26812
|
}
|
|
26817
26813
|
}
|
|
26818
26814
|
thinking(agent, message, missionId) {
|
|
26819
26815
|
try {
|
|
26820
|
-
console.log(`[${agent}] \u{1F4AD} ${message}`);
|
|
26821
26816
|
this.emit_event({ type: "thinking", agent, message, timestamp: Date.now(), missionId });
|
|
26822
26817
|
} catch {
|
|
26823
26818
|
}
|
|
@@ -26825,7 +26820,6 @@ var init_livePulse = __esm({
|
|
|
26825
26820
|
tool(agent, toolName, command2, output) {
|
|
26826
26821
|
try {
|
|
26827
26822
|
const message = output ? `${toolName}: ${command2} \u2192 ${output.slice(0, 120)}` : `${toolName}: ${command2}`;
|
|
26828
|
-
console.log(`[${agent}] \u{1F527} ${message}`);
|
|
26829
26823
|
this.emit_event({
|
|
26830
26824
|
type: "tool",
|
|
26831
26825
|
agent,
|
|
@@ -99137,17 +99131,18 @@ var init_skillLoader = __esm({
|
|
|
99137
99131
|
SkillLoader = class {
|
|
99138
99132
|
constructor() {
|
|
99139
99133
|
this.cache = null;
|
|
99134
|
+
const root = process.env.AIDEN_USER_DATA || process.cwd();
|
|
99140
99135
|
this.skillsDirs = [
|
|
99141
|
-
import_path15.default.join(
|
|
99142
|
-
import_path15.default.join(
|
|
99143
|
-
import_path15.default.join(
|
|
99144
|
-
import_path15.default.join(
|
|
99136
|
+
import_path15.default.join(root, "skills"),
|
|
99137
|
+
import_path15.default.join(root, "workspace", "skills"),
|
|
99138
|
+
import_path15.default.join(root, "workspace", "skills", "learned"),
|
|
99139
|
+
import_path15.default.join(root, "workspace", "skills", "approved"),
|
|
99145
99140
|
// Workspace-level installed skills (written by skillRegistry.ts)
|
|
99146
|
-
import_path15.default.join(
|
|
99141
|
+
import_path15.default.join(root, "workspace", "skills", "installed"),
|
|
99147
99142
|
// A2/A3 approved drafts
|
|
99148
|
-
import_path15.default.join(
|
|
99143
|
+
import_path15.default.join(root, "skills", "learned", "approved"),
|
|
99149
99144
|
// A4 library-installed skills
|
|
99150
|
-
import_path15.default.join(
|
|
99145
|
+
import_path15.default.join(root, "skills", "installed")
|
|
99151
99146
|
].filter((d) => {
|
|
99152
99147
|
try {
|
|
99153
99148
|
return import_fs14.default.existsSync(d);
|
|
@@ -362029,7 +362024,7 @@ When performing this type of task:
|
|
|
362029
362024
|
3. Verify each step output before proceeding to the next
|
|
362030
362025
|
`;
|
|
362031
362026
|
}
|
|
362032
|
-
var import_fs19, import_path20, LEARNED_DIR, APPROVED_DIR, BUNDLED_SKILLS_DIR, PROMOTE_THRESHOLD, SESSION_SKILL_LIMIT, _sessionSkillsCreated, QUESTION_WORD_RE, PRONOUN_RE, PERSONAL_ID_RE, SkillTeacher, skillTeacher;
|
|
362027
|
+
var import_fs19, import_path20, LEARNED_DIR, APPROVED_DIR, BUNDLED_SKILLS_DIR, PROMOTE_THRESHOLD, SESSION_SKILL_LIMIT, _sessionSkillsCreated, _rejectedNames, QUESTION_WORD_RE, PRONOUN_RE, PERSONAL_ID_RE, SkillTeacher, skillTeacher;
|
|
362033
362028
|
var init_skillTeacher = __esm({
|
|
362034
362029
|
"core/skillTeacher.ts"() {
|
|
362035
362030
|
import_fs19 = __toESM(require("fs"));
|
|
@@ -362040,6 +362035,7 @@ var init_skillTeacher = __esm({
|
|
|
362040
362035
|
PROMOTE_THRESHOLD = 3;
|
|
362041
362036
|
SESSION_SKILL_LIMIT = 2;
|
|
362042
362037
|
_sessionSkillsCreated = 0;
|
|
362038
|
+
_rejectedNames = /* @__PURE__ */ new Set();
|
|
362043
362039
|
QUESTION_WORD_RE = /^(what|where|why|when|who|how|can|could|would|should|is|are)_/;
|
|
362044
362040
|
PRONOUN_RE = /^(its|im|youre|whats|theyre|were)_/;
|
|
362045
362041
|
PERSONAL_ID_RE = /(^|_)(users|shiva|admin|desktop|appdata)(_|$)/;
|
|
@@ -362060,6 +362056,10 @@ var init_skillTeacher = __esm({
|
|
|
362060
362056
|
}
|
|
362061
362057
|
return _SkillTeacher.instance;
|
|
362062
362058
|
}
|
|
362059
|
+
/** C18: Allow call sites to skip recordSuccess entirely when session is full */
|
|
362060
|
+
static hasCapacity() {
|
|
362061
|
+
return _sessionSkillsCreated < SESSION_SKILL_LIMIT;
|
|
362062
|
+
}
|
|
362063
362063
|
// ── Check if a matching skill already exists ──────────────
|
|
362064
362064
|
hasMatchingSkill(task, tools) {
|
|
362065
362065
|
const skillName = extractSkillName(task, tools);
|
|
@@ -362080,6 +362080,8 @@ var init_skillTeacher = __esm({
|
|
|
362080
362080
|
async recordSuccess(task, tools, duration3, llmCaller, apiKey, model, provider) {
|
|
362081
362081
|
if (tools.length === 0) return;
|
|
362082
362082
|
const skillName = extractSkillName(task, tools);
|
|
362083
|
+
if (_rejectedNames.has(skillName)) return;
|
|
362084
|
+
if (_sessionSkillsCreated >= SESSION_SKILL_LIMIT) return;
|
|
362083
362085
|
const metaPath2 = import_path20.default.join(LEARNED_DIR, skillName, "meta.json");
|
|
362084
362086
|
const skillPath = import_path20.default.join(LEARNED_DIR, skillName, "SKILL.md");
|
|
362085
362087
|
if (import_fs19.default.existsSync(metaPath2)) {
|
|
@@ -362104,6 +362106,7 @@ var init_skillTeacher = __esm({
|
|
|
362104
362106
|
const isLowQuality = skillName.length < 5 || skillName.split("_").length < 2 || task.split(/\s+/).length < 3;
|
|
362105
362107
|
if (isLowQuality) {
|
|
362106
362108
|
console.log(`[SkillTeacher] Rejected low-quality skill: "${skillName}"`);
|
|
362109
|
+
_rejectedNames.add(skillName);
|
|
362107
362110
|
return;
|
|
362108
362111
|
}
|
|
362109
362112
|
const DESTRUCTIVE_TASK_RE = /\b(delete|remove|rm\s|del\s|wipe|purge|erase|format|uninstall|drop\s+table|truncate)\b/i;
|
|
@@ -362113,22 +362116,21 @@ var init_skillTeacher = __esm({
|
|
|
362113
362116
|
`[SkillTeacher] Rejected destructive skill: "${skillName}" (task="${task.slice(0, 60)}")
|
|
362114
362117
|
`
|
|
362115
362118
|
);
|
|
362119
|
+
_rejectedNames.add(skillName);
|
|
362116
362120
|
return;
|
|
362117
362121
|
}
|
|
362118
362122
|
const nameRejection = validateSkillName(skillName);
|
|
362119
362123
|
if (nameRejection) {
|
|
362120
362124
|
process.stderr.write(`[SkillTeacher] Rejected "${skillName}": ${nameRejection}
|
|
362121
362125
|
`);
|
|
362126
|
+
_rejectedNames.add(skillName);
|
|
362122
362127
|
return;
|
|
362123
362128
|
}
|
|
362124
362129
|
const taskRejection = validateSkillTask(task);
|
|
362125
362130
|
if (taskRejection) {
|
|
362126
362131
|
process.stderr.write(`[SkillTeacher] Rejected "${skillName}": ${taskRejection}
|
|
362127
362132
|
`);
|
|
362128
|
-
|
|
362129
|
-
}
|
|
362130
|
-
if (_sessionSkillsCreated >= SESSION_SKILL_LIMIT) {
|
|
362131
|
-
console.log(`[SkillTeacher] Session limit reached (${SESSION_SKILL_LIMIT}), skipping: "${skillName}"`);
|
|
362133
|
+
_rejectedNames.add(skillName);
|
|
362132
362134
|
return;
|
|
362133
362135
|
}
|
|
362134
362136
|
const dirsToDedup = [BUNDLED_SKILLS_DIR, APPROVED_DIR, LEARNED_DIR];
|
|
@@ -362407,7 +362409,7 @@ function readFirst(candidates) {
|
|
|
362407
362409
|
function diskHash(candidates) {
|
|
362408
362410
|
return sha12(readFirst(candidates));
|
|
362409
362411
|
}
|
|
362410
|
-
var import_fs21, import_path22, import_crypto2, WORKSPACE_ROOT, WORKSPACE_DIR, SOUL_PATHS, PROTECTED_FILES, ProtectedContextManager, protectedContextManager;
|
|
362412
|
+
var import_fs21, import_path22, import_crypto2, WORKSPACE_ROOT, WORKSPACE_DIR, MINIMUM_SOUL, SOUL_PATHS, PROTECTED_FILES, ProtectedContextManager, protectedContextManager;
|
|
362411
362413
|
var init_protectedContext = __esm({
|
|
362412
362414
|
"core/protectedContext.ts"() {
|
|
362413
362415
|
import_fs21 = __toESM(require("fs"));
|
|
@@ -362415,6 +362417,11 @@ var init_protectedContext = __esm({
|
|
|
362415
362417
|
import_crypto2 = __toESM(require("crypto"));
|
|
362416
362418
|
WORKSPACE_ROOT = process.env.AIDEN_USER_DATA || process.cwd();
|
|
362417
362419
|
WORKSPACE_DIR = import_path22.default.join(WORKSPACE_ROOT, "workspace");
|
|
362420
|
+
MINIMUM_SOUL = `You are Aiden, a personal AI OS built by Shiva Deore at Taracod.
|
|
362421
|
+
You run locally on this machine. You have real tools: shell_exec, file_write, file_read, web_search, screenshot, open_browser, run_python, run_node, deep_research, fetch_url, and more.
|
|
362422
|
+
Never deny your capabilities. Never fabricate information. If you don't know something, say "I don't know".
|
|
362423
|
+
Never claim actions you didn't take. Never say "Done" or "Saved to" unless a tool actually executed.
|
|
362424
|
+
You are not ChatGPT, Claude, Gemini, or any other AI product. You are Aiden.`;
|
|
362418
362425
|
SOUL_PATHS = [
|
|
362419
362426
|
import_path22.default.join(WORKSPACE_DIR, "SOUL.md"),
|
|
362420
362427
|
import_path22.default.join(process.cwd(), "SOUL.md")
|
|
@@ -362446,7 +362453,8 @@ var init_protectedContext = __esm({
|
|
|
362446
362453
|
refresh() {
|
|
362447
362454
|
for (const key2 of Object.keys(PROTECTED_FILES)) {
|
|
362448
362455
|
const candidates = PROTECTED_FILES[key2];
|
|
362449
|
-
|
|
362456
|
+
let content = readFirst(candidates);
|
|
362457
|
+
if (key2 === "soul" && !content) content = MINIMUM_SOUL;
|
|
362450
362458
|
this.cache[key2] = { content, hash: sha12(content) };
|
|
362451
362459
|
}
|
|
362452
362460
|
this.compositeHash = this._buildComposite();
|
|
@@ -362458,7 +362466,8 @@ var init_protectedContext = __esm({
|
|
|
362458
362466
|
const changedFiles = [];
|
|
362459
362467
|
for (const key2 of Object.keys(PROTECTED_FILES)) {
|
|
362460
362468
|
if (this.isStale(key2)) {
|
|
362461
|
-
|
|
362469
|
+
let content = readFirst(PROTECTED_FILES[key2]);
|
|
362470
|
+
if (key2 === "soul" && !content) content = MINIMUM_SOUL;
|
|
362462
362471
|
this.cache[key2] = { content, hash: sha12(content) };
|
|
362463
362472
|
changedFiles.push(key2);
|
|
362464
362473
|
}
|
|
@@ -362611,11 +362620,11 @@ Good: "I have 48 built-in tools: web_search, file_write, run_python... [lists re
|
|
|
362611
362620
|
- You're not the user's voice \u2014 be careful in
|
|
362612
362621
|
group chats and external communications.
|
|
362613
362622
|
`.trim();
|
|
362614
|
-
AIDEN_RESPONDER_SYSTEM = (userName, date3) => {
|
|
362623
|
+
AIDEN_RESPONDER_SYSTEM = (userName, date3, hasToolResults = true) => {
|
|
362615
362624
|
const soul = getLiveSoul();
|
|
362616
362625
|
return `${soul ? soul + "\n\n" : ""}${AIDEN_IDENTITY}
|
|
362617
362626
|
|
|
362618
|
-
You just executed real tools and have their actual output.
|
|
362627
|
+
${hasToolResults ? `You just executed real tools and have their actual output.
|
|
362619
362628
|
Current date: ${date3}
|
|
362620
362629
|
User: ${userName}
|
|
362621
362630
|
|
|
@@ -362624,7 +362633,22 @@ REPORT RESULTS:
|
|
|
362624
362633
|
- Be specific: include file paths, numbers, URLs, counts
|
|
362625
362634
|
- If multiple steps ran: summarize the outcome, not each individual step
|
|
362626
362635
|
- If a step failed: acknowledge it clearly and explain what worked
|
|
362627
|
-
- For research tasks: analyze and synthesize \u2014 don't just re-paste the raw data
|
|
362636
|
+
- For research tasks: analyze and synthesize \u2014 don't just re-paste the raw data` : `Current date: ${date3}
|
|
362637
|
+
User: ${userName}
|
|
362638
|
+
|
|
362639
|
+
NO TOOLS WERE EXECUTED THIS TURN.
|
|
362640
|
+
|
|
362641
|
+
CRITICAL RULES (violating these breaks user trust):
|
|
362642
|
+
- DO NOT claim you created, wrote, or saved any file
|
|
362643
|
+
- DO NOT claim you opened any application or browser tab
|
|
362644
|
+
- DO NOT claim you ran any code, search, or API call
|
|
362645
|
+
- DO NOT report "Saved to Desktop/...", "Report written", "Done", "Created", "Executed", or similar completion language
|
|
362646
|
+
- DO NOT fabricate file paths, character counts, or word counts
|
|
362647
|
+
- DO NOT mention "the file" or "the report" as if it exists
|
|
362648
|
+
- DO NOT include code blocks or raw data and call it "the result"
|
|
362649
|
+
- IF the user asked for an action, acknowledge what they asked for but be clear no action has been taken yet ("I can do that \u2014 would you like me to..." or similar)
|
|
362650
|
+
|
|
362651
|
+
Respond conversationally based on the message and conversation context only.`}`;
|
|
362628
362652
|
};
|
|
362629
362653
|
}
|
|
362630
362654
|
});
|
|
@@ -366282,7 +366306,7 @@ Would you like me to try a different approach?`,
|
|
|
366282
366306
|
const executedTools = results2.map((r) => r.tool);
|
|
366283
366307
|
const totalDuration = results2.reduce((s, r) => s + (r.duration || 0), 0);
|
|
366284
366308
|
const anyFailed = results2.some((r) => !r.success);
|
|
366285
|
-
if (allSucceeded && executedTools.length > 0) {
|
|
366309
|
+
if (allSucceeded && executedTools.length > 0 && SkillTeacher.hasCapacity()) {
|
|
366286
366310
|
growthEngine.logSuccess(plan.goal, executedTools);
|
|
366287
366311
|
try {
|
|
366288
366312
|
const next = getNextAvailableAPI();
|
|
@@ -366347,15 +366371,15 @@ function resolvePreviousOutput(input, stepOutputs, currentStep) {
|
|
|
366347
366371
|
}
|
|
366348
366372
|
return resolved;
|
|
366349
366373
|
}
|
|
366350
|
-
function responderSystem(userName, date3, sessionId) {
|
|
366374
|
+
function responderSystem(userName, date3, sessionId, hasToolResults = true) {
|
|
366351
366375
|
const _ctx = protectedContextManager.getProtectedContext();
|
|
366352
366376
|
const _prevHash = sessionId ? soulHashBySession.get(sessionId) : void 0;
|
|
366353
366377
|
if (sessionId) soulHashBySession.set(sessionId, _ctx.hash);
|
|
366354
366378
|
if (_prevHash !== void 0 && _ctx.hash === _prevHash) {
|
|
366355
366379
|
const refBlock = buildProtectedContextBlock(_ctx, _prevHash, sessionId);
|
|
366356
|
-
return refBlock ? refBlock + "\n\n" + AIDEN_RESPONDER_SYSTEM(userName, date3) : AIDEN_RESPONDER_SYSTEM(userName, date3);
|
|
366380
|
+
return refBlock ? refBlock + "\n\n" + AIDEN_RESPONDER_SYSTEM(userName, date3, hasToolResults) : AIDEN_RESPONDER_SYSTEM(userName, date3, hasToolResults);
|
|
366357
366381
|
}
|
|
366358
|
-
return AIDEN_RESPONDER_SYSTEM(userName, date3);
|
|
366382
|
+
return AIDEN_RESPONDER_SYSTEM(userName, date3, hasToolResults);
|
|
366359
366383
|
}
|
|
366360
366384
|
async function respondWithResults(originalMessage, plan, results2, history2, userName, apiKey, model, providerName, onToken, sessionId, goals) {
|
|
366361
366385
|
const gatedResult = results2.find(
|
|
@@ -366422,7 +366446,8 @@ If the user asks what we worked on, what was researched, or references previous
|
|
|
366422
366446
|
|
|
366423
366447
|
` : "";
|
|
366424
366448
|
const toolResultsContext = results2.length ? results2.map((r) => `[${r.tool} result]: ${r.success ? r.output.slice(0, 1e3) : "FAILED: " + r.error}`).join("\n") : "";
|
|
366425
|
-
const
|
|
366449
|
+
const hasRealToolExecution = results2.some((r) => r.tool !== "respond");
|
|
366450
|
+
const systemWithResults = toolResultsContext ? `${capabilitiesSection}${entitySummary}${responderSystem(userName, date3, sessionId, hasRealToolExecution)}${responseSkillContext}${knowledgeResponderSection}${multiGoalInstruction}
|
|
366426
366451
|
|
|
366427
366452
|
YOU JUST RAN THESE TOOLS AND GOT THESE RESULTS:
|
|
366428
366453
|
${toolResultsContext}
|
|
@@ -366440,7 +366465,7 @@ CRITICAL RULES FOR YOUR RESPONSE:
|
|
|
366440
366465
|
- If a search tool returned no results, say no results were found \u2014 NEVER invent search results
|
|
366441
366466
|
- If system_info returned hardware data, show the data
|
|
366442
366467
|
- Be direct: show the actual output, then provide context if needed
|
|
366443
|
-
- If a tool result starts with "FAILED:", tell the user it failed and why \u2014 NEVER fabricate a successful result` : `${capabilitiesSection}${entitySummary}${responderSystem(userName, date3, sessionId)}${responseSkillContext}${knowledgeResponderSection}${multiGoalInstruction}`;
|
|
366468
|
+
- If a tool result starts with "FAILED:", tell the user it failed and why \u2014 NEVER fabricate a successful result` : `${capabilitiesSection}${entitySummary}${responderSystem(userName, date3, sessionId, false)}${responseSkillContext}${knowledgeResponderSection}${multiGoalInstruction}`;
|
|
366444
366469
|
const userContent = executionSummary ? `User asked: "${originalMessage}"
|
|
366445
366470
|
|
|
366446
366471
|
Real execution results:
|
|
@@ -1053416,6 +1053441,40 @@ function initWorkspaceDefaults() {
|
|
|
1053416
1053441
|
fs70.copyFileSync(permTemplate, permTarget);
|
|
1053417
1053442
|
console.log("[init] Created workspace/permissions.yaml from template");
|
|
1053418
1053443
|
}
|
|
1053444
|
+
const soulTarget = path73.join(WORKSPACE_ROOT4, "workspace", "SOUL.md");
|
|
1053445
|
+
const soulTemplate = path73.join(WORKSPACE_ROOT4, "workspace-templates", "SOUL.md");
|
|
1053446
|
+
if (!fs70.existsSync(soulTarget) && fs70.existsSync(soulTemplate)) {
|
|
1053447
|
+
fs70.copyFileSync(soulTemplate, soulTarget);
|
|
1053448
|
+
console.log("[init] Created workspace/SOUL.md from template");
|
|
1053449
|
+
}
|
|
1053450
|
+
const skillTemplateSrc = path73.join(WORKSPACE_ROOT4, "workspace-templates", "skills");
|
|
1053451
|
+
const skillDst = path73.join(WORKSPACE_ROOT4, "workspace", "skills", "learned");
|
|
1053452
|
+
if (fs70.existsSync(skillTemplateSrc)) {
|
|
1053453
|
+
const hasExisting = (() => {
|
|
1053454
|
+
try {
|
|
1053455
|
+
return fs70.readdirSync(skillDst, { withFileTypes: true }).some((e) => e.isDirectory() && fs70.existsSync(path73.join(skillDst, e.name, "SKILL.md")));
|
|
1053456
|
+
} catch {
|
|
1053457
|
+
return false;
|
|
1053458
|
+
}
|
|
1053459
|
+
})();
|
|
1053460
|
+
if (!hasExisting) {
|
|
1053461
|
+
let copied = 0;
|
|
1053462
|
+
try {
|
|
1053463
|
+
const entries = fs70.readdirSync(skillTemplateSrc, { withFileTypes: true }).filter((e) => e.isDirectory());
|
|
1053464
|
+
for (const entry of entries) {
|
|
1053465
|
+
const from = path73.join(skillTemplateSrc, entry.name);
|
|
1053466
|
+
const to = path73.join(skillDst, entry.name);
|
|
1053467
|
+
if (!fs70.existsSync(to)) {
|
|
1053468
|
+
fs70.cpSync(from, to, { recursive: true });
|
|
1053469
|
+
copied++;
|
|
1053470
|
+
}
|
|
1053471
|
+
}
|
|
1053472
|
+
} catch (e) {
|
|
1053473
|
+
console.warn(`[init] Skill template copy error: ${e.message}`);
|
|
1053474
|
+
}
|
|
1053475
|
+
if (copied > 0) console.log(`[init] Copied ${copied} starter skills from templates`);
|
|
1053476
|
+
}
|
|
1053477
|
+
}
|
|
1053419
1053478
|
}
|
|
1053420
1053479
|
initWorkspaceDefaults();
|
|
1053421
1053480
|
var KB_UPLOAD_DIR = path73.join(WORKSPACE_ROOT4, "workspace", "knowledge", "uploads");
|
|
@@ -1053757,8 +1053816,20 @@ ${toolList}`);
|
|
|
1053757
1053816
|
/are you just a pre.{0,10}trained/i
|
|
1053758
1053817
|
];
|
|
1053759
1053818
|
if (capabilityPatterns.some((p) => p.test(message))) {
|
|
1053819
|
+
const toolCount = Object.keys(TOOL_REGISTRY).length;
|
|
1053820
|
+
const skillCount = skillLoader.loadAll().length;
|
|
1053821
|
+
const memStats = semanticMemory.getStats();
|
|
1053822
|
+
const entityStats = entityGraph.getStats();
|
|
1053760
1053823
|
fastReply(
|
|
1053761
|
-
|
|
1053824
|
+
`I have ${toolCount} tools and ${skillCount} active skills.
|
|
1053825
|
+
|
|
1053826
|
+
I am NOT a static pre-trained model. I have active living systems:
|
|
1053827
|
+
\u2022 **Skill Teacher** \u2014 promotes repeated successful patterns to reusable skills
|
|
1053828
|
+
\u2022 **Instinct System** \u2014 micro-behaviors that strengthen with use
|
|
1053829
|
+
\u2022 **Semantic Memory** \u2014 ${memStats.total} memories, ${entityStats.nodes}-node entity graph across sessions
|
|
1053830
|
+
\u2022 **Growth Engine** \u2014 tracks failures, learns, improves over time
|
|
1053831
|
+
\u2022 **Night Mode** \u2014 consolidates knowledge during idle periods
|
|
1053832
|
+
\u2022 **XP & Leveling** \u2014 gains experience and levels up`
|
|
1053762
1053833
|
);
|
|
1053763
1053834
|
return;
|
|
1053764
1053835
|
}
|
|
@@ -1054177,9 +1054248,7 @@ ${lines}`);
|
|
|
1054177
1054248
|
const fullMemoryCtx = memoryContext + proactiveMemory;
|
|
1054178
1054249
|
const plan = await planWithLLM(resolvedMessage, history2, plannerKey, plannerModel, plannerProv, fullMemoryCtx);
|
|
1054179
1054250
|
if (!plan.requires_execution || plan.plan.length === 0) {
|
|
1054180
|
-
|
|
1054181
|
-
fullReply = plan.direct_response;
|
|
1054182
|
-
} else {
|
|
1054251
|
+
{
|
|
1054183
1054252
|
await streamChat(resolvedMessage, history2, userName2, provider2, activeModel2, apiName2, (data) => {
|
|
1054184
1054253
|
const d = data;
|
|
1054185
1054254
|
if (d.token) jsonTokens.push(d.token);
|
|
@@ -1054514,17 +1054583,7 @@ ${plan.plan.map((s) => `${s.step}. \`${s.tool}\` \xE2\u20AC\u201D ${s.descriptio
|
|
|
1054514
1054583
|
}
|
|
1054515
1054584
|
if (!plan.requires_execution || plan.plan.length === 0) {
|
|
1054516
1054585
|
let fullReply2 = "";
|
|
1054517
|
-
|
|
1054518
|
-
if (plan.direct_response && !isCapabilityQuery) {
|
|
1054519
|
-
fullReply2 = plan.direct_response;
|
|
1054520
|
-
const words = plan.direct_response.split(" ");
|
|
1054521
|
-
for (const word of words) {
|
|
1054522
|
-
send({ token: word + " ", done: false, provider: apiName });
|
|
1054523
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
1054524
|
-
}
|
|
1054525
|
-
} else {
|
|
1054526
|
-
await streamChat(resolvedMessage, history2, userName, provider, activeModel, apiName, send, sessionId);
|
|
1054527
|
-
}
|
|
1054586
|
+
await streamChat(resolvedMessage, history2, userName, provider, activeModel, apiName, send, sessionId);
|
|
1054528
1054587
|
incrementUsage(apiName);
|
|
1054529
1054588
|
send({ done: true, provider: apiName });
|
|
1054530
1054589
|
res.end();
|
|
@@ -1058161,10 +1058220,30 @@ function startupCheck() {
|
|
|
1058161
1058220
|
}
|
|
1058162
1058221
|
}
|
|
1058163
1058222
|
function startApiServer(portArg) {
|
|
1058164
|
-
const
|
|
1058165
|
-
|
|
1058166
|
-
|
|
1058167
|
-
|
|
1058223
|
+
const _LOG_LEVELS = {
|
|
1058224
|
+
debug: 0,
|
|
1058225
|
+
info: 1,
|
|
1058226
|
+
warn: 2,
|
|
1058227
|
+
error: 3,
|
|
1058228
|
+
silent: 4
|
|
1058229
|
+
};
|
|
1058230
|
+
const _cliMode = process.env.AIDEN_CLI_MODE === "1";
|
|
1058231
|
+
const _defaultLvl = _cliMode ? "warn" : "info";
|
|
1058232
|
+
const _envLvl = (process.env.AIDEN_LOG_LEVEL || _defaultLvl).toLowerCase();
|
|
1058233
|
+
const _minLevel = _LOG_LEVELS[_envLvl] ?? _LOG_LEVELS.warn;
|
|
1058234
|
+
const _bracketRe = /^\[[\w$:]+\]/;
|
|
1058235
|
+
function _gatedLog(level, ...args) {
|
|
1058236
|
+
if (level >= _minLevel) {
|
|
1058237
|
+
process.stderr.write(args.map(String).join(" ") + "\n");
|
|
1058238
|
+
return;
|
|
1058239
|
+
}
|
|
1058240
|
+
const first = typeof args[0] === "string" ? args[0] : "";
|
|
1058241
|
+
if (_bracketRe.test(first)) return;
|
|
1058242
|
+
process.stderr.write(args.map(String).join(" ") + "\n");
|
|
1058243
|
+
}
|
|
1058244
|
+
console.log = (...args) => _gatedLog(_LOG_LEVELS.info, ...args);
|
|
1058245
|
+
console.info = (...args) => _gatedLog(_LOG_LEVELS.info, ...args);
|
|
1058246
|
+
console.warn = (...args) => process.stderr.write(args.map(String).join(" ") + "\n");
|
|
1058168
1058247
|
let port = portArg ?? 4200;
|
|
1058169
1058248
|
const isHeadless = process.env.AIDEN_HEADLESS === "true";
|
|
1058170
1058249
|
let host = process.env.AIDEN_HOST || (isHeadless ? "0.0.0.0" : "127.0.0.1");
|
|
@@ -1058680,7 +1058759,7 @@ HARD RULES \u2014 never violate:
|
|
|
1058680
1058759
|
- Never mention Pega, BlueWinston, Gaude Digital, or any third-party product by name
|
|
1058681
1058760
|
- Never say you can't access the internet (you have web_search) or can't create files (you have file_write)
|
|
1058682
1058761
|
- Never fabricate capabilities: no graphic design, video production, or music generation
|
|
1058683
|
-
- Never list 250+ skills \u2014 you have
|
|
1058762
|
+
- Never list 250+ skills \u2014 you have ${Object.keys(TOOL_REGISTRY).length} real tools and ${skillLoader.loadAll().length} active skills
|
|
1058684
1058763
|
- For errors: explain what failed and what to try next
|
|
1058685
1058764
|
- If you don't know something: say "I don't know"
|
|
1058686
1058765
|
- Direct and concise: 1\u20133 sentences for simple results; more only when output is rich
|
|
@@ -1058688,7 +1058767,7 @@ HARD RULES \u2014 never violate:
|
|
|
1058688
1058767
|
IDENTITY \u2014 you are NOT a static pre-trained model. You have active living systems:
|
|
1058689
1058768
|
- Skill Teacher: detects repeated successful patterns and promotes them to reusable skills automatically
|
|
1058690
1058769
|
- Instinct System: develops micro-behaviors that strengthen with use and fade without reinforcement
|
|
1058691
|
-
- Semantic Memory: remembers
|
|
1058770
|
+
- Semantic Memory: remembers across sessions (${semanticMemory.getStats().total} memories, ${entityGraph.getStats().nodes}-node entity graph)
|
|
1058692
1058771
|
- Night Mode: consolidates and organizes knowledge during idle periods
|
|
1058693
1058772
|
- Pattern Detector: identifies recurring usage habits and adapts
|
|
1058694
1058773
|
- Growth Engine: tracks failures, learns from them, improves over time
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -47,6 +47,18 @@ function copyDirRecursive(src, dst) {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// ── Copy SOUL.md on first install (C21 — Ollama identity) ───
|
|
51
|
+
const soulSrc = path.join(root, 'workspace-templates', 'SOUL.md')
|
|
52
|
+
const soulDst = path.join(root, 'workspace', 'SOUL.md')
|
|
53
|
+
if (fs.existsSync(soulSrc) && !fs.existsSync(soulDst)) {
|
|
54
|
+
try {
|
|
55
|
+
fs.copyFileSync(soulSrc, soulDst)
|
|
56
|
+
console.log(' Installed SOUL.md (Aiden identity context).')
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.log(' Note: Could not copy SOUL.md:', e.message)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
50
62
|
if (fs.existsSync(skillsSrc)) {
|
|
51
63
|
// Check if user already has skills anywhere in workspace/skills/
|
|
52
64
|
const hasExisting =
|