billion-context-pi 0.1.28 → 0.1.29
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 +17 -2
- package/README.zh-CN.md +19 -2
- package/dist/config.d.ts +3 -1
- package/dist/index.js +223 -87
- package/dist/index.js.map +1 -1
- package/dist/log.d.ts +12 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2411,9 +2411,9 @@ function projectMessage(message, id) {
|
|
|
2411
2411
|
if (calls.length === 1) {
|
|
2412
2412
|
const call = calls[0];
|
|
2413
2413
|
const argStr = stringifyArgs(call.arguments);
|
|
2414
|
-
const
|
|
2414
|
+
const text2 = argStr && textParts ? `${textParts}
|
|
2415
2415
|
${argStr}` : argStr || textParts;
|
|
2416
|
-
return [{ id, role: "assistant", contentType: "tool-call", toolName: call.name, toolCallId: call.id, text }];
|
|
2416
|
+
return [{ id, role: "assistant", contentType: "tool-call", toolName: call.name, toolCallId: call.id, text: text2 }];
|
|
2417
2417
|
}
|
|
2418
2418
|
return calls.map((call) => {
|
|
2419
2419
|
const argStr = stringifyArgs(call.arguments);
|
|
@@ -2427,7 +2427,9 @@ ${argStr}` : argStr || textParts;
|
|
|
2427
2427
|
};
|
|
2428
2428
|
});
|
|
2429
2429
|
}
|
|
2430
|
-
|
|
2430
|
+
const text = extractText(msg.content);
|
|
2431
|
+
if (!text.trim()) return [];
|
|
2432
|
+
return [{ id, role: "assistant", contentType: "text", text }];
|
|
2431
2433
|
}
|
|
2432
2434
|
const customText = extractText(msg.content) || fallbackText(msg);
|
|
2433
2435
|
return customText.length > 0 ? [{ id, role: "user", contentType: "text", text: customText }] : [];
|
|
@@ -2574,7 +2576,87 @@ function peelRefTagBlocks(blocks) {
|
|
|
2574
2576
|
|
|
2575
2577
|
// src/state.ts
|
|
2576
2578
|
import { promises as fs } from "fs";
|
|
2579
|
+
import * as path2 from "path";
|
|
2580
|
+
|
|
2581
|
+
// src/log.ts
|
|
2582
|
+
import { appendFileSync, mkdirSync, statSync, renameSync, existsSync } from "fs";
|
|
2577
2583
|
import * as path from "path";
|
|
2584
|
+
import { homedir } from "os";
|
|
2585
|
+
var MAX_BYTES = 10 * 1024 * 1024;
|
|
2586
|
+
var ENV_DEBUG = process.env.ACP_DEBUG === "1" || process.env.ACP_DEBUG === "true";
|
|
2587
|
+
function resolveLogFile() {
|
|
2588
|
+
return process.env.ACP_LOG_FILE ?? path.join(homedir(), ".pi", "acp.log");
|
|
2589
|
+
}
|
|
2590
|
+
var runtimeDebug = null;
|
|
2591
|
+
function setDebugEnabled(enabled) {
|
|
2592
|
+
runtimeDebug = enabled;
|
|
2593
|
+
}
|
|
2594
|
+
function debugOn() {
|
|
2595
|
+
return runtimeDebug ?? ENV_DEBUG;
|
|
2596
|
+
}
|
|
2597
|
+
function fmt(v) {
|
|
2598
|
+
if (typeof v === "string") return v;
|
|
2599
|
+
if (v instanceof Error) return v.stack || String(v);
|
|
2600
|
+
try {
|
|
2601
|
+
return JSON.stringify(v);
|
|
2602
|
+
} catch {
|
|
2603
|
+
return String(v);
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
function ts() {
|
|
2607
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
2608
|
+
}
|
|
2609
|
+
function writeLine(level, scope, fields) {
|
|
2610
|
+
const file = resolveLogFile();
|
|
2611
|
+
try {
|
|
2612
|
+
if (existsSync(file) && statSync(file).size >= MAX_BYTES) {
|
|
2613
|
+
renameSync(file, file + ".old");
|
|
2614
|
+
}
|
|
2615
|
+
} catch {
|
|
2616
|
+
}
|
|
2617
|
+
const body = Object.keys(fields).map((k) => `${k}=${fmt(fields[k])}`).join(" ");
|
|
2618
|
+
const line = `${ts()} [${level}] [${scope}] ${body}
|
|
2619
|
+
`;
|
|
2620
|
+
try {
|
|
2621
|
+
mkdirSync(path.dirname(file), { recursive: true });
|
|
2622
|
+
appendFileSync(file, line);
|
|
2623
|
+
} catch {
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
function closeLogStream() {
|
|
2627
|
+
}
|
|
2628
|
+
function logError(scope, fields) {
|
|
2629
|
+
writeLine("error", scope, fields);
|
|
2630
|
+
}
|
|
2631
|
+
function logWarn(scope, fields) {
|
|
2632
|
+
writeLine("warn", scope, fields);
|
|
2633
|
+
}
|
|
2634
|
+
function logInfo(scope, fields) {
|
|
2635
|
+
writeLine("info", scope, fields);
|
|
2636
|
+
}
|
|
2637
|
+
function logThrow(scope, err, extra = {}) {
|
|
2638
|
+
const fields = { ...extra };
|
|
2639
|
+
if (err instanceof Error) {
|
|
2640
|
+
fields.error = err.message;
|
|
2641
|
+
fields.stack = err.stack ?? "";
|
|
2642
|
+
} else {
|
|
2643
|
+
fields.error = String(err);
|
|
2644
|
+
}
|
|
2645
|
+
writeLine("error", scope, fields);
|
|
2646
|
+
}
|
|
2647
|
+
var debug = {
|
|
2648
|
+
get enabled() {
|
|
2649
|
+
return debugOn();
|
|
2650
|
+
},
|
|
2651
|
+
get logFile() {
|
|
2652
|
+
return resolveLogFile();
|
|
2653
|
+
},
|
|
2654
|
+
event(scope, fields) {
|
|
2655
|
+
if (debugOn()) writeLine("debug", scope, fields);
|
|
2656
|
+
}
|
|
2657
|
+
};
|
|
2658
|
+
|
|
2659
|
+
// src/state.ts
|
|
2578
2660
|
var STATE_SUFFIX = ".acp.json";
|
|
2579
2661
|
function stateFileFor(sessionFile) {
|
|
2580
2662
|
if (sessionFile) return sessionFile + STATE_SUFFIX;
|
|
@@ -2592,7 +2674,11 @@ var SessionStateStore = class {
|
|
|
2592
2674
|
const raw = await fs.readFile(file, "utf8");
|
|
2593
2675
|
const parsed = JSON.parse(raw);
|
|
2594
2676
|
if (parsed && Array.isArray(parsed.blocks)) state = mergeInitialState(parsed);
|
|
2595
|
-
} catch {
|
|
2677
|
+
} catch (e) {
|
|
2678
|
+
const code = e.code;
|
|
2679
|
+
if (code !== "ENOENT") {
|
|
2680
|
+
logWarn("state", { event: "load-failed", file, error: e instanceof Error ? e.message : String(e) });
|
|
2681
|
+
}
|
|
2596
2682
|
}
|
|
2597
2683
|
}
|
|
2598
2684
|
this.cache = state;
|
|
@@ -2604,12 +2690,17 @@ var SessionStateStore = class {
|
|
|
2604
2690
|
if (!file) return;
|
|
2605
2691
|
this.cache = state;
|
|
2606
2692
|
this.loadedKey = file;
|
|
2607
|
-
const dir =
|
|
2608
|
-
await fs.mkdir(dir, { recursive: true }).catch(() => {
|
|
2693
|
+
const dir = path2.dirname(file);
|
|
2694
|
+
await fs.mkdir(dir, { recursive: true }).catch((e) => {
|
|
2695
|
+
logError("state", { event: "save-mkdir-failed", dir, error: e instanceof Error ? e.message : String(e) });
|
|
2609
2696
|
});
|
|
2610
|
-
const tmp =
|
|
2611
|
-
|
|
2612
|
-
|
|
2697
|
+
const tmp = path2.join(dir, `.acp-tmp-${path2.basename(file)}`);
|
|
2698
|
+
try {
|
|
2699
|
+
await fs.writeFile(tmp, JSON.stringify(state), "utf8");
|
|
2700
|
+
await fs.rename(tmp, file);
|
|
2701
|
+
} catch (e) {
|
|
2702
|
+
logError("state", { event: "save-failed", file, error: e instanceof Error ? e.message : String(e) });
|
|
2703
|
+
}
|
|
2613
2704
|
}
|
|
2614
2705
|
invalidate() {
|
|
2615
2706
|
this.cache = null;
|
|
@@ -7082,64 +7173,6 @@ __export(typebox_exports, {
|
|
|
7082
7173
|
With: () => With2
|
|
7083
7174
|
});
|
|
7084
7175
|
|
|
7085
|
-
// src/log.ts
|
|
7086
|
-
import { promises as fs2 } from "fs";
|
|
7087
|
-
import * as path2 from "path";
|
|
7088
|
-
import { homedir } from "os";
|
|
7089
|
-
var ENV_DEBUG = process.env.ACP_DEBUG === "1" || process.env.ACP_DEBUG === "true";
|
|
7090
|
-
var LOG_FILE = process.env.ACP_LOG_FILE ?? path2.join(homedir(), ".pi", "acp-debug.log");
|
|
7091
|
-
var runtimeDebug = null;
|
|
7092
|
-
var initialized = false;
|
|
7093
|
-
function setDebugEnabled(enabled) {
|
|
7094
|
-
runtimeDebug = enabled;
|
|
7095
|
-
}
|
|
7096
|
-
function debugOn() {
|
|
7097
|
-
return runtimeDebug ?? ENV_DEBUG;
|
|
7098
|
-
}
|
|
7099
|
-
async function write(line) {
|
|
7100
|
-
if (!debugOn()) return;
|
|
7101
|
-
if (!initialized) {
|
|
7102
|
-
initialized = true;
|
|
7103
|
-
await fs2.mkdir(path2.dirname(LOG_FILE), { recursive: true }).catch(() => {
|
|
7104
|
-
});
|
|
7105
|
-
}
|
|
7106
|
-
await fs2.appendFile(LOG_FILE, line, "utf8").catch(() => {
|
|
7107
|
-
});
|
|
7108
|
-
}
|
|
7109
|
-
var debug = {
|
|
7110
|
-
get enabled() {
|
|
7111
|
-
return debugOn();
|
|
7112
|
-
},
|
|
7113
|
-
get logFile() {
|
|
7114
|
-
return LOG_FILE;
|
|
7115
|
-
},
|
|
7116
|
-
event(scope, fields) {
|
|
7117
|
-
if (!debugOn()) return;
|
|
7118
|
-
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
7119
|
-
const body = Object.entries(fields).map(([k, v]) => `${k}=${fmt(v)}`).join(" ");
|
|
7120
|
-
void write(`${ts} [${scope}] ${body}
|
|
7121
|
-
`);
|
|
7122
|
-
}
|
|
7123
|
-
};
|
|
7124
|
-
function fmt(v) {
|
|
7125
|
-
if (typeof v === "string") return v;
|
|
7126
|
-
if (Array.isArray(v)) {
|
|
7127
|
-
try {
|
|
7128
|
-
return JSON.stringify(v);
|
|
7129
|
-
} catch {
|
|
7130
|
-
return `[${v.length}]`;
|
|
7131
|
-
}
|
|
7132
|
-
}
|
|
7133
|
-
if (v && typeof v === "object") {
|
|
7134
|
-
try {
|
|
7135
|
-
return JSON.stringify(v);
|
|
7136
|
-
} catch {
|
|
7137
|
-
return String(v);
|
|
7138
|
-
}
|
|
7139
|
-
}
|
|
7140
|
-
return String(v);
|
|
7141
|
-
}
|
|
7142
|
-
|
|
7143
7176
|
// src/tokens.ts
|
|
7144
7177
|
function collectCoveredMessageIds(state) {
|
|
7145
7178
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -7195,7 +7228,13 @@ function makeCompressTool(runtime) {
|
|
|
7195
7228
|
],
|
|
7196
7229
|
parameters: CompressParams,
|
|
7197
7230
|
async execute(toolCallId, params, _signal, _onUpdate, ctx) {
|
|
7198
|
-
|
|
7231
|
+
let result;
|
|
7232
|
+
try {
|
|
7233
|
+
result = await handleCompress(params, runtime, ctx, toolCallId);
|
|
7234
|
+
} catch (e) {
|
|
7235
|
+
logThrow("compress", e, { sid: ctx.sessionManager.getSessionId(), ranges: params.content?.length ?? 0 });
|
|
7236
|
+
throw e;
|
|
7237
|
+
}
|
|
7199
7238
|
return { details: void 0, content: [{ type: "text", text: result }] };
|
|
7200
7239
|
}
|
|
7201
7240
|
};
|
|
@@ -7240,6 +7279,24 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
|
|
|
7240
7279
|
activeAfter: applied.state.blocks.filter((b) => b.active).length,
|
|
7241
7280
|
newBlocks: newBlocks.map((b) => ({ blockId: b.blockId, tier: b.tier, summaryLen: b.summary.length, directMsgCount: b.directMessageIds.length, effectiveMsgCount: b.effectiveMessageIds.length, summary: b.summary }))
|
|
7242
7281
|
});
|
|
7282
|
+
logInfo("compress", {
|
|
7283
|
+
sid: ctx.sessionManager.getSessionId(),
|
|
7284
|
+
event: "applied",
|
|
7285
|
+
ranges: ranges.length,
|
|
7286
|
+
blocksCreated,
|
|
7287
|
+
tokensCompressed,
|
|
7288
|
+
beforeTokens,
|
|
7289
|
+
afterTokens,
|
|
7290
|
+
warnings: warnings.length,
|
|
7291
|
+
errors: errors.length,
|
|
7292
|
+
newBlockIds: newBlocks.map((b) => b.blockId)
|
|
7293
|
+
});
|
|
7294
|
+
if (errors.length > 0) {
|
|
7295
|
+
logError("compress", { sid: ctx.sessionManager.getSessionId(), event: "errors", count: errors.length, errors: errors.slice(0, 5) });
|
|
7296
|
+
}
|
|
7297
|
+
if (warnings.length > 0) {
|
|
7298
|
+
logError("compress", { sid: ctx.sessionManager.getSessionId(), event: "warnings", count: warnings.length, warnings: warnings.slice(0, 5) });
|
|
7299
|
+
}
|
|
7243
7300
|
const lines = [`\u25A3 ACP | ${formatK2(beforeTokens)} \u2192 ${formatK2(afterTokens)} tokens (~${formatK2(tokensCompressed)} reclaimed, ${blocksCreated} block${blocksCreated > 1 ? "s" : ""})`];
|
|
7244
7301
|
if (warnings.length > 0) lines.push("\u26A0\uFE0F " + warnings.join("; "));
|
|
7245
7302
|
if (errors.length > 0) lines.push("Errors: " + errors.join("; "));
|
|
@@ -7273,7 +7330,13 @@ function makeDecompressTool(runtime) {
|
|
|
7273
7330
|
],
|
|
7274
7331
|
parameters: DecompressParams,
|
|
7275
7332
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
7276
|
-
|
|
7333
|
+
let result;
|
|
7334
|
+
try {
|
|
7335
|
+
result = await handleDecompress(params, runtime, ctx);
|
|
7336
|
+
} catch (e) {
|
|
7337
|
+
logThrow("decompress", e, { sid: ctx.sessionManager.getSessionId(), blockId: params.blockId });
|
|
7338
|
+
throw e;
|
|
7339
|
+
}
|
|
7277
7340
|
return { details: void 0, content: [{ type: "text", text: result }] };
|
|
7278
7341
|
}
|
|
7279
7342
|
};
|
|
@@ -7322,16 +7385,21 @@ async function handleMessageRef(ref, ownerBlockId, args, ctx) {
|
|
|
7322
7385
|
const wantFile = args.toFile !== void 0 || args.inline === false || text.length >= MESSAGE_INLINE_THRESHOLD;
|
|
7323
7386
|
if (!wantFile) {
|
|
7324
7387
|
debug.event("decompress-message", { ref, ownerBlockId, mode: "inline", chars: text.length });
|
|
7388
|
+
logInfo("decompress", { sid: ctx.sessionManager.getSessionId(), event: "message", mode: "inline", ref, ownerBlockId, chars: text.length });
|
|
7325
7389
|
return `Message ${ref} (${role}, block ${ownerBlockId}, ${text.length} chars) restored inline:
|
|
7326
7390
|
|
|
7327
7391
|
${text}`;
|
|
7328
7392
|
}
|
|
7329
7393
|
const targetPath = args.toFile ? resolveToFilePath(args.toFile) : autoFilePath(`msg-${ref}`);
|
|
7330
|
-
if (typeof targetPath === "object" && "error" in targetPath)
|
|
7394
|
+
if (typeof targetPath === "object" && "error" in targetPath) {
|
|
7395
|
+
logError("decompress", { sid: ctx.sessionManager.getSessionId(), event: "message-path-rejected", ref, toFile: args.toFile });
|
|
7396
|
+
return targetPath.error;
|
|
7397
|
+
}
|
|
7331
7398
|
await mkdir(AUTO_DIR, { recursive: true }).catch(() => {
|
|
7332
7399
|
});
|
|
7333
7400
|
await writeFile(targetPath, text, "utf8");
|
|
7334
7401
|
debug.event("decompress-message", { ref, ownerBlockId, mode: "file", path: targetPath, chars: text.length });
|
|
7402
|
+
logInfo("decompress", { sid: ctx.sessionManager.getSessionId(), event: "message", mode: "file", ref, ownerBlockId, path: targetPath, chars: text.length });
|
|
7335
7403
|
return [
|
|
7336
7404
|
`Message ${ref} (${role}, block ${ownerBlockId}, ${text.length} chars) written to ${targetPath}.`,
|
|
7337
7405
|
"Block stays compressed \u2014 context unchanged. Use the read tool to access the content.",
|
|
@@ -7359,16 +7427,21 @@ async function handleDecompress(args, runtime, ctx) {
|
|
|
7359
7427
|
if (count === 0) return `Block ${blockId} has no restorable message content.`;
|
|
7360
7428
|
if (args.inline === true && !args.toFile) {
|
|
7361
7429
|
debug.event("decompress", { blockId, full, count, mode: "inline" });
|
|
7430
|
+
logInfo("decompress", { sid: ctx.sessionManager.getSessionId(), event: "block", mode: "inline", blockId, full, count });
|
|
7362
7431
|
return `Restored block ${blockId} (${count} item${count === 1 ? "" : "s"}) inline:
|
|
7363
7432
|
|
|
7364
7433
|
${text}`;
|
|
7365
7434
|
}
|
|
7366
7435
|
const targetPath = args.toFile ? resolveToFilePath(args.toFile) : autoFilePath(blockId);
|
|
7367
|
-
if (typeof targetPath === "object" && "error" in targetPath)
|
|
7436
|
+
if (typeof targetPath === "object" && "error" in targetPath) {
|
|
7437
|
+
logError("decompress", { sid: ctx.sessionManager.getSessionId(), event: "block-path-rejected", blockId, toFile: args.toFile });
|
|
7438
|
+
return targetPath.error;
|
|
7439
|
+
}
|
|
7368
7440
|
await mkdir(AUTO_DIR, { recursive: true }).catch(() => {
|
|
7369
7441
|
});
|
|
7370
7442
|
await writeFile(targetPath, text, "utf8");
|
|
7371
7443
|
debug.event("decompress", { blockId, full, count, mode: "file", path: targetPath, chars: text.length });
|
|
7444
|
+
logInfo("decompress", { sid: ctx.sessionManager.getSessionId(), event: "block", mode: "file", blockId, full, count, path: targetPath, chars: text.length });
|
|
7372
7445
|
const itemWord = count === 1 ? "item" : "items";
|
|
7373
7446
|
const lines = [
|
|
7374
7447
|
`Block ${blockId} (${count} ${itemWord}, ${text.length} chars) written to ${targetPath}.`,
|
|
@@ -7458,7 +7531,13 @@ function makeSearchTool(runtime) {
|
|
|
7458
7531
|
],
|
|
7459
7532
|
parameters: SearchParams,
|
|
7460
7533
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
7461
|
-
|
|
7534
|
+
let result;
|
|
7535
|
+
try {
|
|
7536
|
+
result = await handleSearch(params, runtime, ctx);
|
|
7537
|
+
} catch (e) {
|
|
7538
|
+
logThrow("search", e, { sid: ctx.sessionManager.getSessionId(), query: params.query });
|
|
7539
|
+
throw e;
|
|
7540
|
+
}
|
|
7462
7541
|
return { details: void 0, content: [{ type: "text", text: result }] };
|
|
7463
7542
|
}
|
|
7464
7543
|
};
|
|
@@ -7523,7 +7602,13 @@ function makeStatusTool(runtime) {
|
|
|
7523
7602
|
],
|
|
7524
7603
|
parameters: StatusParams,
|
|
7525
7604
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
7526
|
-
|
|
7605
|
+
let result;
|
|
7606
|
+
try {
|
|
7607
|
+
result = await handleStatus(params, runtime, ctx);
|
|
7608
|
+
} catch (e) {
|
|
7609
|
+
logThrow("status", e, { sid: ctx.sessionManager.getSessionId(), scope: params.scope ?? null });
|
|
7610
|
+
throw e;
|
|
7611
|
+
}
|
|
7527
7612
|
return { details: void 0, content: [{ type: "text", text: result }] };
|
|
7528
7613
|
}
|
|
7529
7614
|
};
|
|
@@ -8103,6 +8188,7 @@ function makeDelegateCancelTool(_pi) {
|
|
|
8103
8188
|
run.child?.kill("SIGTERM");
|
|
8104
8189
|
} catch (err) {
|
|
8105
8190
|
debug.event("delegate-cancel-kill-error", { runId, error: String(err) });
|
|
8191
|
+
logError("delegate", { event: "cancel-kill-error", runId, error: String(err) });
|
|
8106
8192
|
}
|
|
8107
8193
|
delegateStatusWidget.poke();
|
|
8108
8194
|
return {
|
|
@@ -8133,8 +8219,11 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
8133
8219
|
const requestedAsync = args.async !== false;
|
|
8134
8220
|
if (requestedAsync && !isAsync) {
|
|
8135
8221
|
debug.event("delegate-async-downgraded", { reason: `mode=${ctx.mode}` });
|
|
8222
|
+
logInfo("delegate", { event: "async-downgraded", reason: `mode=${ctx.mode}` });
|
|
8136
8223
|
}
|
|
8137
|
-
|
|
8224
|
+
const runId = `del_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8225
|
+
debug.event("delegate-spawn", { agent: args.agent, runId, cwd, async: isAsync, useJsonStream, cliArgs });
|
|
8226
|
+
logInfo("delegate", { event: "spawn", agent: args.agent, runId, cwd, async: isAsync, useJsonStream, mode: ctx.mode, parentDepth });
|
|
8138
8227
|
const child = spawn(process.execPath, [process.argv[1], ...cliArgs], {
|
|
8139
8228
|
cwd,
|
|
8140
8229
|
env: childEnv,
|
|
@@ -8143,10 +8232,10 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
8143
8232
|
});
|
|
8144
8233
|
child.stdin?.once("error", (e) => {
|
|
8145
8234
|
debug.event("delegate-stdin-error", { runId: "pre-spawn", error: String(e) });
|
|
8235
|
+
logError("delegate", { event: "stdin-error", runId, error: String(e) });
|
|
8146
8236
|
});
|
|
8147
8237
|
child.stdin?.end(args.task);
|
|
8148
8238
|
let stderrText = "";
|
|
8149
|
-
const runId = `del_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8150
8239
|
const startedAt = Date.now();
|
|
8151
8240
|
if (isAsync) {
|
|
8152
8241
|
let settled = false;
|
|
@@ -8278,23 +8367,27 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
8278
8367
|
run.finishedAt = Date.now();
|
|
8279
8368
|
if (run.waiter) {
|
|
8280
8369
|
debug.event("delegate-done", { runId, code, status: run.status, injected: false, via: "wait", outLen: output.length, file: file2 });
|
|
8370
|
+
logInfo("delegate", { event: "done", runId, agent: args.agent, code, status: run.status, injected: false, via: "wait", outLen: output.length, file: file2 });
|
|
8281
8371
|
run.waiter();
|
|
8282
8372
|
delegateStatusWidget.poke();
|
|
8283
8373
|
return;
|
|
8284
8374
|
}
|
|
8285
8375
|
if (run.consumed) {
|
|
8286
8376
|
debug.event("delegate-done", { runId, code, status: run.status, injected: false, via: "consumed", outLen: output.length, file: file2 });
|
|
8377
|
+
logInfo("delegate", { event: "done", runId, agent: args.agent, code, status: run.status, injected: false, via: "consumed", outLen: output.length, file: file2 });
|
|
8287
8378
|
delegateStatusWidget.poke();
|
|
8288
8379
|
return;
|
|
8289
8380
|
}
|
|
8290
8381
|
const injected = injectResult(pi, args.agent, runId, args.task, code, file2, run.timedOut);
|
|
8291
8382
|
run.injected = injected;
|
|
8292
8383
|
debug.event("delegate-done", { runId, code, status: run.status, injected, outLen: output.length, file: file2 });
|
|
8384
|
+
logInfo("delegate", { event: "done", runId, agent: args.agent, code, status: run.status, injected, outLen: output.length, file: file2 });
|
|
8293
8385
|
delegateStatusWidget.poke();
|
|
8294
8386
|
} catch (err) {
|
|
8295
8387
|
run.status = "failed";
|
|
8296
8388
|
run.finishedAt = Date.now();
|
|
8297
8389
|
debug.event("delegate-done-error", { runId, error: String(err) });
|
|
8390
|
+
logError("delegate", { event: "done-error", runId, agent: args.agent, error: String(err) });
|
|
8298
8391
|
run.waiter?.();
|
|
8299
8392
|
delegateStatusWidget.poke();
|
|
8300
8393
|
}
|
|
@@ -8315,6 +8408,7 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
8315
8408
|
run.finishedAt = Date.now();
|
|
8316
8409
|
run.result = { code: null, file: "", body: `spawn error: ${String(err)}` };
|
|
8317
8410
|
debug.event("delegate-spawn-error", { runId, error: String(err) });
|
|
8411
|
+
logError("delegate", { event: "spawn-error", runId, agent: args.agent, error: String(err) });
|
|
8318
8412
|
run.waiter?.();
|
|
8319
8413
|
delegateStatusWidget.poke();
|
|
8320
8414
|
}
|
|
@@ -8409,6 +8503,7 @@ function injectResult(pi, agent, runId, task, code, file, timedOut) {
|
|
|
8409
8503
|
const send = pi.sendUserMessage;
|
|
8410
8504
|
if (typeof send !== "function") {
|
|
8411
8505
|
debug.event("delegate-inject-skipped", { runId, reason: "sendUserMessage unavailable" });
|
|
8506
|
+
logWarn("delegate", { event: "inject-skipped", runId, reason: "sendUserMessage unavailable" });
|
|
8412
8507
|
return false;
|
|
8413
8508
|
}
|
|
8414
8509
|
const status = code === 0 ? "completed" : "failed";
|
|
@@ -8422,6 +8517,7 @@ function injectResult(pi, agent, runId, task, code, file, timedOut) {
|
|
|
8422
8517
|
return true;
|
|
8423
8518
|
} catch (err) {
|
|
8424
8519
|
debug.event("delegate-inject-error", { runId, error: String(err) });
|
|
8520
|
+
logError("delegate", { event: "inject-error", runId, agent, error: String(err) });
|
|
8425
8521
|
return false;
|
|
8426
8522
|
}
|
|
8427
8523
|
}
|
|
@@ -8449,6 +8545,7 @@ async function persistResult(runId, body) {
|
|
|
8449
8545
|
return file;
|
|
8450
8546
|
} catch (err) {
|
|
8451
8547
|
debug.event("delegate-persist-error", { runId, file, error: String(err) });
|
|
8548
|
+
logError("delegate", { event: "persist-error", runId, file, error: String(err) });
|
|
8452
8549
|
return "";
|
|
8453
8550
|
}
|
|
8454
8551
|
}
|
|
@@ -8559,7 +8656,7 @@ async function statusReport(runtime, ctx) {
|
|
|
8559
8656
|
const activeBlocksList = state.blocks.filter((b) => b.active);
|
|
8560
8657
|
const totalBlocksList = state.blocks;
|
|
8561
8658
|
const lines = [];
|
|
8562
|
-
const versionStr = "0.1.
|
|
8659
|
+
const versionStr = "0.1.29" ? `billion-context-pi@${"0.1.29"}` : "";
|
|
8563
8660
|
lines.push("\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E");
|
|
8564
8661
|
lines.push("\u2502 ACP Context Analysis \u2502");
|
|
8565
8662
|
lines.push("\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F");
|
|
@@ -8803,11 +8900,13 @@ function wireToolGuardrails(pi, runtime) {
|
|
|
8803
8900
|
if (next) {
|
|
8804
8901
|
modified = next;
|
|
8805
8902
|
debug.event("guardrail-output-cap", { max, hadPath: !!fullPath });
|
|
8903
|
+
logWarn("guardrail", { event: "output-cap", max, hadPath: !!fullPath });
|
|
8806
8904
|
}
|
|
8807
8905
|
}
|
|
8808
8906
|
if (timeoutSecs !== void 0) {
|
|
8809
8907
|
modified = appendTimeoutNotice(modified ?? event.content, timeoutSecs);
|
|
8810
8908
|
debug.event("guardrail-bash-timeout-notice", { secs: timeoutSecs });
|
|
8909
|
+
logInfo("guardrail", { event: "bash-timeout-notice", secs: timeoutSecs });
|
|
8811
8910
|
}
|
|
8812
8911
|
if (modified) return { content: modified };
|
|
8813
8912
|
});
|
|
@@ -8915,29 +9014,36 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
8915
9014
|
signal: AbortSignal.timeout(5e3),
|
|
8916
9015
|
headers: { Accept: "application/json" }
|
|
8917
9016
|
});
|
|
8918
|
-
if (!res.ok)
|
|
9017
|
+
if (!res.ok) {
|
|
9018
|
+
logWarn("update", { event: "check-http", status: res.status });
|
|
9019
|
+
return;
|
|
9020
|
+
}
|
|
8919
9021
|
const data = await res.json();
|
|
8920
9022
|
const latest = data.version;
|
|
8921
9023
|
if (!latest) return;
|
|
8922
|
-
const current = runtimeVersion ?? "0.1.
|
|
9024
|
+
const current = runtimeVersion ?? "0.1.29";
|
|
9025
|
+
const hasUpdate = isNewer(latest, current);
|
|
8923
9026
|
debug.event("update-check", {
|
|
8924
9027
|
current,
|
|
8925
9028
|
latest,
|
|
8926
|
-
hasUpdate
|
|
9029
|
+
hasUpdate
|
|
8927
9030
|
});
|
|
8928
|
-
|
|
9031
|
+
logInfo("update", { event: "check", current, latest, hasUpdate });
|
|
9032
|
+
if (hasUpdate) {
|
|
8929
9033
|
const installed = await autoInstallLatest(latest);
|
|
8930
9034
|
if (installed && notify) {
|
|
8931
9035
|
notify(
|
|
8932
9036
|
`\x1B[32m\u2714 ACP auto-updated ${current} \u2192 ${latest}. Restart Pi to finish.\x1B[0m`
|
|
8933
9037
|
);
|
|
9038
|
+
logInfo("update", { event: "auto-installed", from: current, to: latest });
|
|
8934
9039
|
} else if (!installed && notify) {
|
|
8935
9040
|
notify(
|
|
8936
9041
|
`${PACKAGE_NAME} ${latest} available (you have ${current}). Run: pi update --extension npm:${PACKAGE_NAME}`
|
|
8937
9042
|
);
|
|
8938
9043
|
}
|
|
8939
9044
|
}
|
|
8940
|
-
} catch {
|
|
9045
|
+
} catch (e) {
|
|
9046
|
+
logWarn("update", { event: "check-error", error: e instanceof Error ? e.message : String(e) });
|
|
8941
9047
|
} finally {
|
|
8942
9048
|
updateInFlight = false;
|
|
8943
9049
|
}
|
|
@@ -8951,7 +9057,7 @@ async function getRuntimeVersion() {
|
|
|
8951
9057
|
|
|
8952
9058
|
// src/setup-subagent-tools.ts
|
|
8953
9059
|
import { readFile as readFile2, writeFile as writeFile4, stat, copyFile, rename } from "fs/promises";
|
|
8954
|
-
import { existsSync } from "fs";
|
|
9060
|
+
import { existsSync as existsSync2 } from "fs";
|
|
8955
9061
|
import { homedir as homedir4 } from "os";
|
|
8956
9062
|
import { join as join6 } from "path";
|
|
8957
9063
|
var ACP_TOOLS2 = ["compress", "decompress", "search_context", "acp_status"];
|
|
@@ -9015,7 +9121,7 @@ async function ensureSubagentAcpTools(settingsPath) {
|
|
|
9015
9121
|
return { path: path4, action: "skipped", reason: "all builtin agents already have ACP tools" };
|
|
9016
9122
|
}
|
|
9017
9123
|
const backupPath = `${path4}.acp-bak`;
|
|
9018
|
-
if (!
|
|
9124
|
+
if (!existsSync2(backupPath)) {
|
|
9019
9125
|
try {
|
|
9020
9126
|
await copyFile(path4, backupPath);
|
|
9021
9127
|
} catch {
|
|
@@ -9067,15 +9173,19 @@ async function runSetupAndNotify(notify) {
|
|
|
9067
9173
|
if (result.action === "updated" && notify) {
|
|
9068
9174
|
notify(`ACP: enabled context tools (compress/decompress/search_context/acp_status) for subagents`);
|
|
9069
9175
|
}
|
|
9176
|
+
if (result.action === "failed") {
|
|
9177
|
+
logWarn("setup", { event: "subagent-tools", action: result.action, reason: result.reason });
|
|
9178
|
+
}
|
|
9070
9179
|
return result;
|
|
9071
9180
|
} catch (e) {
|
|
9072
9181
|
debug.event("setup-subagent-tools-error", { msg: String(e) });
|
|
9182
|
+
logError("setup", { event: "subagent-tools-error", error: e instanceof Error ? e.message : String(e), stack: e instanceof Error ? e.stack ?? "" : "" });
|
|
9073
9183
|
return { path: "", action: "failed", reason: String(e) };
|
|
9074
9184
|
}
|
|
9075
9185
|
}
|
|
9076
9186
|
|
|
9077
9187
|
// src/user-config.ts
|
|
9078
|
-
import { promises as
|
|
9188
|
+
import { promises as fs2 } from "fs";
|
|
9079
9189
|
import * as path3 from "path";
|
|
9080
9190
|
import { homedir as homedir5 } from "os";
|
|
9081
9191
|
import { CONFIG_DIR_NAME } from "@earendil-works/pi-coding-agent";
|
|
@@ -9085,13 +9195,17 @@ async function loadUserConfig(cwd) {
|
|
|
9085
9195
|
for (const base of [join8(home, CONFIG_DIR_NAME), join8(cwd, CONFIG_DIR_NAME)]) {
|
|
9086
9196
|
const file = join8(base, "acp.json");
|
|
9087
9197
|
try {
|
|
9088
|
-
const raw = await
|
|
9198
|
+
const raw = await fs2.readFile(file, "utf8");
|
|
9089
9199
|
const parsed = JSON.parse(raw);
|
|
9090
9200
|
if (parsed && typeof parsed === "object") {
|
|
9091
9201
|
Object.assign(merged, pickKnown(parsed));
|
|
9092
9202
|
debug.event("config-loaded", { file });
|
|
9093
9203
|
}
|
|
9094
|
-
} catch {
|
|
9204
|
+
} catch (e) {
|
|
9205
|
+
const code = e.code;
|
|
9206
|
+
if (code !== "ENOENT") {
|
|
9207
|
+
logWarn("config", { event: "load-failed", file, error: e instanceof Error ? e.message : String(e) });
|
|
9208
|
+
}
|
|
9095
9209
|
}
|
|
9096
9210
|
}
|
|
9097
9211
|
return merged;
|
|
@@ -9145,11 +9259,14 @@ function wireSessionLifecycle(pi, runtime) {
|
|
|
9145
9259
|
pi.on("session_start", async (_event, ctx) => {
|
|
9146
9260
|
runtime.store.invalidate();
|
|
9147
9261
|
runtime.clearNudgeTracking();
|
|
9262
|
+
const sid = ctx.sessionManager.getSessionId();
|
|
9263
|
+
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.29" : null });
|
|
9148
9264
|
try {
|
|
9149
9265
|
const user = await loadUserConfig(ctx.cwd);
|
|
9150
9266
|
runtime.setAdapter(applyUserConfig(runtime.adapter, user));
|
|
9151
9267
|
if (runtime.adapter.debug !== void 0) setDebugEnabled(runtime.adapter.debug);
|
|
9152
|
-
} catch {
|
|
9268
|
+
} catch (e) {
|
|
9269
|
+
logThrow("config", e, { sid, phase: "session_start" });
|
|
9153
9270
|
}
|
|
9154
9271
|
if (runtime.adapter.delegate !== false) {
|
|
9155
9272
|
pi.registerTool(makeDelegateTool(pi));
|
|
@@ -9164,6 +9281,7 @@ function wireSessionLifecycle(pi, runtime) {
|
|
|
9164
9281
|
});
|
|
9165
9282
|
pi.on("session_shutdown", () => {
|
|
9166
9283
|
delegateStatusWidget.dispose();
|
|
9284
|
+
closeLogStream();
|
|
9167
9285
|
});
|
|
9168
9286
|
}
|
|
9169
9287
|
function wireContextTransform(pi, runtime) {
|
|
@@ -9192,6 +9310,18 @@ function wireContextTransform(pi, runtime) {
|
|
|
9192
9310
|
});
|
|
9193
9311
|
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount });
|
|
9194
9312
|
await runtime.save(turn.state, ctx);
|
|
9313
|
+
logInfo("turn", {
|
|
9314
|
+
sid,
|
|
9315
|
+
inMsgs: coreMessages.length,
|
|
9316
|
+
outMsgs: turn.messages.length,
|
|
9317
|
+
tokens: tokenCount,
|
|
9318
|
+
pct: realUsage?.percent ?? (config.modelContextLimit > 0 ? Math.round(tokenCount / config.modelContextLimit * 100) : null),
|
|
9319
|
+
limit: config.modelContextLimit,
|
|
9320
|
+
nudge: turn.nudge?.shouldInject ? turn.nudge.breakdown?.emergencyOverride === 1 ? "emergency" : "active" : "idle",
|
|
9321
|
+
nudgeReason: turn.nudge?.reason ?? null,
|
|
9322
|
+
blocks: turn.state.blocks.length,
|
|
9323
|
+
activeBlocks: turn.state.blocks.filter((b) => b.active).length
|
|
9324
|
+
});
|
|
9195
9325
|
debug.event("processTurn", {
|
|
9196
9326
|
outMsgs: turn.messages.length,
|
|
9197
9327
|
summaryMsgs: turn.messages.filter((m) => m.id.startsWith("acp_summary")).length,
|
|
@@ -9221,6 +9351,9 @@ function wireContextTransform(pi, runtime) {
|
|
|
9221
9351
|
const example = top ? `
|
|
9222
9352
|
|
|
9223
9353
|
Example: compress({ content: [{ startId: "${top.startRef}", endId: "${top.endRef}", summary: "..." }] })` : "";
|
|
9354
|
+
if (emergency) {
|
|
9355
|
+
logWarn("nudge", { sid: ctx.sessionManager.getSessionId(), event: "emergency-inject", pct: Math.round(turn.nudge.contextUsage * 100), voice: rendered.voice, compressible: turn.nudge.compressibleRanges.length });
|
|
9356
|
+
}
|
|
9224
9357
|
if (debugOn2 && ctx.hasUI) {
|
|
9225
9358
|
ctx.ui.notify(`[ACP nudge \u2192 context]${emergency ? " [EMERGENCY]" : ""}
|
|
9226
9359
|
${rendered.text}${example}`);
|
|
@@ -9236,6 +9369,9 @@ ${rendered.text}${example}`);
|
|
|
9236
9369
|
if (ctx.hasUI) ctx.ui.notify(msg);
|
|
9237
9370
|
});
|
|
9238
9371
|
return { messages: rebuilt };
|
|
9372
|
+
} catch (e) {
|
|
9373
|
+
logThrow("context", e, { sid, phase: "transform" });
|
|
9374
|
+
throw e;
|
|
9239
9375
|
} finally {
|
|
9240
9376
|
release();
|
|
9241
9377
|
}
|