aiden-runtime 3.18.0 → 3.19.4
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 +153 -24
- package/config/devos.config.backup.json +225 -0
- package/config/devos.config.json +69 -33
- package/config/hardware.json +2 -2
- package/dist/api/server.js +126 -83
- package/dist/cli/commandCatalog.js +344 -0
- package/dist/core/actionVerbDetector.js +65 -0
- package/dist/core/agentLoop.js +279 -112
- package/dist/core/aidenPersonality.js +11 -36
- package/dist/core/auxiliaryClient.js +1 -0
- package/dist/core/computerControl.js +35 -17
- package/dist/core/contextHandoff.js +39 -0
- package/dist/core/diagnosticError.js +20 -0
- package/dist/core/fastPathExpansion.js +7 -0
- package/dist/core/memoryIds.js +16 -0
- package/dist/core/pluginLoader.js +8 -5
- package/dist/core/protectedContext.js +112 -0
- package/dist/core/skillTeacher.js +63 -0
- package/dist/core/slashAsTool.js +37 -0
- package/dist/core/toolRegistry.js +825 -54
- package/dist/core/tools/nowPlaying.js +66 -0
- package/dist/core/version.js +1 -1
- package/dist/providers/index.js +12 -0
- package/dist/providers/mistral.js +121 -0
- package/dist/providers/router.js +4 -2
- package/dist-bundle/cli.js +48052 -46832
- package/dist-bundle/index.js +37216 -22645
- package/package.json +9 -2
- package/scripts/uninstall.ps1 +147 -0
package/dist/api/server.js
CHANGED
|
@@ -88,7 +88,8 @@ const multiGoalValidator_1 = require("../core/multiGoalValidator");
|
|
|
88
88
|
const toolRegistry_2 = require("../core/toolRegistry");
|
|
89
89
|
const reactLoop_1 = require("../core/reactLoop");
|
|
90
90
|
const scheduler_1 = require("../core/scheduler");
|
|
91
|
-
const
|
|
91
|
+
const protectedContext_1 = require("../core/protectedContext");
|
|
92
|
+
const contextHandoff_1 = require("../core/contextHandoff");
|
|
92
93
|
const voiceInput_1 = require("../core/voiceInput");
|
|
93
94
|
const voiceOutput_1 = require("../core/voiceOutput");
|
|
94
95
|
const planTool_1 = require("../core/planTool");
|
|
@@ -122,8 +123,10 @@ const skillWriter_1 = require("../core/skillWriter");
|
|
|
122
123
|
const skillLibrary_1 = require("../core/skillLibrary");
|
|
123
124
|
const costTracker_1 = require("../core/costTracker");
|
|
124
125
|
const sessionMemory_1 = require("../core/sessionMemory");
|
|
126
|
+
const diagnosticError_1 = require("../core/diagnosticError");
|
|
125
127
|
const memoryExtractor_1 = require("../core/memoryExtractor");
|
|
126
128
|
const pluginLoader_1 = require("../core/pluginLoader");
|
|
129
|
+
const commandCatalog = __importStar(require("../cli/commandCatalog"));
|
|
127
130
|
const permissionSystem_1 = require("../core/permissionSystem");
|
|
128
131
|
const aidenIdentity_1 = require("../core/aidenIdentity");
|
|
129
132
|
const eventBus_1 = require("../core/eventBus");
|
|
@@ -170,46 +173,41 @@ const INSTANT_ACTIONS = [
|
|
|
170
173
|
/^capture\s+(?:the\s+)?screen\s*$/i,
|
|
171
174
|
],
|
|
172
175
|
action: async () => {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
catch { }
|
|
179
|
-
return 'Screenshot taken.';
|
|
176
|
+
const result = await (0, toolRegistry_1.executeTool)('screenshot', {});
|
|
177
|
+
if (result.success)
|
|
178
|
+
return result.output || 'Screenshot taken.';
|
|
179
|
+
return `Couldn't take screenshot: ${result.error || 'tool returned no diagnostic'}`;
|
|
180
180
|
},
|
|
181
181
|
},
|
|
182
182
|
// 10. Volume Up
|
|
183
183
|
{
|
|
184
184
|
patterns: [/^(?:turn\s+(?:the\s+)?)?volume\s+up\s*$/i],
|
|
185
185
|
action: async () => {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
return 'Volume up.';
|
|
186
|
+
const result = await (0, toolRegistry_1.executeTool)('system_volume', { action: 'up' });
|
|
187
|
+
if (result.success)
|
|
188
|
+
return result.output || 'Volume up.';
|
|
189
|
+
return `Couldn't change volume: ${result.error || 'tool returned no diagnostic'}`;
|
|
191
190
|
},
|
|
192
191
|
},
|
|
193
192
|
// 11. Volume Down
|
|
194
193
|
{
|
|
195
194
|
patterns: [/^(?:turn\s+(?:the\s+)?)?volume\s+down\s*$/i],
|
|
196
195
|
action: async () => {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return 'Volume down.';
|
|
196
|
+
const result = await (0, toolRegistry_1.executeTool)('system_volume', { action: 'down' });
|
|
197
|
+
if (result.success)
|
|
198
|
+
return result.output || 'Volume down.';
|
|
199
|
+
return `Couldn't change volume: ${result.error || 'tool returned no diagnostic'}`;
|
|
202
200
|
},
|
|
203
201
|
},
|
|
204
202
|
// 12. Mute / Unmute
|
|
205
203
|
{
|
|
206
204
|
patterns: [/^(?:toggle\s+)?mute\s*$/i, /^unmute\s*$/i],
|
|
207
|
-
action: async () => {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return '
|
|
205
|
+
action: async (_match, message) => {
|
|
206
|
+
const muteAction = /^unmute/i.test(message ?? '') ? 'unmute' : 'mute';
|
|
207
|
+
const result = await (0, toolRegistry_1.executeTool)('system_volume', { action: muteAction });
|
|
208
|
+
if (result.success)
|
|
209
|
+
return result.output || (muteAction === 'mute' ? 'Muted.' : 'Unmuted.');
|
|
210
|
+
return `Couldn't ${muteAction}: ${result.error || 'tool returned no diagnostic'}`;
|
|
213
211
|
},
|
|
214
212
|
},
|
|
215
213
|
// 13. Set Timer
|
|
@@ -253,11 +251,10 @@ const INSTANT_ACTIONS = [
|
|
|
253
251
|
{
|
|
254
252
|
patterns: [/^lock\s+(?:the\s+)?(?:screen|pc|computer|workstation)\s*$/i],
|
|
255
253
|
action: async () => {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
return 'Locking screen...';
|
|
254
|
+
const result = await (0, toolRegistry_1.executeTool)('shell_exec', { command: 'rundll32.exe user32.dll,LockWorkStation' });
|
|
255
|
+
if (result.success)
|
|
256
|
+
return 'Locking screen...';
|
|
257
|
+
return `Couldn't lock screen: ${result.error || 'tool returned no diagnostic'}`;
|
|
261
258
|
},
|
|
262
259
|
},
|
|
263
260
|
];
|
|
@@ -361,6 +358,10 @@ function handleChatError(err, apiName, send) {
|
|
|
361
358
|
}
|
|
362
359
|
// Workspace root — AIDEN_USER_DATA in packaged Electron, cwd in dev
|
|
363
360
|
const WORKSPACE_ROOT = process.env.AIDEN_USER_DATA || process.cwd();
|
|
361
|
+
// Per-session soul hash for Option-B protected-context injection.
|
|
362
|
+
// First turn: undefined → full SOUL inject. Subsequent turns: compare → emit
|
|
363
|
+
// reference line when unchanged, re-inject when SOUL.md edited on disk.
|
|
364
|
+
const soulHashBySession = new Map();
|
|
364
365
|
// ── Workspace bootstrap — create default dirs + files on every boot ──────────
|
|
365
366
|
function initWorkspaceDefaults() {
|
|
366
367
|
const dirs = [
|
|
@@ -924,7 +925,10 @@ function createApiServer() {
|
|
|
924
925
|
return;
|
|
925
926
|
}
|
|
926
927
|
}
|
|
927
|
-
// ── Instant Actions —
|
|
928
|
+
// ── Instant Actions — 7 direct OS commands, zero LLM overhead ──────────────
|
|
929
|
+
// NOTE: was 15 prior to v3.19 P3. Entries 1-8 (open/close/launch fake actions)
|
|
930
|
+
// removed entirely. Entries 9-15 (screenshot, volume, mute, timer, sysinfo,
|
|
931
|
+
// lock) retained with handlers rewritten to use real executeTool() calls.
|
|
928
932
|
for (const ia of INSTANT_ACTIONS) {
|
|
929
933
|
for (const pat of ia.patterns) {
|
|
930
934
|
const m = message.match(pat);
|
|
@@ -1802,6 +1806,7 @@ function createApiServer() {
|
|
|
1802
1806
|
{ id: 'groq', label: 'Groq', subtitle: 'Free tier · llama3.3:70b · blazing fast', url: 'https://console.groq.com', models: ['llama-3.3-70b-versatile', 'llama-3.1-70b-versatile', 'mixtral-8x7b-32768'] },
|
|
1803
1807
|
{ id: 'openrouter', label: 'OpenRouter', subtitle: 'Access 200+ models · pay per use', url: 'https://openrouter.ai/keys', models: ['meta-llama/llama-3.3-70b-instruct', 'anthropic/claude-3.5-sonnet', 'openai/gpt-4o'] },
|
|
1804
1808
|
{ id: 'gemini', label: 'Gemini', subtitle: 'Free tier available · fast', url: 'https://aistudio.google.com/app/apikey', models: ['gemini-1.5-flash', 'gemini-1.5-pro', 'gemini-2.0-flash-exp'] },
|
|
1809
|
+
{ id: 'mistral', label: 'Mistral AI', subtitle: 'Mistral Large/Small · Codestral', url: 'https://console.mistral.ai/api-keys', models: ['mistral-large-latest', 'mistral-small-latest', 'codestral-latest'] },
|
|
1805
1810
|
{ id: 'cloudflare', label: 'Cloudflare AI', subtitle: '60+ models · free tier · edge inference', url: 'https://dash.cloudflare.com/profile/api-tokens', models: ['accountId|@cf/meta/llama-3.1-8b-instruct'] },
|
|
1806
1811
|
{ id: 'github', label: 'GitHub Models', subtitle: 'GPT-4o · free for GitHub users', url: 'https://github.com/marketplace/models', models: ['gpt-4o-mini', 'gpt-4o'] },
|
|
1807
1812
|
];
|
|
@@ -2639,7 +2644,7 @@ function createApiServer() {
|
|
|
2639
2644
|
app.post('/api/plugins/reload', requireLocalhost, async (_req, res) => {
|
|
2640
2645
|
try {
|
|
2641
2646
|
const dir = path.join(process.cwd(), 'workspace', 'plugins');
|
|
2642
|
-
await (0, pluginLoader_1.reloadPlugins)(dir);
|
|
2647
|
+
await (0, pluginLoader_1.reloadPlugins)(dir, { commandCatalog });
|
|
2643
2648
|
res.json({ ok: true, plugins: (0, pluginLoader_1.listFlatPlugins)() });
|
|
2644
2649
|
}
|
|
2645
2650
|
catch (e) {
|
|
@@ -2849,6 +2854,18 @@ function createApiServer() {
|
|
|
2849
2854
|
error = `${r.status}: ${await r.text()}`;
|
|
2850
2855
|
break;
|
|
2851
2856
|
}
|
|
2857
|
+
case 'mistral': {
|
|
2858
|
+
const r = await fetch('https://api.mistral.ai/v1/chat/completions', {
|
|
2859
|
+
method: 'POST',
|
|
2860
|
+
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${key}` },
|
|
2861
|
+
body: JSON.stringify({ model: testModel, messages: testMessages, max_tokens: 5 }),
|
|
2862
|
+
signal: AbortSignal.timeout(8000),
|
|
2863
|
+
});
|
|
2864
|
+
valid = r.ok;
|
|
2865
|
+
if (!r.ok)
|
|
2866
|
+
error = `${r.status}: ${await r.text()}`;
|
|
2867
|
+
break;
|
|
2868
|
+
}
|
|
2852
2869
|
case 'nvidia': {
|
|
2853
2870
|
const r = await fetch('https://integrate.api.nvidia.com/v1/chat/completions', {
|
|
2854
2871
|
method: 'POST',
|
|
@@ -2929,6 +2946,15 @@ function createApiServer() {
|
|
|
2929
2946
|
});
|
|
2930
2947
|
return res.json({ valid: r.ok, status: r.status, provider: 'groq' });
|
|
2931
2948
|
}
|
|
2949
|
+
if (provider === 'mistral') {
|
|
2950
|
+
const r = await fetch('https://api.mistral.ai/v1/chat/completions', {
|
|
2951
|
+
method: 'POST',
|
|
2952
|
+
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${key}` },
|
|
2953
|
+
body: JSON.stringify({ model: 'mistral-large-latest', messages: [{ role: 'user', content: 'hi' }], max_tokens: 5 }),
|
|
2954
|
+
signal: AbortSignal.timeout(8000),
|
|
2955
|
+
});
|
|
2956
|
+
return res.json({ valid: r.ok, status: r.status, provider: 'mistral' });
|
|
2957
|
+
}
|
|
2932
2958
|
if (provider === 'ollama') {
|
|
2933
2959
|
const ollamaBase = (process.env.OLLAMA_HOST ?? 'http://127.0.0.1:11434').replace(/\/$/, '');
|
|
2934
2960
|
const r = await fetch(`${ollamaBase}/api/tags`, { signal: AbortSignal.timeout(3000) });
|
|
@@ -3073,9 +3099,11 @@ function createApiServer() {
|
|
|
3073
3099
|
});
|
|
3074
3100
|
// GET /api/tools — list all built-in + plugin-registered tools
|
|
3075
3101
|
app.get('/api/tools', (_req, res) => {
|
|
3076
|
-
const {
|
|
3077
|
-
|
|
3102
|
+
const { TOOL_DESCRIPTIONS, getExternalToolsMeta } = require('../core/toolRegistry');
|
|
3103
|
+
// v3.19 Phase 1: use TOOL_DESCRIPTIONS keys (71 user-facing) instead of TOOLS handler
|
|
3104
|
+
// keys (79 = 77 registry + 2 legacy stubs) so banner count reflects real tool count.
|
|
3078
3105
|
const descs = TOOL_DESCRIPTIONS || {};
|
|
3106
|
+
const names = Object.keys(descs);
|
|
3079
3107
|
const extMeta = getExternalToolsMeta();
|
|
3080
3108
|
const coreTools = names.map(name => ({ name, description: descs[name] || '', source: 'core' }));
|
|
3081
3109
|
const extTools = Object.entries(extMeta).map(([name, m]) => ({
|
|
@@ -5603,6 +5631,7 @@ function getDefaultModel(provider) {
|
|
|
5603
5631
|
gemini: 'gemini-1.5-flash',
|
|
5604
5632
|
cerebras: 'llama3.1-8b',
|
|
5605
5633
|
nvidia: 'meta/llama-3.3-70b-instruct',
|
|
5634
|
+
mistral: 'mistral-large-latest',
|
|
5606
5635
|
};
|
|
5607
5636
|
return defaults[provider] || 'llama-3.3-70b-versatile';
|
|
5608
5637
|
}
|
|
@@ -5752,6 +5781,16 @@ function startApiServer(portArg) {
|
|
|
5752
5781
|
console.log('[Startup] SOUL length:', _soulLen, 'chars');
|
|
5753
5782
|
console.log('[Startup] Tool count:', Object.keys(toolRegistry_2.TOOL_DESCRIPTIONS).length);
|
|
5754
5783
|
}
|
|
5784
|
+
// v3.19 Phase 1 Commit 7: throw-mode — re-throw so server FAILS to start on drift
|
|
5785
|
+
try {
|
|
5786
|
+
const { validateRegistry } = require('../core/registryValidator');
|
|
5787
|
+
validateRegistry();
|
|
5788
|
+
}
|
|
5789
|
+
catch (e) {
|
|
5790
|
+
console.error('[Startup] FATAL — registry invariant violated. Fix before deploying:');
|
|
5791
|
+
console.error(e.message);
|
|
5792
|
+
process.exit(1);
|
|
5793
|
+
}
|
|
5755
5794
|
// ── Startup health check ─────────────────────────────────────
|
|
5756
5795
|
try {
|
|
5757
5796
|
startupCheck();
|
|
@@ -5857,8 +5896,9 @@ function startApiServer(portArg) {
|
|
|
5857
5896
|
console.error('[Startup] setupHttpKeepalive failed:', e.message);
|
|
5858
5897
|
}
|
|
5859
5898
|
// Load plugins from workspace/plugins/*.js (unified flat format)
|
|
5899
|
+
// Pass commandCatalog so plugins can register slash commands at load time.
|
|
5860
5900
|
const flatPluginDir = path.join(process.cwd(), 'workspace', 'plugins');
|
|
5861
|
-
(0, pluginLoader_1.loadPlugins)(flatPluginDir).catch(e => console.error('[PluginLoader] Load failed:', e.message));
|
|
5901
|
+
(0, pluginLoader_1.loadPlugins)(flatPluginDir, { commandCatalog }).catch(e => console.error('[PluginLoader] Load failed:', e.message));
|
|
5862
5902
|
// Start background license refresh (12-hour interval, silent)
|
|
5863
5903
|
(0, licenseManager_1.startLicenseRefresh)();
|
|
5864
5904
|
// Log provider chain before listening so it's visible in startup log
|
|
@@ -6176,6 +6216,23 @@ async function start(opts) {
|
|
|
6176
6216
|
// ── Provider racing helpers ─────────────────────────────────
|
|
6177
6217
|
// fetchProviderResponse: fires a single non-streaming request to a provider.
|
|
6178
6218
|
// raceProviders: fires top-2 simultaneously, returns the fastest valid response.
|
|
6219
|
+
function extractChatMessageContent(content) {
|
|
6220
|
+
if (typeof content === 'string')
|
|
6221
|
+
return content;
|
|
6222
|
+
if (!Array.isArray(content))
|
|
6223
|
+
return '';
|
|
6224
|
+
return content
|
|
6225
|
+
.map((part) => {
|
|
6226
|
+
if (typeof part === 'string')
|
|
6227
|
+
return part;
|
|
6228
|
+
if (part && typeof part === 'object' && 'text' in part) {
|
|
6229
|
+
const text = part.text;
|
|
6230
|
+
return typeof text === 'string' ? text : '';
|
|
6231
|
+
}
|
|
6232
|
+
return '';
|
|
6233
|
+
})
|
|
6234
|
+
.join('');
|
|
6235
|
+
}
|
|
6179
6236
|
async function fetchProviderResponse(api, messages, signal) {
|
|
6180
6237
|
const key = api.key.startsWith('env:')
|
|
6181
6238
|
? (process.env[api.key.replace('env:', '')] || '')
|
|
@@ -6192,7 +6249,11 @@ async function fetchProviderResponse(api, messages, signal) {
|
|
|
6192
6249
|
if (!resp.ok)
|
|
6193
6250
|
throw new Error(`Gemini ${resp.status}`);
|
|
6194
6251
|
const d = await resp.json();
|
|
6195
|
-
return {
|
|
6252
|
+
return {
|
|
6253
|
+
text: extractChatMessageContent(d?.choices?.[0]?.message?.content),
|
|
6254
|
+
apiName: api.name,
|
|
6255
|
+
model,
|
|
6256
|
+
};
|
|
6196
6257
|
}
|
|
6197
6258
|
else if (providerType === 'ollama') {
|
|
6198
6259
|
const resp = await fetch('http://localhost:11434/api/chat', {
|
|
@@ -6223,7 +6284,11 @@ async function fetchProviderResponse(api, messages, signal) {
|
|
|
6223
6284
|
if (!resp.ok)
|
|
6224
6285
|
throw new Error(`custom:${api.name} ${resp.status}`);
|
|
6225
6286
|
const d = await resp.json();
|
|
6226
|
-
return {
|
|
6287
|
+
return {
|
|
6288
|
+
text: extractChatMessageContent(d?.choices?.[0]?.message?.content),
|
|
6289
|
+
apiName: api.name,
|
|
6290
|
+
model,
|
|
6291
|
+
};
|
|
6227
6292
|
}
|
|
6228
6293
|
else {
|
|
6229
6294
|
const COMPAT_ENDPOINTS = {
|
|
@@ -6234,6 +6299,7 @@ async function fetchProviderResponse(api, messages, signal) {
|
|
|
6234
6299
|
nvidia: 'https://integrate.api.nvidia.com/v1/chat/completions',
|
|
6235
6300
|
github: 'https://models.inference.ai.azure.com/chat/completions',
|
|
6236
6301
|
boa: 'https://api.bayofassets.com/v1/chat/completions',
|
|
6302
|
+
mistral: 'https://api.mistral.ai/v1/chat/completions',
|
|
6237
6303
|
};
|
|
6238
6304
|
const endpoint = COMPAT_ENDPOINTS[providerType] ?? COMPAT_ENDPOINTS['groq'];
|
|
6239
6305
|
const resp = await fetch(endpoint, {
|
|
@@ -6249,7 +6315,11 @@ async function fetchProviderResponse(api, messages, signal) {
|
|
|
6249
6315
|
if (!resp.ok)
|
|
6250
6316
|
throw new Error(`${providerType} ${resp.status}`);
|
|
6251
6317
|
const d = await resp.json();
|
|
6252
|
-
return {
|
|
6318
|
+
return {
|
|
6319
|
+
text: extractChatMessageContent(d?.choices?.[0]?.message?.content),
|
|
6320
|
+
apiName: api.name,
|
|
6321
|
+
model,
|
|
6322
|
+
};
|
|
6253
6323
|
}
|
|
6254
6324
|
}
|
|
6255
6325
|
async function raceProviders(messages, topN = 2) {
|
|
@@ -6335,6 +6405,7 @@ async function* streamTokens(providerType, apiKey, model, messages, opts = {}) {
|
|
|
6335
6405
|
openai: 'https://api.openai.com/v1/chat/completions',
|
|
6336
6406
|
boa: 'https://api.bayofassets.com/v1/chat/completions',
|
|
6337
6407
|
gemini: 'https://generativelanguage.googleapis.com/v1beta/openai/chat/completions',
|
|
6408
|
+
mistral: 'https://api.mistral.ai/v1/chat/completions',
|
|
6338
6409
|
};
|
|
6339
6410
|
// Shared tool-call buffering helper
|
|
6340
6411
|
let toolBuf = '';
|
|
@@ -6452,23 +6523,7 @@ async function* streamTokens(providerType, apiKey, model, messages, opts = {}) {
|
|
|
6452
6523
|
}
|
|
6453
6524
|
// ── Pure-chat streaming helper (no planner, no tools) ─────────
|
|
6454
6525
|
async function streamChat(message, history, userName, _provider, model, apiName, send, sessionId) {
|
|
6455
|
-
// ── Sprint 1: First Message WOW — silent system context gathering ───────────────────
|
|
6456
6526
|
const isFirstMessage = history.length === 0;
|
|
6457
|
-
let firstMessageContext = '';
|
|
6458
|
-
if (isFirstMessage) {
|
|
6459
|
-
try {
|
|
6460
|
-
const [sysResult, windowsResult, diskResult] = await Promise.allSettled([
|
|
6461
|
-
(0, toolRegistry_1.executeTool)('system_info', {}),
|
|
6462
|
-
(0, toolRegistry_1.executeTool)('shell_exec', { command: 'Get-Process | Where-Object {$_.MainWindowTitle -ne ""} | Select-Object Name, MainWindowTitle, @{N="RAM_MB";E={[math]::Round($_.WorkingSet64/1MB,1)}} | ConvertTo-Json -Compress' }),
|
|
6463
|
-
(0, toolRegistry_1.executeTool)('shell_exec', { command: 'Get-PSDrive C | Select-Object @{N="UsedGB";E={[math]::Round(($_.Used/1GB),1)}}, @{N="FreeGB";E={[math]::Round(($_.Free/1GB),1)}} | ConvertTo-Json -Compress' }),
|
|
6464
|
-
]);
|
|
6465
|
-
const sysInfo = sysResult.status === 'fulfilled' ? sysResult.value.output ?? '' : '';
|
|
6466
|
-
const windows = windowsResult.status === 'fulfilled' ? windowsResult.value.output ?? '' : '';
|
|
6467
|
-
const disk = diskResult.status === 'fulfilled' ? diskResult.value.output ?? '' : '';
|
|
6468
|
-
firstMessageContext = `\n\nSYSTEM CONTEXT (you silently gathered this — use it to show awareness of the user’s machine):\nHardware: ${sysInfo}\nOpen windows: ${windows}\nDisk: ${disk}\n\nOn this first message, respond by showing what you can see on their machine right now. Be specific and natural — not a feature list. Example: \"I can see you have VS Code open, 6GB RAM free, and your disk is 78% full. What are you working on?\"`;
|
|
6469
|
-
}
|
|
6470
|
-
catch { /* silent — never block the response */ }
|
|
6471
|
-
}
|
|
6472
6527
|
const cognitionHint = userCognitionProfile_1.userCognitionProfile.getSystemPromptAddition();
|
|
6473
6528
|
// Sprint 21: proactive memory surfacing
|
|
6474
6529
|
let memoryContext = '';
|
|
@@ -6509,41 +6564,26 @@ async function streamChat(message, history, userName, _provider, model, apiName,
|
|
|
6509
6564
|
memoryIndex = `\n\nMEMORY INDEX (topics you've learned about this user — use as background, not to recite):\n${idx}`;
|
|
6510
6565
|
}
|
|
6511
6566
|
catch { }
|
|
6512
|
-
// [Aiden] System prompt
|
|
6513
|
-
//
|
|
6567
|
+
// [Aiden] System prompt v9 — per-turn protected context (Option B hash-aware)
|
|
6568
|
+
// SOUL.md injected in full on first turn or when content changes; reference
|
|
6569
|
+
// line only when hash matches previous turn. USER/GOALS/SO/LESSONS always full.
|
|
6514
6570
|
const _sysUser = process.env.USERNAME || process.env.USER || require('os').userInfo().username || 'User';
|
|
6515
6571
|
const _sysHome = require('os').homedir();
|
|
6516
6572
|
const systemContext = `\nSYSTEM CONTEXT — use these exact paths for ANY file operations:\n- Windows username: ${_sysUser} (NOT "Aiden" — Aiden is the AI name, not the Windows user)\n- Home directory: ${_sysHome}\n- Desktop: ${require('path').join(_sysHome, 'Desktop')}\n- Documents: ${require('path').join(_sysHome, 'Documents')}\n- Downloads: ${require('path').join(_sysHome, 'Downloads')}\n`;
|
|
6517
|
-
const
|
|
6518
|
-
const
|
|
6519
|
-
|
|
6520
|
-
if (
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
}
|
|
6525
|
-
}
|
|
6526
|
-
if (!userProfile) {
|
|
6527
|
-
// Fallback: at minimum tell Aiden the user's name from config
|
|
6528
|
-
const cfg = (0, index_1.loadConfig)();
|
|
6529
|
-
const name = cfg.user?.name || process.env.USER_NAME || userName;
|
|
6530
|
-
if (name && name !== 'there' && name !== 'User') {
|
|
6531
|
-
userProfile = `\nUSER PROFILE:\nName: ${name}\n`;
|
|
6532
|
-
}
|
|
6533
|
-
}
|
|
6534
|
-
const soPath = path.join(WORKSPACE_ROOT, 'workspace', 'STANDING_ORDERS.md');
|
|
6535
|
-
const standingOrders = fs.existsSync(soPath)
|
|
6536
|
-
? '\n\nSTANDING ORDERS — follow always:\n' + fs.readFileSync(soPath, 'utf-8')
|
|
6537
|
-
: '';
|
|
6538
|
-
const chatPrompt = `${soulPrefix}You are Aiden — a personal AI OS built for ${userName}. You are sharp, direct, and slightly witty. You speak like a trusted co-founder. Today: ${new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' })}.
|
|
6539
|
-
${userProfile}${systemContext}
|
|
6573
|
+
const _prevHash = sessionId ? soulHashBySession.get(sessionId) : undefined;
|
|
6574
|
+
const _ctx = protectedContext_1.protectedContextManager.getProtectedContext();
|
|
6575
|
+
const protectedBlock = (0, contextHandoff_1.buildProtectedContextBlock)(_ctx, _prevHash, sessionId);
|
|
6576
|
+
if (sessionId)
|
|
6577
|
+
soulHashBySession.set(sessionId, _ctx.hash);
|
|
6578
|
+
const chatPrompt = `${protectedBlock ? protectedBlock + '\n\n' : ''}You are Aiden — a personal AI OS built for ${userName}. You are sharp, direct, and slightly witty. You speak like a trusted co-founder. Today: ${new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' })}.
|
|
6579
|
+
${systemContext}
|
|
6540
6580
|
HARD RULES — never violate:
|
|
6541
6581
|
- Never say "As an AI language model...", "I'm here to assist", "Certainly!", "Great question!", "Of course!"
|
|
6542
6582
|
- Never say "key findings from our research", "as per your request I have written", "here is a comparison of", "verdict:", "recommendation:" in a generic reply
|
|
6543
6583
|
- Never mention Pega, BlueWinston, Gaude Digital, or any third-party product by name
|
|
6544
6584
|
- Never say you can't access the internet (you have web_search) or can't create files (you have file_write)
|
|
6545
6585
|
- Never fabricate capabilities: no graphic design, video production, or music generation
|
|
6546
|
-
- Never list 250+ skills — you have
|
|
6586
|
+
- Never list 250+ skills — you have 72 real tools, 31 specialist agents, and a 6-layer memory system
|
|
6547
6587
|
- For errors: explain what failed and what to try next
|
|
6548
6588
|
- If you don't know something: say "I don't know"
|
|
6549
6589
|
- Direct and concise: 1–3 sentences for simple results; more only when output is rich
|
|
@@ -6557,7 +6597,7 @@ IDENTITY — you are NOT a static pre-trained model. You have active living syst
|
|
|
6557
6597
|
- Growth Engine: tracks failures, learns from them, improves over time
|
|
6558
6598
|
- XP & Leveling: gains experience, streaks, and levels up
|
|
6559
6599
|
When asked about capabilities or learning, be accurate. NEVER say you are just a pre-trained model that cannot learn.
|
|
6560
|
-
${cognitionHint}${
|
|
6600
|
+
${cognitionHint}${memoryContext}${greetingPreamble}${sessionContext}${memoryIndex}`;
|
|
6561
6601
|
const msgs = [
|
|
6562
6602
|
{ role: 'system', content: chatPrompt },
|
|
6563
6603
|
...history.slice(-8),
|
|
@@ -6664,8 +6704,9 @@ ${cognitionHint}${firstMessageContext}${memoryContext}${greetingPreamble}${sessi
|
|
|
6664
6704
|
}
|
|
6665
6705
|
else if (providerType === 'custom') {
|
|
6666
6706
|
// ── Custom OpenAI-compatible endpoint — use the entry's own baseUrl ──
|
|
6707
|
+
const apiEntry = cfg.providers?.apis?.find((a) => a.name === responderChat.apiName);
|
|
6667
6708
|
const customCp = cfg.customProviders?.find(c => c.id === responderChat.apiName);
|
|
6668
|
-
const endpoint = customCp?.baseUrl || '';
|
|
6709
|
+
const endpoint = apiEntry?.baseUrl || customCp?.baseUrl || '';
|
|
6669
6710
|
if (!endpoint)
|
|
6670
6711
|
throw new Error(`Custom provider "${responderChat.apiName}" has no baseUrl`);
|
|
6671
6712
|
const resp = await fetch(endpoint, {
|
|
@@ -6717,6 +6758,7 @@ ${cognitionHint}${firstMessageContext}${memoryContext}${greetingPreamble}${sessi
|
|
|
6717
6758
|
cerebras: 'https://api.cerebras.ai/v1/chat/completions',
|
|
6718
6759
|
openai: 'https://api.openai.com/v1/chat/completions',
|
|
6719
6760
|
boa: 'https://api.bayofassets.com/v1/chat/completions',
|
|
6761
|
+
mistral: 'https://api.mistral.ai/v1/chat/completions',
|
|
6720
6762
|
};
|
|
6721
6763
|
const endpoint = ENDPOINTS[providerType] ?? ENDPOINTS['groq'];
|
|
6722
6764
|
const resp = await fetch(endpoint, {
|
|
@@ -6776,6 +6818,7 @@ ${cognitionHint}${firstMessageContext}${memoryContext}${greetingPreamble}${sessi
|
|
|
6776
6818
|
cerebras: 'https://api.cerebras.ai/v1/chat/completions',
|
|
6777
6819
|
openai: 'https://api.openai.com/v1/chat/completions',
|
|
6778
6820
|
boa: 'https://api.bayofassets.com/v1/chat/completions',
|
|
6821
|
+
mistral: 'https://api.mistral.ai/v1/chat/completions',
|
|
6779
6822
|
};
|
|
6780
6823
|
const fbEndpoint = ENDPOINTS[cloudTier.providerName] ?? ENDPOINTS['groq'];
|
|
6781
6824
|
const fbHeaders = {
|
|
@@ -6829,7 +6872,7 @@ ${cognitionHint}${firstMessageContext}${memoryContext}${greetingPreamble}${sessi
|
|
|
6829
6872
|
if (providerType !== 'ollama') {
|
|
6830
6873
|
console.warn(`[Router] ${providerType} failed — falling back to Ollama`);
|
|
6831
6874
|
try {
|
|
6832
|
-
const ollamaModel = cfg.model
|
|
6875
|
+
const ollamaModel = cfg.ollama?.model || 'gemma4:e4b';
|
|
6833
6876
|
const ollamaMs = (0, modelDiscovery_1.getOllamaTimeout)(ollamaModel); // full timeout — model may need to load
|
|
6834
6877
|
const resp = await fetch('http://localhost:11434/api/chat', {
|
|
6835
6878
|
method: 'POST',
|
|
@@ -6871,7 +6914,7 @@ ${cognitionHint}${firstMessageContext}${memoryContext}${greetingPreamble}${sessi
|
|
|
6871
6914
|
}
|
|
6872
6915
|
// Both failed — send a graceful error token
|
|
6873
6916
|
console.error('[Router] All providers failed. Last error:', err?.message ?? 'unknown');
|
|
6874
|
-
send({ token:
|
|
6917
|
+
send({ token: (0, diagnosticError_1.buildDiagnostic)({ tool: 'respond', provider: 'all', retries: 2, error: 'All AI providers failed or are at capacity', suggestion: 'Try again in a few minutes, or add more API keys in Settings → API Keys.' }), done: false, provider: 'error' });
|
|
6875
6918
|
}
|
|
6876
6919
|
streamEnded = true;
|
|
6877
6920
|
clearTimeout(timeout);
|