billion-context-pi 0.1.31 → 0.1.33
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/dist/delegate-tool.d.ts +30 -0
- package/dist/index.js +173 -93
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/delegate-tool.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { type SpawnOptions } from "node:child_process";
|
|
1
2
|
import { Type, type Static } from "typebox";
|
|
2
3
|
import type { ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
export declare function delegateSpawnOptions(cwd: string, env: NodeJS.ProcessEnv): SpawnOptions;
|
|
3
5
|
/** Snapshot of currently-running delegate runs, for the TUI status widget. */
|
|
4
6
|
export declare function runningRunsSnapshot(): {
|
|
5
7
|
runId: string;
|
|
@@ -7,6 +9,34 @@ export declare function runningRunsSnapshot(): {
|
|
|
7
9
|
task: string;
|
|
8
10
|
startedAt: number;
|
|
9
11
|
}[];
|
|
12
|
+
/** Minimal writable surface accepted by makeEventApplier — real WriteStreams
|
|
13
|
+
* in production, in-memory collectors in tests. */
|
|
14
|
+
export interface EventApplierWriters {
|
|
15
|
+
reply: {
|
|
16
|
+
write(chunk: string): void;
|
|
17
|
+
};
|
|
18
|
+
activity: {
|
|
19
|
+
write(chunk: string): void;
|
|
20
|
+
} | null;
|
|
21
|
+
}
|
|
22
|
+
export interface EventApplier {
|
|
23
|
+
handleEventLine(line: string): void;
|
|
24
|
+
getReplyText(): string;
|
|
25
|
+
/** omp fallback: `-p` prints the plain reply as raw stdout; append it
|
|
26
|
+
* straight through (no event parsing). */
|
|
27
|
+
appendRaw(text: string): void;
|
|
28
|
+
}
|
|
29
|
+
/** Applies parsed delegate JSON-event lines to the live reply/activity files.
|
|
30
|
+
* Extracted from the spawn closure so the write logic is unit-testable.
|
|
31
|
+
*
|
|
32
|
+
* reply-delta (text_delta) is streamed to the reply file as it arrives;
|
|
33
|
+
* reply-complete (text_end) carries the authoritative full content of the
|
|
34
|
+
* text block — any portion not already written is appended (tracked via
|
|
35
|
+
* msgWritten) so a final answer that arrives without preceding deltas is
|
|
36
|
+
* never lost from the file. */
|
|
37
|
+
export declare function makeEventApplier(opts: {
|
|
38
|
+
showThinking: boolean;
|
|
39
|
+
}, writers: EventApplierWriters): EventApplier;
|
|
10
40
|
declare const DelegateParams: Type.TObject<{
|
|
11
41
|
agent: Type.TString;
|
|
12
42
|
task: Type.TString;
|
package/dist/index.js
CHANGED
|
@@ -463,14 +463,49 @@ function truncateLargeToolOutputs(messages, tokenCount, config, countTokens, opt
|
|
|
463
463
|
return { messages: updated, truncatedCount, savedTokens };
|
|
464
464
|
}
|
|
465
465
|
var KEEP_LAST_ORPHANED = 0;
|
|
466
|
+
function rangeKey(startRef, endRef) {
|
|
467
|
+
return `${startRef}::${endRef}`;
|
|
468
|
+
}
|
|
469
|
+
function rewriteCompressText(text, liveKeys) {
|
|
470
|
+
let parsed;
|
|
471
|
+
try {
|
|
472
|
+
parsed = JSON.parse(text ?? "");
|
|
473
|
+
} catch {
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
477
|
+
const obj = parsed;
|
|
478
|
+
const content = obj.content;
|
|
479
|
+
if (!Array.isArray(content) || content.length === 0) return null;
|
|
480
|
+
const kept = content.filter((entry) => {
|
|
481
|
+
if (!entry || typeof entry !== "object") return false;
|
|
482
|
+
const s = typeof entry.startId === "string" ? entry.startId : typeof entry.messageId === "string" ? entry.messageId : "";
|
|
483
|
+
const e = typeof entry.endId === "string" ? entry.endId : typeof entry.messageId === "string" ? entry.messageId : "";
|
|
484
|
+
return liveKeys.has(rangeKey(s, e));
|
|
485
|
+
});
|
|
486
|
+
if (kept.length === content.length || kept.length === 0) return null;
|
|
487
|
+
return JSON.stringify({ ...obj, content: kept });
|
|
488
|
+
}
|
|
466
489
|
function hideConsumedCompressCalls(state, messages) {
|
|
467
|
-
const activeCallIds = /* @__PURE__ */ new Set();
|
|
468
490
|
const allBlockCallIds = /* @__PURE__ */ new Set();
|
|
491
|
+
const activeCallIds = /* @__PURE__ */ new Set();
|
|
492
|
+
const liveRangeKeysByCallId = /* @__PURE__ */ new Map();
|
|
493
|
+
const legacyLiveByCallId = /* @__PURE__ */ new Set();
|
|
469
494
|
for (const block of state.blocks) {
|
|
470
|
-
if (block.compressCallId)
|
|
471
|
-
|
|
472
|
-
|
|
495
|
+
if (!block.compressCallId) continue;
|
|
496
|
+
allBlockCallIds.add(block.compressCallId);
|
|
497
|
+
if (!block.active) continue;
|
|
498
|
+
activeCallIds.add(block.compressCallId);
|
|
499
|
+
if (block.startRef === void 0 || block.endRef === void 0) {
|
|
500
|
+
legacyLiveByCallId.add(block.compressCallId);
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
let keys = liveRangeKeysByCallId.get(block.compressCallId);
|
|
504
|
+
if (!keys) {
|
|
505
|
+
keys = /* @__PURE__ */ new Set();
|
|
506
|
+
liveRangeKeysByCallId.set(block.compressCallId, keys);
|
|
473
507
|
}
|
|
508
|
+
keys.add(rangeKey(block.startRef, block.endRef));
|
|
474
509
|
}
|
|
475
510
|
const lastOrphanedCallIds = [];
|
|
476
511
|
for (let i = messages.length - 1; i >= 0 && lastOrphanedCallIds.length < KEEP_LAST_ORPHANED; i--) {
|
|
@@ -499,6 +534,16 @@ function hideConsumedCompressCalls(state, messages) {
|
|
|
499
534
|
hidden++;
|
|
500
535
|
continue;
|
|
501
536
|
}
|
|
537
|
+
if (message.toolName === "compress" && message.contentType === "tool-call" && message.toolCallId && keepCallIds.has(message.toolCallId)) {
|
|
538
|
+
const liveKeys = liveRangeKeysByCallId.get(message.toolCallId);
|
|
539
|
+
if (liveKeys && liveKeys.size > 0 && !legacyLiveByCallId.has(message.toolCallId)) {
|
|
540
|
+
const rewritten = rewriteCompressText(message.text, liveKeys);
|
|
541
|
+
if (rewritten !== null) {
|
|
542
|
+
result.push({ ...message, text: rewritten });
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
502
547
|
result.push(message);
|
|
503
548
|
}
|
|
504
549
|
return { messages: result, hidden };
|
|
@@ -732,8 +777,8 @@ function refNum(ref) {
|
|
|
732
777
|
const n = parseInt(ref.slice(1), 10);
|
|
733
778
|
return Number.isNaN(n) ? -1 : n;
|
|
734
779
|
}
|
|
735
|
-
function
|
|
736
|
-
return Math.ceil(
|
|
780
|
+
function estimateTextTokens(text) {
|
|
781
|
+
return Math.ceil(text.length / 4);
|
|
737
782
|
}
|
|
738
783
|
function isToolMessage(message) {
|
|
739
784
|
return message.contentType === "tool-call" || message.contentType === "tool-result";
|
|
@@ -745,7 +790,7 @@ function isSyntheticOrPruned(message, state) {
|
|
|
745
790
|
}
|
|
746
791
|
return false;
|
|
747
792
|
}
|
|
748
|
-
function computeProtectedRefs(messages, state, config) {
|
|
793
|
+
function computeProtectedRefs(messages, state, config, countTokens = estimateTextTokens) {
|
|
749
794
|
const preserveN = config.preserveRecentMessages;
|
|
750
795
|
const preserveTokens = config.preserveRecentTokens;
|
|
751
796
|
const result = /* @__PURE__ */ new Set();
|
|
@@ -755,7 +800,7 @@ function computeProtectedRefs(messages, state, config) {
|
|
|
755
800
|
if (isNeverPreserveRecent(msg)) continue;
|
|
756
801
|
const ref = state.messageRefs.byRaw[msg.id];
|
|
757
802
|
if (!ref || ref === "BLOCKED") continue;
|
|
758
|
-
visible.push({ ref, tokens:
|
|
803
|
+
visible.push({ ref, tokens: countTokens(msg.text ?? "") });
|
|
759
804
|
}
|
|
760
805
|
if (preserveN > 0) {
|
|
761
806
|
for (const m of visible.slice(-preserveN)) {
|
|
@@ -780,7 +825,7 @@ function computeProtectedRefs(messages, state, config) {
|
|
|
780
825
|
}
|
|
781
826
|
return result;
|
|
782
827
|
}
|
|
783
|
-
function buildCompressibleRanges(messages, state, config, protectedZoneRefs) {
|
|
828
|
+
function buildCompressibleRanges(messages, state, config, protectedZoneRefs, countTokens = estimateTextTokens) {
|
|
784
829
|
const compressibleMsgs = [];
|
|
785
830
|
const protectedMsgs = [];
|
|
786
831
|
const protectedCallIds = collectProtectedToolCallIds(messages, config);
|
|
@@ -793,7 +838,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs) {
|
|
|
793
838
|
protectedMsgs.push({
|
|
794
839
|
ref,
|
|
795
840
|
refNum: rn,
|
|
796
|
-
tokens:
|
|
841
|
+
tokens: countTokens(msg.text ?? ""),
|
|
797
842
|
tools: msg.toolName ? [msg.toolName] : []
|
|
798
843
|
});
|
|
799
844
|
continue;
|
|
@@ -804,7 +849,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs) {
|
|
|
804
849
|
compressibleMsgs.push({
|
|
805
850
|
ref,
|
|
806
851
|
refNum: rn,
|
|
807
|
-
tokens:
|
|
852
|
+
tokens: countTokens(msg.text ?? ""),
|
|
808
853
|
isTool: isToolMessage(msg),
|
|
809
854
|
isUser: msg.role === "user"
|
|
810
855
|
});
|
|
@@ -891,7 +936,7 @@ function createCore(ports = {}) {
|
|
|
891
936
|
let tokensCompressed = 0;
|
|
892
937
|
const errors = [];
|
|
893
938
|
const warnings = [];
|
|
894
|
-
const protectedMessageIds = input.protectedMessageIds ?? computeProtectedRefs(input.messages, input.state, input.config);
|
|
939
|
+
const protectedMessageIds = input.protectedMessageIds ?? computeProtectedRefs(input.messages, input.state, input.config, countTokens);
|
|
895
940
|
const preExistingCoverage = collectCoverage(state);
|
|
896
941
|
const rangeIndexSets = [];
|
|
897
942
|
for (const spec of input.ranges) {
|
|
@@ -916,29 +961,25 @@ function createCore(ports = {}) {
|
|
|
916
961
|
const bMin = b.indices.length > 0 ? Math.min(...b.indices) : Infinity;
|
|
917
962
|
return aMin - bMin;
|
|
918
963
|
});
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
const
|
|
923
|
-
const
|
|
924
|
-
if (
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
errors: [
|
|
931
|
-
`content: range (${prev.spec.startRef}..${prev.spec.endRef}) overlaps (${curr.spec.startRef}..${curr.spec.endRef}). Overlapping ranges cannot be compressed in the same batch.`
|
|
932
|
-
],
|
|
933
|
-
warnings: []
|
|
934
|
-
}
|
|
935
|
-
};
|
|
964
|
+
const skipSpecs = /* @__PURE__ */ new Set();
|
|
965
|
+
let acceptedMaxIndex = -1;
|
|
966
|
+
for (const entry of sortedRanges) {
|
|
967
|
+
const entryMax = entry.indices.length > 0 ? Math.max(...entry.indices) : -1;
|
|
968
|
+
const entryMin = entry.indices.length > 0 ? Math.min(...entry.indices) : -1;
|
|
969
|
+
if (entryMin >= 0 && entryMin <= acceptedMaxIndex) {
|
|
970
|
+
skipSpecs.add(entry.spec);
|
|
971
|
+
warnings.push(
|
|
972
|
+
`Skipped range (${entry.spec.startRef}..${entry.spec.endRef}) \u2014 overlaps an earlier range in the batch; the earlier range takes precedence. Keep ranges disjoint.`
|
|
973
|
+
);
|
|
974
|
+
continue;
|
|
936
975
|
}
|
|
976
|
+
if (entryMax > acceptedMaxIndex) acceptedMaxIndex = entryMax;
|
|
937
977
|
}
|
|
938
978
|
if (input.config.compress.minCompressRange > 0 && input.ranges.length > 0) {
|
|
939
979
|
let totalRangeChars = 0;
|
|
940
980
|
let hasBlockBoundaryRange = false;
|
|
941
981
|
for (const spec of input.ranges) {
|
|
982
|
+
if (skipSpecs.has(spec)) continue;
|
|
942
983
|
let resolved;
|
|
943
984
|
try {
|
|
944
985
|
resolved = resolveBoundaries({
|
|
@@ -974,6 +1015,7 @@ function createCore(ports = {}) {
|
|
|
974
1015
|
}
|
|
975
1016
|
}
|
|
976
1017
|
for (const spec of input.ranges) {
|
|
1018
|
+
if (skipSpecs.has(spec)) continue;
|
|
977
1019
|
try {
|
|
978
1020
|
const outcome = applySingleRange({
|
|
979
1021
|
spec,
|
|
@@ -1114,13 +1156,15 @@ var recommendNode = {
|
|
|
1114
1156
|
const protectedRefs = computeProtectedRefs(
|
|
1115
1157
|
io.messages,
|
|
1116
1158
|
io.state,
|
|
1117
|
-
ctx.config
|
|
1159
|
+
ctx.config,
|
|
1160
|
+
ctx.countTokens
|
|
1118
1161
|
);
|
|
1119
1162
|
const contextRanges = buildCompressibleRanges(
|
|
1120
1163
|
io.messages,
|
|
1121
1164
|
io.state,
|
|
1122
1165
|
ctx.config,
|
|
1123
|
-
protectedRefs
|
|
1166
|
+
protectedRefs,
|
|
1167
|
+
ctx.countTokens
|
|
1124
1168
|
);
|
|
1125
1169
|
const nothingToCompress = contextRanges.compressible.length === 0;
|
|
1126
1170
|
const recommendation = {
|
|
@@ -1298,7 +1342,9 @@ function applySingleRange(input) {
|
|
|
1298
1342
|
survivedCount: 0,
|
|
1299
1343
|
generation: "young",
|
|
1300
1344
|
active: true,
|
|
1301
|
-
compressCallId: input.spec.compressCallId
|
|
1345
|
+
compressCallId: input.spec.compressCallId,
|
|
1346
|
+
startRef: input.spec.startRef,
|
|
1347
|
+
endRef: input.spec.endRef
|
|
1302
1348
|
};
|
|
1303
1349
|
input.state.blocks.push(block);
|
|
1304
1350
|
for (const consumedId of consumedBlockIds) {
|
|
@@ -1789,7 +1835,7 @@ function renderNudgeText(decision) {
|
|
|
1789
1835
|
breakdownStr,
|
|
1790
1836
|
"",
|
|
1791
1837
|
`[TIER ${decision.tier} ${isT2 ? "DISTILLATION" : "CONDENSATION"} TRIGGER]`,
|
|
1792
|
-
isT2 ? `Your tier-1 compression summaries have accumulated. Distill them into a single denser tier-2 summary. Use block IDs as boundaries.` : `Your tier-2 compression summaries have accumulated. Condense them further into a tier-3 ultra-condensed summary. Use block IDs as boundaries.`,
|
|
1838
|
+
isT2 ? `Your tier-1 compression summaries have accumulated. Distill them into a single denser tier-2 summary. Use block IDs as boundaries (startId and endId as bN). Any raw (uncompressed) messages sitting between the boundary blocks are absorbed into the tier-2 block as well \u2014 apply HOW TO COMPRESS to those raw messages and the TIER 2 distillation rules to the existing summaries, so the whole span is covered and nothing is lost.` : `Your tier-2 compression summaries have accumulated. Condense them further into a tier-3 ultra-condensed summary. Use block IDs as boundaries (startId and endId as bN). Any raw (uncompressed) messages sitting between the boundary blocks are absorbed into the tier-3 block as well \u2014 apply HOW TO COMPRESS to those raw messages and the TIER 3 condensation rules to the existing summaries, so the whole span is covered and nothing is lost.`,
|
|
1793
1839
|
blockList,
|
|
1794
1840
|
`Example: compress({ content: [{ startId: "${startId}", endId: "${endId}", summary: "..." }] })`,
|
|
1795
1841
|
"",
|
|
@@ -2608,10 +2654,11 @@ import * as path2 from "path";
|
|
|
2608
2654
|
import { appendFileSync, mkdirSync, statSync, renameSync, existsSync } from "fs";
|
|
2609
2655
|
import * as path from "path";
|
|
2610
2656
|
import { homedir } from "os";
|
|
2657
|
+
import { CONFIG_DIR_NAME } from "@earendil-works/pi-coding-agent";
|
|
2611
2658
|
var MAX_BYTES = 10 * 1024 * 1024;
|
|
2612
2659
|
var ENV_DEBUG = process.env.ACP_DEBUG === "1" || process.env.ACP_DEBUG === "true";
|
|
2613
2660
|
function resolveLogFile() {
|
|
2614
|
-
return process.env.ACP_LOG_FILE ?? path.join(homedir(),
|
|
2661
|
+
return process.env.ACP_LOG_FILE ?? path.join(homedir(), CONFIG_DIR_NAME, "acp.log");
|
|
2615
2662
|
}
|
|
2616
2663
|
var runtimeDebug = null;
|
|
2617
2664
|
function setDebugEnabled(enabled) {
|
|
@@ -8018,6 +8065,14 @@ var ASYNC_TIMEOUT_MS = 30 * 6e4;
|
|
|
8018
8065
|
var KILL_GRACE_MS = 1e4;
|
|
8019
8066
|
var RESULT_SUMMARY_CHARS = 500;
|
|
8020
8067
|
var OUT_DIR = join4(tmpdir2(), "acp-delegate");
|
|
8068
|
+
function delegateSpawnOptions(cwd, env) {
|
|
8069
|
+
return {
|
|
8070
|
+
cwd,
|
|
8071
|
+
env,
|
|
8072
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
8073
|
+
shell: false
|
|
8074
|
+
};
|
|
8075
|
+
}
|
|
8021
8076
|
var ACP_TOOLS = ["compress", "decompress", "search_context", "acp_status"];
|
|
8022
8077
|
var RESTRICTED_TOOLS = "read,bash,grep,find,ls";
|
|
8023
8078
|
var AGENTS = {
|
|
@@ -8064,6 +8119,69 @@ function runningRunsSnapshot() {
|
|
|
8064
8119
|
}
|
|
8065
8120
|
return out;
|
|
8066
8121
|
}
|
|
8122
|
+
function makeEventApplier(opts, writers) {
|
|
8123
|
+
let replyText = "";
|
|
8124
|
+
let msgWritten = 0;
|
|
8125
|
+
const lastToolText = /* @__PURE__ */ new Map();
|
|
8126
|
+
const thinking = new ThinkingCollector(opts.showThinking);
|
|
8127
|
+
const flushThinking = () => {
|
|
8128
|
+
const line = thinking.flush();
|
|
8129
|
+
if (line) writers.activity?.write(line);
|
|
8130
|
+
};
|
|
8131
|
+
const handleEventLine = (line) => {
|
|
8132
|
+
const ev = parseEventLine(line);
|
|
8133
|
+
if (!ev) return;
|
|
8134
|
+
if (ev.kind === "thinking-delta") {
|
|
8135
|
+
thinking.push(ev.delta);
|
|
8136
|
+
return;
|
|
8137
|
+
}
|
|
8138
|
+
if (ev.kind === "thinking-end") {
|
|
8139
|
+
flushThinking();
|
|
8140
|
+
return;
|
|
8141
|
+
}
|
|
8142
|
+
if (ev.kind === "reply-delta") {
|
|
8143
|
+
flushThinking();
|
|
8144
|
+
replyText += ev.delta;
|
|
8145
|
+
msgWritten += ev.delta.length;
|
|
8146
|
+
writers.reply.write(ev.delta);
|
|
8147
|
+
return;
|
|
8148
|
+
}
|
|
8149
|
+
if (ev.kind === "reply-complete") {
|
|
8150
|
+
flushThinking();
|
|
8151
|
+
const tail = ev.content.slice(msgWritten);
|
|
8152
|
+
if (tail) {
|
|
8153
|
+
writers.reply.write(tail);
|
|
8154
|
+
debug.event("reply-complete-tail", { tailLen: tail.length, contentLen: ev.content.length });
|
|
8155
|
+
}
|
|
8156
|
+
if (ev.content.length < msgWritten) {
|
|
8157
|
+
logWarn("delegate", { event: "reply-content-shorter-than-delta", contentLen: ev.content.length, written: msgWritten });
|
|
8158
|
+
}
|
|
8159
|
+
msgWritten = 0;
|
|
8160
|
+
replyText = ev.content;
|
|
8161
|
+
return;
|
|
8162
|
+
}
|
|
8163
|
+
if (ev.kind === "tool-update") {
|
|
8164
|
+
flushThinking();
|
|
8165
|
+
const prev = lastToolText.get(ev.toolCallId) ?? "";
|
|
8166
|
+
const add = newPortion(ev.text, prev);
|
|
8167
|
+
lastToolText.set(ev.toolCallId, ev.text);
|
|
8168
|
+
if (add) writers.activity?.write(add.endsWith("\n") ? add : `${add}
|
|
8169
|
+
`);
|
|
8170
|
+
return;
|
|
8171
|
+
}
|
|
8172
|
+
flushThinking();
|
|
8173
|
+
const lines = activityLines(ev, { showThinking: opts.showThinking });
|
|
8174
|
+
if (lines.length) writers.activity?.write(lines.join(""));
|
|
8175
|
+
};
|
|
8176
|
+
return {
|
|
8177
|
+
handleEventLine,
|
|
8178
|
+
getReplyText: () => replyText,
|
|
8179
|
+
appendRaw(text) {
|
|
8180
|
+
replyText += text;
|
|
8181
|
+
writers.reply.write(text);
|
|
8182
|
+
}
|
|
8183
|
+
};
|
|
8184
|
+
}
|
|
8067
8185
|
var WAIT_TIMEOUT_MS_DEFAULT = 1e4;
|
|
8068
8186
|
var WAIT_TIMEOUT_MS_MAX = 3e5;
|
|
8069
8187
|
var DelegateParams = typebox_exports.Object({
|
|
@@ -8295,12 +8413,11 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
8295
8413
|
const runId = `del_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8296
8414
|
debug.event("delegate-spawn", { agent: args.agent, runId, cwd, async: isAsync, useJsonStream, cliArgs });
|
|
8297
8415
|
logInfo("delegate", { event: "spawn", agent: args.agent, runId, cwd, async: isAsync, useJsonStream, mode: ctx.mode, parentDepth });
|
|
8298
|
-
const child = spawn(
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
});
|
|
8416
|
+
const child = spawn(
|
|
8417
|
+
process.execPath,
|
|
8418
|
+
[process.argv[1], ...cliArgs],
|
|
8419
|
+
delegateSpawnOptions(cwd, childEnv)
|
|
8420
|
+
);
|
|
8304
8421
|
child.stdin?.once("error", (e) => {
|
|
8305
8422
|
debug.event("delegate-stdin-error", { runId: "pre-spawn", error: String(e) });
|
|
8306
8423
|
logError("delegate", { event: "stdin-error", runId, error: String(e) });
|
|
@@ -8334,49 +8451,11 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
8334
8451
|
if (!s || s.destroyed || s.closed) return resolve2();
|
|
8335
8452
|
s.end(() => resolve2());
|
|
8336
8453
|
});
|
|
8337
|
-
let replyText = "";
|
|
8338
8454
|
let stdoutBuf = "";
|
|
8339
|
-
const
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
if (line) activityStream?.write(line);
|
|
8344
|
-
};
|
|
8345
|
-
const handleEventLine = (line) => {
|
|
8346
|
-
const ev = parseEventLine(line);
|
|
8347
|
-
if (!ev) return;
|
|
8348
|
-
if (ev.kind === "thinking-delta") {
|
|
8349
|
-
thinking.push(ev.delta);
|
|
8350
|
-
return;
|
|
8351
|
-
}
|
|
8352
|
-
if (ev.kind === "thinking-end") {
|
|
8353
|
-
flushThinking();
|
|
8354
|
-
return;
|
|
8355
|
-
}
|
|
8356
|
-
if (ev.kind === "reply-delta") {
|
|
8357
|
-
flushThinking();
|
|
8358
|
-
replyText += ev.delta;
|
|
8359
|
-
replyStream.write(ev.delta);
|
|
8360
|
-
return;
|
|
8361
|
-
}
|
|
8362
|
-
if (ev.kind === "reply-complete") {
|
|
8363
|
-
flushThinking();
|
|
8364
|
-
replyText = ev.content;
|
|
8365
|
-
return;
|
|
8366
|
-
}
|
|
8367
|
-
if (ev.kind === "tool-update") {
|
|
8368
|
-
flushThinking();
|
|
8369
|
-
const prev = lastToolText.get(ev.toolCallId) ?? "";
|
|
8370
|
-
const add = newPortion(ev.text, prev);
|
|
8371
|
-
lastToolText.set(ev.toolCallId, ev.text);
|
|
8372
|
-
if (add) activityStream?.write(add.endsWith("\n") ? add : `${add}
|
|
8373
|
-
`);
|
|
8374
|
-
return;
|
|
8375
|
-
}
|
|
8376
|
-
flushThinking();
|
|
8377
|
-
const lines = activityLines(ev, { showThinking: args.showThinking === true });
|
|
8378
|
-
if (lines.length) activityStream?.write(lines.join(""));
|
|
8379
|
-
};
|
|
8455
|
+
const applier = makeEventApplier(
|
|
8456
|
+
{ showThinking: args.showThinking === true },
|
|
8457
|
+
{ reply: replyStream, activity: activityStream }
|
|
8458
|
+
);
|
|
8380
8459
|
child.stdout?.on("data", (c) => {
|
|
8381
8460
|
watchdog.poke();
|
|
8382
8461
|
if (useJsonStream) {
|
|
@@ -8385,12 +8464,11 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
8385
8464
|
while ((nl = stdoutBuf.indexOf("\n")) >= 0) {
|
|
8386
8465
|
const line = stdoutBuf.slice(0, nl);
|
|
8387
8466
|
stdoutBuf = stdoutBuf.slice(nl + 1);
|
|
8388
|
-
handleEventLine(line);
|
|
8467
|
+
applier.handleEventLine(line);
|
|
8389
8468
|
}
|
|
8390
8469
|
} else {
|
|
8391
8470
|
const text = c.toString("utf8");
|
|
8392
|
-
|
|
8393
|
-
replyStream.write(text);
|
|
8471
|
+
applier.appendRaw(text);
|
|
8394
8472
|
}
|
|
8395
8473
|
});
|
|
8396
8474
|
child.stderr?.on("data", (c) => {
|
|
@@ -8415,7 +8493,7 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
8415
8493
|
void cleanupTmp(tmpDir);
|
|
8416
8494
|
await Promise.all([endStream(replyStream), endStream(activityStream)]);
|
|
8417
8495
|
run.exitCode = code;
|
|
8418
|
-
const output =
|
|
8496
|
+
const output = applier.getReplyText().trim();
|
|
8419
8497
|
const body2 = code === 0 ? output || "(no output)" : stderrText.trim() || output || "(no output)";
|
|
8420
8498
|
if (run.status === "cancelled") {
|
|
8421
8499
|
await Promise.all([rm(replyFile, { force: true }), rm(activityFile, { force: true })]);
|
|
@@ -8744,7 +8822,7 @@ async function statusReport(runtime, ctx) {
|
|
|
8744
8822
|
const activeBlocksList = state.blocks.filter((b) => b.active);
|
|
8745
8823
|
const totalBlocksList = state.blocks;
|
|
8746
8824
|
const lines = [];
|
|
8747
|
-
const versionStr = "0.1.
|
|
8825
|
+
const versionStr = "0.1.33" ? `billion-context-pi@${"0.1.33"}` : "";
|
|
8748
8826
|
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");
|
|
8749
8827
|
lines.push("\u2502 ACP Context Analysis \u2502");
|
|
8750
8828
|
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");
|
|
@@ -9006,11 +9084,12 @@ import { join as join5, dirname as dirname3 } from "path";
|
|
|
9006
9084
|
import { fileURLToPath } from "url";
|
|
9007
9085
|
import { execFile } from "child_process";
|
|
9008
9086
|
import { homedir as homedir3 } from "os";
|
|
9087
|
+
import { CONFIG_DIR_NAME as CONFIG_DIR_NAME2 } from "@earendil-works/pi-coding-agent";
|
|
9009
9088
|
var PACKAGE_NAME = "billion-context-pi";
|
|
9010
9089
|
var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
9011
9090
|
var SEMVER_RE = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/;
|
|
9012
9091
|
var CHECK_INTERVAL_MS = 3 * 60 * 1e3;
|
|
9013
|
-
var THROTTLE_FILE = join5(homedir3(),
|
|
9092
|
+
var THROTTLE_FILE = join5(homedir3(), CONFIG_DIR_NAME2, "agent", ".billion-context-pi-update-check");
|
|
9014
9093
|
var updateInFlight = false;
|
|
9015
9094
|
function parseVersion(v) {
|
|
9016
9095
|
return v.replace(/^v/, "").split(".").map((n) => parseInt(n, 10) || 0);
|
|
@@ -9110,7 +9189,7 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
9110
9189
|
const data = await res.json();
|
|
9111
9190
|
const latest = data.version;
|
|
9112
9191
|
if (!latest) return;
|
|
9113
|
-
const current = runtimeVersion ?? "0.1.
|
|
9192
|
+
const current = runtimeVersion ?? "0.1.33";
|
|
9114
9193
|
const hasUpdate = isNewer(latest, current);
|
|
9115
9194
|
debug.event("update-check", {
|
|
9116
9195
|
current,
|
|
@@ -9149,6 +9228,7 @@ import { readFile as readFile2, writeFile as writeFile4, stat, copyFile, rename
|
|
|
9149
9228
|
import { existsSync as existsSync2 } from "fs";
|
|
9150
9229
|
import { homedir as homedir4 } from "os";
|
|
9151
9230
|
import { join as join6 } from "path";
|
|
9231
|
+
import { CONFIG_DIR_NAME as CONFIG_DIR_NAME3 } from "@earendil-works/pi-coding-agent";
|
|
9152
9232
|
var ACP_TOOLS2 = ["compress", "decompress", "search_context", "acp_status"];
|
|
9153
9233
|
var BUILTIN_DEFAULT_TOOLS = {
|
|
9154
9234
|
advisor: ["read", "grep", "find", "ls", "bash", "intercom"],
|
|
@@ -9165,7 +9245,7 @@ function resolveAgentDir() {
|
|
|
9165
9245
|
const configured = process.env.PI_CODING_AGENT_DIR;
|
|
9166
9246
|
if (configured === "~") return homedir4();
|
|
9167
9247
|
if (configured?.startsWith("~/")) return join6(homedir4(), configured.slice(2));
|
|
9168
|
-
return configured || join6(homedir4(),
|
|
9248
|
+
return configured || join6(homedir4(), CONFIG_DIR_NAME3, "agent");
|
|
9169
9249
|
}
|
|
9170
9250
|
function desiredTools(existing, name) {
|
|
9171
9251
|
const base = Array.isArray(existing?.tools) && existing.tools.length > 0 ? [...existing.tools] : [...BUILTIN_DEFAULT_TOOLS[name] ?? []];
|
|
@@ -9277,11 +9357,11 @@ async function runSetupAndNotify(notify) {
|
|
|
9277
9357
|
import { promises as fs2 } from "fs";
|
|
9278
9358
|
import * as path3 from "path";
|
|
9279
9359
|
import { homedir as homedir5 } from "os";
|
|
9280
|
-
import { CONFIG_DIR_NAME } from "@earendil-works/pi-coding-agent";
|
|
9360
|
+
import { CONFIG_DIR_NAME as CONFIG_DIR_NAME4 } from "@earendil-works/pi-coding-agent";
|
|
9281
9361
|
async function loadUserConfig(cwd) {
|
|
9282
9362
|
const home = homedir5();
|
|
9283
9363
|
const merged = {};
|
|
9284
|
-
for (const base of [join8(home,
|
|
9364
|
+
for (const base of [join8(home, CONFIG_DIR_NAME4), join8(cwd, CONFIG_DIR_NAME4)]) {
|
|
9285
9365
|
const file = join8(base, "acp.json");
|
|
9286
9366
|
try {
|
|
9287
9367
|
const raw = await fs2.readFile(file, "utf8");
|
|
@@ -9349,7 +9429,7 @@ function wireSessionLifecycle(pi, runtime) {
|
|
|
9349
9429
|
runtime.store.invalidate();
|
|
9350
9430
|
runtime.clearNudgeTracking();
|
|
9351
9431
|
const sid = ctx.sessionManager.getSessionId();
|
|
9352
|
-
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.
|
|
9432
|
+
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.33" : null });
|
|
9353
9433
|
try {
|
|
9354
9434
|
const user = await loadUserConfig(ctx.cwd);
|
|
9355
9435
|
runtime.setAdapter(applyUserConfig(runtime.adapter, user));
|