0agent 1.0.83 → 1.0.85
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/bin/0agent.js +113 -2
- package/bin/chat.js +33 -1
- package/dist/daemon.mjs +106 -125
- package/package.json +1 -1
package/bin/0agent.js
CHANGED
|
@@ -307,14 +307,75 @@ async function runInit() {
|
|
|
307
307
|
], 0);
|
|
308
308
|
const seedName = seedIdx === 0 ? 'software-engineering' : null;
|
|
309
309
|
|
|
310
|
+
// ── Step 7: Chat channels ─────────────────────────────────────────────────
|
|
311
|
+
console.log('\n \x1b[1mChat channels\x1b[0m');
|
|
312
|
+
console.log(' \x1b[2mConnect messaging apps so you can chat with your agent from anywhere.\x1b[0m');
|
|
313
|
+
console.log(' \x1b[2mYou can add more later in ~/.0agent/config.yaml\x1b[0m\n');
|
|
314
|
+
|
|
315
|
+
let tgToken = '', slackBotToken = '', slackAppToken = '', slackSecret = '';
|
|
316
|
+
let waProvider = '', waAccountSid = '', waAuthToken = '', waFromNumber = '';
|
|
317
|
+
const channelChoices = [
|
|
318
|
+
'Telegram bot',
|
|
319
|
+
'Slack bot',
|
|
320
|
+
'WhatsApp (via Twilio)',
|
|
321
|
+
'Skip — set up later',
|
|
322
|
+
];
|
|
323
|
+
const channelIdx = await arrowSelect('Connect a chat channel?', channelChoices, 3);
|
|
324
|
+
|
|
325
|
+
if (channelIdx === 0) {
|
|
326
|
+
// Telegram
|
|
327
|
+
console.log('\n \x1b[2m1. Open @BotFather on Telegram\x1b[0m');
|
|
328
|
+
console.log(' \x1b[2m2. Send /newbot and follow the prompts\x1b[0m');
|
|
329
|
+
console.log(' \x1b[2m3. Copy the token below\x1b[0m\n');
|
|
330
|
+
tgToken = await arrowPassword('Telegram bot token');
|
|
331
|
+
tgToken = tgToken.trim();
|
|
332
|
+
if (tgToken) {
|
|
333
|
+
console.log(' \x1b[32m✓\x1b[0m Telegram connected. Message your bot to chat with 0agent.');
|
|
334
|
+
}
|
|
335
|
+
} else if (channelIdx === 1) {
|
|
336
|
+
// Slack
|
|
337
|
+
console.log('\n \x1b[2m1. Create a Slack app at api.slack.com/apps\x1b[0m');
|
|
338
|
+
console.log(' \x1b[2m2. Enable Socket Mode + Event Subscriptions\x1b[0m');
|
|
339
|
+
console.log(' \x1b[2m3. Add bot scopes: chat:write, app_mentions:read, im:history\x1b[0m\n');
|
|
340
|
+
slackBotToken = (await arrowPassword('Slack bot token (xoxb-...)')).trim();
|
|
341
|
+
slackAppToken = (await arrowPassword('Slack app token (xapp-...)')).trim();
|
|
342
|
+
slackSecret = (await arrowPassword('Slack signing secret')).trim();
|
|
343
|
+
if (slackBotToken && slackAppToken) {
|
|
344
|
+
console.log(' \x1b[32m✓\x1b[0m Slack connected. @mention your bot or DM it.');
|
|
345
|
+
}
|
|
346
|
+
} else if (channelIdx === 2) {
|
|
347
|
+
// WhatsApp via Twilio
|
|
348
|
+
console.log('\n \x1b[2m1. Sign up at twilio.com\x1b[0m');
|
|
349
|
+
console.log(' \x1b[2m2. Enable WhatsApp sandbox or a production number\x1b[0m\n');
|
|
350
|
+
waProvider = 'twilio';
|
|
351
|
+
waAccountSid = (await arrowInput('Twilio Account SID')).trim();
|
|
352
|
+
waAuthToken = (await arrowPassword('Twilio Auth Token')).trim();
|
|
353
|
+
waFromNumber = (await arrowInput('WhatsApp from number (whatsapp:+1...)')).trim();
|
|
354
|
+
if (waAccountSid && waAuthToken) {
|
|
355
|
+
console.log(' \x1b[32m✓\x1b[0m WhatsApp connected via Twilio.');
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Build surfaces config YAML section
|
|
360
|
+
let surfacesYaml = '';
|
|
361
|
+
if (tgToken) {
|
|
362
|
+
surfacesYaml += `\nsurfaces:\n telegram:\n token: "${tgToken}"`;
|
|
363
|
+
} else if (slackBotToken && slackAppToken) {
|
|
364
|
+
surfacesYaml += `\nsurfaces:\n slack:\n bot_token: "${slackBotToken}"\n app_token: "${slackAppToken}"\n signing_secret: "${slackSecret}"`;
|
|
365
|
+
} else if (waAccountSid && waAuthToken) {
|
|
366
|
+
surfacesYaml += `\nsurfaces:\n whatsapp:\n provider: "twilio"\n account_sid: "${waAccountSid}"\n auth_token: "${waAuthToken}"\n from_number: "${waFromNumber}"`;
|
|
367
|
+
}
|
|
368
|
+
|
|
310
369
|
// ── Summary ───────────────────────────────────────────────────────────────
|
|
370
|
+
const channelLabel = tgToken ? 'Telegram' : (slackBotToken ? 'Slack' : (waAccountSid ? 'WhatsApp' : 'none'));
|
|
311
371
|
console.log('\n \x1b[1mReady to launch\x1b[0m\n');
|
|
312
372
|
console.log(` LLM: \x1b[36m${providerKey}/${model}\x1b[0m`);
|
|
313
373
|
console.log(` API Key: ${apiKey ? '\x1b[32m✓ set\x1b[0m (' + apiKey.slice(0, 8) + '••••)' : '\x1b[33mnot set\x1b[0m'}`);
|
|
314
374
|
console.log(` Memory: ${ghToken ? `\x1b[32mgithub.com/${ghOwner}/0agent-memory\x1b[0m` : '\x1b[2mlocal only\x1b[0m'}`);
|
|
315
375
|
console.log(` Workspace: \x1b[36m${workspacePath}\x1b[0m`);
|
|
316
376
|
console.log(` Sandbox: \x1b[36m${sandboxChoice}\x1b[0m`);
|
|
317
|
-
console.log(` Seed: \x1b[36m${seedName ?? 'scratch'}\x1b[0m
|
|
377
|
+
console.log(` Seed: \x1b[36m${seedName ?? 'scratch'}\x1b[0m`);
|
|
378
|
+
console.log(` Channel: \x1b[36m${channelLabel}\x1b[0m\n`);
|
|
318
379
|
|
|
319
380
|
// Write config
|
|
320
381
|
const dbPath = resolve(AGENT_DIR, 'graph.db');
|
|
@@ -354,6 +415,7 @@ graph:
|
|
|
354
415
|
object_store_path: "${objPath}"
|
|
355
416
|
${seedName ? `\nseed: "${seedName}"` : ''}
|
|
356
417
|
${ghToken && ghOwner ? `\ngithub_memory:\n enabled: true\n token: "${ghToken}"\n owner: "${ghOwner}"\n repo: "${ghRepo}"` : ''}
|
|
418
|
+
${surfacesYaml}
|
|
357
419
|
`;
|
|
358
420
|
|
|
359
421
|
writeFileSync(CONFIG_PATH, config, 'utf8');
|
|
@@ -376,7 +438,56 @@ ${ghToken && ghOwner ? `\ngithub_memory:\n enabled: true\n token: "${ghToken}"
|
|
|
376
438
|
console.log('\n Starting...');
|
|
377
439
|
await startDaemon();
|
|
378
440
|
|
|
379
|
-
//
|
|
441
|
+
// Wait for daemon to be ready
|
|
442
|
+
for (let i = 0; i < 10; i++) {
|
|
443
|
+
if (await isDaemonRunning()) break;
|
|
444
|
+
await sleep(500);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// ── First-run onboarding: agent learns about the user ──────────────────
|
|
448
|
+
console.log('\n \x1b[1m┌─────────────────────────────────────────────────┐\x1b[0m');
|
|
449
|
+
console.log(' \x1b[1m│ Your agent is ready! │\x1b[0m');
|
|
450
|
+
console.log(' \x1b[1m│ │\x1b[0m');
|
|
451
|
+
console.log(' \x1b[1m│ Here\'s what you can do: │\x1b[0m');
|
|
452
|
+
console.log(' \x1b[1m│ │\x1b[0m');
|
|
453
|
+
console.log(' \x1b[1m│ \x1b[36m0agent "build a landing page"\x1b[0m\x1b[1m │\x1b[0m');
|
|
454
|
+
console.log(' \x1b[1m│ \x1b[36m0agent chat\x1b[0m\x1b[1m — persistent chat │\x1b[0m');
|
|
455
|
+
if (tgToken) {
|
|
456
|
+
console.log(' \x1b[1m│ \x1b[36mTelegram bot\x1b[0m\x1b[1m — message your bot │\x1b[0m');
|
|
457
|
+
} else if (slackBotToken) {
|
|
458
|
+
console.log(' \x1b[1m│ \x1b[36mSlack bot\x1b[0m\x1b[1m — @mention in Slack │\x1b[0m');
|
|
459
|
+
}
|
|
460
|
+
console.log(' \x1b[1m│ \x1b[36m0agent skill list\x1b[0m\x1b[1m — see all skills │\x1b[0m');
|
|
461
|
+
console.log(' \x1b[1m│ \x1b[36m0agent help\x1b[0m\x1b[1m — full command list │\x1b[0m');
|
|
462
|
+
console.log(' \x1b[1m│ │\x1b[0m');
|
|
463
|
+
console.log(' \x1b[1m└─────────────────────────────────────────────────┘\x1b[0m');
|
|
464
|
+
|
|
465
|
+
// Fire the onboarding session — agent introduces itself and learns about the user
|
|
466
|
+
console.log('\n \x1b[2mYour agent would like to get to know you...\x1b[0m\n');
|
|
467
|
+
try {
|
|
468
|
+
const onboardingTask = [
|
|
469
|
+
'This is your very first conversation with a new user who just set up 0agent.',
|
|
470
|
+
'Introduce yourself warmly and briefly — you are their personal AI agent that lives on their machine, learns from every interaction, and can code, browse, automate tasks, and more.',
|
|
471
|
+
'',
|
|
472
|
+
'Then ask them a few questions to learn about them (ONE at a time):',
|
|
473
|
+
'1. What\'s your name?',
|
|
474
|
+
'2. What do you do? (role, field, what kind of work)',
|
|
475
|
+
'3. What are you hoping to use 0agent for? (coding, automation, research, etc.)',
|
|
476
|
+
'',
|
|
477
|
+
'Save everything they tell you to memory_write immediately.',
|
|
478
|
+
'Keep it conversational — not a form. Be genuinely curious.',
|
|
479
|
+
'If they mention a specific project or tech stack, remember that too.',
|
|
480
|
+
'End by suggesting one thing you can do for them right now based on what they shared.',
|
|
481
|
+
].join('\n');
|
|
482
|
+
|
|
483
|
+
await fetch(`${BASE_URL}/api/sessions`, {
|
|
484
|
+
method: 'POST',
|
|
485
|
+
headers: { 'Content-Type': 'application/json' },
|
|
486
|
+
body: JSON.stringify({ task: onboardingTask }),
|
|
487
|
+
});
|
|
488
|
+
} catch {}
|
|
489
|
+
|
|
490
|
+
// Open chat TUI — the onboarding response will stream in
|
|
380
491
|
const chatSc = resolve(dirname(new URL(import.meta.url).pathname), 'chat.js');
|
|
381
492
|
if (existsSync(chatSc)) {
|
|
382
493
|
const { spawn: sp } = await import('node:child_process');
|
package/bin/chat.js
CHANGED
|
@@ -408,14 +408,46 @@ const spinner = new Spinner('Thinking');
|
|
|
408
408
|
const history = []; // command history for arrow keys
|
|
409
409
|
|
|
410
410
|
// ─── Header ──────────────────────────────────────────────────────────────────
|
|
411
|
+
function isFirstRun() {
|
|
412
|
+
// Check if the graph DB has any conversations yet
|
|
413
|
+
try {
|
|
414
|
+
const dbPath = cfg?.graph?.db_path;
|
|
415
|
+
if (!dbPath || !existsSync(dbPath)) return true;
|
|
416
|
+
// If DB exists but is tiny (<10KB), likely first run
|
|
417
|
+
const { statSync } = require('node:fs');
|
|
418
|
+
return statSync(dbPath).size < 10240;
|
|
419
|
+
} catch { return true; }
|
|
420
|
+
}
|
|
421
|
+
|
|
411
422
|
function printHeader() {
|
|
412
423
|
const provider = getCurrentProvider(cfg);
|
|
413
424
|
const modelStr = provider ? `${provider.provider}/${provider.model}` : 'no model';
|
|
414
425
|
const ws = cfg?.workspace?.path ?? null;
|
|
426
|
+
const first = isFirstRun();
|
|
415
427
|
console.log();
|
|
416
428
|
console.log(` ${fmt(C.bold, '0agent')} ${fmt(C.dim, '·')} ${fmt(C.cyan, modelStr)}`);
|
|
417
429
|
if (ws) console.log(fmt(C.dim, ` ${ws}`));
|
|
418
|
-
|
|
430
|
+
|
|
431
|
+
if (first) {
|
|
432
|
+
console.log();
|
|
433
|
+
console.log(fmt(C.bold, ' Welcome! I\'m your personal AI agent.'));
|
|
434
|
+
console.log(fmt(C.dim, ' I live on your machine, learn from every interaction, and get better over time.'));
|
|
435
|
+
console.log();
|
|
436
|
+
console.log(` ${fmt(C.bold, 'What I can do:')}`);
|
|
437
|
+
console.log(` ${fmt(C.cyan, 'Code')} — build features, fix bugs, refactor, test, review`);
|
|
438
|
+
console.log(` ${fmt(C.cyan, 'Automate')} — browse websites, fill forms, book tickets, file taxes`);
|
|
439
|
+
console.log(` ${fmt(C.cyan, 'Monitor')} — watch prices, slots, availability — act when ready`);
|
|
440
|
+
console.log(` ${fmt(C.cyan, 'Publish')} — create HTML artifacts and share via live surge.sh links`);
|
|
441
|
+
console.log(` ${fmt(C.cyan, 'Remember')} — I learn your preferences, patterns, and project context`);
|
|
442
|
+
if (cfg?.surfaces?.telegram) console.log(` ${fmt(C.cyan, 'Telegram')} — message your bot to chat with me from anywhere`);
|
|
443
|
+
if (cfg?.surfaces?.slack) console.log(` ${fmt(C.cyan, 'Slack')} — @mention me or DM me in Slack`);
|
|
444
|
+
if (cfg?.surfaces?.whatsapp) console.log(` ${fmt(C.cyan, 'WhatsApp')} — send me a message on WhatsApp`);
|
|
445
|
+
console.log();
|
|
446
|
+
console.log(fmt(C.bold, ' Let\'s start by getting to know each other. Tell me about yourself!'));
|
|
447
|
+
console.log(fmt(C.dim, ' (Your name, what you do, what you\'re working on)\n'));
|
|
448
|
+
} else {
|
|
449
|
+
console.log(fmt(C.dim, '\n Type a task, or / for commands.\n'));
|
|
450
|
+
}
|
|
419
451
|
}
|
|
420
452
|
|
|
421
453
|
function printInsights() {
|
package/dist/daemon.mjs
CHANGED
|
@@ -2866,7 +2866,7 @@ var init_FileCapability = __esm({
|
|
|
2866
2866
|
const rel = String(input.path ?? ".");
|
|
2867
2867
|
const safe = resolve2(cwd, rel);
|
|
2868
2868
|
const start = Date.now();
|
|
2869
|
-
if (!safe.startsWith(cwd)) {
|
|
2869
|
+
if (!safe.startsWith(cwd + "/") && safe !== cwd) {
|
|
2870
2870
|
return { success: false, output: "Path outside working directory", duration_ms: 0 };
|
|
2871
2871
|
}
|
|
2872
2872
|
try {
|
|
@@ -4858,13 +4858,9 @@ var init_CredentialVaultCapability = __esm({
|
|
|
4858
4858
|
}
|
|
4859
4859
|
case "destroy": {
|
|
4860
4860
|
const prefix = `${sessionId}:`;
|
|
4861
|
-
|
|
4862
|
-
for (const k of credStore.
|
|
4863
|
-
|
|
4864
|
-
credStore.delete(k);
|
|
4865
|
-
count++;
|
|
4866
|
-
}
|
|
4867
|
-
}
|
|
4861
|
+
const keysToDelete = [...credStore.keys()].filter((k) => k.startsWith(prefix));
|
|
4862
|
+
for (const k of keysToDelete) credStore.delete(k);
|
|
4863
|
+
const count = keysToDelete.length;
|
|
4868
4864
|
sessionKeys.delete(sessionId);
|
|
4869
4865
|
return {
|
|
4870
4866
|
success: true,
|
|
@@ -5100,17 +5096,21 @@ var init_SessionSearchCapability = __esm({
|
|
|
5100
5096
|
try {
|
|
5101
5097
|
const Database2 = (await import("better-sqlite3")).default;
|
|
5102
5098
|
const db = new Database2(this.getDbPath());
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5099
|
+
let rows;
|
|
5100
|
+
try {
|
|
5101
|
+
const keywords = query.split(/\s+/).filter((w) => w.length > 2);
|
|
5102
|
+
const likeClause = keywords.map(() => `content LIKE ?`).join(" OR ");
|
|
5103
|
+
const likeParams = keywords.map((k) => `%${k.replace(/%/g, "\\%").replace(/_/g, "\\_")}%`);
|
|
5104
|
+
rows = db.prepare(`
|
|
5105
|
+
SELECT session_id, role, content, created_at
|
|
5106
|
+
FROM conversations
|
|
5107
|
+
WHERE ${likeClause || "1=1"}
|
|
5108
|
+
ORDER BY created_at DESC
|
|
5109
|
+
LIMIT ?
|
|
5110
|
+
`).all(...likeParams, maxResults * 3);
|
|
5111
|
+
} finally {
|
|
5112
|
+
db.close();
|
|
5113
|
+
}
|
|
5114
5114
|
if (!rows.length) {
|
|
5115
5115
|
return {
|
|
5116
5116
|
success: true,
|
|
@@ -5294,6 +5294,9 @@ ${lines.join("\n")}`,
|
|
|
5294
5294
|
import { execSync as execSync5 } from "node:child_process";
|
|
5295
5295
|
import { readFileSync as readFileSync4, existsSync as existsSync6 } from "node:fs";
|
|
5296
5296
|
import { resolve as resolve6, extname } from "node:path";
|
|
5297
|
+
function shellSafe(s) {
|
|
5298
|
+
return s.replace(/[^a-zA-Z0-9_.$ \-\/]/g, "");
|
|
5299
|
+
}
|
|
5297
5300
|
var LSPCapability;
|
|
5298
5301
|
var init_LSPCapability = __esm({
|
|
5299
5302
|
"packages/daemon/src/tools/LSPCapability.ts"() {
|
|
@@ -5364,7 +5367,7 @@ var init_LSPCapability = __esm({
|
|
|
5364
5367
|
for (const pattern of defPatterns) {
|
|
5365
5368
|
try {
|
|
5366
5369
|
const grep = execSync5(
|
|
5367
|
-
`rg -n "${pattern}" --type ts --type js "${cwd}" 2>/dev/null | head -10`,
|
|
5370
|
+
`rg -n "${shellSafe(pattern)}" --type ts --type js "${cwd}" 2>/dev/null | head -10`,
|
|
5368
5371
|
{ encoding: "utf8", timeout: 5e3 }
|
|
5369
5372
|
).trim();
|
|
5370
5373
|
if (grep) results.push(grep);
|
|
@@ -5388,7 +5391,7 @@ ${results.join("\n")}`,
|
|
|
5388
5391
|
if (!word) return { success: false, output: "No symbol at that position", duration_ms: Date.now() - start };
|
|
5389
5392
|
try {
|
|
5390
5393
|
const grep = execSync5(
|
|
5391
|
-
`rg -n "\\b${word}\\b" --type ts --type js "${cwd}" 2>/dev/null | head -20`,
|
|
5394
|
+
`rg -n "\\b${shellSafe(word)}\\b" --type ts --type js "${cwd}" 2>/dev/null | head -20`,
|
|
5392
5395
|
{ encoding: "utf8", timeout: 5e3 }
|
|
5393
5396
|
).trim();
|
|
5394
5397
|
const refCount = grep.split("\n").filter(Boolean).length;
|
|
@@ -5447,7 +5450,7 @@ ${grep || "(no symbols found)"}`,
|
|
|
5447
5450
|
if (!word) return { success: false, output: "No symbol to search for", duration_ms: 0 };
|
|
5448
5451
|
try {
|
|
5449
5452
|
const grep = execSync5(
|
|
5450
|
-
`rg -n "\\b${word}\\b" "${cwd}" 2>/dev/null | head -20`,
|
|
5453
|
+
`rg -n "\\b${shellSafe(word)}\\b" "${cwd}" 2>/dev/null | head -20`,
|
|
5451
5454
|
{ encoding: "utf8", timeout: 5e3 }
|
|
5452
5455
|
).trim();
|
|
5453
5456
|
return {
|
|
@@ -5992,7 +5995,7 @@ var init_StreamingToolExecutor = __esm({
|
|
|
5992
5995
|
});
|
|
5993
5996
|
|
|
5994
5997
|
// packages/daemon/src/AgentExecutor.ts
|
|
5995
|
-
import { spawn as
|
|
5998
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
5996
5999
|
import { writeFileSync as writeFileSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, mkdirSync as mkdirSync3, existsSync as existsSync7 } from "node:fs";
|
|
5997
6000
|
import { resolve as resolve7, dirname as dirname2, relative } from "node:path";
|
|
5998
6001
|
import { homedir as homedir2 } from "node:os";
|
|
@@ -6118,8 +6121,9 @@ var init_AgentExecutor = __esm({
|
|
|
6118
6121
|
await new Promise((r) => setTimeout(r, waitMs));
|
|
6119
6122
|
continue;
|
|
6120
6123
|
}
|
|
6121
|
-
if (this._isContextOverflow(msg) && messages.length > 3) {
|
|
6122
|
-
|
|
6124
|
+
if (this._isContextOverflow(msg) && messages.length > 3 && llmRetry < 2) {
|
|
6125
|
+
llmRetry++;
|
|
6126
|
+
this.onStep(`Context limit hit \u2014 compacting history (attempt ${llmRetry}/2)\u2026`);
|
|
6123
6127
|
this._compactHistory(messages);
|
|
6124
6128
|
continue;
|
|
6125
6129
|
}
|
|
@@ -6197,40 +6201,11 @@ var init_AgentExecutor = __esm({
|
|
|
6197
6201
|
iterations: messages.filter((m) => m.role === "assistant").length
|
|
6198
6202
|
};
|
|
6199
6203
|
}
|
|
6200
|
-
// ───
|
|
6201
|
-
async executeTool(name, input) {
|
|
6202
|
-
switch (name) {
|
|
6203
|
-
case "shell_exec":
|
|
6204
|
-
return this.shellExec(
|
|
6205
|
-
String(input.command ?? ""),
|
|
6206
|
-
Number(input.timeout_ms ?? this.maxCommandMs)
|
|
6207
|
-
);
|
|
6208
|
-
case "write_file":
|
|
6209
|
-
return this.writeFile(String(input.path ?? ""), String(input.content ?? ""));
|
|
6210
|
-
case "read_file":
|
|
6211
|
-
return this.readFile(String(input.path ?? ""));
|
|
6212
|
-
case "list_dir":
|
|
6213
|
-
return this.listDir(input.path ? String(input.path) : void 0);
|
|
6214
|
-
case "web_search":
|
|
6215
|
-
return this.webSearch(
|
|
6216
|
-
String(input.query ?? ""),
|
|
6217
|
-
Math.min(10, Number(input.num_results ?? 5))
|
|
6218
|
-
);
|
|
6219
|
-
case "scrape_url":
|
|
6220
|
-
return this.scrapeUrl(
|
|
6221
|
-
String(input.url ?? ""),
|
|
6222
|
-
String(input.mode ?? "text"),
|
|
6223
|
-
input.selector ? String(input.selector) : void 0,
|
|
6224
|
-
Number(input.wait_ms ?? 0)
|
|
6225
|
-
);
|
|
6226
|
-
default:
|
|
6227
|
-
return `Unknown tool: ${name}`;
|
|
6228
|
-
}
|
|
6229
|
-
}
|
|
6204
|
+
// ─── Legacy tool execution (used by built-in tools, not capabilities) ──────
|
|
6230
6205
|
shellExec(command, timeoutMs) {
|
|
6231
6206
|
return new Promise((resolve19) => {
|
|
6232
6207
|
const chunks = [];
|
|
6233
|
-
const proc =
|
|
6208
|
+
const proc = spawn5("bash", ["-c", command], {
|
|
6234
6209
|
cwd: this.cwd,
|
|
6235
6210
|
env: { ...process.env, TERM: "dumb" },
|
|
6236
6211
|
timeout: timeoutMs
|
|
@@ -6360,7 +6335,7 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
|
|
|
6360
6335
|
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
6361
6336
|
safePath(p) {
|
|
6362
6337
|
const resolved = resolve7(this.cwd, p);
|
|
6363
|
-
return resolved.startsWith(this.cwd) ? resolved : null;
|
|
6338
|
+
return resolved.startsWith(this.cwd + "/") || resolved === this.cwd ? resolved : null;
|
|
6364
6339
|
}
|
|
6365
6340
|
buildSystemPrompt(extra, task) {
|
|
6366
6341
|
const isSelfMod = !!(task && SELF_MOD_PATTERN.test(task));
|
|
@@ -6370,10 +6345,15 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
|
|
|
6370
6345
|
const isJustdoTask = !!(task && /book|file.*itr|tax.*file|irctc|train.*ticket|flight|passport|appointment|login.*portal|pan.*card|aadhaar|monitor.*watch|price.*drop|slot.*available|justdo/i.test(task));
|
|
6371
6346
|
const dateStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
6372
6347
|
const lines = [
|
|
6373
|
-
`You are 0agent,
|
|
6348
|
+
`You are 0agent, a persistent AI agent that lives on the user's machine.`,
|
|
6349
|
+
`You learn from every interaction, remember across sessions, and can code, automate, browse, and more.`,
|
|
6374
6350
|
`Working directory: ${this.cwd}`,
|
|
6375
6351
|
`Date: ${dateStr}`,
|
|
6376
6352
|
``,
|
|
6353
|
+
`PERSONALITY: Be warm, helpful, and genuinely curious about the user. You are their personal agent.`,
|
|
6354
|
+
`If this is the first interaction, introduce yourself and learn about them \u2014 their name, role, goals.`,
|
|
6355
|
+
`Save anything they share about themselves to memory_write immediately.`,
|
|
6356
|
+
``,
|
|
6377
6357
|
`Use tools to accomplish tasks \u2014 don't describe what to do, do it.`,
|
|
6378
6358
|
`For background processes, always redirect output: cmd > /tmp/log 2>&1 &`,
|
|
6379
6359
|
`Prefer file_op edit (find-and-replace) over rewriting entire files.`,
|
|
@@ -6764,7 +6744,7 @@ var init_ExecutionVerifier = __esm({
|
|
|
6764
6744
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync10 } from "node:fs";
|
|
6765
6745
|
import { resolve as resolve9, dirname as dirname3 } from "node:path";
|
|
6766
6746
|
import { fileURLToPath } from "node:url";
|
|
6767
|
-
import { execSync as execSync7, spawn as
|
|
6747
|
+
import { execSync as execSync7, spawn as spawn6 } from "node:child_process";
|
|
6768
6748
|
function isRuntimeBug(error) {
|
|
6769
6749
|
if (TASK_FAILURE_PATTERNS.some((p) => p.test(error))) return false;
|
|
6770
6750
|
return RUNTIME_BUG_PATTERNS.some((p) => p.test(error));
|
|
@@ -6999,7 +6979,7 @@ Rules:
|
|
|
6999
6979
|
restartDaemon() {
|
|
7000
6980
|
const bundlePath = resolve9(this.projectRoot, "dist", "daemon.mjs");
|
|
7001
6981
|
if (existsSync10(bundlePath)) {
|
|
7002
|
-
const child =
|
|
6982
|
+
const child = spawn6(process.execPath, [bundlePath], {
|
|
7003
6983
|
detached: true,
|
|
7004
6984
|
stdio: "ignore",
|
|
7005
6985
|
env: process.env
|
|
@@ -7920,12 +7900,6 @@ function getFastModelId(provider, _currentModel) {
|
|
|
7920
7900
|
|
|
7921
7901
|
// packages/daemon/src/services/AutoMemoryExtractor.ts
|
|
7922
7902
|
init_src();
|
|
7923
|
-
var state = {
|
|
7924
|
-
lastMessageIndex: 0,
|
|
7925
|
-
inProgress: false,
|
|
7926
|
-
pendingRun: false,
|
|
7927
|
-
turnsSinceExtraction: 0
|
|
7928
|
-
};
|
|
7929
7903
|
var MIN_TURNS_BETWEEN = 3;
|
|
7930
7904
|
var MAX_MESSAGES_PER_RUN = 20;
|
|
7931
7905
|
var AutoMemoryExtractor = class {
|
|
@@ -7934,6 +7908,13 @@ var AutoMemoryExtractor = class {
|
|
|
7934
7908
|
this.graph = graph;
|
|
7935
7909
|
this.entityNodeId = entityNodeId;
|
|
7936
7910
|
}
|
|
7911
|
+
// Instance-scoped state (not module-level — prevents cross-session contamination)
|
|
7912
|
+
state = {
|
|
7913
|
+
lastMessageIndex: 0,
|
|
7914
|
+
inProgress: false,
|
|
7915
|
+
pendingRun: false,
|
|
7916
|
+
turnsSinceExtraction: 0
|
|
7917
|
+
};
|
|
7937
7918
|
/**
|
|
7938
7919
|
* Called after each session turn. Decides whether to extract memories
|
|
7939
7920
|
* and runs extraction in the background if needed.
|
|
@@ -7941,30 +7922,30 @@ var AutoMemoryExtractor = class {
|
|
|
7941
7922
|
* Fire-and-forget — never blocks the main session.
|
|
7942
7923
|
*/
|
|
7943
7924
|
async maybeExtract(messages, memoryWritesSinceLast) {
|
|
7944
|
-
state.turnsSinceExtraction++;
|
|
7925
|
+
this.state.turnsSinceExtraction++;
|
|
7945
7926
|
if (memoryWritesSinceLast) {
|
|
7946
|
-
state.turnsSinceExtraction = 0;
|
|
7927
|
+
this.state.turnsSinceExtraction = 0;
|
|
7947
7928
|
return;
|
|
7948
7929
|
}
|
|
7949
|
-
if (state.turnsSinceExtraction < MIN_TURNS_BETWEEN) return;
|
|
7950
|
-
if (messages.length <= state.lastMessageIndex) return;
|
|
7951
|
-
if (state.inProgress) {
|
|
7952
|
-
state.pendingRun = true;
|
|
7930
|
+
if (this.state.turnsSinceExtraction < MIN_TURNS_BETWEEN) return;
|
|
7931
|
+
if (messages.length <= this.state.lastMessageIndex) return;
|
|
7932
|
+
if (this.state.inProgress) {
|
|
7933
|
+
this.state.pendingRun = true;
|
|
7953
7934
|
return;
|
|
7954
7935
|
}
|
|
7955
7936
|
await this._runExtraction(messages);
|
|
7956
|
-
if (state.pendingRun) {
|
|
7957
|
-
state.pendingRun = false;
|
|
7937
|
+
if (this.state.pendingRun) {
|
|
7938
|
+
this.state.pendingRun = false;
|
|
7958
7939
|
await this._runExtraction(messages);
|
|
7959
7940
|
}
|
|
7960
7941
|
}
|
|
7961
7942
|
async _runExtraction(messages) {
|
|
7962
7943
|
if (!this.llm?.isConfigured) return;
|
|
7963
|
-
state.inProgress = true;
|
|
7944
|
+
this.state.inProgress = true;
|
|
7964
7945
|
try {
|
|
7965
7946
|
const newMessages = messages.slice(
|
|
7966
|
-
state.lastMessageIndex,
|
|
7967
|
-
state.lastMessageIndex + MAX_MESSAGES_PER_RUN
|
|
7947
|
+
this.state.lastMessageIndex,
|
|
7948
|
+
this.state.lastMessageIndex + MAX_MESSAGES_PER_RUN
|
|
7968
7949
|
);
|
|
7969
7950
|
if (newMessages.length === 0) return;
|
|
7970
7951
|
const conversationText = newMessages.filter((m) => m.role === "user" || m.role === "assistant" && !m.tool_calls).map((m) => `${m.role}: ${m.content.slice(0, 500)}`).join("\n");
|
|
@@ -8023,19 +8004,19 @@ var AutoMemoryExtractor = class {
|
|
|
8023
8004
|
this.graph.addNode(node);
|
|
8024
8005
|
}
|
|
8025
8006
|
}
|
|
8026
|
-
state.lastMessageIndex = messages.length;
|
|
8027
|
-
state.turnsSinceExtraction = 0;
|
|
8007
|
+
this.state.lastMessageIndex = messages.length;
|
|
8008
|
+
this.state.turnsSinceExtraction = 0;
|
|
8028
8009
|
} catch {
|
|
8029
8010
|
} finally {
|
|
8030
|
-
state.inProgress = false;
|
|
8011
|
+
this.state.inProgress = false;
|
|
8031
8012
|
}
|
|
8032
8013
|
}
|
|
8033
8014
|
/** Reset state (e.g., on new session). */
|
|
8034
8015
|
reset() {
|
|
8035
|
-
state.lastMessageIndex = 0;
|
|
8036
|
-
state.inProgress = false;
|
|
8037
|
-
state.pendingRun = false;
|
|
8038
|
-
state.turnsSinceExtraction = 0;
|
|
8016
|
+
this.state.lastMessageIndex = 0;
|
|
8017
|
+
this.state.inProgress = false;
|
|
8018
|
+
this.state.pendingRun = false;
|
|
8019
|
+
this.state.turnsSinceExtraction = 0;
|
|
8039
8020
|
}
|
|
8040
8021
|
};
|
|
8041
8022
|
|
|
@@ -10513,7 +10494,7 @@ git checkout <commit> graph/ # restore graph files
|
|
|
10513
10494
|
};
|
|
10514
10495
|
|
|
10515
10496
|
// packages/daemon/src/services/CodespaceManager.ts
|
|
10516
|
-
import { execSync as execSync8, spawn as
|
|
10497
|
+
import { execSync as execSync8, spawn as spawn7 } from "node:child_process";
|
|
10517
10498
|
var BROWSER_PORT_REMOTE = 3e3;
|
|
10518
10499
|
var BROWSER_PORT_LOCAL = 3001;
|
|
10519
10500
|
var DISPLAY_NAME = "0agent-browser";
|
|
@@ -10608,7 +10589,7 @@ var CodespaceManager = class {
|
|
|
10608
10589
|
async openTunnel(name) {
|
|
10609
10590
|
this.closeTunnel();
|
|
10610
10591
|
console.log(`[Codespace] Opening tunnel port ${BROWSER_PORT_REMOTE} \u2192 localhost:${BROWSER_PORT_LOCAL}...`);
|
|
10611
|
-
this.forwardProcess =
|
|
10592
|
+
this.forwardProcess = spawn7(
|
|
10612
10593
|
"gh",
|
|
10613
10594
|
["codespace", "ports", "forward", `${BROWSER_PORT_REMOTE}:${BROWSER_PORT_LOCAL}`, "--codespace", name],
|
|
10614
10595
|
{ stdio: ["ignore", "ignore", "ignore"] }
|
|
@@ -10997,52 +10978,52 @@ var SurfaceRouter = class {
|
|
|
10997
10978
|
}
|
|
10998
10979
|
_handleDaemonEvent(event) {
|
|
10999
10980
|
const sessionId = String(event.session_id ?? "");
|
|
11000
|
-
const
|
|
11001
|
-
if (!
|
|
11002
|
-
const adapter = this.adapters.get(
|
|
10981
|
+
const state = this.activeSessions.get(sessionId);
|
|
10982
|
+
if (!state) return;
|
|
10983
|
+
const adapter = this.adapters.get(state.surface);
|
|
11003
10984
|
if (!adapter) return;
|
|
11004
10985
|
if (event.type === "session.token") {
|
|
11005
|
-
|
|
11006
|
-
if (
|
|
11007
|
-
|
|
11008
|
-
if (!
|
|
10986
|
+
state.tokenBuffer += String(event.token ?? "");
|
|
10987
|
+
if (state.streamTimer) clearTimeout(state.streamTimer);
|
|
10988
|
+
state.streamTimer = setTimeout(() => {
|
|
10989
|
+
if (!state.tokenBuffer) return;
|
|
11009
10990
|
adapter.send({
|
|
11010
|
-
surface_channel_id:
|
|
11011
|
-
text:
|
|
10991
|
+
surface_channel_id: state.channelId,
|
|
10992
|
+
text: state.tokenBuffer,
|
|
11012
10993
|
format: "markdown",
|
|
11013
10994
|
is_progress: true,
|
|
11014
|
-
thread_id:
|
|
10995
|
+
thread_id: state.threadId
|
|
11015
10996
|
}).catch(() => {
|
|
11016
10997
|
});
|
|
11017
10998
|
}, 400);
|
|
11018
10999
|
} else if (event.type === "session.completed") {
|
|
11019
|
-
if (
|
|
11020
|
-
clearTimeout(
|
|
11021
|
-
|
|
11000
|
+
if (state.streamTimer) {
|
|
11001
|
+
clearTimeout(state.streamTimer);
|
|
11002
|
+
state.streamTimer = null;
|
|
11022
11003
|
}
|
|
11023
11004
|
const result = event.result;
|
|
11024
11005
|
const output = String(result?.output ?? "").trim();
|
|
11025
11006
|
if (output && output !== "(no output)") {
|
|
11026
11007
|
adapter.send({
|
|
11027
|
-
surface_channel_id:
|
|
11008
|
+
surface_channel_id: state.channelId,
|
|
11028
11009
|
text: output,
|
|
11029
11010
|
format: "markdown",
|
|
11030
11011
|
is_progress: false,
|
|
11031
|
-
thread_id:
|
|
11012
|
+
thread_id: state.threadId
|
|
11032
11013
|
}).catch(() => {
|
|
11033
11014
|
});
|
|
11034
11015
|
}
|
|
11035
11016
|
this.activeSessions.delete(sessionId);
|
|
11036
11017
|
} else if (event.type === "session.failed") {
|
|
11037
|
-
if (
|
|
11038
|
-
clearTimeout(
|
|
11039
|
-
|
|
11018
|
+
if (state.streamTimer) {
|
|
11019
|
+
clearTimeout(state.streamTimer);
|
|
11020
|
+
state.streamTimer = null;
|
|
11040
11021
|
}
|
|
11041
11022
|
adapter.send({
|
|
11042
|
-
surface_channel_id:
|
|
11023
|
+
surface_channel_id: state.channelId,
|
|
11043
11024
|
text: `\u26A0\uFE0F ${String(event.error ?? "Task failed")}`,
|
|
11044
11025
|
format: "prose",
|
|
11045
|
-
thread_id:
|
|
11026
|
+
thread_id: state.threadId
|
|
11046
11027
|
}).catch(() => {
|
|
11047
11028
|
});
|
|
11048
11029
|
this.activeSessions.delete(sessionId);
|
|
@@ -11107,13 +11088,13 @@ var TelegramAdapter = class {
|
|
|
11107
11088
|
async send(msg) {
|
|
11108
11089
|
const chatId = Number(msg.surface_channel_id);
|
|
11109
11090
|
if (!chatId) return;
|
|
11110
|
-
const
|
|
11111
|
-
if (msg.is_progress &&
|
|
11112
|
-
|
|
11113
|
-
await this._editMessage(chatId,
|
|
11091
|
+
const state = this.streamingState.get(chatId);
|
|
11092
|
+
if (msg.is_progress && state) {
|
|
11093
|
+
state.accumulatedText = msg.text;
|
|
11094
|
+
await this._editMessage(chatId, state.workingMsgId, `\u23F3 ${this._truncate(msg.text, 3800)}`);
|
|
11114
11095
|
} else {
|
|
11115
|
-
if (
|
|
11116
|
-
await this._editMessage(chatId,
|
|
11096
|
+
if (state) {
|
|
11097
|
+
await this._editMessage(chatId, state.workingMsgId, msg.text);
|
|
11117
11098
|
this.streamingState.delete(chatId);
|
|
11118
11099
|
} else {
|
|
11119
11100
|
await this._sendMessage(chatId, msg.text);
|
|
@@ -11451,24 +11432,24 @@ var SlackAdapter = class {
|
|
|
11451
11432
|
if (!this.app) return;
|
|
11452
11433
|
const client = this.app["client"];
|
|
11453
11434
|
const stateKey = `${msg.surface_channel_id}:${msg.thread_id ?? ""}`;
|
|
11454
|
-
const
|
|
11455
|
-
if (msg.is_progress &&
|
|
11435
|
+
const state = this.streamingState.get(stateKey);
|
|
11436
|
+
if (msg.is_progress && state) {
|
|
11456
11437
|
try {
|
|
11457
11438
|
await client["chat.update"]({
|
|
11458
|
-
channel:
|
|
11459
|
-
ts:
|
|
11439
|
+
channel: state.channelId,
|
|
11440
|
+
ts: state.ts,
|
|
11460
11441
|
text: `\u23F3 ${this._truncate(msg.text, 3e3)}`
|
|
11461
11442
|
});
|
|
11462
11443
|
} catch {
|
|
11463
11444
|
}
|
|
11464
11445
|
} else {
|
|
11465
|
-
if (
|
|
11446
|
+
if (state) {
|
|
11466
11447
|
try {
|
|
11467
11448
|
await client["chat.update"]({
|
|
11468
|
-
channel:
|
|
11469
|
-
ts:
|
|
11449
|
+
channel: state.channelId,
|
|
11450
|
+
ts: state.ts,
|
|
11470
11451
|
text: msg.text,
|
|
11471
|
-
thread_ts:
|
|
11452
|
+
thread_ts: state.threadTs || void 0
|
|
11472
11453
|
});
|
|
11473
11454
|
} catch {
|
|
11474
11455
|
await this._postMessage(client, msg.surface_channel_id, msg.text, msg.thread_id);
|
|
@@ -11810,7 +11791,7 @@ async function recordAudio(durationSeconds) {
|
|
|
11810
11791
|
}
|
|
11811
11792
|
|
|
11812
11793
|
// packages/daemon/src/surfaces/NativeTTS.ts
|
|
11813
|
-
import { spawnSync as spawnSync6, spawn as
|
|
11794
|
+
import { spawnSync as spawnSync6, spawn as spawn8 } from "node:child_process";
|
|
11814
11795
|
var NativeTTS = class _NativeTTS {
|
|
11815
11796
|
engine;
|
|
11816
11797
|
voice;
|
|
@@ -11836,7 +11817,7 @@ var NativeTTS = class _NativeTTS {
|
|
|
11836
11817
|
if (!cleaned) return;
|
|
11837
11818
|
return new Promise((resolve19) => {
|
|
11838
11819
|
const args = this._buildArgs(this.resolvedEngine, cleaned);
|
|
11839
|
-
const proc =
|
|
11820
|
+
const proc = spawn8(this.resolvedEngine, args, { stdio: "ignore" });
|
|
11840
11821
|
proc.on("close", () => resolve19());
|
|
11841
11822
|
proc.on("error", () => resolve19());
|
|
11842
11823
|
});
|
|
@@ -11896,7 +11877,7 @@ var NativeTTS = class _NativeTTS {
|
|
|
11896
11877
|
}
|
|
11897
11878
|
_speakWith(engine, text) {
|
|
11898
11879
|
const args = this._buildArgs(engine, text);
|
|
11899
|
-
const proc =
|
|
11880
|
+
const proc = spawn8(engine, args, { stdio: "ignore", detached: true });
|
|
11900
11881
|
proc.unref();
|
|
11901
11882
|
}
|
|
11902
11883
|
/** Remove markdown/ANSI and control chars before speaking */
|
|
@@ -12024,7 +12005,7 @@ var VoiceAdapter = class {
|
|
|
12024
12005
|
import { existsSync as existsSync19, mkdirSync as mkdirSync9, writeFileSync as writeFileSync11 } from "node:fs";
|
|
12025
12006
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
12026
12007
|
import { join as join6 } from "node:path";
|
|
12027
|
-
import { spawn as
|
|
12008
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
12028
12009
|
var MeetingAdapter = class {
|
|
12029
12010
|
name = "meeting";
|
|
12030
12011
|
messageHandler = null;
|
|
@@ -12166,7 +12147,7 @@ ${msg.text}
|
|
|
12166
12147
|
resolve19(false);
|
|
12167
12148
|
return;
|
|
12168
12149
|
}
|
|
12169
|
-
const proc =
|
|
12150
|
+
const proc = spawn9("ffmpeg", args, { stdio: "pipe" });
|
|
12170
12151
|
this.ffmpegProcess = proc;
|
|
12171
12152
|
proc.on("close", (code) => {
|
|
12172
12153
|
this.ffmpegProcess = null;
|