0agent 1.0.82 → 1.0.84
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 +63 -1
- package/dist/daemon.mjs +118 -132
- 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');
|
package/dist/daemon.mjs
CHANGED
|
@@ -2135,6 +2135,8 @@ var init_LLMExecutor = __esm({
|
|
|
2135
2135
|
currentToolId = block.id;
|
|
2136
2136
|
toolInputBuffers[currentToolId] = "";
|
|
2137
2137
|
toolCalls.push({ id: currentToolId, name: block.name, input: {} });
|
|
2138
|
+
} else {
|
|
2139
|
+
currentToolId = "";
|
|
2138
2140
|
}
|
|
2139
2141
|
} else if (type === "content_block_delta") {
|
|
2140
2142
|
const delta = evt.delta;
|
|
@@ -2142,21 +2144,26 @@ var init_LLMExecutor = __esm({
|
|
|
2142
2144
|
const token = delta.text ?? "";
|
|
2143
2145
|
textContent += token;
|
|
2144
2146
|
if (onToken && token) onToken(token);
|
|
2145
|
-
} else if (delta?.type === "input_json_delta") {
|
|
2147
|
+
} else if (delta?.type === "input_json_delta" && currentToolId) {
|
|
2146
2148
|
toolInputBuffers[currentToolId] = (toolInputBuffers[currentToolId] ?? "") + (delta.partial_json ?? "");
|
|
2147
2149
|
}
|
|
2148
2150
|
} else if (type === "content_block_stop") {
|
|
2149
|
-
if (currentToolId && toolInputBuffers
|
|
2151
|
+
if (currentToolId && currentToolId in toolInputBuffers) {
|
|
2150
2152
|
const tc = toolCalls.find((t) => t.id === currentToolId);
|
|
2151
2153
|
if (tc) {
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2154
|
+
const buf2 = toolInputBuffers[currentToolId];
|
|
2155
|
+
if (buf2) {
|
|
2156
|
+
try {
|
|
2157
|
+
tc.input = JSON.parse(buf2);
|
|
2158
|
+
} catch {
|
|
2159
|
+
tc.input = { _parse_error: true, _raw: buf2.slice(0, 200) };
|
|
2160
|
+
}
|
|
2155
2161
|
}
|
|
2156
|
-
if (onToolUseBlock && tc.input && Object.keys(tc.input).length > 0) {
|
|
2162
|
+
if (onToolUseBlock && tc.input && Object.keys(tc.input).length > 0 && !tc.input._parse_error) {
|
|
2157
2163
|
onToolUseBlock(tc);
|
|
2158
2164
|
}
|
|
2159
2165
|
}
|
|
2166
|
+
currentToolId = "";
|
|
2160
2167
|
}
|
|
2161
2168
|
} else if (type === "message_delta") {
|
|
2162
2169
|
const usage = evt.usage;
|
|
@@ -2168,10 +2175,13 @@ var init_LLMExecutor = __esm({
|
|
|
2168
2175
|
}
|
|
2169
2176
|
}
|
|
2170
2177
|
}
|
|
2178
|
+
const validToolCalls = toolCalls.filter(
|
|
2179
|
+
(tc) => tc.input && Object.keys(tc.input).length > 0 && !tc.input._parse_error
|
|
2180
|
+
);
|
|
2171
2181
|
return {
|
|
2172
2182
|
content: textContent,
|
|
2173
|
-
tool_calls:
|
|
2174
|
-
stop_reason: stopReason,
|
|
2183
|
+
tool_calls: validToolCalls.length > 0 ? validToolCalls : null,
|
|
2184
|
+
stop_reason: validToolCalls.length > 0 && stopReason === "tool_use" ? "tool_use" : stopReason,
|
|
2175
2185
|
tokens_used: inputTokens + outputTokens,
|
|
2176
2186
|
input_tokens: inputTokens,
|
|
2177
2187
|
output_tokens: outputTokens,
|
|
@@ -2856,7 +2866,7 @@ var init_FileCapability = __esm({
|
|
|
2856
2866
|
const rel = String(input.path ?? ".");
|
|
2857
2867
|
const safe = resolve2(cwd, rel);
|
|
2858
2868
|
const start = Date.now();
|
|
2859
|
-
if (!safe.startsWith(cwd)) {
|
|
2869
|
+
if (!safe.startsWith(cwd + "/") && safe !== cwd) {
|
|
2860
2870
|
return { success: false, output: "Path outside working directory", duration_ms: 0 };
|
|
2861
2871
|
}
|
|
2862
2872
|
try {
|
|
@@ -4848,13 +4858,9 @@ var init_CredentialVaultCapability = __esm({
|
|
|
4848
4858
|
}
|
|
4849
4859
|
case "destroy": {
|
|
4850
4860
|
const prefix = `${sessionId}:`;
|
|
4851
|
-
|
|
4852
|
-
for (const k of credStore.
|
|
4853
|
-
|
|
4854
|
-
credStore.delete(k);
|
|
4855
|
-
count++;
|
|
4856
|
-
}
|
|
4857
|
-
}
|
|
4861
|
+
const keysToDelete = [...credStore.keys()].filter((k) => k.startsWith(prefix));
|
|
4862
|
+
for (const k of keysToDelete) credStore.delete(k);
|
|
4863
|
+
const count = keysToDelete.length;
|
|
4858
4864
|
sessionKeys.delete(sessionId);
|
|
4859
4865
|
return {
|
|
4860
4866
|
success: true,
|
|
@@ -5090,17 +5096,21 @@ var init_SessionSearchCapability = __esm({
|
|
|
5090
5096
|
try {
|
|
5091
5097
|
const Database2 = (await import("better-sqlite3")).default;
|
|
5092
5098
|
const db = new Database2(this.getDbPath());
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
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
|
+
}
|
|
5104
5114
|
if (!rows.length) {
|
|
5105
5115
|
return {
|
|
5106
5116
|
success: true,
|
|
@@ -5284,6 +5294,9 @@ ${lines.join("\n")}`,
|
|
|
5284
5294
|
import { execSync as execSync5 } from "node:child_process";
|
|
5285
5295
|
import { readFileSync as readFileSync4, existsSync as existsSync6 } from "node:fs";
|
|
5286
5296
|
import { resolve as resolve6, extname } from "node:path";
|
|
5297
|
+
function shellSafe(s) {
|
|
5298
|
+
return s.replace(/[^a-zA-Z0-9_.$ \-\/]/g, "");
|
|
5299
|
+
}
|
|
5287
5300
|
var LSPCapability;
|
|
5288
5301
|
var init_LSPCapability = __esm({
|
|
5289
5302
|
"packages/daemon/src/tools/LSPCapability.ts"() {
|
|
@@ -5354,7 +5367,7 @@ var init_LSPCapability = __esm({
|
|
|
5354
5367
|
for (const pattern of defPatterns) {
|
|
5355
5368
|
try {
|
|
5356
5369
|
const grep = execSync5(
|
|
5357
|
-
`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`,
|
|
5358
5371
|
{ encoding: "utf8", timeout: 5e3 }
|
|
5359
5372
|
).trim();
|
|
5360
5373
|
if (grep) results.push(grep);
|
|
@@ -5378,7 +5391,7 @@ ${results.join("\n")}`,
|
|
|
5378
5391
|
if (!word) return { success: false, output: "No symbol at that position", duration_ms: Date.now() - start };
|
|
5379
5392
|
try {
|
|
5380
5393
|
const grep = execSync5(
|
|
5381
|
-
`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`,
|
|
5382
5395
|
{ encoding: "utf8", timeout: 5e3 }
|
|
5383
5396
|
).trim();
|
|
5384
5397
|
const refCount = grep.split("\n").filter(Boolean).length;
|
|
@@ -5437,7 +5450,7 @@ ${grep || "(no symbols found)"}`,
|
|
|
5437
5450
|
if (!word) return { success: false, output: "No symbol to search for", duration_ms: 0 };
|
|
5438
5451
|
try {
|
|
5439
5452
|
const grep = execSync5(
|
|
5440
|
-
`rg -n "\\b${word}\\b" "${cwd}" 2>/dev/null | head -20`,
|
|
5453
|
+
`rg -n "\\b${shellSafe(word)}\\b" "${cwd}" 2>/dev/null | head -20`,
|
|
5441
5454
|
{ encoding: "utf8", timeout: 5e3 }
|
|
5442
5455
|
).trim();
|
|
5443
5456
|
return {
|
|
@@ -5982,7 +5995,7 @@ var init_StreamingToolExecutor = __esm({
|
|
|
5982
5995
|
});
|
|
5983
5996
|
|
|
5984
5997
|
// packages/daemon/src/AgentExecutor.ts
|
|
5985
|
-
import { spawn as
|
|
5998
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
5986
5999
|
import { writeFileSync as writeFileSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, mkdirSync as mkdirSync3, existsSync as existsSync7 } from "node:fs";
|
|
5987
6000
|
import { resolve as resolve7, dirname as dirname2, relative } from "node:path";
|
|
5988
6001
|
import { homedir as homedir2 } from "node:os";
|
|
@@ -6108,8 +6121,9 @@ var init_AgentExecutor = __esm({
|
|
|
6108
6121
|
await new Promise((r) => setTimeout(r, waitMs));
|
|
6109
6122
|
continue;
|
|
6110
6123
|
}
|
|
6111
|
-
if (this._isContextOverflow(msg) && messages.length > 3) {
|
|
6112
|
-
|
|
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`);
|
|
6113
6127
|
this._compactHistory(messages);
|
|
6114
6128
|
continue;
|
|
6115
6129
|
}
|
|
@@ -6187,40 +6201,11 @@ var init_AgentExecutor = __esm({
|
|
|
6187
6201
|
iterations: messages.filter((m) => m.role === "assistant").length
|
|
6188
6202
|
};
|
|
6189
6203
|
}
|
|
6190
|
-
// ───
|
|
6191
|
-
async executeTool(name, input) {
|
|
6192
|
-
switch (name) {
|
|
6193
|
-
case "shell_exec":
|
|
6194
|
-
return this.shellExec(
|
|
6195
|
-
String(input.command ?? ""),
|
|
6196
|
-
Number(input.timeout_ms ?? this.maxCommandMs)
|
|
6197
|
-
);
|
|
6198
|
-
case "write_file":
|
|
6199
|
-
return this.writeFile(String(input.path ?? ""), String(input.content ?? ""));
|
|
6200
|
-
case "read_file":
|
|
6201
|
-
return this.readFile(String(input.path ?? ""));
|
|
6202
|
-
case "list_dir":
|
|
6203
|
-
return this.listDir(input.path ? String(input.path) : void 0);
|
|
6204
|
-
case "web_search":
|
|
6205
|
-
return this.webSearch(
|
|
6206
|
-
String(input.query ?? ""),
|
|
6207
|
-
Math.min(10, Number(input.num_results ?? 5))
|
|
6208
|
-
);
|
|
6209
|
-
case "scrape_url":
|
|
6210
|
-
return this.scrapeUrl(
|
|
6211
|
-
String(input.url ?? ""),
|
|
6212
|
-
String(input.mode ?? "text"),
|
|
6213
|
-
input.selector ? String(input.selector) : void 0,
|
|
6214
|
-
Number(input.wait_ms ?? 0)
|
|
6215
|
-
);
|
|
6216
|
-
default:
|
|
6217
|
-
return `Unknown tool: ${name}`;
|
|
6218
|
-
}
|
|
6219
|
-
}
|
|
6204
|
+
// ─── Legacy tool execution (used by built-in tools, not capabilities) ──────
|
|
6220
6205
|
shellExec(command, timeoutMs) {
|
|
6221
6206
|
return new Promise((resolve19) => {
|
|
6222
6207
|
const chunks = [];
|
|
6223
|
-
const proc =
|
|
6208
|
+
const proc = spawn5("bash", ["-c", command], {
|
|
6224
6209
|
cwd: this.cwd,
|
|
6225
6210
|
env: { ...process.env, TERM: "dumb" },
|
|
6226
6211
|
timeout: timeoutMs
|
|
@@ -6350,7 +6335,7 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
|
|
|
6350
6335
|
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
6351
6336
|
safePath(p) {
|
|
6352
6337
|
const resolved = resolve7(this.cwd, p);
|
|
6353
|
-
return resolved.startsWith(this.cwd) ? resolved : null;
|
|
6338
|
+
return resolved.startsWith(this.cwd + "/") || resolved === this.cwd ? resolved : null;
|
|
6354
6339
|
}
|
|
6355
6340
|
buildSystemPrompt(extra, task) {
|
|
6356
6341
|
const isSelfMod = !!(task && SELF_MOD_PATTERN.test(task));
|
|
@@ -6754,7 +6739,7 @@ var init_ExecutionVerifier = __esm({
|
|
|
6754
6739
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync10 } from "node:fs";
|
|
6755
6740
|
import { resolve as resolve9, dirname as dirname3 } from "node:path";
|
|
6756
6741
|
import { fileURLToPath } from "node:url";
|
|
6757
|
-
import { execSync as execSync7, spawn as
|
|
6742
|
+
import { execSync as execSync7, spawn as spawn6 } from "node:child_process";
|
|
6758
6743
|
function isRuntimeBug(error) {
|
|
6759
6744
|
if (TASK_FAILURE_PATTERNS.some((p) => p.test(error))) return false;
|
|
6760
6745
|
return RUNTIME_BUG_PATTERNS.some((p) => p.test(error));
|
|
@@ -6989,7 +6974,7 @@ Rules:
|
|
|
6989
6974
|
restartDaemon() {
|
|
6990
6975
|
const bundlePath = resolve9(this.projectRoot, "dist", "daemon.mjs");
|
|
6991
6976
|
if (existsSync10(bundlePath)) {
|
|
6992
|
-
const child =
|
|
6977
|
+
const child = spawn6(process.execPath, [bundlePath], {
|
|
6993
6978
|
detached: true,
|
|
6994
6979
|
stdio: "ignore",
|
|
6995
6980
|
env: process.env
|
|
@@ -7910,12 +7895,6 @@ function getFastModelId(provider, _currentModel) {
|
|
|
7910
7895
|
|
|
7911
7896
|
// packages/daemon/src/services/AutoMemoryExtractor.ts
|
|
7912
7897
|
init_src();
|
|
7913
|
-
var state = {
|
|
7914
|
-
lastMessageIndex: 0,
|
|
7915
|
-
inProgress: false,
|
|
7916
|
-
pendingRun: false,
|
|
7917
|
-
turnsSinceExtraction: 0
|
|
7918
|
-
};
|
|
7919
7898
|
var MIN_TURNS_BETWEEN = 3;
|
|
7920
7899
|
var MAX_MESSAGES_PER_RUN = 20;
|
|
7921
7900
|
var AutoMemoryExtractor = class {
|
|
@@ -7924,6 +7903,13 @@ var AutoMemoryExtractor = class {
|
|
|
7924
7903
|
this.graph = graph;
|
|
7925
7904
|
this.entityNodeId = entityNodeId;
|
|
7926
7905
|
}
|
|
7906
|
+
// Instance-scoped state (not module-level — prevents cross-session contamination)
|
|
7907
|
+
state = {
|
|
7908
|
+
lastMessageIndex: 0,
|
|
7909
|
+
inProgress: false,
|
|
7910
|
+
pendingRun: false,
|
|
7911
|
+
turnsSinceExtraction: 0
|
|
7912
|
+
};
|
|
7927
7913
|
/**
|
|
7928
7914
|
* Called after each session turn. Decides whether to extract memories
|
|
7929
7915
|
* and runs extraction in the background if needed.
|
|
@@ -7931,30 +7917,30 @@ var AutoMemoryExtractor = class {
|
|
|
7931
7917
|
* Fire-and-forget — never blocks the main session.
|
|
7932
7918
|
*/
|
|
7933
7919
|
async maybeExtract(messages, memoryWritesSinceLast) {
|
|
7934
|
-
state.turnsSinceExtraction++;
|
|
7920
|
+
this.state.turnsSinceExtraction++;
|
|
7935
7921
|
if (memoryWritesSinceLast) {
|
|
7936
|
-
state.turnsSinceExtraction = 0;
|
|
7922
|
+
this.state.turnsSinceExtraction = 0;
|
|
7937
7923
|
return;
|
|
7938
7924
|
}
|
|
7939
|
-
if (state.turnsSinceExtraction < MIN_TURNS_BETWEEN) return;
|
|
7940
|
-
if (messages.length <= state.lastMessageIndex) return;
|
|
7941
|
-
if (state.inProgress) {
|
|
7942
|
-
state.pendingRun = true;
|
|
7925
|
+
if (this.state.turnsSinceExtraction < MIN_TURNS_BETWEEN) return;
|
|
7926
|
+
if (messages.length <= this.state.lastMessageIndex) return;
|
|
7927
|
+
if (this.state.inProgress) {
|
|
7928
|
+
this.state.pendingRun = true;
|
|
7943
7929
|
return;
|
|
7944
7930
|
}
|
|
7945
7931
|
await this._runExtraction(messages);
|
|
7946
|
-
if (state.pendingRun) {
|
|
7947
|
-
state.pendingRun = false;
|
|
7932
|
+
if (this.state.pendingRun) {
|
|
7933
|
+
this.state.pendingRun = false;
|
|
7948
7934
|
await this._runExtraction(messages);
|
|
7949
7935
|
}
|
|
7950
7936
|
}
|
|
7951
7937
|
async _runExtraction(messages) {
|
|
7952
7938
|
if (!this.llm?.isConfigured) return;
|
|
7953
|
-
state.inProgress = true;
|
|
7939
|
+
this.state.inProgress = true;
|
|
7954
7940
|
try {
|
|
7955
7941
|
const newMessages = messages.slice(
|
|
7956
|
-
state.lastMessageIndex,
|
|
7957
|
-
state.lastMessageIndex + MAX_MESSAGES_PER_RUN
|
|
7942
|
+
this.state.lastMessageIndex,
|
|
7943
|
+
this.state.lastMessageIndex + MAX_MESSAGES_PER_RUN
|
|
7958
7944
|
);
|
|
7959
7945
|
if (newMessages.length === 0) return;
|
|
7960
7946
|
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");
|
|
@@ -8013,19 +7999,19 @@ var AutoMemoryExtractor = class {
|
|
|
8013
7999
|
this.graph.addNode(node);
|
|
8014
8000
|
}
|
|
8015
8001
|
}
|
|
8016
|
-
state.lastMessageIndex = messages.length;
|
|
8017
|
-
state.turnsSinceExtraction = 0;
|
|
8002
|
+
this.state.lastMessageIndex = messages.length;
|
|
8003
|
+
this.state.turnsSinceExtraction = 0;
|
|
8018
8004
|
} catch {
|
|
8019
8005
|
} finally {
|
|
8020
|
-
state.inProgress = false;
|
|
8006
|
+
this.state.inProgress = false;
|
|
8021
8007
|
}
|
|
8022
8008
|
}
|
|
8023
8009
|
/** Reset state (e.g., on new session). */
|
|
8024
8010
|
reset() {
|
|
8025
|
-
state.lastMessageIndex = 0;
|
|
8026
|
-
state.inProgress = false;
|
|
8027
|
-
state.pendingRun = false;
|
|
8028
|
-
state.turnsSinceExtraction = 0;
|
|
8011
|
+
this.state.lastMessageIndex = 0;
|
|
8012
|
+
this.state.inProgress = false;
|
|
8013
|
+
this.state.pendingRun = false;
|
|
8014
|
+
this.state.turnsSinceExtraction = 0;
|
|
8029
8015
|
}
|
|
8030
8016
|
};
|
|
8031
8017
|
|
|
@@ -10503,7 +10489,7 @@ git checkout <commit> graph/ # restore graph files
|
|
|
10503
10489
|
};
|
|
10504
10490
|
|
|
10505
10491
|
// packages/daemon/src/services/CodespaceManager.ts
|
|
10506
|
-
import { execSync as execSync8, spawn as
|
|
10492
|
+
import { execSync as execSync8, spawn as spawn7 } from "node:child_process";
|
|
10507
10493
|
var BROWSER_PORT_REMOTE = 3e3;
|
|
10508
10494
|
var BROWSER_PORT_LOCAL = 3001;
|
|
10509
10495
|
var DISPLAY_NAME = "0agent-browser";
|
|
@@ -10598,7 +10584,7 @@ var CodespaceManager = class {
|
|
|
10598
10584
|
async openTunnel(name) {
|
|
10599
10585
|
this.closeTunnel();
|
|
10600
10586
|
console.log(`[Codespace] Opening tunnel port ${BROWSER_PORT_REMOTE} \u2192 localhost:${BROWSER_PORT_LOCAL}...`);
|
|
10601
|
-
this.forwardProcess =
|
|
10587
|
+
this.forwardProcess = spawn7(
|
|
10602
10588
|
"gh",
|
|
10603
10589
|
["codespace", "ports", "forward", `${BROWSER_PORT_REMOTE}:${BROWSER_PORT_LOCAL}`, "--codespace", name],
|
|
10604
10590
|
{ stdio: ["ignore", "ignore", "ignore"] }
|
|
@@ -10987,52 +10973,52 @@ var SurfaceRouter = class {
|
|
|
10987
10973
|
}
|
|
10988
10974
|
_handleDaemonEvent(event) {
|
|
10989
10975
|
const sessionId = String(event.session_id ?? "");
|
|
10990
|
-
const
|
|
10991
|
-
if (!
|
|
10992
|
-
const adapter = this.adapters.get(
|
|
10976
|
+
const state = this.activeSessions.get(sessionId);
|
|
10977
|
+
if (!state) return;
|
|
10978
|
+
const adapter = this.adapters.get(state.surface);
|
|
10993
10979
|
if (!adapter) return;
|
|
10994
10980
|
if (event.type === "session.token") {
|
|
10995
|
-
|
|
10996
|
-
if (
|
|
10997
|
-
|
|
10998
|
-
if (!
|
|
10981
|
+
state.tokenBuffer += String(event.token ?? "");
|
|
10982
|
+
if (state.streamTimer) clearTimeout(state.streamTimer);
|
|
10983
|
+
state.streamTimer = setTimeout(() => {
|
|
10984
|
+
if (!state.tokenBuffer) return;
|
|
10999
10985
|
adapter.send({
|
|
11000
|
-
surface_channel_id:
|
|
11001
|
-
text:
|
|
10986
|
+
surface_channel_id: state.channelId,
|
|
10987
|
+
text: state.tokenBuffer,
|
|
11002
10988
|
format: "markdown",
|
|
11003
10989
|
is_progress: true,
|
|
11004
|
-
thread_id:
|
|
10990
|
+
thread_id: state.threadId
|
|
11005
10991
|
}).catch(() => {
|
|
11006
10992
|
});
|
|
11007
10993
|
}, 400);
|
|
11008
10994
|
} else if (event.type === "session.completed") {
|
|
11009
|
-
if (
|
|
11010
|
-
clearTimeout(
|
|
11011
|
-
|
|
10995
|
+
if (state.streamTimer) {
|
|
10996
|
+
clearTimeout(state.streamTimer);
|
|
10997
|
+
state.streamTimer = null;
|
|
11012
10998
|
}
|
|
11013
10999
|
const result = event.result;
|
|
11014
11000
|
const output = String(result?.output ?? "").trim();
|
|
11015
11001
|
if (output && output !== "(no output)") {
|
|
11016
11002
|
adapter.send({
|
|
11017
|
-
surface_channel_id:
|
|
11003
|
+
surface_channel_id: state.channelId,
|
|
11018
11004
|
text: output,
|
|
11019
11005
|
format: "markdown",
|
|
11020
11006
|
is_progress: false,
|
|
11021
|
-
thread_id:
|
|
11007
|
+
thread_id: state.threadId
|
|
11022
11008
|
}).catch(() => {
|
|
11023
11009
|
});
|
|
11024
11010
|
}
|
|
11025
11011
|
this.activeSessions.delete(sessionId);
|
|
11026
11012
|
} else if (event.type === "session.failed") {
|
|
11027
|
-
if (
|
|
11028
|
-
clearTimeout(
|
|
11029
|
-
|
|
11013
|
+
if (state.streamTimer) {
|
|
11014
|
+
clearTimeout(state.streamTimer);
|
|
11015
|
+
state.streamTimer = null;
|
|
11030
11016
|
}
|
|
11031
11017
|
adapter.send({
|
|
11032
|
-
surface_channel_id:
|
|
11018
|
+
surface_channel_id: state.channelId,
|
|
11033
11019
|
text: `\u26A0\uFE0F ${String(event.error ?? "Task failed")}`,
|
|
11034
11020
|
format: "prose",
|
|
11035
|
-
thread_id:
|
|
11021
|
+
thread_id: state.threadId
|
|
11036
11022
|
}).catch(() => {
|
|
11037
11023
|
});
|
|
11038
11024
|
this.activeSessions.delete(sessionId);
|
|
@@ -11097,13 +11083,13 @@ var TelegramAdapter = class {
|
|
|
11097
11083
|
async send(msg) {
|
|
11098
11084
|
const chatId = Number(msg.surface_channel_id);
|
|
11099
11085
|
if (!chatId) return;
|
|
11100
|
-
const
|
|
11101
|
-
if (msg.is_progress &&
|
|
11102
|
-
|
|
11103
|
-
await this._editMessage(chatId,
|
|
11086
|
+
const state = this.streamingState.get(chatId);
|
|
11087
|
+
if (msg.is_progress && state) {
|
|
11088
|
+
state.accumulatedText = msg.text;
|
|
11089
|
+
await this._editMessage(chatId, state.workingMsgId, `\u23F3 ${this._truncate(msg.text, 3800)}`);
|
|
11104
11090
|
} else {
|
|
11105
|
-
if (
|
|
11106
|
-
await this._editMessage(chatId,
|
|
11091
|
+
if (state) {
|
|
11092
|
+
await this._editMessage(chatId, state.workingMsgId, msg.text);
|
|
11107
11093
|
this.streamingState.delete(chatId);
|
|
11108
11094
|
} else {
|
|
11109
11095
|
await this._sendMessage(chatId, msg.text);
|
|
@@ -11441,24 +11427,24 @@ var SlackAdapter = class {
|
|
|
11441
11427
|
if (!this.app) return;
|
|
11442
11428
|
const client = this.app["client"];
|
|
11443
11429
|
const stateKey = `${msg.surface_channel_id}:${msg.thread_id ?? ""}`;
|
|
11444
|
-
const
|
|
11445
|
-
if (msg.is_progress &&
|
|
11430
|
+
const state = this.streamingState.get(stateKey);
|
|
11431
|
+
if (msg.is_progress && state) {
|
|
11446
11432
|
try {
|
|
11447
11433
|
await client["chat.update"]({
|
|
11448
|
-
channel:
|
|
11449
|
-
ts:
|
|
11434
|
+
channel: state.channelId,
|
|
11435
|
+
ts: state.ts,
|
|
11450
11436
|
text: `\u23F3 ${this._truncate(msg.text, 3e3)}`
|
|
11451
11437
|
});
|
|
11452
11438
|
} catch {
|
|
11453
11439
|
}
|
|
11454
11440
|
} else {
|
|
11455
|
-
if (
|
|
11441
|
+
if (state) {
|
|
11456
11442
|
try {
|
|
11457
11443
|
await client["chat.update"]({
|
|
11458
|
-
channel:
|
|
11459
|
-
ts:
|
|
11444
|
+
channel: state.channelId,
|
|
11445
|
+
ts: state.ts,
|
|
11460
11446
|
text: msg.text,
|
|
11461
|
-
thread_ts:
|
|
11447
|
+
thread_ts: state.threadTs || void 0
|
|
11462
11448
|
});
|
|
11463
11449
|
} catch {
|
|
11464
11450
|
await this._postMessage(client, msg.surface_channel_id, msg.text, msg.thread_id);
|
|
@@ -11800,7 +11786,7 @@ async function recordAudio(durationSeconds) {
|
|
|
11800
11786
|
}
|
|
11801
11787
|
|
|
11802
11788
|
// packages/daemon/src/surfaces/NativeTTS.ts
|
|
11803
|
-
import { spawnSync as spawnSync6, spawn as
|
|
11789
|
+
import { spawnSync as spawnSync6, spawn as spawn8 } from "node:child_process";
|
|
11804
11790
|
var NativeTTS = class _NativeTTS {
|
|
11805
11791
|
engine;
|
|
11806
11792
|
voice;
|
|
@@ -11826,7 +11812,7 @@ var NativeTTS = class _NativeTTS {
|
|
|
11826
11812
|
if (!cleaned) return;
|
|
11827
11813
|
return new Promise((resolve19) => {
|
|
11828
11814
|
const args = this._buildArgs(this.resolvedEngine, cleaned);
|
|
11829
|
-
const proc =
|
|
11815
|
+
const proc = spawn8(this.resolvedEngine, args, { stdio: "ignore" });
|
|
11830
11816
|
proc.on("close", () => resolve19());
|
|
11831
11817
|
proc.on("error", () => resolve19());
|
|
11832
11818
|
});
|
|
@@ -11886,7 +11872,7 @@ var NativeTTS = class _NativeTTS {
|
|
|
11886
11872
|
}
|
|
11887
11873
|
_speakWith(engine, text) {
|
|
11888
11874
|
const args = this._buildArgs(engine, text);
|
|
11889
|
-
const proc =
|
|
11875
|
+
const proc = spawn8(engine, args, { stdio: "ignore", detached: true });
|
|
11890
11876
|
proc.unref();
|
|
11891
11877
|
}
|
|
11892
11878
|
/** Remove markdown/ANSI and control chars before speaking */
|
|
@@ -12014,7 +12000,7 @@ var VoiceAdapter = class {
|
|
|
12014
12000
|
import { existsSync as existsSync19, mkdirSync as mkdirSync9, writeFileSync as writeFileSync11 } from "node:fs";
|
|
12015
12001
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
12016
12002
|
import { join as join6 } from "node:path";
|
|
12017
|
-
import { spawn as
|
|
12003
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
12018
12004
|
var MeetingAdapter = class {
|
|
12019
12005
|
name = "meeting";
|
|
12020
12006
|
messageHandler = null;
|
|
@@ -12156,7 +12142,7 @@ ${msg.text}
|
|
|
12156
12142
|
resolve19(false);
|
|
12157
12143
|
return;
|
|
12158
12144
|
}
|
|
12159
|
-
const proc =
|
|
12145
|
+
const proc = spawn9("ffmpeg", args, { stdio: "pipe" });
|
|
12160
12146
|
this.ffmpegProcess = proc;
|
|
12161
12147
|
proc.on("close", (code) => {
|
|
12162
12148
|
this.ffmpegProcess = null;
|