billion-context-pi 0.1.53 → 0.1.54-pr.264.52
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 +10 -2
- package/dist/index.js +147 -57
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/delegate-tool.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare function delegateSpawnOptions(cwd: string, env: NodeJS.ProcessEnv
|
|
|
8
8
|
* run the SDK inside another node process, so probe instead. Non-pi hosts
|
|
9
9
|
* (omp) keep argv[1] untouched. */
|
|
10
10
|
export declare function resolvePiCliEntry(argv1: string, env?: NodeJS.ProcessEnv, piHost?: boolean): string;
|
|
11
|
-
type RunStatus = "running" | "completed" | "failed" | "cancelled";
|
|
11
|
+
export type RunStatus = "running" | "completed" | "failed" | "cancelled";
|
|
12
12
|
interface DelegateRun {
|
|
13
13
|
runId: string;
|
|
14
14
|
agent: string;
|
|
@@ -104,6 +104,7 @@ declare const WaitParams: Type.TObject<{
|
|
|
104
104
|
}>;
|
|
105
105
|
export declare function accumulateUsage(a: Usage | undefined, b: Usage): Usage;
|
|
106
106
|
export declare function makeDelegateTool(pi: ExtensionAPI): ToolDefinition<typeof DelegateParams>;
|
|
107
|
+
export declare function formatRunResult(run: DelegateRun): string;
|
|
107
108
|
/** Runs that reached a terminal state but whose result never reached the
|
|
108
109
|
* model: no parked waiter, not consumed by a tool result, and never injected
|
|
109
110
|
* as a notification. The model was promised a notification ("do NOT keep
|
|
@@ -163,5 +164,12 @@ export declare function buildChildArgs(args: DelegateArgs, rolePrompt: string, c
|
|
|
163
164
|
isAsync: boolean;
|
|
164
165
|
useJsonStream: boolean;
|
|
165
166
|
}>;
|
|
166
|
-
|
|
167
|
+
/** Watchdog/EOF finalize arrives with code === null (the child was killed or
|
|
168
|
+
* never exited). If a result was delivered (non-empty reply or stderr), the
|
|
169
|
+
* run counts as completed (0); otherwise it stays null = genuine failure. */
|
|
170
|
+
export declare function effectiveExitCode(code: number | null, output: string, stderr: string): number | null;
|
|
171
|
+
/** status (set by finalize from the effective exit code) is the authority for
|
|
172
|
+
* the FAILED/completed decision; the raw code is diagnostic display only
|
|
173
|
+
* ("exit ?"), so the notification can never disagree with run.status. */
|
|
174
|
+
export declare function injectResult(pi: ExtensionAPI, agent: string, runId: string, task: string, status: RunStatus, code: number | null, file: string, timedOut?: string, usage?: Usage, mode?: "merged" | "separate", usageAlreadyReported?: boolean, body?: string): boolean;
|
|
167
175
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -424,18 +424,42 @@ function assignRefs(messages, options) {
|
|
|
424
424
|
return { map, nextIndex: cursor, newlyAssigned };
|
|
425
425
|
}
|
|
426
426
|
function allocateFreeRef(map, start) {
|
|
427
|
-
|
|
428
|
-
|
|
427
|
+
const from = Math.max(start, MIN_INDEX);
|
|
428
|
+
for (let candidate = from; candidate <= MAX_INDEX; candidate++) {
|
|
429
|
+
const text = indexToRef(candidate);
|
|
430
|
+
if (!map.byRef[text]) {
|
|
431
|
+
return { text, index: candidate };
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
for (let candidate = MIN_INDEX; candidate < from; candidate++) {
|
|
429
435
|
const text = indexToRef(candidate);
|
|
430
436
|
if (!map.byRef[text]) {
|
|
431
437
|
return { text, index: candidate };
|
|
432
438
|
}
|
|
433
|
-
candidate++;
|
|
434
439
|
}
|
|
435
440
|
throw new Error(
|
|
436
|
-
`ref capacity exhausted:
|
|
441
|
+
`ref capacity exhausted: all ${MAX_INDEX} ref slots are occupied by live messages \u2014 nothing left to reclaim`
|
|
437
442
|
);
|
|
438
443
|
}
|
|
444
|
+
function pruneDeadRefs(map, liveIds) {
|
|
445
|
+
let pruned = 0;
|
|
446
|
+
const byRaw = {};
|
|
447
|
+
for (const [rawId, ref] of Object.entries(map.byRaw)) {
|
|
448
|
+
if (liveIds.has(rawId)) {
|
|
449
|
+
byRaw[rawId] = ref;
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
pruned++;
|
|
453
|
+
}
|
|
454
|
+
return { map: rebuildRefIndex({ byRaw, byRef: {} }), pruned };
|
|
455
|
+
}
|
|
456
|
+
function rebuildRefIndex(map) {
|
|
457
|
+
const byRef = {};
|
|
458
|
+
for (const [rawId, ref] of Object.entries(map.byRaw)) {
|
|
459
|
+
if (ref !== BLOCKED_REF) byRef[ref] = rawId;
|
|
460
|
+
}
|
|
461
|
+
return { byRaw: { ...map.byRaw }, byRef };
|
|
462
|
+
}
|
|
439
463
|
function highestUsedIndex(map) {
|
|
440
464
|
let highest = 0;
|
|
441
465
|
for (const ref of Object.values(map.byRaw)) {
|
|
@@ -634,6 +658,13 @@ function syncBlocks(messages, state) {
|
|
|
634
658
|
deactivated.push(block.blockId);
|
|
635
659
|
}
|
|
636
660
|
}
|
|
661
|
+
const liveIds = new Set(presentIds);
|
|
662
|
+
for (const block of result.blocks) {
|
|
663
|
+
if (!block.active) continue;
|
|
664
|
+
for (const id of block.effectiveMessageIds) liveIds.add(id);
|
|
665
|
+
}
|
|
666
|
+
const prunedRefs = pruneDeadRefs(result.messageRefs, liveIds);
|
|
667
|
+
result.messageRefs = prunedRefs.map;
|
|
637
668
|
return { state: result, deactivated };
|
|
638
669
|
}
|
|
639
670
|
function defaultConfig(modelContextLimit, overrides = {}) {
|
|
@@ -744,12 +775,14 @@ var BoundaryNotFoundError = class extends Error {
|
|
|
744
775
|
code = "BOUNDARY_NOT_FOUND";
|
|
745
776
|
kind;
|
|
746
777
|
endpoint;
|
|
747
|
-
|
|
778
|
+
reason;
|
|
779
|
+
constructor(kind, endpoint, message, reason = null) {
|
|
748
780
|
super(message);
|
|
749
781
|
this.name = "BoundaryNotFoundError";
|
|
750
782
|
this.code = "BOUNDARY_NOT_FOUND";
|
|
751
783
|
this.kind = kind;
|
|
752
784
|
this.endpoint = endpoint;
|
|
785
|
+
this.reason = reason;
|
|
753
786
|
}
|
|
754
787
|
};
|
|
755
788
|
function resolveBoundaries(input) {
|
|
@@ -820,7 +853,7 @@ function resolveAnchorIndex(boundary, state, indexByMessageId, endpoint) {
|
|
|
820
853
|
throw new BoundaryNotFoundError(
|
|
821
854
|
"unknown",
|
|
822
855
|
endpoint,
|
|
823
|
-
`${label}="${boundary.raw}" does not exist in this session (typo or
|
|
856
|
+
`${label}="${boundary.raw}" does not exist in this session (typo, wrong session, or the message was edited/removed and its ref released) \u2014 run acp_status for current refs.`
|
|
824
857
|
);
|
|
825
858
|
}
|
|
826
859
|
const index = indexByMessageId.get(rawId);
|
|
@@ -834,10 +867,33 @@ function resolveAnchorIndex(boundary, state, indexByMessageId, endpoint) {
|
|
|
834
867
|
snapped: `${label}="${boundary.raw}" refers to a message already compressed into an active block \u2014 anchored to the active block covering it instead.`
|
|
835
868
|
};
|
|
836
869
|
}
|
|
870
|
+
const coveringActive = state.blocks.filter(
|
|
871
|
+
(block2) => block2.active && block2.effectiveMessageIds.includes(rawId)
|
|
872
|
+
);
|
|
873
|
+
if (coveringActive.length > 0) {
|
|
874
|
+
throw new BoundaryNotFoundError(
|
|
875
|
+
"consumed",
|
|
876
|
+
endpoint,
|
|
877
|
+
`${label}="${boundary.raw}" is already compressed into active block(s) ${coveringActive.map((block2) => block2.blockId).join(", ")} \u2014 retry with the block ref(s) instead of the message ref.`,
|
|
878
|
+
"consumed"
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
const generationReplaced = state.blocks.some(
|
|
882
|
+
(block2) => !block2.active && block2.effectiveMessageIds.includes(rawId)
|
|
883
|
+
);
|
|
884
|
+
if (generationReplaced) {
|
|
885
|
+
throw new BoundaryNotFoundError(
|
|
886
|
+
"consumed",
|
|
887
|
+
endpoint,
|
|
888
|
+
`${label}="${boundary.raw}" was compressed into a block that has since been distilled or consumed \u2014 its content is no longer available in this session; run acp_status for current refs.`,
|
|
889
|
+
"generation-replaced"
|
|
890
|
+
);
|
|
891
|
+
}
|
|
837
892
|
throw new BoundaryNotFoundError(
|
|
838
893
|
"consumed",
|
|
839
894
|
endpoint,
|
|
840
|
-
`${label}="${boundary.raw}"
|
|
895
|
+
`${label}="${boundary.raw}" no longer exists \u2014 the message was edited or removed (its content id changed); run acp_status for current refs.`,
|
|
896
|
+
"edit-drift"
|
|
841
897
|
);
|
|
842
898
|
}
|
|
843
899
|
const block = blockById(state, `b${boundary.numericId}`);
|
|
@@ -866,16 +922,21 @@ function resolveAnchorIndex(boundary, state, indexByMessageId, endpoint) {
|
|
|
866
922
|
};
|
|
867
923
|
}
|
|
868
924
|
if (!block.active) {
|
|
925
|
+
const consumer = state.blocks.find(
|
|
926
|
+
(candidate) => candidate.active && candidate.directBlockIds.includes(block.blockId) && visibleBlockAnchor(candidate, indexByMessageId) !== null
|
|
927
|
+
);
|
|
869
928
|
throw new BoundaryNotFoundError(
|
|
870
929
|
"consumed",
|
|
871
930
|
endpoint,
|
|
872
|
-
`${label}="b${boundary.numericId}"
|
|
931
|
+
consumer ? `${label}="b${boundary.numericId}" was consumed by ${consumer.blockId} (higher-tier block) \u2014 retry with ${consumer.blockId} instead.` : `${label}="b${boundary.numericId}" is inactive (distilled or garbage-collected) and none of its content is visible in the current context \u2014 run acp_status for current refs.`,
|
|
932
|
+
"generation-replaced"
|
|
873
933
|
);
|
|
874
934
|
}
|
|
875
935
|
throw new BoundaryNotFoundError(
|
|
876
936
|
"consumed",
|
|
877
937
|
endpoint,
|
|
878
|
-
`${label}="b${boundary.numericId}" is an active block but none of its content (raw messages or rendered summary) is
|
|
938
|
+
`${label}="b${boundary.numericId}" is an active block but none of its content (raw messages or rendered summary) is present in the current view \u2014 its messages were likely edited or removed (id drift); it will be deactivated on the next state sync. Run acp_status to verify.`,
|
|
939
|
+
"edit-drift"
|
|
879
940
|
);
|
|
880
941
|
}
|
|
881
942
|
function activeOwnerAnchor(state, ownedIds, indexByMessageId) {
|
|
@@ -1800,10 +1861,33 @@ function numericBlockId(id) {
|
|
|
1800
1861
|
const parsed = /^b(\d+)$/.exec(id);
|
|
1801
1862
|
return parsed ? Number(parsed[1]) : 0;
|
|
1802
1863
|
}
|
|
1864
|
+
function refGateDiagnostics(state, requestedRanges, unknownCount) {
|
|
1865
|
+
const highest = highestUsedIndex(state.messageRefs);
|
|
1866
|
+
const highestRef = highest > 0 ? indexToRef(highest) : "none";
|
|
1867
|
+
return `[diagnostics: session highest ref=${highestRef}, unknown ranges in request=${unknownCount}/${requestedRanges}, session history=${state.stats.compressionCount} compression(s), ${state.blocks.length} block(s)]`;
|
|
1868
|
+
}
|
|
1869
|
+
function danglingMessageRefs(state, messages, spec) {
|
|
1870
|
+
const visible = new Set(messages.map((m) => m.id));
|
|
1871
|
+
const dangling = [];
|
|
1872
|
+
for (const ref of [spec.startRef, spec.endRef]) {
|
|
1873
|
+
const parsed = parseBoundary(ref);
|
|
1874
|
+
if (!parsed || parsed.kind !== "message") continue;
|
|
1875
|
+
const rawId = state.messageRefs.byRef[parsed.raw] ?? state.messageRefs.byRef[indexToRef(parsed.numericId)];
|
|
1876
|
+
if (!rawId || visible.has(rawId)) continue;
|
|
1877
|
+
const covered = state.blocks.some(
|
|
1878
|
+
(block) => block.active && block.effectiveMessageIds.includes(rawId)
|
|
1879
|
+
);
|
|
1880
|
+
if (!covered) dangling.push(parsed.raw);
|
|
1881
|
+
}
|
|
1882
|
+
return dangling;
|
|
1883
|
+
}
|
|
1803
1884
|
function createCore(ports = {}) {
|
|
1804
1885
|
const countTokens = ports.countTokens ?? defaultCountTokens;
|
|
1805
1886
|
function applyCompression(input) {
|
|
1806
|
-
const state =
|
|
1887
|
+
const state = syncBlocks(
|
|
1888
|
+
input.messages,
|
|
1889
|
+
input.state
|
|
1890
|
+
).state;
|
|
1807
1891
|
const runId = allocateRunId(state);
|
|
1808
1892
|
let blocksCreated = 0;
|
|
1809
1893
|
let tokensCompressed = 0;
|
|
@@ -1900,7 +1984,15 @@ function createCore(ports = {}) {
|
|
|
1900
1984
|
if (!hasBlockBoundaryRange && totalRangeChars < input.config.compress.minCompressRange) {
|
|
1901
1985
|
const live = activeBlocks(state).map((b) => b.blockId).sort((x, y) => numericBlockId(x) - numericBlockId(y));
|
|
1902
1986
|
const liveHint = live.length > 0 ? ` Current active blocks span ${live[0]}..${live[live.length - 1]} \u2014 retry with startId/endId set to active block IDs in that span.` : "";
|
|
1903
|
-
const
|
|
1987
|
+
const diagnostics = refGateDiagnostics(
|
|
1988
|
+
state,
|
|
1989
|
+
input.ranges.length,
|
|
1990
|
+
unknownCount
|
|
1991
|
+
);
|
|
1992
|
+
const danglingRefs = consumedRanges.flatMap(
|
|
1993
|
+
(spec) => danglingMessageRefs(state, input.messages, spec)
|
|
1994
|
+
);
|
|
1995
|
+
const gateMessage = resolvableCount === 0 && consumedRanges.length === 0 && unknownCount > 0 ? `None of the ${input.ranges.length} requested range(s) resolved \u2014 every ref is unknown to this session. Refs are per-session snapshots, assigned once when a message is first rendered; no compress reassigns them, so unknown refs cannot come from an earlier compress in this session. They come from a different generation: a previous session instance (switching model or upstream mid-conversation starts a fresh session whose refs restart at m00001), the generation before a native-compaction rebase (which also resets refs to m00001), a typo, or a message that was edited or removed (its old ref was released when the content id changed). ${diagnostics} Run acp_status, then call the compress tool again using only the refs it reports.` : consumedRanges.length > 0 ? danglingRefs.length > 0 ? `Requested range(s) cannot be anchored (e.g. ${consumedRanges[0].startRef}..${consumedRanges[0].endRef}) \u2014 the refs exist in this session's ref map, but the messages they point to are no longer in the visible context and no active block covers them: the message content changed (or the message was filtered out of the view) and now carries a new ref, leaving your old refs dangling. ${diagnostics} Run acp_status, then call the compress tool again using only the refs it reports.` : `Requested range(s) already compressed (e.g. ${consumedRanges[0].startRef}..${consumedRanges[0].endRef}) \u2014 those refs no longer point to directly compressible content: the range is covered by active block(s) or the block ref(s) are stale (distilled or consumed). ${diagnostics} Run acp_status, then call the compress tool again using only the CURRENT compressible ranges it reports.${liveHint}` : `Total compressible content too small (${totalRangeChars} chars across ${countedRanges} range(s), min ${input.config.compress.minCompressRange}). Combine more messages into your range(s) to meet the threshold.`;
|
|
1904
1996
|
return {
|
|
1905
1997
|
state: input.state,
|
|
1906
1998
|
result: {
|
|
@@ -2043,9 +2135,15 @@ var assignRefsNode = {
|
|
|
2043
2135
|
run(io, ctx) {
|
|
2044
2136
|
const hasProtection = ctx.config.protectedTools.length > 0 || !!ctx.config.isToolProtected;
|
|
2045
2137
|
const protectedFn = hasProtection ? (m) => isMessageProtected(m, ctx.config) : void 0;
|
|
2138
|
+
const liveIds = new Set(io.messages.map((m) => m.id));
|
|
2139
|
+
for (const block of io.state.blocks) {
|
|
2140
|
+
if (!block.active) continue;
|
|
2141
|
+
for (const id of block.effectiveMessageIds) liveIds.add(id);
|
|
2142
|
+
}
|
|
2143
|
+
const pruned = pruneDeadRefs(io.state.messageRefs, liveIds);
|
|
2046
2144
|
const refResult = assignRefs(io.messages, {
|
|
2047
|
-
existing:
|
|
2048
|
-
nextIndex: highestUsedIndex(
|
|
2145
|
+
existing: pruned.map,
|
|
2146
|
+
nextIndex: highestUsedIndex(pruned.map) + 1,
|
|
2049
2147
|
isProtected: protectedFn
|
|
2050
2148
|
});
|
|
2051
2149
|
return { ...io, state: { ...io.state, messageRefs: refResult.map } };
|
|
@@ -2617,26 +2715,6 @@ function computeContextBreakdown(messages, total, growth, countTokens) {
|
|
|
2617
2715
|
}
|
|
2618
2716
|
return { system, tool, summaries, code, text, total, growth };
|
|
2619
2717
|
}
|
|
2620
|
-
function cloneState(state) {
|
|
2621
|
-
return {
|
|
2622
|
-
blocks: state.blocks.map((block) => ({
|
|
2623
|
-
...block,
|
|
2624
|
-
directMessageIds: [...block.directMessageIds],
|
|
2625
|
-
effectiveMessageIds: [...block.effectiveMessageIds],
|
|
2626
|
-
directBlockIds: [...block.directBlockIds]
|
|
2627
|
-
})),
|
|
2628
|
-
messageRefs: {
|
|
2629
|
-
byRaw: { ...state.messageRefs.byRaw },
|
|
2630
|
-
byRef: { ...state.messageRefs.byRef }
|
|
2631
|
-
},
|
|
2632
|
-
tokenSnapshot: { ...state.tokenSnapshot ?? {} },
|
|
2633
|
-
nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },
|
|
2634
|
-
stats: { ...state.stats },
|
|
2635
|
-
absorbed: (state.absorbed ?? []).map((record) => ({ ...record })),
|
|
2636
|
-
nextBlockId: state.nextBlockId,
|
|
2637
|
-
nextRunId: state.nextRunId
|
|
2638
|
-
};
|
|
2639
|
-
}
|
|
2640
2718
|
function scoreRelevance(block, terms) {
|
|
2641
2719
|
const topic = (block.topic ?? "").toLowerCase();
|
|
2642
2720
|
const summary = block.summary.toLowerCase();
|
|
@@ -2967,9 +3045,9 @@ function parseObjectValue(value, callId, diag) {
|
|
|
2967
3045
|
const content = value["content"];
|
|
2968
3046
|
if (content === void 0) {
|
|
2969
3047
|
const single = validateEntry(value, callId);
|
|
2970
|
-
if (single) {
|
|
3048
|
+
if ("range" in single) {
|
|
2971
3049
|
diag.kind = "ok";
|
|
2972
|
-
return finish([single], diag);
|
|
3050
|
+
return finish([single.range], diag);
|
|
2973
3051
|
}
|
|
2974
3052
|
diag.kind = "missing-content";
|
|
2975
3053
|
return finish([], diag);
|
|
@@ -2990,7 +3068,7 @@ function parseObjectValue(value, callId, diag) {
|
|
|
2990
3068
|
diag.kind = "content-not-array";
|
|
2991
3069
|
return finish([], diag);
|
|
2992
3070
|
}
|
|
2993
|
-
const { ranges, invalid } = validateEntries(entries, callId);
|
|
3071
|
+
const { ranges, invalid, reasons } = validateEntries(entries, callId);
|
|
2994
3072
|
const topTopic = stringOr(value["topic"]);
|
|
2995
3073
|
const topMaxChars = value["summaryMaxChars"];
|
|
2996
3074
|
const hasTopMaxChars = typeof topMaxChars === "number" && Number.isFinite(topMaxChars);
|
|
@@ -3001,6 +3079,7 @@ function parseObjectValue(value, callId, diag) {
|
|
|
3001
3079
|
}
|
|
3002
3080
|
}
|
|
3003
3081
|
diag.invalidItems = invalid;
|
|
3082
|
+
if (reasons.length > 0) diag.invalidReasons = reasons;
|
|
3004
3083
|
diag.kind = salvaged ? "truncated" : ranges.length > 0 ? "ok" : "no-valid-ranges";
|
|
3005
3084
|
return finish(ranges, diag);
|
|
3006
3085
|
}
|
|
@@ -3024,36 +3103,43 @@ function finish(ranges, diag) {
|
|
|
3024
3103
|
return { ranges, diagnostics: diag };
|
|
3025
3104
|
}
|
|
3026
3105
|
function finishSalvage(entries, callId, diag, truncatedShape) {
|
|
3027
|
-
const { ranges, invalid } = validateEntries(entries, callId);
|
|
3106
|
+
const { ranges, invalid, reasons } = validateEntries(entries, callId);
|
|
3028
3107
|
diag.invalidItems = invalid;
|
|
3108
|
+
if (reasons.length > 0) diag.invalidReasons = reasons;
|
|
3029
3109
|
diag.kind = entries.length > 0 || truncatedShape ? "truncated" : "malformed-json";
|
|
3030
3110
|
return finish(ranges, diag);
|
|
3031
3111
|
}
|
|
3032
3112
|
function validateEntries(entries, callId) {
|
|
3033
3113
|
const ranges = [];
|
|
3114
|
+
const reasons = [];
|
|
3034
3115
|
let invalid = 0;
|
|
3035
|
-
for (
|
|
3036
|
-
const
|
|
3037
|
-
if (range
|
|
3038
|
-
else
|
|
3116
|
+
for (let i = 0; i < entries.length; i++) {
|
|
3117
|
+
const outcome = validateEntry(entries[i], callId);
|
|
3118
|
+
if ("range" in outcome) ranges.push(outcome.range);
|
|
3119
|
+
else {
|
|
3120
|
+
invalid++;
|
|
3121
|
+
reasons.push(`entry ${i}: ${outcome.reason}`);
|
|
3122
|
+
}
|
|
3039
3123
|
}
|
|
3040
|
-
return { ranges, invalid };
|
|
3124
|
+
return { ranges, invalid, reasons };
|
|
3041
3125
|
}
|
|
3042
3126
|
function validateEntry(entry, callId) {
|
|
3043
|
-
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return
|
|
3127
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return { reason: "not an object" };
|
|
3044
3128
|
const e = entry;
|
|
3045
3129
|
const start = stringOr(e["startRef"]) ?? stringOr(e["startId"]) ?? stringOr(e["messageId"]);
|
|
3046
3130
|
const end = stringOr(e["endRef"]) ?? stringOr(e["endId"]) ?? stringOr(e["messageId"]);
|
|
3047
|
-
if (start === void 0 || end === void 0)
|
|
3131
|
+
if (start === void 0 || end === void 0) {
|
|
3132
|
+
return { reason: "missing range bounds (need startRef/startId and endRef/endId)" };
|
|
3133
|
+
}
|
|
3048
3134
|
const summary = stringOr(e["summary"]);
|
|
3049
|
-
if (summary === void 0) return
|
|
3135
|
+
if (summary === void 0) return { reason: "missing summary" };
|
|
3050
3136
|
const range = { startRef: start, endRef: end, summary };
|
|
3051
3137
|
const topic = stringOr(e["topic"]);
|
|
3052
3138
|
if (topic !== void 0) range.topic = topic;
|
|
3053
3139
|
const maxChars = e["summaryMaxChars"];
|
|
3054
3140
|
if (typeof maxChars === "number" && Number.isFinite(maxChars)) range.summaryMaxChars = maxChars;
|
|
3055
3141
|
if (callId !== void 0) range.compressCallId = callId;
|
|
3056
|
-
return range;
|
|
3142
|
+
return { range };
|
|
3057
3143
|
}
|
|
3058
3144
|
function stringOr(value) {
|
|
3059
3145
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
@@ -10691,7 +10777,7 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
10691
10777
|
await appendFile(file2, fallback ? `${fallback}
|
|
10692
10778
|
` : "(no output)\n");
|
|
10693
10779
|
}
|
|
10694
|
-
const effectiveCode = code
|
|
10780
|
+
const effectiveCode = effectiveExitCode(code, output, stderrText);
|
|
10695
10781
|
run.result = { code, file: file2, body: body2 };
|
|
10696
10782
|
run.status = effectiveCode === 0 ? "completed" : "failed";
|
|
10697
10783
|
run.finishedAt = Date.now();
|
|
@@ -10709,7 +10795,7 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
10709
10795
|
return;
|
|
10710
10796
|
}
|
|
10711
10797
|
const mode = delegateDisplayUsage;
|
|
10712
|
-
const injected = injectResult(pi, args.agent, runId, args.task, code, file2, run.timedOut, run.usage, mode, run.usageReported, run.status === "failed" ? body2 : void 0);
|
|
10798
|
+
const injected = injectResult(pi, args.agent, runId, args.task, run.status, code, file2, run.timedOut, run.usage, mode, run.usageReported, run.status === "failed" ? body2 : void 0);
|
|
10713
10799
|
if (run.usage && !run.usageReported && (mode === "separate" || injected)) {
|
|
10714
10800
|
run.usageReported = true;
|
|
10715
10801
|
}
|
|
@@ -10834,15 +10920,18 @@ function formatSyncResult(agent, runId, task, r, file) {
|
|
|
10834
10920
|
const body = r.timedOut ? "(timed out)" : r.stderr.trim() || "(no stderr)";
|
|
10835
10921
|
return formatPayload(header, file, task, body);
|
|
10836
10922
|
}
|
|
10837
|
-
function
|
|
10923
|
+
function effectiveExitCode(code, output, stderr) {
|
|
10924
|
+
return code ?? (output || stderr ? 0 : null);
|
|
10925
|
+
}
|
|
10926
|
+
function injectResult(pi, agent, runId, task, status, code, file, timedOut, usage, mode = "separate", usageAlreadyReported, body) {
|
|
10838
10927
|
const send = pi.sendUserMessage;
|
|
10839
10928
|
if (typeof send !== "function") {
|
|
10840
10929
|
debug.event("delegate-inject-skipped", { runId, reason: "sendUserMessage unavailable" });
|
|
10841
10930
|
logWarn("delegate", { event: "inject-skipped", runId, reason: "sendUserMessage unavailable" });
|
|
10842
10931
|
return false;
|
|
10843
10932
|
}
|
|
10844
|
-
const failed =
|
|
10845
|
-
const
|
|
10933
|
+
const failed = status === "failed";
|
|
10934
|
+
const statusLabel = failed ? "FAILED \u26A0\uFE0F" : "completed";
|
|
10846
10935
|
const remaining = Array.from(runs.values()).filter((r) => r.status === "running").length;
|
|
10847
10936
|
const remainingLine = remaining > 0 ? ` ${remaining} delegate${remaining === 1 ? " is" : "s are"} still running; keep doing other work and their notifications will arrive as they finish.` : " No delegates are currently running.";
|
|
10848
10937
|
const timeoutNote = timedOut ? ` (timed out: ${timedOut})` : "";
|
|
@@ -10877,7 +10966,7 @@ Tokens: ${totalUsage.input.toLocaleString()} in, ${totalUsage.output.toLocaleStr
|
|
|
10877
10966
|
if (lines.length) usageNote = ` Usage: ${lines.join(", ")}.`;
|
|
10878
10967
|
}
|
|
10879
10968
|
const closing = failed ? "This delegate did NOT complete its task \u2014 its result is missing from your work. Read the error excerpt (and the result file if present), then decide whether to re-dispatch the task before wrapping up. This is an automated system notification, NOT a user message." : "This is an automated system notification, NOT a user message. Read the result file if you need the details, then continue your original task; do not treat this as a new user request.";
|
|
10880
|
-
const header = `[acp_delegate ${
|
|
10969
|
+
const header = `[acp_delegate ${statusLabel}] **${agent}** (runId \`${runId}\`, exit ${code ?? "?"})${timeoutNote}${remainingLine}${usageNote} ${closing}`;
|
|
10881
10970
|
const { text: recoveryText, covered } = buildRecoveryNotice(Array.from(runs.values()), runId);
|
|
10882
10971
|
const text = formatPayload(header, file, task, failed ? body : void 0) + (recoveryText ? `
|
|
10883
10972
|
|
|
@@ -10902,6 +10991,7 @@ function notifyTerminalFailure(pi, run, body) {
|
|
|
10902
10991
|
run.agent,
|
|
10903
10992
|
run.runId,
|
|
10904
10993
|
run.task,
|
|
10994
|
+
run.status,
|
|
10905
10995
|
run.result?.code ?? null,
|
|
10906
10996
|
run.result?.file ?? "",
|
|
10907
10997
|
run.timedOut,
|
|
@@ -11503,7 +11593,7 @@ async function statusReport(runtime, ctx) {
|
|
|
11503
11593
|
const coveredIds = collectCoveredMessageIds(state);
|
|
11504
11594
|
const sentTokens = estimateTokens(coreMessages, coveredIds, imageTokens) + systemPromptTokens;
|
|
11505
11595
|
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount: anchorStale ? sentTokens : Math.max(sentTokens, realUsage?.tokens ?? 0) });
|
|
11506
|
-
const versionStr = "0.1.
|
|
11596
|
+
const versionStr = "0.1.54" ? `billion-context-pi@${"0.1.54"}` : void 0;
|
|
11507
11597
|
let text = buildStatusPanel({
|
|
11508
11598
|
version: versionStr,
|
|
11509
11599
|
tokenCount: sessionTokens,
|
|
@@ -11866,7 +11956,7 @@ async function autoInstallLatest(latest, extDirOverride) {
|
|
|
11866
11956
|
"--no-fund",
|
|
11867
11957
|
"--no-save"
|
|
11868
11958
|
];
|
|
11869
|
-
const prevVersion = (await readPackageJson(join8(extDir, "package.json")))?.version ?? "0.1.
|
|
11959
|
+
const prevVersion = (await readPackageJson(join8(extDir, "package.json")))?.version ?? "0.1.54";
|
|
11870
11960
|
const { code, stderr } = await runNpmImpl(installArgs(latest), { cwd: npmDir, timeout: 6e4 });
|
|
11871
11961
|
if (code !== 0) {
|
|
11872
11962
|
logWarn("update", {
|
|
@@ -11879,7 +11969,7 @@ async function autoInstallLatest(latest, extDirOverride) {
|
|
|
11879
11969
|
}
|
|
11880
11970
|
const verify = await verifyInstall(npmDir, latest);
|
|
11881
11971
|
if (!verify.ok) {
|
|
11882
|
-
const rollbackTo = SEMVER_RE.test(prevVersion) ? prevVersion : "0.1.
|
|
11972
|
+
const rollbackTo = SEMVER_RE.test(prevVersion) ? prevVersion : "0.1.54";
|
|
11883
11973
|
logWarn("update", { event: "auto-install-verify-failed", latest, reason: verify.reason, rollbackTo });
|
|
11884
11974
|
const rb = await runNpmImpl(installArgs(rollbackTo), { cwd: npmDir, timeout: 6e4 });
|
|
11885
11975
|
logInfo("update", { event: "rollback", from: latest, to: rollbackTo, ok: rb.code === 0 });
|
|
@@ -11940,7 +12030,7 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
11940
12030
|
const runtimeVersion = await getRuntimeVersion();
|
|
11941
12031
|
const latest = await fetchLatestVersion();
|
|
11942
12032
|
if (!latest) return;
|
|
11943
|
-
const current = runtimeVersion ?? "0.1.
|
|
12033
|
+
const current = runtimeVersion ?? "0.1.54";
|
|
11944
12034
|
const hasUpdate = isNewer(latest, current);
|
|
11945
12035
|
debug.event("update-check", {
|
|
11946
12036
|
current,
|
|
@@ -12016,7 +12106,7 @@ function wireSessionLifecycle(pi, runtime) {
|
|
|
12016
12106
|
setDelegateDisplayUsage("separate");
|
|
12017
12107
|
const sid = ctx.sessionManager.getSessionId();
|
|
12018
12108
|
const modelInfo = ctx.model;
|
|
12019
|
-
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.
|
|
12109
|
+
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.54" : null, model: modelInfo?.id ?? null, modelApi: modelInfo?.api ?? null, contextWindow: modelInfo?.contextWindow ?? null });
|
|
12020
12110
|
try {
|
|
12021
12111
|
await runtime.reloadConfig(ctx.cwd);
|
|
12022
12112
|
setDelegateDisplayUsage(resolveDelegate(runtime.adapter).displayUsage);
|