billion-context-pi 0.1.34 → 0.1.35
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/config.d.ts +6 -0
- package/dist/delegate-events.d.ts +28 -2
- package/dist/delegate-tool.d.ts +62 -2
- package/dist/delegate-watchdog.d.ts +11 -0
- package/dist/footer-status.d.ts +8 -0
- package/dist/index.js +657 -174
- package/dist/index.js.map +1 -1
- package/dist/messages.d.ts +4 -0
- package/dist/runtime.d.ts +0 -5
- package/dist/state.d.ts +10 -3
- package/dist/user-config.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2416,7 +2416,9 @@ function resolveConfig(adapter, liveContextLimit) {
|
|
|
2416
2416
|
}
|
|
2417
2417
|
|
|
2418
2418
|
// src/messages.ts
|
|
2419
|
-
var
|
|
2419
|
+
var REF_TAG_SOURCE = "(?:<acp\\s[^>]*>m\\d{5}</acp>|\\[m\\d{1,5}\\])";
|
|
2420
|
+
var REF_TAG = new RegExp(`^${REF_TAG_SOURCE}\\s?\\n?`);
|
|
2421
|
+
var TRAILING_REF_TAG = new RegExp(`\\n*${REF_TAG_SOURCE}\\s*$`);
|
|
2420
2422
|
function entriesToCoreMessages(entries) {
|
|
2421
2423
|
const out = [];
|
|
2422
2424
|
for (const entry of entries) {
|
|
@@ -2494,17 +2496,74 @@ function stringifyArgs(args) {
|
|
|
2494
2496
|
return safeStringify(args);
|
|
2495
2497
|
}
|
|
2496
2498
|
function extractText(content) {
|
|
2497
|
-
if (typeof content === "string") return content
|
|
2499
|
+
if (typeof content === "string") return stripRefTag(content);
|
|
2498
2500
|
if (!Array.isArray(content)) return "";
|
|
2499
2501
|
const parts = [];
|
|
2500
2502
|
for (const block of content) {
|
|
2501
2503
|
const b = block;
|
|
2502
|
-
if (b.type === "text" && typeof b.text === "string")
|
|
2503
|
-
parts.push(b.text.replace(REF_TAG, ""));
|
|
2504
|
-
}
|
|
2504
|
+
if (b.type === "text" && typeof b.text === "string") parts.push(stripRefTag(b.text));
|
|
2505
2505
|
}
|
|
2506
2506
|
return parts.join("\n");
|
|
2507
2507
|
}
|
|
2508
|
+
function stripRefTag(text) {
|
|
2509
|
+
return text.replace(REF_TAG, "").replace(TRAILING_REF_TAG, "");
|
|
2510
|
+
}
|
|
2511
|
+
function messageIdentity(message) {
|
|
2512
|
+
return JSON.stringify(normalizeIdentityValue(message, true));
|
|
2513
|
+
}
|
|
2514
|
+
function messageRef(message) {
|
|
2515
|
+
if (message === null || typeof message !== "object" || !("content" in message)) return void 0;
|
|
2516
|
+
const content = message.content;
|
|
2517
|
+
const texts = typeof content === "string" ? [content] : Array.isArray(content) ? content.flatMap((block) => {
|
|
2518
|
+
const value = block;
|
|
2519
|
+
return value.type === "text" && typeof value.text === "string" ? [value.text] : [];
|
|
2520
|
+
}) : [];
|
|
2521
|
+
for (const text of texts) {
|
|
2522
|
+
const tag = text.match(REF_TAG)?.[0] ?? text.match(TRAILING_REF_TAG)?.[0];
|
|
2523
|
+
const ref = tag?.match(/m\d{1,5}/)?.[0];
|
|
2524
|
+
if (ref) return ref;
|
|
2525
|
+
}
|
|
2526
|
+
return void 0;
|
|
2527
|
+
}
|
|
2528
|
+
function normalizeIdentityValue(value, message = false) {
|
|
2529
|
+
if (Array.isArray(value)) {
|
|
2530
|
+
return value.flatMap((item) => {
|
|
2531
|
+
if (!item || typeof item !== "object") return [normalizeIdentityValue(item)];
|
|
2532
|
+
const block = item;
|
|
2533
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
2534
|
+
const stripped = stripRefTag(block.text);
|
|
2535
|
+
if (block.text !== stripped && stripped === "") return [];
|
|
2536
|
+
}
|
|
2537
|
+
return [normalizeIdentityValue(item)];
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
if (value === null || typeof value !== "object") return value;
|
|
2541
|
+
const out = {};
|
|
2542
|
+
for (const key of Object.keys(value).sort()) {
|
|
2543
|
+
if (message && key === "timestamp") continue;
|
|
2544
|
+
const item = value[key];
|
|
2545
|
+
if (message && key === "content" && typeof item === "string") {
|
|
2546
|
+
out[key] = [{ text: stripRefTag(item), type: "text" }];
|
|
2547
|
+
} else if (key === "text" && typeof item === "string" && value.type === "text") {
|
|
2548
|
+
out[key] = stripRefTag(item);
|
|
2549
|
+
} else {
|
|
2550
|
+
out[key] = normalizeIdentityValue(item);
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2553
|
+
return out;
|
|
2554
|
+
}
|
|
2555
|
+
var TRUNCATION_MARKER2 = "[truncated for context space]";
|
|
2556
|
+
function matchesStoredText(stored, visible) {
|
|
2557
|
+
const marker = `...${TRUNCATION_MARKER2} \u2014 original ~`;
|
|
2558
|
+
const markerStart = visible.indexOf(marker);
|
|
2559
|
+
if (markerStart < 2 || visible.slice(markerStart - 2, markerStart) !== "\n\n") return false;
|
|
2560
|
+
const suffixMarker = " tokens]...\n\n";
|
|
2561
|
+
const suffixStart = visible.indexOf(suffixMarker, markerStart + marker.length);
|
|
2562
|
+
if (suffixStart < 0 || !/^\d+$/.test(visible.slice(markerStart + marker.length, suffixStart))) return false;
|
|
2563
|
+
const prefix = visible.slice(0, markerStart - 2);
|
|
2564
|
+
const suffix = visible.slice(suffixStart + suffixMarker.length);
|
|
2565
|
+
return prefix.length > 0 && suffix.length > 0 && stored.startsWith(prefix) && stored.endsWith(suffix);
|
|
2566
|
+
}
|
|
2508
2567
|
function allToolCalls(content) {
|
|
2509
2568
|
if (!Array.isArray(content)) return [];
|
|
2510
2569
|
const calls = [];
|
|
@@ -2598,11 +2657,11 @@ function patchRefTag(original, core) {
|
|
|
2598
2657
|
let injected = false;
|
|
2599
2658
|
for (let i = newBlocks.length - 1; i >= 0; i--) {
|
|
2600
2659
|
const b = newBlocks[i];
|
|
2601
|
-
if (b?.type === "text" && typeof b.text === "string") {
|
|
2660
|
+
if (b?.type === "text" && typeof b.text === "string" && b.text.length > 0) {
|
|
2602
2661
|
const baseText = b.text.replace(/\n*$/, "");
|
|
2603
|
-
newBlocks[i] = { ...b, text:
|
|
2662
|
+
newBlocks[i] = { ...b, text: `${baseText}
|
|
2604
2663
|
|
|
2605
|
-
${tag}`
|
|
2664
|
+
${tag}` };
|
|
2606
2665
|
injected = true;
|
|
2607
2666
|
break;
|
|
2608
2667
|
}
|
|
@@ -2637,8 +2696,8 @@ function peelRefTagBlocks(blocks) {
|
|
|
2637
2696
|
for (const block of blocks) {
|
|
2638
2697
|
const b = block;
|
|
2639
2698
|
if (b?.type === "text" && typeof b.text === "string") {
|
|
2640
|
-
const stripped = b.text
|
|
2641
|
-
if (stripped.length > 0) out.push({ ...b, text: stripped });
|
|
2699
|
+
const stripped = stripRefTag(b.text);
|
|
2700
|
+
if (stripped.length > 0 || b.text.length === 0) out.push({ ...b, text: stripped });
|
|
2642
2701
|
} else {
|
|
2643
2702
|
out.push(block);
|
|
2644
2703
|
}
|
|
@@ -2735,51 +2794,127 @@ function stateFileFor(sessionFile) {
|
|
|
2735
2794
|
if (sessionFile) return sessionFile + STATE_SUFFIX;
|
|
2736
2795
|
return null;
|
|
2737
2796
|
}
|
|
2797
|
+
async function readParentSessionPath(sessionFile) {
|
|
2798
|
+
try {
|
|
2799
|
+
const handle = await fs.open(sessionFile, "r");
|
|
2800
|
+
try {
|
|
2801
|
+
const buf = Buffer.alloc(65536);
|
|
2802
|
+
const { bytesRead } = await handle.read(buf, 0, buf.length, 0);
|
|
2803
|
+
if (bytesRead === 0) return void 0;
|
|
2804
|
+
const firstLine = buf.subarray(0, bytesRead).toString("utf8").split("\n")[0] ?? "";
|
|
2805
|
+
if (!firstLine.startsWith("{")) return void 0;
|
|
2806
|
+
const header = JSON.parse(firstLine);
|
|
2807
|
+
return typeof header.parentSession === "string" ? header.parentSession : void 0;
|
|
2808
|
+
} finally {
|
|
2809
|
+
await handle.close();
|
|
2810
|
+
}
|
|
2811
|
+
} catch (e) {
|
|
2812
|
+
const code = e.code;
|
|
2813
|
+
if (code !== "ENOENT") {
|
|
2814
|
+
logWarn("state", { event: "read-parent-header-failed", file: sessionFile, error: e instanceof Error ? e.message : String(e) });
|
|
2815
|
+
}
|
|
2816
|
+
return void 0;
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
function cacheKey(sessionFile, sessionId) {
|
|
2820
|
+
return sessionFile ? `file:${sessionFile}` : `session:${sessionId}`;
|
|
2821
|
+
}
|
|
2738
2822
|
var SessionStateStore = class {
|
|
2739
|
-
cache =
|
|
2740
|
-
|
|
2741
|
-
async load(sessionFile, _sessionId) {
|
|
2823
|
+
cache = /* @__PURE__ */ new Map();
|
|
2824
|
+
async load(sessionFile, sessionId) {
|
|
2742
2825
|
const file = stateFileFor(sessionFile);
|
|
2743
|
-
|
|
2826
|
+
const key = cacheKey(sessionFile, sessionId);
|
|
2827
|
+
const cached = this.cache.get(key);
|
|
2828
|
+
if (cached) return cached.state;
|
|
2744
2829
|
let state = createInitialState();
|
|
2830
|
+
let liveRefOrigins = [];
|
|
2745
2831
|
if (file) {
|
|
2746
2832
|
try {
|
|
2747
2833
|
const raw = await fs.readFile(file, "utf8");
|
|
2748
2834
|
const parsed = JSON.parse(raw);
|
|
2749
|
-
if (parsed && Array.isArray(parsed.blocks))
|
|
2835
|
+
if (parsed && Array.isArray(parsed.blocks)) {
|
|
2836
|
+
state = mergeInitialState(parsed);
|
|
2837
|
+
liveRefOrigins = parseLiveRefOrigins(parsed.liveRefOrigins);
|
|
2838
|
+
}
|
|
2750
2839
|
} catch (e) {
|
|
2751
2840
|
const code = e.code;
|
|
2752
2841
|
if (code !== "ENOENT") {
|
|
2753
2842
|
logWarn("state", { event: "load-failed", file, error: e instanceof Error ? e.message : String(e) });
|
|
2754
2843
|
}
|
|
2755
2844
|
}
|
|
2845
|
+
if (state.blocks.length === 0 && sessionFile) {
|
|
2846
|
+
const parentState = await this.tryLoadParentState(sessionFile);
|
|
2847
|
+
if (parentState) state = parentState;
|
|
2848
|
+
}
|
|
2756
2849
|
}
|
|
2757
|
-
this.cache
|
|
2758
|
-
this.loadedKey = file;
|
|
2850
|
+
this.cache.set(key, { state, liveRefOrigins });
|
|
2759
2851
|
return state;
|
|
2760
2852
|
}
|
|
2761
|
-
async save(state, sessionFile,
|
|
2853
|
+
async save(state, sessionFile, sessionId) {
|
|
2762
2854
|
const file = stateFileFor(sessionFile);
|
|
2763
2855
|
if (!file) return;
|
|
2764
|
-
|
|
2765
|
-
this.
|
|
2856
|
+
const key = cacheKey(sessionFile, sessionId);
|
|
2857
|
+
const liveRefOrigins = this.cache.get(key)?.liveRefOrigins ?? [];
|
|
2858
|
+
this.cache.set(key, { state, liveRefOrigins });
|
|
2766
2859
|
const dir = path2.dirname(file);
|
|
2767
2860
|
await fs.mkdir(dir, { recursive: true }).catch((e) => {
|
|
2768
2861
|
logError("state", { event: "save-mkdir-failed", dir, error: e instanceof Error ? e.message : String(e) });
|
|
2769
2862
|
});
|
|
2770
2863
|
const tmp = path2.join(dir, `.acp-tmp-${path2.basename(file)}`);
|
|
2771
2864
|
try {
|
|
2772
|
-
await fs.writeFile(tmp, JSON.stringify(state), "utf8");
|
|
2865
|
+
await fs.writeFile(tmp, JSON.stringify({ ...state, liveRefOrigins }), "utf8");
|
|
2773
2866
|
await fs.rename(tmp, file);
|
|
2774
2867
|
} catch (e) {
|
|
2775
2868
|
logError("state", { event: "save-failed", file, error: e instanceof Error ? e.message : String(e) });
|
|
2776
2869
|
}
|
|
2777
2870
|
}
|
|
2871
|
+
getLiveRefOrigins(sessionFile, sessionId) {
|
|
2872
|
+
return [...this.cache.get(cacheKey(sessionFile, sessionId))?.liveRefOrigins ?? []];
|
|
2873
|
+
}
|
|
2874
|
+
setLiveRefOrigins(sessionFile, sessionId, origins) {
|
|
2875
|
+
const key = cacheKey(sessionFile, sessionId);
|
|
2876
|
+
const slot = this.cache.get(key);
|
|
2877
|
+
if (slot) this.cache.set(key, { state: slot.state, liveRefOrigins: [...origins] });
|
|
2878
|
+
}
|
|
2778
2879
|
invalidate() {
|
|
2779
|
-
this.cache
|
|
2780
|
-
|
|
2880
|
+
this.cache.clear();
|
|
2881
|
+
}
|
|
2882
|
+
async tryLoadParentState(sessionFile) {
|
|
2883
|
+
const MAX_CHAIN_DEPTH = 8;
|
|
2884
|
+
let current = sessionFile;
|
|
2885
|
+
for (let depth = 0; depth < MAX_CHAIN_DEPTH; depth++) {
|
|
2886
|
+
const parentJsonl = await readParentSessionPath(current);
|
|
2887
|
+
if (!parentJsonl) return void 0;
|
|
2888
|
+
const parentAcp = stateFileFor(parentJsonl);
|
|
2889
|
+
if (!parentAcp) return void 0;
|
|
2890
|
+
try {
|
|
2891
|
+
const raw = await fs.readFile(parentAcp, "utf8");
|
|
2892
|
+
const parsed = JSON.parse(raw);
|
|
2893
|
+
if (parsed && Array.isArray(parsed.blocks) && parsed.blocks.length > 0) {
|
|
2894
|
+
logInfo("state", { event: "inherited-parent-state", file: parentAcp, depth, blocks: parsed.blocks.length, tokensCompressed: parsed.stats?.tokensCompressed ?? 0 });
|
|
2895
|
+
return mergeInitialState(parsed);
|
|
2896
|
+
}
|
|
2897
|
+
} catch (e) {
|
|
2898
|
+
const code = e.code;
|
|
2899
|
+
if (code !== "ENOENT") {
|
|
2900
|
+
logWarn("state", { event: "parent-state-load-failed", file: parentAcp, error: e instanceof Error ? e.message : String(e) });
|
|
2901
|
+
return void 0;
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
current = parentJsonl;
|
|
2905
|
+
}
|
|
2906
|
+
logWarn("state", { event: "parent-chain-exhausted", file: sessionFile, maxDepth: MAX_CHAIN_DEPTH });
|
|
2907
|
+
return void 0;
|
|
2781
2908
|
}
|
|
2782
2909
|
};
|
|
2910
|
+
function parseLiveRefOrigins(value) {
|
|
2911
|
+
if (!Array.isArray(value)) return [];
|
|
2912
|
+
return value.filter((item) => {
|
|
2913
|
+
if (!item || typeof item !== "object") return false;
|
|
2914
|
+
const origin = item;
|
|
2915
|
+
return typeof origin.rawId === "string" && typeof origin.identity === "string";
|
|
2916
|
+
});
|
|
2917
|
+
}
|
|
2783
2918
|
function mergeInitialState(parsed) {
|
|
2784
2919
|
const fresh = createInitialState();
|
|
2785
2920
|
return {
|
|
@@ -2803,50 +2938,116 @@ function isPiHost(sm) {
|
|
|
2803
2938
|
const source = sm;
|
|
2804
2939
|
return typeof source.buildContextEntries === "function";
|
|
2805
2940
|
}
|
|
2806
|
-
function mergeLiveEntries(entries, live) {
|
|
2941
|
+
function mergeLiveEntries(entries, live, state, origins) {
|
|
2807
2942
|
const persisted = entries.filter((e) => e.type === "message");
|
|
2943
|
+
const matched = matchPersistedSuffix(persisted, live);
|
|
2944
|
+
const prior = matchOrigins(origins, live);
|
|
2808
2945
|
const out = [];
|
|
2809
|
-
|
|
2810
|
-
|
|
2946
|
+
const nextOrigins = [];
|
|
2947
|
+
const usedIds = /* @__PURE__ */ new Set();
|
|
2811
2948
|
for (let i = 0; i < live.length; i++) {
|
|
2812
2949
|
const msg = live[i];
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
if (matched) {
|
|
2821
|
-
out.push(matched);
|
|
2822
|
-
} else {
|
|
2823
|
-
unmatched++;
|
|
2824
|
-
out.push({
|
|
2825
|
-
type: "message",
|
|
2826
|
-
id: `live-${i}`,
|
|
2827
|
-
parentId: null,
|
|
2828
|
-
timestamp: String(msg.timestamp ?? Date.now()),
|
|
2829
|
-
message: msg
|
|
2830
|
-
});
|
|
2950
|
+
const entry = matched[i];
|
|
2951
|
+
const origin = prior[i];
|
|
2952
|
+
if (entry) {
|
|
2953
|
+
if (origin) migrateLiveRefs(state, origin.rawId, entry.id);
|
|
2954
|
+
else migrateTaggedRef(state, msg, entry.id);
|
|
2955
|
+
out.push(entry);
|
|
2956
|
+
continue;
|
|
2831
2957
|
}
|
|
2958
|
+
const id = origin?.rawId ?? nextLiveId(state, usedIds, i);
|
|
2959
|
+
usedIds.add(id);
|
|
2960
|
+
out.push({ type: "message", id, parentId: null, timestamp: String(msg.timestamp ?? Date.now()), message: msg });
|
|
2961
|
+
nextOrigins.push({ rawId: id, identity: messageIdentity(msg) });
|
|
2832
2962
|
}
|
|
2963
|
+
origins.splice(0, origins.length, ...nextOrigins);
|
|
2964
|
+
const unmatched = live.length - matched.length;
|
|
2833
2965
|
if (unmatched > 0) logInfo("runtime", { event: "merge-live-entries", live: live.length, unmatched });
|
|
2834
2966
|
return out;
|
|
2835
2967
|
}
|
|
2968
|
+
function matchOrigins(origins, live) {
|
|
2969
|
+
for (let start = 0; start < origins.length; start++) {
|
|
2970
|
+
const count = origins.length - start;
|
|
2971
|
+
if (count > live.length) continue;
|
|
2972
|
+
if (origins.slice(start).every((origin, index) => origin.identity === messageIdentity(live[index]))) {
|
|
2973
|
+
return [...origins.slice(start), ...Array(live.length - count)];
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
return Array(live.length);
|
|
2977
|
+
}
|
|
2978
|
+
function nextLiveId(state, used, index) {
|
|
2979
|
+
let id = `live-${index}`;
|
|
2980
|
+
let suffix = index;
|
|
2981
|
+
while (used.has(id) || state.messageRefs.byRaw[id] !== void 0) id = `live-${++suffix}`;
|
|
2982
|
+
return id;
|
|
2983
|
+
}
|
|
2984
|
+
function migrateTaggedRef(state, message, stableId) {
|
|
2985
|
+
const ref = messageRef(message);
|
|
2986
|
+
const rawId = ref ? state.messageRefs.byRef[ref] : void 0;
|
|
2987
|
+
if (rawId?.startsWith("live-")) migrateLiveRefs(state, rawId, stableId);
|
|
2988
|
+
}
|
|
2989
|
+
function migrateLiveRefs(state, liveId, stableId) {
|
|
2990
|
+
const rootId = liveId.split("#", 1)[0];
|
|
2991
|
+
if (!rootId.startsWith("live-")) return;
|
|
2992
|
+
for (const [rawId, ref] of Object.entries(state.messageRefs.byRaw)) {
|
|
2993
|
+
if (rawId !== rootId && !rawId.startsWith(`${rootId}#`)) continue;
|
|
2994
|
+
const stableRawId = `${stableId}${rawId.slice(rootId.length)}`;
|
|
2995
|
+
if (state.messageRefs.byRaw[stableRawId] === void 0) {
|
|
2996
|
+
state.messageRefs.byRaw[stableRawId] = ref;
|
|
2997
|
+
state.messageRefs.byRef[ref] = stableRawId;
|
|
2998
|
+
} else if (state.messageRefs.byRef[ref] === rawId) {
|
|
2999
|
+
delete state.messageRefs.byRef[ref];
|
|
3000
|
+
}
|
|
3001
|
+
delete state.messageRefs.byRaw[rawId];
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
function matchPersistedSuffix(persisted, live) {
|
|
3005
|
+
for (let start = 0; start < persisted.length; start++) {
|
|
3006
|
+
const count = persisted.length - start;
|
|
3007
|
+
if (count > live.length) continue;
|
|
3008
|
+
const suffix = persisted.slice(start);
|
|
3009
|
+
if (suffix.every((entry, index) => sameMessage(entry.message, live[index]))) return suffix;
|
|
3010
|
+
}
|
|
3011
|
+
return [];
|
|
3012
|
+
}
|
|
2836
3013
|
function sameMessage(a, b) {
|
|
2837
|
-
const ra = a.role;
|
|
2838
|
-
const rb = b.role;
|
|
2839
|
-
if (ra !== rb) return false;
|
|
2840
|
-
const ca = a.content;
|
|
2841
|
-
const cb = b.content;
|
|
2842
|
-
if (ca === void 0 || cb === void 0) return false;
|
|
2843
3014
|
try {
|
|
2844
|
-
|
|
3015
|
+
if (messageIdentity(a) === messageIdentity(b)) return true;
|
|
3016
|
+
const ra = a.role;
|
|
3017
|
+
const rb = b.role;
|
|
3018
|
+
if (ra !== rb || ra !== "toolResult") return false;
|
|
3019
|
+
const ca = a.content;
|
|
3020
|
+
const cb = b.content;
|
|
3021
|
+
return sameNonTextBlocks(ca, cb) && matchesStoredText(extractText(ca), extractText(cb));
|
|
2845
3022
|
} catch (e) {
|
|
2846
3023
|
logWarn("runtime", { event: "message-compare-failed", error: e instanceof Error ? e.message : String(e) });
|
|
2847
3024
|
return a === b;
|
|
2848
3025
|
}
|
|
2849
3026
|
}
|
|
3027
|
+
function sameNonTextBlocks(a, b) {
|
|
3028
|
+
const nonText = (blocks) => blocks.filter((block) => block.type !== "text");
|
|
3029
|
+
try {
|
|
3030
|
+
const na = Array.isArray(a) ? nonText(a) : [];
|
|
3031
|
+
const nb = Array.isArray(b) ? nonText(b) : [];
|
|
3032
|
+
return JSON.stringify(na) === JSON.stringify(nb);
|
|
3033
|
+
} catch {
|
|
3034
|
+
return false;
|
|
3035
|
+
}
|
|
3036
|
+
}
|
|
3037
|
+
function pruneOrphanRefs(state, messages) {
|
|
3038
|
+
const retainedRawIds = new Set(messages.map((message) => message.id));
|
|
3039
|
+
for (const block of state.blocks) {
|
|
3040
|
+
for (const rawId of [...block.directMessageIds, ...block.effectiveMessageIds]) retainedRawIds.add(rawId);
|
|
3041
|
+
}
|
|
3042
|
+
for (const [rawId, ref] of Object.entries(state.messageRefs.byRaw)) {
|
|
3043
|
+
if (retainedRawIds.has(rawId)) continue;
|
|
3044
|
+
delete state.messageRefs.byRaw[rawId];
|
|
3045
|
+
if (state.messageRefs.byRef[ref] === rawId) delete state.messageRefs.byRef[ref];
|
|
3046
|
+
}
|
|
3047
|
+
for (const [ref, rawId] of Object.entries(state.messageRefs.byRef)) {
|
|
3048
|
+
if (!retainedRawIds.has(rawId)) delete state.messageRefs.byRef[ref];
|
|
3049
|
+
}
|
|
3050
|
+
}
|
|
2850
3051
|
function createRuntime(adapter) {
|
|
2851
3052
|
const core = createCore({ countTokens: defaultCountTokens });
|
|
2852
3053
|
const store = new SessionStateStore();
|
|
@@ -2877,10 +3078,20 @@ function createRuntime(adapter) {
|
|
|
2877
3078
|
}
|
|
2878
3079
|
async function stateFor(ctx, liveMessages) {
|
|
2879
3080
|
const sm = ctx.sessionManager;
|
|
2880
|
-
const
|
|
3081
|
+
const sessionFile = sm.getSessionFile() ?? void 0;
|
|
3082
|
+
const sessionId = sm.getSessionId();
|
|
3083
|
+
const state = await store.load(sessionFile, sessionId);
|
|
2881
3084
|
const entries = readContextEntries(sm);
|
|
2882
|
-
|
|
2883
|
-
|
|
3085
|
+
if (!isPiHost(sm) && liveMessages && liveMessages.length > 0) {
|
|
3086
|
+
const origins = store.getLiveRefOrigins(sessionFile, sessionId);
|
|
3087
|
+
const merged = mergeLiveEntries(entries, liveMessages, state, origins);
|
|
3088
|
+
store.setLiveRefOrigins(sessionFile, sessionId, origins);
|
|
3089
|
+
const coreMessages2 = entriesToCoreMessages(merged);
|
|
3090
|
+
return { state, coreMessages: coreMessages2, entries: merged };
|
|
3091
|
+
}
|
|
3092
|
+
const coreMessages = entriesToCoreMessages(entries);
|
|
3093
|
+
if (liveMessages === void 0) pruneOrphanRefs(state, coreMessages);
|
|
3094
|
+
return { state, coreMessages, entries };
|
|
2884
3095
|
}
|
|
2885
3096
|
async function save(state, ctx) {
|
|
2886
3097
|
const sm = ctx.sessionManager;
|
|
@@ -7360,9 +7571,19 @@ function makeCompressTool(runtime) {
|
|
|
7360
7571
|
async function handleCompress(args, runtime, ctx, toolCallId) {
|
|
7361
7572
|
const ranges = args.content ?? [];
|
|
7362
7573
|
if (ranges.length === 0) return "No ranges provided.";
|
|
7363
|
-
const { state, coreMessages } = await runtime.stateFor(ctx);
|
|
7574
|
+
const { state: initialState, coreMessages } = await runtime.stateFor(ctx);
|
|
7364
7575
|
const config = runtime.configFor(ctx);
|
|
7365
|
-
const
|
|
7576
|
+
const estimatedTokens = estimateTokens(coreMessages, collectCoveredMessageIds(initialState));
|
|
7577
|
+
const realUsage = ctx.getContextUsage?.();
|
|
7578
|
+
const turn = runtime.core.processTurn({
|
|
7579
|
+
messages: coreMessages,
|
|
7580
|
+
state: initialState,
|
|
7581
|
+
config,
|
|
7582
|
+
tokenCount: realUsage?.tokens && realUsage.tokens > 0 ? realUsage.tokens : estimatedTokens
|
|
7583
|
+
});
|
|
7584
|
+
const state = turn.state;
|
|
7585
|
+
const messages = turn.messages;
|
|
7586
|
+
const beforeTokens = estimateTokens(messages, collectCoveredMessageIds(state));
|
|
7366
7587
|
const summaryMaxChars = args.summaryMaxChars;
|
|
7367
7588
|
const topLevelTopic = args.topic;
|
|
7368
7589
|
debug.event("compress-in", {
|
|
@@ -7371,12 +7592,12 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
|
|
|
7371
7592
|
spans: ranges.map((r) => ({ span: `${r.startId}..${r.endId}`, summaryLen: r.summary.length, summary: r.summary, topic: r.topic ?? topLevelTopic ?? null })),
|
|
7372
7593
|
blocksBefore: state.blocks.length,
|
|
7373
7594
|
activeBefore: state.blocks.filter((b) => b.active).length,
|
|
7374
|
-
beforeMsgCount:
|
|
7595
|
+
beforeMsgCount: messages.length,
|
|
7375
7596
|
beforeTokens
|
|
7376
7597
|
});
|
|
7377
7598
|
const applied = runtime.core.applyCompression({
|
|
7378
7599
|
ranges: ranges.map((r) => ({ startRef: r.startId, endRef: r.endId, summary: r.summary, topic: r.topic ?? topLevelTopic, summaryMaxChars, compressCallId: toolCallId })),
|
|
7379
|
-
messages
|
|
7600
|
+
messages,
|
|
7380
7601
|
state,
|
|
7381
7602
|
config
|
|
7382
7603
|
});
|
|
@@ -7699,76 +7920,6 @@ function formatSize(tokens) {
|
|
|
7699
7920
|
return `${(tokens / 1e6).toFixed(1)}M`;
|
|
7700
7921
|
}
|
|
7701
7922
|
|
|
7702
|
-
// src/status-tool.ts
|
|
7703
|
-
var StatusParams = typebox_exports.Object({
|
|
7704
|
-
scope: typebox_exports.Optional(typebox_exports.Union([typebox_exports.Literal("compressed"), typebox_exports.Literal("uncompressed")], { description: '"compressed" = drill into blocks; "uncompressed" = show visible messages/ranges. Default: overview.' })),
|
|
7705
|
-
view: typebox_exports.Optional(typebox_exports.Union([typebox_exports.Literal("ranges"), typebox_exports.Literal("messages")], { description: 'For uncompressed scope: "ranges" (default) or "messages" (per-message listing).' })),
|
|
7706
|
-
tool: typebox_exports.Optional(typebox_exports.String({ description: 'Filter by tool name (e.g. "bash", "read"). Only for uncompressed+messages.' })),
|
|
7707
|
-
sort: typebox_exports.Optional(typebox_exports.Union([typebox_exports.Literal("size"), typebox_exports.Literal("time"), typebox_exports.Literal("tool"), typebox_exports.Literal("age")], { description: "Sort order. Default: size." })),
|
|
7708
|
-
limit: typebox_exports.Optional(typebox_exports.Number({ description: "Max items to show (default: 30)." }))
|
|
7709
|
-
});
|
|
7710
|
-
function makeStatusTool(runtime) {
|
|
7711
|
-
return {
|
|
7712
|
-
name: "acp_status",
|
|
7713
|
-
label: "ACP Status",
|
|
7714
|
-
description: "Context status: overview, compressed blocks, or uncompressed ranges/messages. No args = overview + totals + compressible ranges. scope:'uncompressed' + view:'messages' for per-message listing. scope:'compressed' for block drilldown.",
|
|
7715
|
-
promptSnippet: 'acp_status({}) or acp_status({ scope: "uncompressed", view: "messages" })',
|
|
7716
|
-
promptGuidelines: [
|
|
7717
|
-
"Call with no args for a quick overview of context usage.",
|
|
7718
|
-
"Use scope:'uncompressed' to find the largest compressible ranges.",
|
|
7719
|
-
"Use scope:'compressed' to inspect existing compression blocks."
|
|
7720
|
-
],
|
|
7721
|
-
parameters: StatusParams,
|
|
7722
|
-
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
7723
|
-
let result;
|
|
7724
|
-
try {
|
|
7725
|
-
result = await handleStatus(params, runtime, ctx);
|
|
7726
|
-
} catch (e) {
|
|
7727
|
-
logThrow("status", e, { sid: ctx.sessionManager.getSessionId(), scope: params.scope ?? null });
|
|
7728
|
-
throw e;
|
|
7729
|
-
}
|
|
7730
|
-
return { details: void 0, content: [{ type: "text", text: result }] };
|
|
7731
|
-
}
|
|
7732
|
-
};
|
|
7733
|
-
}
|
|
7734
|
-
async function handleStatus(args, runtime, ctx) {
|
|
7735
|
-
const { state, coreMessages } = await runtime.stateFor(ctx);
|
|
7736
|
-
const config = runtime.configFor(ctx);
|
|
7737
|
-
const tokenCount = estimateTokens(coreMessages, collectCoveredMessageIds(state));
|
|
7738
|
-
const realUsage = ctx.getContextUsage?.();
|
|
7739
|
-
const turn = runtime.core.processTurn({
|
|
7740
|
-
messages: coreMessages,
|
|
7741
|
-
state,
|
|
7742
|
-
config,
|
|
7743
|
-
tokenCount: realUsage?.tokens && realUsage.tokens > 0 ? realUsage.tokens : tokenCount
|
|
7744
|
-
});
|
|
7745
|
-
const processed = turn.messages;
|
|
7746
|
-
const base = buildStatusReport(turn.state, processed, defaultCountTokens, {
|
|
7747
|
-
scope: args.scope,
|
|
7748
|
-
view: args.view,
|
|
7749
|
-
tool: args.tool,
|
|
7750
|
-
sort: args.sort,
|
|
7751
|
-
limit: args.limit
|
|
7752
|
-
});
|
|
7753
|
-
if (args.scope) return base;
|
|
7754
|
-
const nudge = turn.nudge;
|
|
7755
|
-
const ranges = nudge?.compressibleRanges ?? [];
|
|
7756
|
-
const protectedRanges = nudge?.protectedRanges ?? [];
|
|
7757
|
-
const extra = [];
|
|
7758
|
-
if (nudge) {
|
|
7759
|
-
extra.push("");
|
|
7760
|
-
extra.push(
|
|
7761
|
-
nudge.shouldInject ? `Nudge: ACTIVE \u2014 ${nudge.reason}` : `Nudge: idle \u2014 ${nudge.reason}`
|
|
7762
|
-
);
|
|
7763
|
-
}
|
|
7764
|
-
if (ranges.length > 0 || protectedRanges.length > 0) {
|
|
7765
|
-
extra.push("");
|
|
7766
|
-
extra.push(formatRanges(ranges, protectedRanges));
|
|
7767
|
-
}
|
|
7768
|
-
return extra.length > 0 ? `${base}
|
|
7769
|
-
${extra.join("\n")}` : base;
|
|
7770
|
-
}
|
|
7771
|
-
|
|
7772
7923
|
// src/delegate-tool.ts
|
|
7773
7924
|
import {
|
|
7774
7925
|
spawn
|
|
@@ -7778,11 +7929,52 @@ import { mkdir as mkdir2, mkdtemp, writeFile as writeFile2, rm, appendFile } fro
|
|
|
7778
7929
|
import { tmpdir as tmpdir2 } from "os";
|
|
7779
7930
|
import { join as join4 } from "path";
|
|
7780
7931
|
|
|
7932
|
+
// src/footer-status.ts
|
|
7933
|
+
var FOOTER_STATUS_KEY = "billion-context-pi";
|
|
7934
|
+
var ui;
|
|
7935
|
+
var lastFooterText = "";
|
|
7936
|
+
function formatCompactTokens(count) {
|
|
7937
|
+
if (count < 1e3) return count.toString();
|
|
7938
|
+
if (count < 1e4) return `${(count / 1e3).toFixed(1)}k`;
|
|
7939
|
+
if (count < 1e6) return `${Math.round(count / 1e3)}k`;
|
|
7940
|
+
if (count < 1e7) return `${(count / 1e6).toFixed(1)}M`;
|
|
7941
|
+
return `${Math.round(count / 1e6)}M`;
|
|
7942
|
+
}
|
|
7943
|
+
function initFooterStatus(ctx) {
|
|
7944
|
+
ui = ctx.ui;
|
|
7945
|
+
lastFooterText = void 0;
|
|
7946
|
+
}
|
|
7947
|
+
function updateFooterStatus() {
|
|
7948
|
+
if (!ui) return;
|
|
7949
|
+
const usage = getDelegateUsage();
|
|
7950
|
+
let text;
|
|
7951
|
+
if (usage && usage.totalTokens > 0) {
|
|
7952
|
+
const costStr = usage.cost.total > 0 ? ` ($${usage.cost.total.toFixed(4)})` : "";
|
|
7953
|
+
text = `sub-agents \u2191${formatCompactTokens(usage.input)} \u2193${formatCompactTokens(usage.output)}${costStr}`;
|
|
7954
|
+
}
|
|
7955
|
+
if ((text ?? "") === lastFooterText) return;
|
|
7956
|
+
lastFooterText = text ?? "";
|
|
7957
|
+
try {
|
|
7958
|
+
ui.setStatus(FOOTER_STATUS_KEY, text);
|
|
7959
|
+
} catch {
|
|
7960
|
+
}
|
|
7961
|
+
}
|
|
7962
|
+
function disposeFooterStatus() {
|
|
7963
|
+
if (ui) {
|
|
7964
|
+
try {
|
|
7965
|
+
ui.setStatus(FOOTER_STATUS_KEY, void 0);
|
|
7966
|
+
} catch {
|
|
7967
|
+
}
|
|
7968
|
+
}
|
|
7969
|
+
ui = void 0;
|
|
7970
|
+
lastFooterText = "";
|
|
7971
|
+
}
|
|
7972
|
+
|
|
7781
7973
|
// src/fleet-widget.ts
|
|
7782
7974
|
var DELEGATE_WIDGET_KEY = "billion-context-pi-delegates";
|
|
7783
7975
|
var REFRESH_MS = 500;
|
|
7784
7976
|
var MAX_TASK_LEN = 48;
|
|
7785
|
-
var
|
|
7977
|
+
var ui2;
|
|
7786
7978
|
var timer;
|
|
7787
7979
|
var lastRenderKey = "";
|
|
7788
7980
|
var runsSnapshot;
|
|
@@ -7811,20 +8003,21 @@ function stopTimer() {
|
|
|
7811
8003
|
}
|
|
7812
8004
|
}
|
|
7813
8005
|
function clearWidget() {
|
|
7814
|
-
if (!
|
|
8006
|
+
if (!ui2) return;
|
|
7815
8007
|
try {
|
|
7816
|
-
|
|
8008
|
+
ui2.setWidget(DELEGATE_WIDGET_KEY, void 0);
|
|
7817
8009
|
} catch {
|
|
7818
8010
|
}
|
|
7819
8011
|
}
|
|
7820
8012
|
function refresh() {
|
|
7821
|
-
if (!
|
|
8013
|
+
if (!ui2) return;
|
|
7822
8014
|
const runs2 = runsSnapshot ? runsSnapshot() : [];
|
|
7823
8015
|
if (runs2.length === 0) {
|
|
7824
8016
|
if (lastRenderKey !== "") {
|
|
7825
8017
|
lastRenderKey = "";
|
|
7826
8018
|
clearWidget();
|
|
7827
8019
|
}
|
|
8020
|
+
updateFooterStatus();
|
|
7828
8021
|
stopTimer();
|
|
7829
8022
|
return;
|
|
7830
8023
|
}
|
|
@@ -7834,16 +8027,18 @@ function refresh() {
|
|
|
7834
8027
|
lastRenderKey = renderKey;
|
|
7835
8028
|
const lines = renderLines(sorted);
|
|
7836
8029
|
try {
|
|
7837
|
-
|
|
8030
|
+
ui2.setWidget(DELEGATE_WIDGET_KEY, lines, { placement: "belowEditor" });
|
|
7838
8031
|
} catch {
|
|
7839
|
-
|
|
8032
|
+
ui2 = void 0;
|
|
7840
8033
|
stopTimer();
|
|
7841
8034
|
}
|
|
8035
|
+
updateFooterStatus();
|
|
7842
8036
|
}
|
|
7843
8037
|
var delegateStatusWidget = {
|
|
7844
8038
|
setContext(ctx, snapshot) {
|
|
7845
8039
|
if (ctx.mode !== "tui") return;
|
|
7846
|
-
|
|
8040
|
+
initFooterStatus(ctx);
|
|
8041
|
+
ui2 = ctx.ui;
|
|
7847
8042
|
runsSnapshot = snapshot;
|
|
7848
8043
|
if (!timer) {
|
|
7849
8044
|
timer = setInterval(refresh, REFRESH_MS);
|
|
@@ -7854,11 +8049,12 @@ var delegateStatusWidget = {
|
|
|
7854
8049
|
dispose() {
|
|
7855
8050
|
stopTimer();
|
|
7856
8051
|
clearWidget();
|
|
7857
|
-
|
|
8052
|
+
disposeFooterStatus();
|
|
8053
|
+
ui2 = void 0;
|
|
7858
8054
|
lastRenderKey = "";
|
|
7859
8055
|
},
|
|
7860
8056
|
poke() {
|
|
7861
|
-
if (
|
|
8057
|
+
if (ui2 && !timer) {
|
|
7862
8058
|
timer = setInterval(refresh, REFRESH_MS);
|
|
7863
8059
|
timer.unref?.();
|
|
7864
8060
|
}
|
|
@@ -7872,11 +8068,13 @@ function attachWatchdogs(child, hooks, opts) {
|
|
|
7872
8068
|
let eofTimer;
|
|
7873
8069
|
let killGraceTimer;
|
|
7874
8070
|
let timeoutTimer;
|
|
8071
|
+
let settledGraceTimer;
|
|
7875
8072
|
const clearTimers = () => {
|
|
7876
8073
|
if (idleTimer) clearTimeout(idleTimer);
|
|
7877
8074
|
if (eofTimer) clearTimeout(eofTimer);
|
|
7878
8075
|
if (killGraceTimer) clearTimeout(killGraceTimer);
|
|
7879
8076
|
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
8077
|
+
if (settledGraceTimer) clearTimeout(settledGraceTimer);
|
|
7880
8078
|
};
|
|
7881
8079
|
const killByWatchdog = (reason) => {
|
|
7882
8080
|
if (hooks.isSettled()) return;
|
|
@@ -7894,6 +8092,14 @@ function attachWatchdogs(child, hooks, opts) {
|
|
|
7894
8092
|
}, opts.killGraceMs);
|
|
7895
8093
|
killGraceTimer.unref?.();
|
|
7896
8094
|
};
|
|
8095
|
+
const settledGrace = (graceMs, _killGraceMs, reason) => {
|
|
8096
|
+
if (hooks.isSettled() || settledGraceTimer) return;
|
|
8097
|
+
settledGraceTimer = setTimeout(() => {
|
|
8098
|
+
settledGraceTimer = void 0;
|
|
8099
|
+
killByWatchdog(reason);
|
|
8100
|
+
}, graceMs);
|
|
8101
|
+
settledGraceTimer.unref?.();
|
|
8102
|
+
};
|
|
7897
8103
|
const poke = () => {
|
|
7898
8104
|
if (idleTimer) clearTimeout(idleTimer);
|
|
7899
8105
|
idleTimer = setTimeout(() => killByWatchdog(`no output for ${opts.idleMs / 6e4}m`), opts.idleMs);
|
|
@@ -7917,6 +8123,7 @@ function attachWatchdogs(child, hooks, opts) {
|
|
|
7917
8123
|
child.stdout?.once("end", onStdoutEnd);
|
|
7918
8124
|
return {
|
|
7919
8125
|
poke,
|
|
8126
|
+
settledGrace,
|
|
7920
8127
|
dispose: () => {
|
|
7921
8128
|
clearTimers();
|
|
7922
8129
|
child.stdout?.removeListener("end", onStdoutEnd);
|
|
@@ -7925,16 +8132,66 @@ function attachWatchdogs(child, hooks, opts) {
|
|
|
7925
8132
|
}
|
|
7926
8133
|
|
|
7927
8134
|
// src/delegate-events.ts
|
|
8135
|
+
function safeNumber(v) {
|
|
8136
|
+
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
8137
|
+
}
|
|
8138
|
+
function handleMessageEnd(event) {
|
|
8139
|
+
const msg = event.message;
|
|
8140
|
+
if (!msg || msg.role !== "assistant") return null;
|
|
8141
|
+
const u = msg.usage;
|
|
8142
|
+
if (!u || typeof u !== "object") return null;
|
|
8143
|
+
const raw = u;
|
|
8144
|
+
const input = safeNumber(raw.input);
|
|
8145
|
+
const output = safeNumber(raw.output);
|
|
8146
|
+
const cacheRead = safeNumber(raw.cacheRead);
|
|
8147
|
+
const cacheWrite = safeNumber(raw.cacheWrite);
|
|
8148
|
+
if (input === void 0 && output === void 0 && cacheRead === void 0 && cacheWrite === void 0) return null;
|
|
8149
|
+
const cost = raw.cost;
|
|
8150
|
+
let parsedCost;
|
|
8151
|
+
if (cost && typeof cost === "object") {
|
|
8152
|
+
const c = cost;
|
|
8153
|
+
parsedCost = {
|
|
8154
|
+
input: typeof c.input === "number" ? c.input : 0,
|
|
8155
|
+
output: typeof c.output === "number" ? c.output : 0,
|
|
8156
|
+
cacheRead: typeof c.cacheRead === "number" ? c.cacheRead : 0,
|
|
8157
|
+
cacheWrite: typeof c.cacheWrite === "number" ? c.cacheWrite : 0,
|
|
8158
|
+
total: typeof c.total === "number" ? c.total : 0
|
|
8159
|
+
};
|
|
8160
|
+
} else {
|
|
8161
|
+
parsedCost = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 };
|
|
8162
|
+
}
|
|
8163
|
+
return {
|
|
8164
|
+
kind: "usage-update",
|
|
8165
|
+
usage: {
|
|
8166
|
+
input: input ?? 0,
|
|
8167
|
+
output: output ?? 0,
|
|
8168
|
+
cacheRead: cacheRead ?? 0,
|
|
8169
|
+
cacheWrite: cacheWrite ?? 0,
|
|
8170
|
+
cacheWrite1h: safeNumber(raw.cacheWrite1h),
|
|
8171
|
+
reasoning: safeNumber(raw.reasoning),
|
|
8172
|
+
totalTokens: typeof raw.totalTokens === "number" ? raw.totalTokens : 0,
|
|
8173
|
+
cost: parsedCost
|
|
8174
|
+
}
|
|
8175
|
+
};
|
|
8176
|
+
}
|
|
7928
8177
|
var ThinkingCollector = class {
|
|
7929
8178
|
constructor(showThinking) {
|
|
7930
8179
|
this.showThinking = showThinking;
|
|
7931
8180
|
}
|
|
7932
8181
|
showThinking;
|
|
7933
8182
|
buf = "";
|
|
8183
|
+
usage;
|
|
7934
8184
|
push(delta) {
|
|
7935
8185
|
this.buf += delta;
|
|
7936
8186
|
}
|
|
7937
|
-
|
|
8187
|
+
process(ev) {
|
|
8188
|
+
if (ev.kind === "thinking-delta") {
|
|
8189
|
+
this.push(ev.delta);
|
|
8190
|
+
}
|
|
8191
|
+
if (ev.kind === "usage-update") {
|
|
8192
|
+
this.usage = ev.usage;
|
|
8193
|
+
}
|
|
8194
|
+
}
|
|
7938
8195
|
flush() {
|
|
7939
8196
|
const text = this.buf.trim();
|
|
7940
8197
|
this.buf = "";
|
|
@@ -7942,6 +8199,9 @@ var ThinkingCollector = class {
|
|
|
7942
8199
|
return `[thinking] ${text}
|
|
7943
8200
|
`;
|
|
7944
8201
|
}
|
|
8202
|
+
getUsage() {
|
|
8203
|
+
return this.usage;
|
|
8204
|
+
}
|
|
7945
8205
|
};
|
|
7946
8206
|
function parseEventLine(line) {
|
|
7947
8207
|
let ev;
|
|
@@ -8006,6 +8266,12 @@ function parseEventLine(line) {
|
|
|
8006
8266
|
attempt: Number(e.attempt ?? 0)
|
|
8007
8267
|
};
|
|
8008
8268
|
}
|
|
8269
|
+
if (e.type === "message_end") {
|
|
8270
|
+
return handleMessageEnd(e);
|
|
8271
|
+
}
|
|
8272
|
+
if (e.type === "agent_settled") {
|
|
8273
|
+
return { kind: "agent-settled" };
|
|
8274
|
+
}
|
|
8009
8275
|
return null;
|
|
8010
8276
|
}
|
|
8011
8277
|
function formatArgs(args) {
|
|
@@ -8060,6 +8326,7 @@ function newPortion(text, prev) {
|
|
|
8060
8326
|
var MAX_DEPTH = 2;
|
|
8061
8327
|
var SYNC_TIMEOUT_MS = 5 * 6e4;
|
|
8062
8328
|
var EOF_GRACE_MS = 1e4;
|
|
8329
|
+
var SETTLED_GRACE_MS = 1e4;
|
|
8063
8330
|
var IDLE_GRACE_MS = 5 * 6e4;
|
|
8064
8331
|
var ASYNC_TIMEOUT_MS = 30 * 6e4;
|
|
8065
8332
|
var KILL_GRACE_MS = 1e4;
|
|
@@ -8112,6 +8379,20 @@ Answer the question concisely with clear reasoning. Cite file:line when referenc
|
|
|
8112
8379
|
};
|
|
8113
8380
|
var AGENT_NAMES = Object.keys(AGENTS);
|
|
8114
8381
|
var runs = /* @__PURE__ */ new Map();
|
|
8382
|
+
var delegateUsageTotal;
|
|
8383
|
+
function addDelegateUsage(u) {
|
|
8384
|
+
delegateUsageTotal = delegateUsageTotal ? accumulateUsage(delegateUsageTotal, u) : u;
|
|
8385
|
+
}
|
|
8386
|
+
function getDelegateUsage() {
|
|
8387
|
+
return delegateUsageTotal;
|
|
8388
|
+
}
|
|
8389
|
+
function resetDelegateUsage() {
|
|
8390
|
+
delegateUsageTotal = void 0;
|
|
8391
|
+
}
|
|
8392
|
+
var delegateDisplayUsage = "separate";
|
|
8393
|
+
function setDelegateDisplayUsage(mode) {
|
|
8394
|
+
delegateDisplayUsage = mode;
|
|
8395
|
+
}
|
|
8115
8396
|
function runningRunsSnapshot() {
|
|
8116
8397
|
const out = [];
|
|
8117
8398
|
for (const r of runs.values()) {
|
|
@@ -8131,6 +8412,10 @@ function makeEventApplier(opts, writers) {
|
|
|
8131
8412
|
const handleEventLine = (line) => {
|
|
8132
8413
|
const ev = parseEventLine(line);
|
|
8133
8414
|
if (!ev) return;
|
|
8415
|
+
if (ev.kind === "usage-update") {
|
|
8416
|
+
opts.onUsage?.(ev.usage);
|
|
8417
|
+
return;
|
|
8418
|
+
}
|
|
8134
8419
|
if (ev.kind === "thinking-delta") {
|
|
8135
8420
|
thinking.push(ev.delta);
|
|
8136
8421
|
return;
|
|
@@ -8139,6 +8424,11 @@ function makeEventApplier(opts, writers) {
|
|
|
8139
8424
|
flushThinking();
|
|
8140
8425
|
return;
|
|
8141
8426
|
}
|
|
8427
|
+
if (ev.kind === "agent-settled") {
|
|
8428
|
+
flushThinking();
|
|
8429
|
+
opts.onSettled?.();
|
|
8430
|
+
return;
|
|
8431
|
+
}
|
|
8142
8432
|
if (ev.kind === "reply-delta") {
|
|
8143
8433
|
flushThinking();
|
|
8144
8434
|
replyText += ev.delta;
|
|
@@ -8219,6 +8509,37 @@ var WaitParams = typebox_exports.Object({
|
|
|
8219
8509
|
})
|
|
8220
8510
|
)
|
|
8221
8511
|
});
|
|
8512
|
+
function safeCost(u) {
|
|
8513
|
+
if (u.cost.input > 0 || u.cost.output > 0 || u.cost.cacheRead > 0 || u.cost.cacheWrite > 0 || u.cost.total > 0) {
|
|
8514
|
+
return {
|
|
8515
|
+
input: u.cost.input > 0 ? u.cost.input : 0,
|
|
8516
|
+
output: u.cost.output > 0 ? u.cost.output : 0,
|
|
8517
|
+
cacheRead: u.cost.cacheRead > 0 ? u.cost.cacheRead : 0,
|
|
8518
|
+
cacheWrite: u.cost.cacheWrite > 0 ? u.cost.cacheWrite : 0,
|
|
8519
|
+
total: u.cost.total > 0 ? u.cost.total : 0
|
|
8520
|
+
};
|
|
8521
|
+
}
|
|
8522
|
+
return void 0;
|
|
8523
|
+
}
|
|
8524
|
+
function accumulateUsage(a, b) {
|
|
8525
|
+
if (!a) return b;
|
|
8526
|
+
return {
|
|
8527
|
+
input: a.input + b.input,
|
|
8528
|
+
output: a.output + b.output,
|
|
8529
|
+
cacheRead: a.cacheRead + b.cacheRead,
|
|
8530
|
+
cacheWrite: a.cacheWrite + b.cacheWrite,
|
|
8531
|
+
cacheWrite1h: (a.cacheWrite1h ?? 0) + (b.cacheWrite1h ?? 0),
|
|
8532
|
+
reasoning: (a.reasoning ?? 0) + (b.reasoning ?? 0),
|
|
8533
|
+
totalTokens: a.totalTokens + b.totalTokens,
|
|
8534
|
+
cost: {
|
|
8535
|
+
input: a.cost.input + b.cost.input,
|
|
8536
|
+
output: a.cost.output + b.cost.output,
|
|
8537
|
+
cacheRead: a.cost.cacheRead + b.cost.cacheRead,
|
|
8538
|
+
cacheWrite: a.cost.cacheWrite + b.cost.cacheWrite,
|
|
8539
|
+
total: a.cost.total + b.cost.total
|
|
8540
|
+
}
|
|
8541
|
+
};
|
|
8542
|
+
}
|
|
8222
8543
|
var agentListLine = (name) => {
|
|
8223
8544
|
const def = AGENTS[name];
|
|
8224
8545
|
if (!def) return "";
|
|
@@ -8277,6 +8598,38 @@ function injectedWaitMessage(run, runId, remainingLine) {
|
|
|
8277
8598
|
const fileLine = file ? ` If you need details, read the result file: \`${file}\`.` : "";
|
|
8278
8599
|
return `Delegate \`${runId}\` already delivered its result via a system notification when it finished \u2014 no need to wait on it again.${remainingLine}${fileLine}`;
|
|
8279
8600
|
}
|
|
8601
|
+
function buildWaitResult(run, content, mode = "separate", contentType = "text") {
|
|
8602
|
+
if (run.usage && !run.usageReported) {
|
|
8603
|
+
run.usageReported = true;
|
|
8604
|
+
if (mode === "merged") {
|
|
8605
|
+
const cost = safeCost(run.usage);
|
|
8606
|
+
return {
|
|
8607
|
+
details: void 0,
|
|
8608
|
+
content: [{ type: contentType, text: content }],
|
|
8609
|
+
usage: { ...run.usage, cost: cost ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } }
|
|
8610
|
+
};
|
|
8611
|
+
} else {
|
|
8612
|
+
addDelegateUsage(run.usage);
|
|
8613
|
+
}
|
|
8614
|
+
}
|
|
8615
|
+
return { details: void 0, content: [{ type: contentType, text: content }] };
|
|
8616
|
+
}
|
|
8617
|
+
function buildCancelResult(run, content, mode = "separate") {
|
|
8618
|
+
if (run.usage && !run.usageReported) {
|
|
8619
|
+
run.usageReported = true;
|
|
8620
|
+
if (mode === "merged") {
|
|
8621
|
+
const cost = safeCost(run.usage);
|
|
8622
|
+
return {
|
|
8623
|
+
details: void 0,
|
|
8624
|
+
content: [{ type: "text", text: content }],
|
|
8625
|
+
usage: { ...run.usage, cost: cost ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } }
|
|
8626
|
+
};
|
|
8627
|
+
} else {
|
|
8628
|
+
addDelegateUsage(run.usage);
|
|
8629
|
+
}
|
|
8630
|
+
}
|
|
8631
|
+
return { details: void 0, content: [{ type: "text", text: content }] };
|
|
8632
|
+
}
|
|
8280
8633
|
function makeDelegateWaitTool(_pi) {
|
|
8281
8634
|
return {
|
|
8282
8635
|
name: "acp_delegate_wait",
|
|
@@ -8294,21 +8647,22 @@ function makeDelegateWaitTool(_pi) {
|
|
|
8294
8647
|
if (!run) {
|
|
8295
8648
|
return { details: void 0, content: [{ type: "text", text: `No delegate run with runId \`${args.runId}\`. It may have already been reported or never existed.` }] };
|
|
8296
8649
|
}
|
|
8650
|
+
const displayMode = delegateDisplayUsage;
|
|
8297
8651
|
if (run.status === "cancelled") {
|
|
8298
8652
|
run.consumed = true;
|
|
8299
|
-
return
|
|
8653
|
+
return buildWaitResult(run, `Delegate \`${args.runId}\` was cancelled (no result).${remainingLineForWait(args.runId)}`, displayMode);
|
|
8300
8654
|
}
|
|
8301
8655
|
if (run.status !== "running") {
|
|
8302
8656
|
const dedup = injectedWaitMessage(run, args.runId, remainingLineForWait(args.runId));
|
|
8303
8657
|
if (dedup) {
|
|
8304
8658
|
run.consumed = true;
|
|
8305
|
-
return
|
|
8659
|
+
return buildWaitResult(run, dedup, displayMode);
|
|
8306
8660
|
}
|
|
8307
8661
|
run.consumed = true;
|
|
8308
8662
|
if (!run.result) {
|
|
8309
|
-
return
|
|
8663
|
+
return buildWaitResult(run, `Delegate \`${args.runId}\` finished but no result is available (persist error).`, displayMode);
|
|
8310
8664
|
}
|
|
8311
|
-
return
|
|
8665
|
+
return buildWaitResult(run, formatRunResult(run), displayMode);
|
|
8312
8666
|
}
|
|
8313
8667
|
const timeoutMs = Math.min(
|
|
8314
8668
|
Math.max(args.timeout ?? WAIT_TIMEOUT_MS_DEFAULT, 1e3),
|
|
@@ -8320,28 +8674,28 @@ function makeDelegateWaitTool(_pi) {
|
|
|
8320
8674
|
return new Promise((resolve2) => {
|
|
8321
8675
|
let settled = false;
|
|
8322
8676
|
let timer2;
|
|
8323
|
-
const finish = (
|
|
8677
|
+
const finish = (result) => {
|
|
8324
8678
|
if (settled) return;
|
|
8325
8679
|
settled = true;
|
|
8326
8680
|
run.waiter = void 0;
|
|
8327
8681
|
if (timer2) clearTimeout(timer2);
|
|
8328
8682
|
signal?.removeEventListener("abort", onAbort);
|
|
8329
|
-
resolve2(
|
|
8683
|
+
resolve2(result);
|
|
8330
8684
|
};
|
|
8331
8685
|
const onAbort = () => {
|
|
8332
|
-
finish(`Aborted; delegate \`${args.runId}\` is still running in the background. A notification will be injected when it finishes.`);
|
|
8686
|
+
finish({ details: void 0, content: [{ type: "text", text: `Aborted; delegate \`${args.runId}\` is still running in the background. A notification will be injected when it finishes.` }] });
|
|
8333
8687
|
};
|
|
8334
8688
|
run.waiter = () => {
|
|
8335
8689
|
run.consumed = true;
|
|
8336
8690
|
if (run.status === "cancelled") {
|
|
8337
|
-
finish(`Delegate \`${run.runId}\` was cancelled (no result).${remainingLineForWait(run.runId)}
|
|
8691
|
+
finish(buildWaitResult(run, `Delegate \`${run.runId}\` was cancelled (no result).${remainingLineForWait(run.runId)}`, displayMode));
|
|
8338
8692
|
return;
|
|
8339
8693
|
}
|
|
8340
|
-
finish(formatRunResult(run));
|
|
8694
|
+
finish(buildWaitResult(run, formatRunResult(run), displayMode));
|
|
8341
8695
|
};
|
|
8342
8696
|
signal?.addEventListener("abort", onAbort);
|
|
8343
8697
|
timer2 = setTimeout(
|
|
8344
|
-
() => finish(`Failed: delegate \`${args.runId}\` result not ready after ${Math.round(timeoutMs / 1e3)}s. Do NOT keep waiting or retry \u2014 go do other work now. The run continues in the background and a completion notification (with the result file path) will be injected into the chat when it finishes.`),
|
|
8698
|
+
() => finish({ details: void 0, content: [{ type: "text", text: `Failed: delegate \`${args.runId}\` result not ready after ${Math.round(timeoutMs / 1e3)}s. Do NOT keep waiting or retry \u2014 go do other work now. The run continues in the background and a completion notification (with the result file path) will be injected into the chat when it finishes.` }] }),
|
|
8345
8699
|
timeoutMs
|
|
8346
8700
|
);
|
|
8347
8701
|
});
|
|
@@ -8360,16 +8714,10 @@ function makeDelegateCancelTool(_pi) {
|
|
|
8360
8714
|
const { runId } = params;
|
|
8361
8715
|
const run = runs.get(runId);
|
|
8362
8716
|
if (!run) {
|
|
8363
|
-
return {
|
|
8364
|
-
details: void 0,
|
|
8365
|
-
content: [{ type: "text", text: `Unknown runId "${runId}".` }]
|
|
8366
|
-
};
|
|
8717
|
+
return { details: void 0, content: [{ type: "text", text: `Unknown runId "${runId}".` }] };
|
|
8367
8718
|
}
|
|
8368
8719
|
if (run.status !== "running") {
|
|
8369
|
-
return {
|
|
8370
|
-
details: void 0,
|
|
8371
|
-
content: [{ type: "text", text: `Run ${runId} already ${run.status} (no action).` }]
|
|
8372
|
-
};
|
|
8720
|
+
return buildCancelResult(run, `Run ${runId} already ${run.status} (no action).`);
|
|
8373
8721
|
}
|
|
8374
8722
|
run.status = "cancelled";
|
|
8375
8723
|
run.consumed = true;
|
|
@@ -8380,10 +8728,8 @@ function makeDelegateCancelTool(_pi) {
|
|
|
8380
8728
|
logError("delegate", { event: "cancel-kill-error", runId, error: String(err) });
|
|
8381
8729
|
}
|
|
8382
8730
|
delegateStatusWidget.poke();
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
content: [{ type: "text", text: `Cancelled ${runId} (${run.agent}).` }]
|
|
8386
|
-
};
|
|
8731
|
+
const displayMode = delegateDisplayUsage;
|
|
8732
|
+
return buildCancelResult(run, `Cancelled ${runId} (${run.agent}).`, displayMode);
|
|
8387
8733
|
}
|
|
8388
8734
|
};
|
|
8389
8735
|
}
|
|
@@ -8432,11 +8778,11 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
8432
8778
|
{
|
|
8433
8779
|
isSettled: () => settled || run.status !== "running",
|
|
8434
8780
|
onKill: (reason) => {
|
|
8435
|
-
run.timedOut = reason;
|
|
8781
|
+
if (!run.agentSettled) run.timedOut = reason;
|
|
8436
8782
|
debug.event("delegate-watchdog", { runId, reason });
|
|
8437
8783
|
},
|
|
8438
8784
|
onEofGrace: () => {
|
|
8439
|
-
run.timedOut = "output ended but process did not exit";
|
|
8785
|
+
if (!run.agentSettled) run.timedOut = "output ended but process did not exit";
|
|
8440
8786
|
debug.event("delegate-eof-grace", { runId, ms: EOF_GRACE_MS });
|
|
8441
8787
|
}
|
|
8442
8788
|
},
|
|
@@ -8453,7 +8799,16 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
8453
8799
|
});
|
|
8454
8800
|
let stdoutBuf = "";
|
|
8455
8801
|
const applier = makeEventApplier(
|
|
8456
|
-
{
|
|
8802
|
+
{
|
|
8803
|
+
showThinking: args.showThinking === true,
|
|
8804
|
+
onUsage: (u) => {
|
|
8805
|
+
run.usage = accumulateUsage(run.usage, u);
|
|
8806
|
+
},
|
|
8807
|
+
onSettled: () => {
|
|
8808
|
+
run.agentSettled = true;
|
|
8809
|
+
watchdog.settledGrace(SETTLED_GRACE_MS, KILL_GRACE_MS, "agent settled but process did not exit");
|
|
8810
|
+
}
|
|
8811
|
+
},
|
|
8457
8812
|
{ reply: replyStream, activity: activityStream }
|
|
8458
8813
|
);
|
|
8459
8814
|
child.stdout?.on("data", (c) => {
|
|
@@ -8527,7 +8882,11 @@ async function runDelegate(pi, args, ctx, signal) {
|
|
|
8527
8882
|
delegateStatusWidget.poke();
|
|
8528
8883
|
return;
|
|
8529
8884
|
}
|
|
8530
|
-
const
|
|
8885
|
+
const mode = delegateDisplayUsage;
|
|
8886
|
+
const injected = injectResult(pi, args.agent, runId, args.task, code, file2, run.timedOut, run.usage, mode, run.usageReported);
|
|
8887
|
+
if (run.usage && !run.usageReported && (mode === "separate" || injected)) {
|
|
8888
|
+
run.usageReported = true;
|
|
8889
|
+
}
|
|
8531
8890
|
run.injected = injected;
|
|
8532
8891
|
debug.event("delegate-done", { runId, code, status: run.status, injected, outLen: output.length, file: file2 });
|
|
8533
8892
|
logInfo("delegate", { event: "done", runId, agent: args.agent, code, status: run.status, injected, outLen: output.length, file: file2 });
|
|
@@ -8648,7 +9007,7 @@ function formatSyncResult(agent, runId, task, r, file) {
|
|
|
8648
9007
|
const body = r.timedOut ? "(timed out)" : r.stderr.trim() || "(no stderr)";
|
|
8649
9008
|
return formatPayload(header, file, task, body);
|
|
8650
9009
|
}
|
|
8651
|
-
function injectResult(pi, agent, runId, task, code, file, timedOut) {
|
|
9010
|
+
function injectResult(pi, agent, runId, task, code, file, timedOut, usage, mode = "separate", usageAlreadyReported) {
|
|
8652
9011
|
const send = pi.sendUserMessage;
|
|
8653
9012
|
if (typeof send !== "function") {
|
|
8654
9013
|
debug.event("delegate-inject-skipped", { runId, reason: "sendUserMessage unavailable" });
|
|
@@ -8659,7 +9018,37 @@ function injectResult(pi, agent, runId, task, code, file, timedOut) {
|
|
|
8659
9018
|
const remaining = Array.from(runs.values()).filter((r) => r.status === "running").length;
|
|
8660
9019
|
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.";
|
|
8661
9020
|
const timeoutNote = timedOut ? ` (timed out: ${timedOut})` : "";
|
|
8662
|
-
|
|
9021
|
+
let usageNote = "";
|
|
9022
|
+
if (mode === "separate") {
|
|
9023
|
+
if (usage && !usageAlreadyReported) {
|
|
9024
|
+
addDelegateUsage(usage);
|
|
9025
|
+
}
|
|
9026
|
+
const totalUsage = getDelegateUsage();
|
|
9027
|
+
if (totalUsage) {
|
|
9028
|
+
const cost = totalUsage.cost.total;
|
|
9029
|
+
const costStr = cost > 0 ? ` ($${cost.toFixed(4)})` : "";
|
|
9030
|
+
usageNote = `
|
|
9031
|
+
|
|
9032
|
+
\u2500\u2500 Session delegate usage (excluded from main totals) \u2500\u2500
|
|
9033
|
+
Tokens: ${totalUsage.input.toLocaleString()} in, ${totalUsage.output.toLocaleString()} out (${totalUsage.totalTokens.toLocaleString()} total)${costStr}`;
|
|
9034
|
+
}
|
|
9035
|
+
} else if (usage) {
|
|
9036
|
+
const lines = [];
|
|
9037
|
+
if (usage.totalTokens) lines.push(`tokens=${usage.totalTokens.toLocaleString()}`);
|
|
9038
|
+
if (usage.input || usage.output) lines.push(`in=${usage.input.toLocaleString()} out=${usage.output.toLocaleString()}`);
|
|
9039
|
+
if (usage.cacheRead) lines.push(`cache_read=${usage.cacheRead.toLocaleString()}`);
|
|
9040
|
+
if (usage.cacheWrite) lines.push(`cache_write=${usage.cacheWrite.toLocaleString()}`);
|
|
9041
|
+
if (usage.cost && typeof usage.cost === "object") {
|
|
9042
|
+
const c = usage.cost;
|
|
9043
|
+
if (typeof c.total === "number" && c.total > 0) {
|
|
9044
|
+
lines.push(`cost=$${c.total.toFixed(4)}`);
|
|
9045
|
+
} else if (typeof c.input === "number" && c.input > 0 || typeof c.output === "number" && c.output > 0) {
|
|
9046
|
+
lines.push(`cost=${JSON.stringify(c)}`);
|
|
9047
|
+
}
|
|
9048
|
+
}
|
|
9049
|
+
if (lines.length) usageNote = ` Usage: ${lines.join(", ")}.`;
|
|
9050
|
+
}
|
|
9051
|
+
const header = `[acp_delegate ${status}] **${agent}** (runId \`${runId}\`, exit ${code ?? "?"})${timeoutNote}${remainingLine}${usageNote} 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.`;
|
|
8663
9052
|
const text = formatPayload(header, file, task);
|
|
8664
9053
|
try {
|
|
8665
9054
|
send.call(pi, text, { deliverAs: "followUp" });
|
|
@@ -8710,6 +9099,90 @@ function truncate2(s, n) {
|
|
|
8710
9099
|
return s.slice(0, n - 1) + "\u2026";
|
|
8711
9100
|
}
|
|
8712
9101
|
|
|
9102
|
+
// src/status-tool.ts
|
|
9103
|
+
var StatusParams = typebox_exports.Object({
|
|
9104
|
+
scope: typebox_exports.Optional(typebox_exports.Union([typebox_exports.Literal("compressed"), typebox_exports.Literal("uncompressed")], { description: '"compressed" = drill into blocks; "uncompressed" = show visible messages/ranges. Default: overview.' })),
|
|
9105
|
+
view: typebox_exports.Optional(typebox_exports.Union([typebox_exports.Literal("ranges"), typebox_exports.Literal("messages")], { description: 'For uncompressed scope: "ranges" (default) or "messages" (per-message listing).' })),
|
|
9106
|
+
tool: typebox_exports.Optional(typebox_exports.String({ description: 'Filter by tool name (e.g. "bash", "read"). Only for uncompressed+messages.' })),
|
|
9107
|
+
sort: typebox_exports.Optional(typebox_exports.Union([typebox_exports.Literal("size"), typebox_exports.Literal("time"), typebox_exports.Literal("tool"), typebox_exports.Literal("age")], { description: "Sort order. Default: size." })),
|
|
9108
|
+
limit: typebox_exports.Optional(typebox_exports.Number({ description: "Max items to show (default: 30)." }))
|
|
9109
|
+
});
|
|
9110
|
+
function makeStatusTool(runtime) {
|
|
9111
|
+
return {
|
|
9112
|
+
name: "acp_status",
|
|
9113
|
+
label: "ACP Status",
|
|
9114
|
+
description: "Context status: overview, compressed blocks, or uncompressed ranges/messages. No args = overview + totals + compressible ranges. scope:'uncompressed' + view:'messages' for per-message listing. scope:'compressed' for block drilldown.",
|
|
9115
|
+
promptSnippet: 'acp_status({}) or acp_status({ scope: "uncompressed", view: "messages" })',
|
|
9116
|
+
promptGuidelines: [
|
|
9117
|
+
"Call with no args for a quick overview of context usage.",
|
|
9118
|
+
"Use scope:'uncompressed' to find the largest compressible ranges.",
|
|
9119
|
+
"Use scope:'compressed' to inspect existing compression blocks."
|
|
9120
|
+
],
|
|
9121
|
+
parameters: StatusParams,
|
|
9122
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
9123
|
+
let result;
|
|
9124
|
+
try {
|
|
9125
|
+
result = await handleStatus(params, runtime, ctx);
|
|
9126
|
+
} catch (e) {
|
|
9127
|
+
logThrow("status", e, { sid: ctx.sessionManager.getSessionId(), scope: params.scope ?? null });
|
|
9128
|
+
throw e;
|
|
9129
|
+
}
|
|
9130
|
+
return { details: void 0, content: [{ type: "text", text: result }] };
|
|
9131
|
+
}
|
|
9132
|
+
};
|
|
9133
|
+
}
|
|
9134
|
+
async function handleStatus(args, runtime, ctx) {
|
|
9135
|
+
const { state, coreMessages } = await runtime.stateFor(ctx);
|
|
9136
|
+
const config = runtime.configFor(ctx);
|
|
9137
|
+
const tokenCount = estimateTokens(coreMessages, collectCoveredMessageIds(state));
|
|
9138
|
+
const realUsage = ctx.getContextUsage?.();
|
|
9139
|
+
const turn = runtime.core.processTurn({
|
|
9140
|
+
messages: coreMessages,
|
|
9141
|
+
state,
|
|
9142
|
+
config,
|
|
9143
|
+
tokenCount: realUsage?.tokens && realUsage.tokens > 0 ? realUsage.tokens : tokenCount
|
|
9144
|
+
});
|
|
9145
|
+
const processed = turn.messages;
|
|
9146
|
+
const base = buildStatusReport(turn.state, processed, defaultCountTokens, {
|
|
9147
|
+
scope: args.scope,
|
|
9148
|
+
view: args.view,
|
|
9149
|
+
tool: args.tool,
|
|
9150
|
+
sort: args.sort,
|
|
9151
|
+
limit: args.limit
|
|
9152
|
+
});
|
|
9153
|
+
if (args.scope) return base;
|
|
9154
|
+
const nudge = turn.nudge;
|
|
9155
|
+
const ranges = nudge?.compressibleRanges ?? [];
|
|
9156
|
+
const protectedRanges = nudge?.protectedRanges ?? [];
|
|
9157
|
+
const extra = [];
|
|
9158
|
+
if (nudge) {
|
|
9159
|
+
extra.push("");
|
|
9160
|
+
extra.push(
|
|
9161
|
+
nudge.shouldInject ? `Nudge: ACTIVE \u2014 ${nudge.reason}` : `Nudge: idle \u2014 ${nudge.reason}`
|
|
9162
|
+
);
|
|
9163
|
+
}
|
|
9164
|
+
if (ranges.length > 0 || protectedRanges.length > 0) {
|
|
9165
|
+
extra.push("");
|
|
9166
|
+
extra.push(formatRanges(ranges, protectedRanges));
|
|
9167
|
+
}
|
|
9168
|
+
const delegateUsage = getDelegateUsage();
|
|
9169
|
+
if (delegateUsage && delegateUsage.totalTokens > 0) {
|
|
9170
|
+
extra.push("");
|
|
9171
|
+
const cost = delegateUsage.cost.total;
|
|
9172
|
+
const costStr = cost > 0 ? ` ($${cost.toFixed(4)})` : "";
|
|
9173
|
+
extra.push("\u2500\u2500 Session delegate usage (excluded from main totals) \u2500\u2500");
|
|
9174
|
+
extra.push(`Tokens: ${delegateUsage.input.toLocaleString()} in, ${delegateUsage.output.toLocaleString()} out (${delegateUsage.totalTokens.toLocaleString()} total)${costStr}`);
|
|
9175
|
+
} else if (runtime.adapter.displayUsage === "merged") {
|
|
9176
|
+
extra.push("");
|
|
9177
|
+
extra.push("merged mode: delegate usage is included in main session totals.");
|
|
9178
|
+
} else {
|
|
9179
|
+
extra.push("");
|
|
9180
|
+
extra.push("Delegate usage: none this session.");
|
|
9181
|
+
}
|
|
9182
|
+
return extra.length > 0 ? `${base}
|
|
9183
|
+
${extra.join("\n")}` : base;
|
|
9184
|
+
}
|
|
9185
|
+
|
|
8713
9186
|
// src/compat.ts
|
|
8714
9187
|
function normalizeSystemPrompt(input) {
|
|
8715
9188
|
if (input === void 0) return "";
|
|
@@ -8740,7 +9213,7 @@ function makeCommands(runtime) {
|
|
|
8740
9213
|
{
|
|
8741
9214
|
name: "acp-status",
|
|
8742
9215
|
options: {
|
|
8743
|
-
description: "Detailed ACP status (block tiers, token breakdown).",
|
|
9216
|
+
description: "Detailed ACP status (block tiers, token breakdown, delegate usage).",
|
|
8744
9217
|
handler: async (_args, ctx) => ctx.ui.notify(await statusReport(runtime, ctx))
|
|
8745
9218
|
}
|
|
8746
9219
|
},
|
|
@@ -8795,9 +9268,7 @@ ${text}`);
|
|
|
8795
9268
|
];
|
|
8796
9269
|
}
|
|
8797
9270
|
function fmtTokens(n) {
|
|
8798
|
-
|
|
8799
|
-
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
8800
|
-
return String(n);
|
|
9271
|
+
return formatCompactTokens(n);
|
|
8801
9272
|
}
|
|
8802
9273
|
function bar(value, total, width = 20) {
|
|
8803
9274
|
if (total === 0) return "";
|
|
@@ -8822,7 +9293,7 @@ async function statusReport(runtime, ctx) {
|
|
|
8822
9293
|
const activeBlocksList = state.blocks.filter((b) => b.active);
|
|
8823
9294
|
const totalBlocksList = state.blocks;
|
|
8824
9295
|
const lines = [];
|
|
8825
|
-
const versionStr = "0.1.
|
|
9296
|
+
const versionStr = "0.1.35" ? `billion-context-pi@${"0.1.35"}` : "";
|
|
8826
9297
|
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");
|
|
8827
9298
|
lines.push("\u2502 ACP Context Analysis \u2502");
|
|
8828
9299
|
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");
|
|
@@ -8885,6 +9356,15 @@ async function statusReport(runtime, ctx) {
|
|
|
8885
9356
|
lines.push("Blocks: none (nothing compressed yet)");
|
|
8886
9357
|
}
|
|
8887
9358
|
lines.push("");
|
|
9359
|
+
const delegateUsage = getDelegateUsage();
|
|
9360
|
+
if (delegateUsage && delegateUsage.totalTokens > 0) {
|
|
9361
|
+
lines.push("");
|
|
9362
|
+
const cost = delegateUsage.cost.total;
|
|
9363
|
+
const costStr = cost > 0 ? ` ($${cost.toFixed(4)})` : "";
|
|
9364
|
+
lines.push("\u2500\u2500 Session delegate usage (excluded from main totals) \u2500\u2500");
|
|
9365
|
+
lines.push(`Tokens: ${delegateUsage.input.toLocaleString()} in, ${delegateUsage.output.toLocaleString()} out (${delegateUsage.totalTokens.toLocaleString()} total)${costStr}`);
|
|
9366
|
+
}
|
|
9367
|
+
lines.push("");
|
|
8888
9368
|
lines.push("Tag visibility: tags injected to LLM only (deep copy), not persisted in session, not shown in terminal.");
|
|
8889
9369
|
return lines.join("\n");
|
|
8890
9370
|
}
|
|
@@ -9189,7 +9669,7 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
9189
9669
|
const data = await res.json();
|
|
9190
9670
|
const latest = data.version;
|
|
9191
9671
|
if (!latest) return;
|
|
9192
|
-
const current = runtimeVersion ?? "0.1.
|
|
9672
|
+
const current = runtimeVersion ?? "0.1.35";
|
|
9193
9673
|
const hasUpdate = isNewer(latest, current);
|
|
9194
9674
|
debug.event("update-check", {
|
|
9195
9675
|
current,
|
|
@@ -9382,7 +9862,7 @@ async function loadUserConfig(cwd) {
|
|
|
9382
9862
|
function join8(...parts) {
|
|
9383
9863
|
return path3.join(...parts);
|
|
9384
9864
|
}
|
|
9385
|
-
var KNOWN = /* @__PURE__ */ new Set(["debug", "autoUpdate", "modelContextLimit", "delegate", "toolBashDefaultTimeout", "toolOutputMaxBytes"]);
|
|
9865
|
+
var KNOWN = /* @__PURE__ */ new Set(["debug", "autoUpdate", "modelContextLimit", "delegate", "displayUsage", "toolBashDefaultTimeout", "toolOutputMaxBytes"]);
|
|
9386
9866
|
function pickKnown(parsed) {
|
|
9387
9867
|
const out = {};
|
|
9388
9868
|
for (const [k, v] of Object.entries(parsed)) {
|
|
@@ -9428,11 +9908,14 @@ function wireSessionLifecycle(pi, runtime) {
|
|
|
9428
9908
|
pi.on("session_start", async (_event, ctx) => {
|
|
9429
9909
|
runtime.store.invalidate();
|
|
9430
9910
|
runtime.clearNudgeTracking();
|
|
9911
|
+
resetDelegateUsage();
|
|
9912
|
+
setDelegateDisplayUsage("separate");
|
|
9431
9913
|
const sid = ctx.sessionManager.getSessionId();
|
|
9432
|
-
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.
|
|
9914
|
+
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.1.35" : null });
|
|
9433
9915
|
try {
|
|
9434
9916
|
const user = await loadUserConfig(ctx.cwd);
|
|
9435
9917
|
runtime.setAdapter(applyUserConfig(runtime.adapter, user));
|
|
9918
|
+
setDelegateDisplayUsage(runtime.adapter.displayUsage ?? "separate");
|
|
9436
9919
|
if (runtime.adapter.debug !== void 0) setDebugEnabled(runtime.adapter.debug);
|
|
9437
9920
|
} catch (e) {
|
|
9438
9921
|
logThrow("config", e, { sid, phase: "session_start" });
|