billion-context-omp 0.2.6 → 0.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/config.d.ts +14 -8
- package/dist/index.js +980 -281
- package/dist/index.js.map +1 -1
- package/dist/messages.d.ts +19 -0
- package/dist/runtime.d.ts +16 -1
- package/dist/transform-mode.d.ts +5 -0
- package/dist/wire-fold.d.ts +140 -0
- package/package.json +7 -7
- package/dist/wire-transform.d.ts +0 -71
package/dist/index.js
CHANGED
|
@@ -70,6 +70,7 @@ function createInitialState() {
|
|
|
70
70
|
return {
|
|
71
71
|
blocks: [],
|
|
72
72
|
messageRefs: { byRaw: {}, byRef: {} },
|
|
73
|
+
tokenSnapshot: {},
|
|
73
74
|
nudge: {
|
|
74
75
|
lastPerMessageNudgeTokens: 0,
|
|
75
76
|
lastNudgeShownTokens: 0,
|
|
@@ -239,11 +240,23 @@ function syncBlocks(messages, state) {
|
|
|
239
240
|
byRaw: { ...state.messageRefs.byRaw },
|
|
240
241
|
byRef: { ...state.messageRefs.byRef }
|
|
241
242
|
},
|
|
243
|
+
// Snapshot is keyed by ref with primitive values — shallow copy suffices.
|
|
244
|
+
tokenSnapshot: { ...state.tokenSnapshot ?? {} },
|
|
242
245
|
nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },
|
|
243
246
|
stats: { ...state.stats },
|
|
244
247
|
nextBlockId: state.nextBlockId,
|
|
245
248
|
nextRunId: state.nextRunId
|
|
246
249
|
};
|
|
250
|
+
const liveRefs = new Set(
|
|
251
|
+
messages.map((m) => result.messageRefs.byRaw[m.id]).filter((r) => typeof r === "string")
|
|
252
|
+
);
|
|
253
|
+
if (Object.keys(result.tokenSnapshot).length !== liveRefs.size) {
|
|
254
|
+
const pruned = {};
|
|
255
|
+
for (const [ref, n] of Object.entries(result.tokenSnapshot)) {
|
|
256
|
+
if (liveRefs.has(ref)) pruned[ref] = n;
|
|
257
|
+
}
|
|
258
|
+
result.tokenSnapshot = pruned;
|
|
259
|
+
}
|
|
247
260
|
const consumedBlockIds = /* @__PURE__ */ new Set();
|
|
248
261
|
for (const block of result.blocks) {
|
|
249
262
|
for (const consumedId of block.directBlockIds) {
|
|
@@ -718,7 +731,7 @@ var TAG_CLOSE = LT + "/acp" + GT;
|
|
|
718
731
|
function acpTag(ref, tokens, type5) {
|
|
719
732
|
return TAG_OPEN + 'tokens="' + formatTokens(tokens) + '" type="' + type5 + '"' + GT + ref + TAG_CLOSE;
|
|
720
733
|
}
|
|
721
|
-
function renderMessage(message, map, countTokens, strategy) {
|
|
734
|
+
function renderMessage(message, map, countTokens, strategy, snapshot = null) {
|
|
722
735
|
const ref = refForRaw(map, message.id);
|
|
723
736
|
if (!ref || ref === BLOCKED_REF) return message;
|
|
724
737
|
if (strategy === "none") return message;
|
|
@@ -729,26 +742,33 @@ function renderMessage(message, map, countTokens, strategy) {
|
|
|
729
742
|
"^" + escapeRegex(TAG_OPEN) + "[^>]*" + GT + escapeRegex(ref) + escapeRegex(TAG_CLOSE) + "\\n?"
|
|
730
743
|
);
|
|
731
744
|
const cleanText = (message.text || "").replace(ownTagRe, "");
|
|
732
|
-
const tokens = countTokens(cleanText);
|
|
745
|
+
const tokens = snapshot ? snapshot[ref] ?? (snapshot[ref] = countTokens(cleanText)) : countTokens(cleanText);
|
|
733
746
|
const type5 = classifyType(message);
|
|
734
747
|
const prefix = acpTag(ref, tokens, type5) + "\n";
|
|
735
748
|
if (!cleanText) return { ...message, text: prefix };
|
|
736
749
|
return { ...message, text: prefix + cleanText };
|
|
737
750
|
}
|
|
738
|
-
function
|
|
751
|
+
function renderWithSnapshot(messages, state, countTokens = (text) => Math.ceil(text.length / 4), strategy = "all") {
|
|
739
752
|
const map = state.messageRefs;
|
|
740
|
-
|
|
741
|
-
|
|
753
|
+
const snapshot = { ...state.tokenSnapshot ?? {} };
|
|
754
|
+
const rendered = messages.map(
|
|
755
|
+
(message) => renderMessage(message, map, countTokens, strategy, snapshot)
|
|
742
756
|
);
|
|
757
|
+
return { messages: rendered, tokenSnapshot: snapshot };
|
|
743
758
|
}
|
|
744
759
|
function createRenderRefsNode(strategy) {
|
|
745
760
|
return {
|
|
746
761
|
name: "render-refs",
|
|
747
762
|
run(io, ctx) {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
763
|
+
const { messages, tokenSnapshot } = renderWithSnapshot(
|
|
764
|
+
io.messages,
|
|
765
|
+
io.state,
|
|
766
|
+
ctx.countTokens,
|
|
767
|
+
strategy
|
|
768
|
+
);
|
|
769
|
+
const prev = io.state.tokenSnapshot;
|
|
770
|
+
const changed = !prev || Object.keys(tokenSnapshot).length !== Object.keys(prev).length;
|
|
771
|
+
return changed ? { ...io, messages, state: { ...io.state, tokenSnapshot } } : { ...io, messages };
|
|
752
772
|
}
|
|
753
773
|
};
|
|
754
774
|
}
|
|
@@ -944,6 +964,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
|
|
|
944
964
|
ref,
|
|
945
965
|
refNum: rn,
|
|
946
966
|
tokens: countTokens(msg.text ?? ""),
|
|
967
|
+
chars: (msg.text ?? "").length,
|
|
947
968
|
isTool: isToolMessage(msg),
|
|
948
969
|
isUser: msg.role === "user"
|
|
949
970
|
});
|
|
@@ -964,6 +985,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
|
|
|
964
985
|
endRef: info.ref,
|
|
965
986
|
count: 1,
|
|
966
987
|
tokens: info.tokens,
|
|
988
|
+
chars: info.chars,
|
|
967
989
|
toolPct: info.isTool ? 100 : 0,
|
|
968
990
|
textPct: info.isTool ? 0 : 100
|
|
969
991
|
};
|
|
@@ -971,6 +993,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
|
|
|
971
993
|
cur.endRef = info.ref;
|
|
972
994
|
cur.count++;
|
|
973
995
|
cur.tokens += info.tokens;
|
|
996
|
+
cur.chars = (cur.chars ?? 0) + info.chars;
|
|
974
997
|
if (info.isTool) {
|
|
975
998
|
cur.toolPct = Math.round((cur.toolPct * (cur.count - 1) + 100) / cur.count);
|
|
976
999
|
} else {
|
|
@@ -1018,6 +1041,7 @@ function mergeBatch(batch) {
|
|
|
1018
1041
|
const last = batch[batch.length - 1];
|
|
1019
1042
|
const count = batch.reduce((s, r) => s + r.count, 0);
|
|
1020
1043
|
const tokens = batch.reduce((s, r) => s + r.tokens, 0);
|
|
1044
|
+
const chars = batch.reduce((s, r) => s + rangeChars(r), 0);
|
|
1021
1045
|
const toolPct = Math.round(
|
|
1022
1046
|
batch.reduce((s, r) => s + r.toolPct * r.count, 0) / count
|
|
1023
1047
|
);
|
|
@@ -1026,6 +1050,7 @@ function mergeBatch(batch) {
|
|
|
1026
1050
|
endRef: last.endRef,
|
|
1027
1051
|
count,
|
|
1028
1052
|
tokens,
|
|
1053
|
+
chars,
|
|
1029
1054
|
toolPct,
|
|
1030
1055
|
textPct: 100 - toolPct
|
|
1031
1056
|
};
|
|
@@ -1034,16 +1059,21 @@ function mergeBatch(batch) {
|
|
|
1034
1059
|
}
|
|
1035
1060
|
return merged;
|
|
1036
1061
|
}
|
|
1062
|
+
function rangeChars(r) {
|
|
1063
|
+
return r.chars ?? r.tokens * 4;
|
|
1064
|
+
}
|
|
1037
1065
|
function mergeRangesToThreshold(ranges, minChars) {
|
|
1038
1066
|
if (minChars <= 0 || ranges.length === 0) return ranges;
|
|
1039
1067
|
const result = [];
|
|
1040
1068
|
let batch = [];
|
|
1069
|
+
let batchChars = 0;
|
|
1041
1070
|
for (const r of ranges) {
|
|
1042
1071
|
batch.push(r);
|
|
1043
|
-
|
|
1044
|
-
if (
|
|
1072
|
+
batchChars += rangeChars(r);
|
|
1073
|
+
if (batchChars >= minChars) {
|
|
1045
1074
|
result.push(mergeBatch(batch));
|
|
1046
1075
|
batch = [];
|
|
1076
|
+
batchChars = 0;
|
|
1047
1077
|
}
|
|
1048
1078
|
}
|
|
1049
1079
|
if (batch.length > 0) {
|
|
@@ -1631,7 +1661,7 @@ function resolveAdaptiveGrowth(modelContextLimit, nudge) {
|
|
|
1631
1661
|
function pendingByTier(state, recommendation, countTokens, minCompressRange) {
|
|
1632
1662
|
const out = {};
|
|
1633
1663
|
const merged = recommendation?.recommendedRanges ?? [];
|
|
1634
|
-
const effective = minCompressRange > 0 ? merged.filter((r) => r.tokens * 4 >= minCompressRange) : merged;
|
|
1664
|
+
const effective = minCompressRange > 0 ? merged.filter((r) => (r.chars ?? r.tokens * 4) >= minCompressRange) : merged;
|
|
1635
1665
|
out[1] = { pending: effective.reduce((s, r) => s + r.tokens, 0), targetBlocks: [] };
|
|
1636
1666
|
const active = activeBlocks(state);
|
|
1637
1667
|
const t1 = active.filter((b) => b.tier === 1);
|
|
@@ -1793,6 +1823,7 @@ function cloneState(state) {
|
|
|
1793
1823
|
byRaw: { ...state.messageRefs.byRaw },
|
|
1794
1824
|
byRef: { ...state.messageRefs.byRef }
|
|
1795
1825
|
},
|
|
1826
|
+
tokenSnapshot: { ...state.tokenSnapshot ?? {} },
|
|
1796
1827
|
nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },
|
|
1797
1828
|
stats: { ...state.stats },
|
|
1798
1829
|
nextBlockId: state.nextBlockId,
|
|
@@ -2757,8 +2788,12 @@ function resolveConfig(adapter, liveContextLimit) {
|
|
|
2757
2788
|
if (c?.maxContextLimit !== void 0) config.nudge.maxContextLimitPct = parsePercent(c.maxContextLimit);
|
|
2758
2789
|
if (c?.emergencyThresholdPercent !== void 0) {
|
|
2759
2790
|
const pct2 = parsePercent(c.emergencyThresholdPercent);
|
|
2760
|
-
|
|
2761
|
-
|
|
2791
|
+
if (pct2 <= 0) {
|
|
2792
|
+
logWarn("config", { event: "emergency-threshold-ignored", value: String(c.emergencyThresholdPercent), reason: "zero threshold would truncate every turn" });
|
|
2793
|
+
} else {
|
|
2794
|
+
config.nudge.emergencyThresholdPct = pct2;
|
|
2795
|
+
config.truncate.threshold = pct2;
|
|
2796
|
+
}
|
|
2762
2797
|
}
|
|
2763
2798
|
if (c?.nudgeGrowthTokens !== void 0) {
|
|
2764
2799
|
config.nudge.growthFloor = c.nudgeGrowthTokens;
|
|
@@ -2863,8 +2898,396 @@ When context usage passes a threshold, the system appends a breakdown showing wh
|
|
|
2863
2898
|
`;
|
|
2864
2899
|
}
|
|
2865
2900
|
|
|
2866
|
-
// src/
|
|
2901
|
+
// src/transform-mode.ts
|
|
2902
|
+
import { VERSION } from "@oh-my-pi/pi-utils";
|
|
2903
|
+
var PROVIDER_VIABLE_APIS = /* @__PURE__ */ new Set(["anthropic-messages", "ollama-chat"]);
|
|
2904
|
+
var OPENAI_COMPLETIONS_VIABLE_FROM = [17, 3, 8];
|
|
2905
|
+
function hostVersionAtLeast(min, version = VERSION) {
|
|
2906
|
+
const m = /^(\d+)\.(\d+)\.(\d+)/.exec(version ?? "");
|
|
2907
|
+
if (!m) return false;
|
|
2908
|
+
const v = [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
2909
|
+
return v[0] > min[0] || v[0] === min[0] && (v[1] > min[1] || v[1] === min[1] && v[2] >= min[2]);
|
|
2910
|
+
}
|
|
2911
|
+
function resolveTransformMode(adapter, model, hostVersion = VERSION) {
|
|
2912
|
+
if (adapter.transformMode) return adapter.transformMode;
|
|
2913
|
+
const api = model?.api;
|
|
2914
|
+
if (api == null) return "context";
|
|
2915
|
+
if (PROVIDER_VIABLE_APIS.has(api)) return "provider";
|
|
2916
|
+
if (api === "openai-completions" && hostVersionAtLeast(OPENAI_COMPLETIONS_VIABLE_FROM, hostVersion)) return "provider";
|
|
2917
|
+
return "context";
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2920
|
+
// node_modules/acp-kernel/dist/wire/index.js
|
|
2867
2921
|
import { createHash } from "crypto";
|
|
2922
|
+
function hashId(s) {
|
|
2923
|
+
return createHash("sha256").update(s, "utf8").digest("hex").slice(0, 16);
|
|
2924
|
+
}
|
|
2925
|
+
function deriveMessageId(role, contentType, text, options = {}) {
|
|
2926
|
+
const seed = `${role}|${contentType}|${options.toolCallId ?? ""}|${options.toolName ?? ""}|${text}`;
|
|
2927
|
+
return "h_" + hashId(seed);
|
|
2928
|
+
}
|
|
2929
|
+
var ClusterCounter = class {
|
|
2930
|
+
counts = /* @__PURE__ */ new Map();
|
|
2931
|
+
next(baseId) {
|
|
2932
|
+
const n = this.counts.get(baseId) ?? 0;
|
|
2933
|
+
this.counts.set(baseId, n + 1);
|
|
2934
|
+
return n === 0 ? baseId : `${baseId}_${n}`;
|
|
2935
|
+
}
|
|
2936
|
+
};
|
|
2937
|
+
function anthropicToCore(body) {
|
|
2938
|
+
const msgs = [];
|
|
2939
|
+
const cacheControls = /* @__PURE__ */ new Map();
|
|
2940
|
+
const clusters = new ClusterCounter();
|
|
2941
|
+
for (const m of body.messages) {
|
|
2942
|
+
const blocks = typeof m.content === "string" ? [{ type: "text", text: m.content }] : m.content;
|
|
2943
|
+
for (const b of blocks) {
|
|
2944
|
+
switch (b.type) {
|
|
2945
|
+
case "text": {
|
|
2946
|
+
const base = deriveMessageId(m.role, "text", b.text);
|
|
2947
|
+
const id = clusters.next(base);
|
|
2948
|
+
msgs.push({ id, role: m.role, contentType: "text", text: b.text });
|
|
2949
|
+
if (b.cache_control) cacheControls.set(id, b.cache_control);
|
|
2950
|
+
break;
|
|
2951
|
+
}
|
|
2952
|
+
case "tool_use": {
|
|
2953
|
+
const base = deriveMessageId("assistant", "tool-call", safeStringify(b.input), {
|
|
2954
|
+
toolCallId: b.id,
|
|
2955
|
+
toolName: b.name
|
|
2956
|
+
});
|
|
2957
|
+
const id = clusters.next(base);
|
|
2958
|
+
msgs.push({
|
|
2959
|
+
id,
|
|
2960
|
+
role: "assistant",
|
|
2961
|
+
contentType: "tool-call",
|
|
2962
|
+
toolName: b.name,
|
|
2963
|
+
toolCallId: b.id,
|
|
2964
|
+
text: safeStringify(b.input)
|
|
2965
|
+
});
|
|
2966
|
+
if (b.cache_control) cacheControls.set(id, b.cache_control);
|
|
2967
|
+
break;
|
|
2968
|
+
}
|
|
2969
|
+
case "tool_result": {
|
|
2970
|
+
const text = typeof b.content === "string" ? b.content : b.content.map((c) => c.text).join("\n");
|
|
2971
|
+
const base = deriveMessageId("tool", "tool-result", text, { toolCallId: b.tool_use_id });
|
|
2972
|
+
const id = clusters.next(base);
|
|
2973
|
+
msgs.push({
|
|
2974
|
+
id,
|
|
2975
|
+
role: "tool",
|
|
2976
|
+
contentType: "tool-result",
|
|
2977
|
+
toolCallId: b.tool_use_id,
|
|
2978
|
+
text,
|
|
2979
|
+
...b.is_error === true ? { toolIsError: true } : {}
|
|
2980
|
+
});
|
|
2981
|
+
if (b.cache_control) cacheControls.set(id, b.cache_control);
|
|
2982
|
+
break;
|
|
2983
|
+
}
|
|
2984
|
+
case "thinking": {
|
|
2985
|
+
const base = deriveMessageId("assistant", "reasoning", b.thinking);
|
|
2986
|
+
msgs.push({
|
|
2987
|
+
id: clusters.next(base),
|
|
2988
|
+
role: "assistant",
|
|
2989
|
+
contentType: "reasoning",
|
|
2990
|
+
text: b.thinking,
|
|
2991
|
+
...b.signature ? { thinkingSignature: b.signature } : {}
|
|
2992
|
+
});
|
|
2993
|
+
break;
|
|
2994
|
+
}
|
|
2995
|
+
case "image": {
|
|
2996
|
+
const base = deriveMessageId(m.role, "text", "[image]");
|
|
2997
|
+
msgs.push({
|
|
2998
|
+
id: clusters.next(base),
|
|
2999
|
+
role: m.role,
|
|
3000
|
+
contentType: "text",
|
|
3001
|
+
text: "[image]",
|
|
3002
|
+
rawAnthropicBlock: b
|
|
3003
|
+
});
|
|
3004
|
+
break;
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
return { msgs, cacheControls };
|
|
3010
|
+
}
|
|
3011
|
+
function coreToAnthropic(messages, cacheControls) {
|
|
3012
|
+
const out = [];
|
|
3013
|
+
let current = null;
|
|
3014
|
+
const flush = () => {
|
|
3015
|
+
if (current && current.blocks.length > 0) {
|
|
3016
|
+
out.push({ role: current.role, content: current.blocks });
|
|
3017
|
+
}
|
|
3018
|
+
current = null;
|
|
3019
|
+
};
|
|
3020
|
+
const cc = (id) => {
|
|
3021
|
+
const v = cacheControls?.get(id);
|
|
3022
|
+
return v ? { cache_control: v } : {};
|
|
3023
|
+
};
|
|
3024
|
+
for (const m of messages) {
|
|
3025
|
+
const target = m.role === "assistant" ? "assistant" : "user";
|
|
3026
|
+
if (!current || current.role !== target) {
|
|
3027
|
+
flush();
|
|
3028
|
+
current = { role: target, blocks: [] };
|
|
3029
|
+
}
|
|
3030
|
+
switch (m.contentType) {
|
|
3031
|
+
case "text": {
|
|
3032
|
+
if (m.rawAnthropicBlock) {
|
|
3033
|
+
current.blocks.push(m.rawAnthropicBlock);
|
|
3034
|
+
break;
|
|
3035
|
+
}
|
|
3036
|
+
current.blocks.push({ type: "text", text: m.text ?? "", ...cc(m.id) });
|
|
3037
|
+
break;
|
|
3038
|
+
}
|
|
3039
|
+
case "tool-call":
|
|
3040
|
+
current.blocks.push({
|
|
3041
|
+
type: "tool_use",
|
|
3042
|
+
id: m.toolCallId ?? `call_${m.id}`,
|
|
3043
|
+
name: m.toolName ?? "unknown",
|
|
3044
|
+
input: safeParse(m.text),
|
|
3045
|
+
...cc(m.id)
|
|
3046
|
+
});
|
|
3047
|
+
break;
|
|
3048
|
+
case "tool-result":
|
|
3049
|
+
current.blocks.push({
|
|
3050
|
+
type: "tool_result",
|
|
3051
|
+
tool_use_id: m.toolCallId ?? "",
|
|
3052
|
+
content: m.text ?? "",
|
|
3053
|
+
...m.toolIsError ? { is_error: true } : {},
|
|
3054
|
+
...cc(m.id)
|
|
3055
|
+
});
|
|
3056
|
+
break;
|
|
3057
|
+
case "reasoning":
|
|
3058
|
+
current.blocks.push({
|
|
3059
|
+
type: "thinking",
|
|
3060
|
+
thinking: m.text ?? "",
|
|
3061
|
+
...m.thinkingSignature ? { signature: m.thinkingSignature } : {}
|
|
3062
|
+
});
|
|
3063
|
+
break;
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
flush();
|
|
3067
|
+
return out;
|
|
3068
|
+
}
|
|
3069
|
+
function safeStringify(v) {
|
|
3070
|
+
try {
|
|
3071
|
+
return JSON.stringify(v ?? {});
|
|
3072
|
+
} catch {
|
|
3073
|
+
return "{}";
|
|
3074
|
+
}
|
|
3075
|
+
}
|
|
3076
|
+
function safeParse(s) {
|
|
3077
|
+
if (!s) return {};
|
|
3078
|
+
try {
|
|
3079
|
+
return JSON.parse(s);
|
|
3080
|
+
} catch {
|
|
3081
|
+
return {};
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
function parseDataUrl(url) {
|
|
3085
|
+
const m = /^data:([^;,]+)(?:;base64)?,(.+)$/i.exec(url);
|
|
3086
|
+
if (!m) return void 0;
|
|
3087
|
+
return { mediaType: m[1], base64: m[2] };
|
|
3088
|
+
}
|
|
3089
|
+
function openaiToCore(body) {
|
|
3090
|
+
const msgs = [];
|
|
3091
|
+
const clusters = new ClusterCounter();
|
|
3092
|
+
for (const m of body.messages) {
|
|
3093
|
+
switch (m.role) {
|
|
3094
|
+
case "system":
|
|
3095
|
+
case "developer": {
|
|
3096
|
+
const base = deriveMessageId(m.role, "text", stringContent(m.content));
|
|
3097
|
+
msgs.push({ id: clusters.next(base), role: "system", contentType: "text", text: stringContent(m.content), originalRole: m.role });
|
|
3098
|
+
break;
|
|
3099
|
+
}
|
|
3100
|
+
case "user": {
|
|
3101
|
+
const text = stringContent(m.content);
|
|
3102
|
+
const img = firstImagePart(m.content);
|
|
3103
|
+
const base = deriveMessageId("user", "text", text);
|
|
3104
|
+
msgs.push({
|
|
3105
|
+
id: clusters.next(base),
|
|
3106
|
+
role: "user",
|
|
3107
|
+
contentType: "text",
|
|
3108
|
+
text,
|
|
3109
|
+
...img ? { rawOpenaiContent: img.part, imageMediaType: img.mediaType, imageBase64: img.base64 } : {}
|
|
3110
|
+
});
|
|
3111
|
+
break;
|
|
3112
|
+
}
|
|
3113
|
+
case "assistant": {
|
|
3114
|
+
const reasoning = typeof m.reasoning_content === "string" ? m.reasoning_content : "";
|
|
3115
|
+
if (reasoning) {
|
|
3116
|
+
const base = deriveMessageId("assistant", "reasoning", reasoning);
|
|
3117
|
+
msgs.push({
|
|
3118
|
+
id: clusters.next(base),
|
|
3119
|
+
role: "assistant",
|
|
3120
|
+
contentType: "reasoning",
|
|
3121
|
+
text: reasoning,
|
|
3122
|
+
reasoningContent: reasoning
|
|
3123
|
+
});
|
|
3124
|
+
}
|
|
3125
|
+
const text = stringContent(m.content);
|
|
3126
|
+
if (text) {
|
|
3127
|
+
const base = deriveMessageId("assistant", "text", text);
|
|
3128
|
+
msgs.push({ id: clusters.next(base), role: "assistant", contentType: "text", text });
|
|
3129
|
+
}
|
|
3130
|
+
if (Array.isArray(m.tool_calls)) {
|
|
3131
|
+
for (const tc of m.tool_calls) {
|
|
3132
|
+
const base = deriveMessageId("assistant", "tool-call", tc.function.arguments ?? "", {
|
|
3133
|
+
toolCallId: tc.id,
|
|
3134
|
+
toolName: tc.function.name
|
|
3135
|
+
});
|
|
3136
|
+
msgs.push({
|
|
3137
|
+
id: clusters.next(base),
|
|
3138
|
+
role: "assistant",
|
|
3139
|
+
contentType: "tool-call",
|
|
3140
|
+
toolName: tc.function.name,
|
|
3141
|
+
toolCallId: tc.id,
|
|
3142
|
+
text: tc.function.arguments ?? ""
|
|
3143
|
+
});
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
break;
|
|
3147
|
+
}
|
|
3148
|
+
case "tool": {
|
|
3149
|
+
const base = deriveMessageId("tool", "tool-result", stringContent(m.content), {
|
|
3150
|
+
toolCallId: m.tool_call_id ?? ""
|
|
3151
|
+
});
|
|
3152
|
+
msgs.push({
|
|
3153
|
+
id: clusters.next(base),
|
|
3154
|
+
role: "tool",
|
|
3155
|
+
contentType: "tool-result",
|
|
3156
|
+
toolCallId: m.tool_call_id ?? "",
|
|
3157
|
+
text: stringContent(m.content)
|
|
3158
|
+
});
|
|
3159
|
+
break;
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
3163
|
+
return { msgs };
|
|
3164
|
+
}
|
|
3165
|
+
function coreToOpenai(messages) {
|
|
3166
|
+
const out = [];
|
|
3167
|
+
let pending = null;
|
|
3168
|
+
const flush = () => {
|
|
3169
|
+
if (!pending) return;
|
|
3170
|
+
const reasoning = pending.reasoning !== null && pending.reasoning.length > 0 ? pending.reasoning : void 0;
|
|
3171
|
+
if (pending.toolCalls.length > 0) {
|
|
3172
|
+
out.push({
|
|
3173
|
+
role: "assistant",
|
|
3174
|
+
content: pending.text ?? null,
|
|
3175
|
+
tool_calls: pending.toolCalls,
|
|
3176
|
+
...reasoning ? { reasoning_content: reasoning } : {}
|
|
3177
|
+
});
|
|
3178
|
+
} else if (pending.text !== null) {
|
|
3179
|
+
out.push({ role: "assistant", content: pending.text, ...reasoning ? { reasoning_content: reasoning } : {} });
|
|
3180
|
+
} else if (reasoning) {
|
|
3181
|
+
out.push({ role: "assistant", content: null, reasoning_content: reasoning });
|
|
3182
|
+
}
|
|
3183
|
+
pending = null;
|
|
3184
|
+
};
|
|
3185
|
+
for (const m of messages) {
|
|
3186
|
+
if (m.role === "assistant") {
|
|
3187
|
+
if (!pending) pending = { text: null, toolCalls: [], reasoning: null };
|
|
3188
|
+
if (m.contentType === "reasoning") {
|
|
3189
|
+
pending.reasoning = (pending.reasoning ?? "") + (m.reasoningContent ?? m.text ?? "");
|
|
3190
|
+
} else if (m.contentType === "text") {
|
|
3191
|
+
pending.text = (pending.text ?? "") + (m.text ?? "");
|
|
3192
|
+
} else if (m.contentType === "tool-call") {
|
|
3193
|
+
pending.toolCalls.push({
|
|
3194
|
+
id: m.toolCallId ?? `call_${m.id}`,
|
|
3195
|
+
type: "function",
|
|
3196
|
+
function: { name: m.toolName ?? "unknown", arguments: m.text ?? "" }
|
|
3197
|
+
});
|
|
3198
|
+
}
|
|
3199
|
+
} else {
|
|
3200
|
+
flush();
|
|
3201
|
+
if (m.role === "system") {
|
|
3202
|
+
out.push({ role: m.originalRole === "developer" ? "developer" : "system", content: m.text ?? "" });
|
|
3203
|
+
} else if (m.role === "user") {
|
|
3204
|
+
if (m.rawOpenaiContent || m.imageBase64) {
|
|
3205
|
+
const parts = [];
|
|
3206
|
+
if (m.text) parts.push({ type: "text", text: m.text });
|
|
3207
|
+
if (m.rawOpenaiContent) {
|
|
3208
|
+
parts.push(m.rawOpenaiContent);
|
|
3209
|
+
} else if (m.imageBase64 && m.imageMediaType) {
|
|
3210
|
+
parts.push({ type: "image_url", image_url: { url: `data:${m.imageMediaType};base64,${m.imageBase64}` } });
|
|
3211
|
+
}
|
|
3212
|
+
out.push({ role: "user", content: parts });
|
|
3213
|
+
} else {
|
|
3214
|
+
out.push({ role: "user", content: m.text ?? "" });
|
|
3215
|
+
}
|
|
3216
|
+
} else if (m.role === "tool") {
|
|
3217
|
+
out.push({ role: "tool", tool_call_id: m.toolCallId ?? "", content: m.text ?? "" });
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
flush();
|
|
3222
|
+
return out;
|
|
3223
|
+
}
|
|
3224
|
+
function stringContent(content) {
|
|
3225
|
+
if (content == null) return "";
|
|
3226
|
+
if (typeof content === "string") return content;
|
|
3227
|
+
if (Array.isArray(content)) {
|
|
3228
|
+
return content.map((p) => typeof p === "string" ? p : p.type === "text" ? p.text ?? "" : "").join("\n");
|
|
3229
|
+
}
|
|
3230
|
+
return "";
|
|
3231
|
+
}
|
|
3232
|
+
function firstImagePart(content) {
|
|
3233
|
+
if (!Array.isArray(content)) return void 0;
|
|
3234
|
+
for (const p of content) {
|
|
3235
|
+
if (p && typeof p === "object" && p.type === "image_url") {
|
|
3236
|
+
const iu = p.image_url;
|
|
3237
|
+
const url = iu?.url;
|
|
3238
|
+
if (typeof url === "string") {
|
|
3239
|
+
const parsed = parseDataUrl(url);
|
|
3240
|
+
if (parsed) return { part: p, mediaType: parsed.mediaType, base64: parsed.base64 };
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
return void 0;
|
|
3245
|
+
}
|
|
3246
|
+
function createSubagentNamespaces() {
|
|
3247
|
+
const anchors = /* @__PURE__ */ new Map();
|
|
3248
|
+
return {
|
|
3249
|
+
namespaceFor(identityValue, instructions) {
|
|
3250
|
+
if (typeof instructions !== "string" || instructions.trim().length === 0) return identityValue;
|
|
3251
|
+
const fp = hashId(instructions);
|
|
3252
|
+
const anchor = anchors.get(identityValue);
|
|
3253
|
+
if (anchor === void 0) {
|
|
3254
|
+
anchors.set(identityValue, fp);
|
|
3255
|
+
return identityValue;
|
|
3256
|
+
}
|
|
3257
|
+
return anchor === fp ? identityValue : `${identityValue}|sub:${fp}`;
|
|
3258
|
+
}
|
|
3259
|
+
};
|
|
3260
|
+
}
|
|
3261
|
+
var defaultNamespaces = createSubagentNamespaces();
|
|
3262
|
+
function detectWireFormat(payload) {
|
|
3263
|
+
if (payload === null || typeof payload !== "object") return void 0;
|
|
3264
|
+
const p = payload;
|
|
3265
|
+
if (Array.isArray(p.input)) return "responses";
|
|
3266
|
+
const messages = p.messages;
|
|
3267
|
+
if (!Array.isArray(messages)) return void 0;
|
|
3268
|
+
if ("system" in p || "anthropic_version" in p) return "anthropic";
|
|
3269
|
+
for (const m of messages) {
|
|
3270
|
+
if (m === null || typeof m !== "object") continue;
|
|
3271
|
+
const c = m.content;
|
|
3272
|
+
if (Array.isArray(c)) {
|
|
3273
|
+
for (const b of c) {
|
|
3274
|
+
if (b && typeof b === "object" && typeof b.type === "string") {
|
|
3275
|
+
if (b.type === "tool_use" || b.type === "tool_result" || b.type === "thinking")
|
|
3276
|
+
return "anthropic";
|
|
3277
|
+
if (b.type === "text" && "cache_control" in b) return "anthropic";
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
if (Array.isArray(m.tool_calls)) return "openai";
|
|
3282
|
+
if (m.role === "tool" && typeof m.tool_call_id === "string")
|
|
3283
|
+
return "openai";
|
|
3284
|
+
if (m.role === "system" || m.role === "developer") return "openai";
|
|
3285
|
+
}
|
|
3286
|
+
return "openai";
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3289
|
+
// src/messages.ts
|
|
3290
|
+
import { createHash as createHash2 } from "crypto";
|
|
2868
3291
|
var REF_TAG_SOURCE = "(?:<acp\\s[^>]*>m\\d+</acp>|\\[m\\d+\\])";
|
|
2869
3292
|
var REF_TAG = new RegExp(`^${REF_TAG_SOURCE}\\s?\\n?`);
|
|
2870
3293
|
var TRAILING_REF_TAG = new RegExp(`\\n*${REF_TAG_SOURCE}\\s*$`);
|
|
@@ -3004,7 +3427,7 @@ function fallbackText(msg) {
|
|
|
3004
3427
|
function stringifyArgs(args) {
|
|
3005
3428
|
if (!args) return "";
|
|
3006
3429
|
if (typeof args === "string") return args;
|
|
3007
|
-
return
|
|
3430
|
+
return safeStringify2(args);
|
|
3008
3431
|
}
|
|
3009
3432
|
function extractText(content, stripTags = true) {
|
|
3010
3433
|
const clean = stripTags ? stripRefTag : (s) => s;
|
|
@@ -3060,7 +3483,7 @@ function allToolCalls(content) {
|
|
|
3060
3483
|
}
|
|
3061
3484
|
return calls;
|
|
3062
3485
|
}
|
|
3063
|
-
function
|
|
3486
|
+
function safeStringify2(value) {
|
|
3064
3487
|
try {
|
|
3065
3488
|
return JSON.stringify(value);
|
|
3066
3489
|
} catch {
|
|
@@ -3218,7 +3641,7 @@ function spanFingerprint(coreMessages, startId, endId) {
|
|
|
3218
3641
|
const first = find(startId);
|
|
3219
3642
|
const last = find(endId);
|
|
3220
3643
|
if (!first || !last) return "";
|
|
3221
|
-
return
|
|
3644
|
+
return createHash2("sha1").update(`${key(first)}\0${key(last)}`).digest("hex").slice(0, 8);
|
|
3222
3645
|
}
|
|
3223
3646
|
function isBlockRef(ref) {
|
|
3224
3647
|
return /^b\d+$/i.test(ref.trim());
|
|
@@ -3247,249 +3670,241 @@ function rangeFingerprints(ranges, coreMessages, byRef, blocks) {
|
|
|
3247
3670
|
});
|
|
3248
3671
|
}
|
|
3249
3672
|
|
|
3250
|
-
// src/wire-
|
|
3251
|
-
|
|
3252
|
-
function
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
if (
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3673
|
+
// src/wire-fold.ts
|
|
3674
|
+
import { createHash as createHash3 } from "crypto";
|
|
3675
|
+
function detectProviderWireFormat(payload) {
|
|
3676
|
+
const fmt2 = detectWireFormat(payload);
|
|
3677
|
+
return fmt2 === "anthropic" || fmt2 === "openai" ? fmt2 : null;
|
|
3678
|
+
}
|
|
3679
|
+
function payloadToCore(payload, fmt2) {
|
|
3680
|
+
if (fmt2 === "anthropic") {
|
|
3681
|
+
const { msgs: msgs2, cacheControls } = anthropicToCore(payload);
|
|
3682
|
+
return { msgs: msgs2, cacheControls };
|
|
3683
|
+
}
|
|
3684
|
+
const { msgs } = openaiToCore(payload);
|
|
3685
|
+
return { msgs };
|
|
3686
|
+
}
|
|
3687
|
+
function coreToPayloadMessages(msgs, fmt2, cacheControls) {
|
|
3688
|
+
return fmt2 === "anthropic" ? coreToAnthropic(msgs, cacheControls) : coreToOpenai(msgs);
|
|
3689
|
+
}
|
|
3690
|
+
var ANTHROPIC_CODEC_BLOCKS = /* @__PURE__ */ new Set(["text", "tool_use", "tool_result", "thinking", "image"]);
|
|
3691
|
+
var OPENAI_CODEC_ROLES = /* @__PURE__ */ new Set(["system", "developer", "user", "assistant", "tool"]);
|
|
3692
|
+
function payloadRepresentable(payload, fmt2) {
|
|
3693
|
+
const messages = payload.messages;
|
|
3694
|
+
if (!Array.isArray(messages)) return { ok: false, reason: "messages not an array" };
|
|
3695
|
+
for (const message of messages) {
|
|
3696
|
+
if (message === null || typeof message !== "object") return { ok: false, reason: "message not an object" };
|
|
3697
|
+
const bad = fmt2 === "anthropic" ? unrepresentableAnthropicMessage(message) : unrepresentableOpenaiMessage(message);
|
|
3698
|
+
if (bad) return { ok: false, reason: bad };
|
|
3272
3699
|
}
|
|
3273
|
-
return
|
|
3274
|
-
}
|
|
3275
|
-
function anthropicBlocks(m) {
|
|
3276
|
-
return typeof m.content === "string" ? [{ type: "text", text: m.content }] : m.content ?? [];
|
|
3700
|
+
return { ok: true };
|
|
3277
3701
|
}
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
}
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
msg[AI] = stream.length;
|
|
3292
|
-
stream.push(msg);
|
|
3293
|
-
back.push({ wi, kind });
|
|
3294
|
-
};
|
|
3295
|
-
if (format === "anthropic") {
|
|
3296
|
-
const toolNames = /* @__PURE__ */ new Map();
|
|
3297
|
-
for (const raw of messages) {
|
|
3298
|
-
if (raw === null || typeof raw !== "object") continue;
|
|
3299
|
-
const m = raw;
|
|
3300
|
-
if (m.role !== "assistant") continue;
|
|
3301
|
-
for (const b of anthropicBlocks(m)) if (b.type === "tool_use" && b.id) toolNames.set(b.id, b.name ?? "");
|
|
3302
|
-
}
|
|
3303
|
-
messages.forEach((raw, wi) => {
|
|
3304
|
-
if (raw === null || typeof raw !== "object") return;
|
|
3305
|
-
const m = raw;
|
|
3306
|
-
const blocks = anthropicBlocks(m);
|
|
3307
|
-
if (m.role === "user") {
|
|
3308
|
-
let texts = [];
|
|
3309
|
-
for (const b of blocks) {
|
|
3310
|
-
if (b.type === "text" && typeof b.text === "string") texts.push(b.text);
|
|
3311
|
-
else if (b.type === "tool_result") {
|
|
3312
|
-
if (texts.length > 0) {
|
|
3313
|
-
push({ role: "user", content: texts.map((t2) => ({ type: "text", text: t2 })), timestamp: Date.now() }, wi, "text");
|
|
3314
|
-
texts = [];
|
|
3315
|
-
}
|
|
3316
|
-
const trText = typeof b.content === "string" ? b.content : Array.isArray(b.content) ? b.content.map((c) => c.text ?? "").join("\n") : "";
|
|
3317
|
-
push({
|
|
3318
|
-
role: "toolResult",
|
|
3319
|
-
content: [{ type: "text", text: trText }],
|
|
3320
|
-
toolName: toolNames.get(b.tool_use_id ?? "") ?? "",
|
|
3321
|
-
toolCallId: b.tool_use_id ?? "",
|
|
3322
|
-
isError: b.is_error === true,
|
|
3323
|
-
timestamp: Date.now()
|
|
3324
|
-
}, wi, "toolResult");
|
|
3325
|
-
}
|
|
3326
|
-
}
|
|
3327
|
-
if (texts.length > 0) push({ role: "user", content: texts.map((t2) => ({ type: "text", text: t2 })), timestamp: Date.now() }, wi, "text");
|
|
3328
|
-
return;
|
|
3329
|
-
}
|
|
3330
|
-
if (m.role === "assistant") {
|
|
3331
|
-
const content = [];
|
|
3332
|
-
for (const b of blocks) {
|
|
3333
|
-
if (b.type === "text" && typeof b.text === "string" && b.text.length > 0) content.push({ type: "text", text: b.text });
|
|
3334
|
-
else if (b.type === "tool_use") content.push({ type: "toolCall", id: b.id, name: b.name, arguments: b.input ?? {} });
|
|
3335
|
-
}
|
|
3336
|
-
if (content.length > 0) push({ role: "assistant", ...assistantBase(), content }, wi, "toolCall");
|
|
3337
|
-
return;
|
|
3702
|
+
function unrepresentableAnthropicMessage(message) {
|
|
3703
|
+
const content = message.content;
|
|
3704
|
+
if (content == null || typeof content === "string") return null;
|
|
3705
|
+
if (!Array.isArray(content)) return "content neither string nor block array";
|
|
3706
|
+
for (const block of content) {
|
|
3707
|
+
const type5 = block?.type;
|
|
3708
|
+
if (typeof type5 !== "string" || !ANTHROPIC_CODEC_BLOCKS.has(type5)) {
|
|
3709
|
+
return `anthropic block type ${JSON.stringify(type5) ?? "missing"}`;
|
|
3710
|
+
}
|
|
3711
|
+
if (type5 === "tool_result") {
|
|
3712
|
+
const inner = block.content;
|
|
3713
|
+
if (Array.isArray(inner) && inner.some((c) => c?.type !== "text")) {
|
|
3714
|
+
return "tool_result content carries non-text parts (images are flattened away)";
|
|
3338
3715
|
}
|
|
3339
|
-
const t = blocks.map((b) => typeof b.text === "string" ? b.text : "").join("\n");
|
|
3340
|
-
if (t) push({ role: "user", content: [{ type: "text", text: t }], timestamp: Date.now() }, wi, "text");
|
|
3341
|
-
});
|
|
3342
|
-
return { stream, back, format };
|
|
3343
|
-
}
|
|
3344
|
-
messages.forEach((raw, wi) => {
|
|
3345
|
-
if (raw === null || typeof raw !== "object") return;
|
|
3346
|
-
const m = raw;
|
|
3347
|
-
const textOf = () => {
|
|
3348
|
-
const c = m.content;
|
|
3349
|
-
if (typeof c === "string") return c;
|
|
3350
|
-
if (Array.isArray(c)) return c.map((p) => p.type === "text" ? p.text ?? "" : "").join("\n");
|
|
3351
|
-
return "";
|
|
3352
|
-
};
|
|
3353
|
-
if (m.role === "system" || m.role === "developer") {
|
|
3354
|
-
const t2 = textOf();
|
|
3355
|
-
if (t2) push({ role: "user", content: [{ type: "text", text: t2 }], timestamp: Date.now() }, wi, "text");
|
|
3356
|
-
return;
|
|
3357
3716
|
}
|
|
3358
|
-
if (
|
|
3359
|
-
|
|
3360
|
-
role: "toolResult",
|
|
3361
|
-
content: [{ type: "text", text: textOf() }],
|
|
3362
|
-
toolName: "",
|
|
3363
|
-
toolCallId: m.tool_call_id ?? "",
|
|
3364
|
-
isError: false,
|
|
3365
|
-
timestamp: Date.now()
|
|
3366
|
-
}, wi, "toolResult");
|
|
3367
|
-
return;
|
|
3368
|
-
}
|
|
3369
|
-
if (m.role === "assistant") {
|
|
3370
|
-
const calls = m.tool_calls ?? [];
|
|
3371
|
-
if (calls.length > 0) {
|
|
3372
|
-
const content = [];
|
|
3373
|
-
const t3 = textOf();
|
|
3374
|
-
if (t3) content.push({ type: "text", text: t3 });
|
|
3375
|
-
for (const c of calls) {
|
|
3376
|
-
let args = {};
|
|
3377
|
-
try {
|
|
3378
|
-
args = c.function?.arguments ? JSON.parse(c.function.arguments) : {};
|
|
3379
|
-
} catch {
|
|
3380
|
-
args = { raw: c.function?.arguments ?? "" };
|
|
3381
|
-
}
|
|
3382
|
-
content.push({ type: "toolCall", id: c.id, name: c.function?.name ?? "", arguments: args });
|
|
3383
|
-
}
|
|
3384
|
-
push({ role: "assistant", ...assistantBase(), content }, wi, "toolCall");
|
|
3385
|
-
return;
|
|
3386
|
-
}
|
|
3387
|
-
const t2 = textOf();
|
|
3388
|
-
if (t2) push({ role: "assistant", ...assistantBase(), content: [{ type: "text", text: t2 }] }, wi, "text");
|
|
3389
|
-
return;
|
|
3717
|
+
if (type5 === "thinking" && block.cache_control != null) {
|
|
3718
|
+
return "cache_control on a thinking block is not re-attached";
|
|
3390
3719
|
}
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
});
|
|
3394
|
-
return { stream, back, format };
|
|
3720
|
+
}
|
|
3721
|
+
return null;
|
|
3395
3722
|
}
|
|
3396
|
-
function
|
|
3397
|
-
const
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3723
|
+
function unrepresentableOpenaiMessage(message) {
|
|
3724
|
+
const role = message.role;
|
|
3725
|
+
if (typeof role !== "string" || !OPENAI_CODEC_ROLES.has(role)) {
|
|
3726
|
+
return `openai role ${JSON.stringify(role) ?? "missing"}`;
|
|
3727
|
+
}
|
|
3728
|
+
const content = message.content;
|
|
3729
|
+
if (content == null || typeof content === "string") return null;
|
|
3730
|
+
if (!Array.isArray(content)) return "content neither string nor part array";
|
|
3731
|
+
let dataImages = 0;
|
|
3732
|
+
for (const part of content) {
|
|
3733
|
+
if (typeof part === "string") continue;
|
|
3734
|
+
const type5 = part?.type;
|
|
3735
|
+
if (type5 === "text") continue;
|
|
3736
|
+
if (type5 === "image_url" && role === "user") {
|
|
3737
|
+
const url = part?.image_url?.url;
|
|
3738
|
+
if (typeof url !== "string" || !url.startsWith("data:")) return "image_url without a data: URL is dropped";
|
|
3739
|
+
if (++dataImages > 1) return "second image_url in one message is dropped";
|
|
3410
3740
|
continue;
|
|
3411
3741
|
}
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
if (
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3742
|
+
return `openai content part type ${JSON.stringify(type5) ?? "missing"}`;
|
|
3743
|
+
}
|
|
3744
|
+
return null;
|
|
3745
|
+
}
|
|
3746
|
+
var renderRefsAll = createRenderRefsNode("all");
|
|
3747
|
+
function applyWireTagContract(msgs, state, scope) {
|
|
3748
|
+
const stripAssistantTags = (m) => m.contentType === "text" && m.role === "assistant" ? { ...m, text: stripRefTag(m.text ?? "") } : m;
|
|
3749
|
+
const toolResults = msgs.filter((m) => m.contentType === "tool-result");
|
|
3750
|
+
if (toolResults.length === 0) return msgs.map(stripAssistantTags);
|
|
3751
|
+
const names = toolCallNames(msgs);
|
|
3752
|
+
const named = toolResults.map((m) => m.toolName ? m : { ...m, toolName: names.get(m.toolCallId ?? "") ?? "tool" });
|
|
3753
|
+
const io = renderRefsAll.run(
|
|
3754
|
+
{ messages: named, state, effects: {} },
|
|
3755
|
+
{ config: scope.config, tokenCount: scope.tokenCount, countTokens: defaultCountTokens }
|
|
3756
|
+
);
|
|
3757
|
+
if (io.state !== state) state.tokenSnapshot = io.state.tokenSnapshot;
|
|
3758
|
+
const tagged = io.messages;
|
|
3759
|
+
const bySource = new Map(toolResults.map((m, i) => [m, tagged[i]]));
|
|
3760
|
+
return msgs.map((m) => m.contentType === "tool-result" ? bySource.get(m) ?? m : stripAssistantTags(m));
|
|
3761
|
+
}
|
|
3762
|
+
function coreIdentity(msg) {
|
|
3763
|
+
return JSON.stringify({
|
|
3764
|
+
role: msg.role,
|
|
3765
|
+
contentType: msg.contentType,
|
|
3766
|
+
toolName: msg.toolName ?? null,
|
|
3767
|
+
toolCallId: msg.toolCallId ?? null,
|
|
3768
|
+
text: stripRefTag(msg.text ?? "")
|
|
3769
|
+
});
|
|
3770
|
+
}
|
|
3771
|
+
function toolCallNames(msgs) {
|
|
3772
|
+
const names = /* @__PURE__ */ new Map();
|
|
3773
|
+
for (const m of msgs) {
|
|
3774
|
+
if (m.contentType === "tool-call" && m.toolCallId && m.toolName) names.set(m.toolCallId, m.toolName);
|
|
3775
|
+
}
|
|
3776
|
+
return names;
|
|
3777
|
+
}
|
|
3778
|
+
function toolResultTextsCore(msgs) {
|
|
3779
|
+
const results = /* @__PURE__ */ new Map();
|
|
3780
|
+
for (const m of msgs) {
|
|
3781
|
+
if (m.contentType !== "tool-result" || !m.toolCallId) continue;
|
|
3782
|
+
results.set(m.toolCallId, m.text ?? "");
|
|
3783
|
+
}
|
|
3784
|
+
return results;
|
|
3785
|
+
}
|
|
3786
|
+
function findCompressCallsCore(msg) {
|
|
3787
|
+
if (msg.contentType !== "tool-call" || !msg.toolName) return [];
|
|
3788
|
+
const args = compressToolArgs({ name: msg.toolName, arguments: msg.text });
|
|
3789
|
+
if (!args) return [];
|
|
3790
|
+
const content = args.content;
|
|
3791
|
+
if (!Array.isArray(content)) return [];
|
|
3792
|
+
const ranges = [];
|
|
3793
|
+
const callTopic = typeof args.topic === "string" ? args.topic : void 0;
|
|
3794
|
+
for (const item of content) {
|
|
3795
|
+
const r = item;
|
|
3796
|
+
if (typeof r.startId !== "string" || typeof r.endId !== "string" || typeof r.summary !== "string" || r.summary.length === 0) continue;
|
|
3797
|
+
ranges.push({
|
|
3798
|
+
startRef: r.startId,
|
|
3799
|
+
endRef: r.endId,
|
|
3800
|
+
summary: r.summary,
|
|
3801
|
+
topic: typeof r.topic === "string" ? r.topic : callTopic,
|
|
3802
|
+
summaryMaxChars: typeof args.summaryMaxChars === "number" ? args.summaryMaxChars : void 0,
|
|
3803
|
+
compressCallId: msg.toolCallId ?? ""
|
|
3804
|
+
});
|
|
3805
|
+
}
|
|
3806
|
+
return ranges.length > 0 ? [{ id: msg.toolCallId ?? "", ranges }] : [];
|
|
3807
|
+
}
|
|
3808
|
+
function corePieceKey(cm) {
|
|
3809
|
+
return `${cm.role}|${cm.contentType}|${cm.toolName ?? ""}|${(cm.text ?? "").slice(0, 4096)}`;
|
|
3810
|
+
}
|
|
3811
|
+
function spanFingerprintCoreIdx(coreMessages, startIdx, endIdx) {
|
|
3812
|
+
const first = coreMessages[startIdx];
|
|
3813
|
+
const last = coreMessages[endIdx];
|
|
3814
|
+
if (!first || !last) return "";
|
|
3815
|
+
return createHash3("sha1").update(`${corePieceKey(first)}\0${corePieceKey(last)}`).digest("hex").slice(0, 8);
|
|
3816
|
+
}
|
|
3817
|
+
function boundaryRawCore(ref, byRef, blocks, coreMessages, pick) {
|
|
3818
|
+
const raw = byRef[ref];
|
|
3819
|
+
if (raw) return raw;
|
|
3820
|
+
const m = /^b(\d+)$/i.exec(ref.trim());
|
|
3821
|
+
if (!m) return "";
|
|
3822
|
+
const block = blocks.find((b) => b.blockId.toLowerCase() === `b${m[1]}`);
|
|
3823
|
+
if (!block) return "";
|
|
3824
|
+
const idx = (id) => coreMessages.findIndex((cm) => cm.id === (byRef[id] ?? id));
|
|
3825
|
+
let best = -1;
|
|
3826
|
+
for (const id of block.effectiveMessageIds) {
|
|
3827
|
+
const i = idx(id);
|
|
3828
|
+
if (i < 0) continue;
|
|
3829
|
+
if (best < 0 || (pick === "min" ? i < best : i > best)) best = i;
|
|
3830
|
+
}
|
|
3831
|
+
return best < 0 ? "" : coreMessages[best]?.id ?? "";
|
|
3832
|
+
}
|
|
3833
|
+
function boundaryIndexCore(ref, byRef, blocks, coreMessages, pick, fallbackIdx = -1) {
|
|
3834
|
+
const id = boundaryRawCore(ref, byRef, blocks, coreMessages, pick);
|
|
3835
|
+
if (id) {
|
|
3836
|
+
const i = coreMessages.findIndex((cm) => cm.id === id);
|
|
3837
|
+
if (i >= 0) return i;
|
|
3838
|
+
}
|
|
3839
|
+
return fallbackIdx >= 0 && fallbackIdx < coreMessages.length ? fallbackIdx : -1;
|
|
3840
|
+
}
|
|
3841
|
+
function refOfPieceCore(coreMessages, idx, byRef) {
|
|
3842
|
+
const id = coreMessages[idx]?.id;
|
|
3843
|
+
if (!id) return "";
|
|
3844
|
+
for (const [ref, mapped] of Object.entries(byRef)) if (mapped === id) return ref;
|
|
3845
|
+
return "";
|
|
3846
|
+
}
|
|
3847
|
+
function staleRangeCore(r, rangeIndex, resultText, coreMessages, callIndex, byRef, blocks) {
|
|
3848
|
+
const pm = resultText.match(/\[pos=([0-9,-]+)\]/);
|
|
3849
|
+
const pair = pm ? pm[1].split(",")[rangeIndex] ?? "-" : "-";
|
|
3850
|
+
const hinted = pair !== "-";
|
|
3851
|
+
const [ps, pe] = pair === "-" ? ["", ""] : pair.split("-");
|
|
3852
|
+
const fbStart = ps && ps !== "" ? Number.parseInt(ps, 10) : -1;
|
|
3853
|
+
const fbEnd = pe && pe !== "" ? Number.parseInt(pe, 10) : -1;
|
|
3854
|
+
const startRaw = boundaryRawCore(r.startRef, byRef, blocks, coreMessages, "min");
|
|
3855
|
+
const endRaw = boundaryRawCore(r.endRef, byRef, blocks, coreMessages, "max");
|
|
3856
|
+
const rawStartIdx = startRaw ? coreMessages.findIndex((cm) => cm.id === startRaw) : -1;
|
|
3857
|
+
const rawEndIdx = endRaw ? coreMessages.findIndex((cm) => cm.id === endRaw) : -1;
|
|
3858
|
+
const startIdx = rawStartIdx >= 0 ? rawStartIdx : fbStart >= 0 && fbStart < coreMessages.length ? fbStart : -1;
|
|
3859
|
+
const endIdx = rawEndIdx >= 0 ? rawEndIdx : fbEnd >= 0 && fbEnd < coreMessages.length ? fbEnd : -1;
|
|
3860
|
+
if (startIdx < 0 || endIdx < 0) {
|
|
3861
|
+
if (!/^b\d+$/i.test(r.startRef.trim()) && !/^b\d+$/i.test(r.endRef.trim()))
|
|
3862
|
+
return { reject: `unresolved ${r.startRef}..${r.endRef} -> ${startIdx}..${endIdx}`, ...hinted ? { hint: true } : {} };
|
|
3863
|
+
return {};
|
|
3864
|
+
}
|
|
3865
|
+
if (endIdx > callIndex) return { reject: `end idx ${endIdx} > callIndex ${callIndex}`, ...hinted ? { hint: true } : {} };
|
|
3866
|
+
const m = resultText.match(/\[fp=([0-9a-f,-]+)\]/);
|
|
3867
|
+
if (m) {
|
|
3868
|
+
const want = m[1].split(",")[rangeIndex];
|
|
3869
|
+
if (want !== void 0 && want !== "-") {
|
|
3870
|
+
const got = spanFingerprintCoreIdx(coreMessages, startIdx, endIdx);
|
|
3871
|
+
if (want !== got) return { reject: `fp ${r.startRef}..${r.endRef} want ${want} got ${got} @${startIdx}..${endIdx}`, ...hinted ? { hint: true } : {} };
|
|
3475
3872
|
}
|
|
3476
|
-
out.push({ role: srcMsg.role === "assistant" ? "assistant" : srcMsg.role, content: text });
|
|
3477
3873
|
}
|
|
3478
|
-
|
|
3874
|
+
const remap = {};
|
|
3875
|
+
if (/^m\d+$/i.test(r.startRef.trim()) && rawStartIdx < 0) {
|
|
3876
|
+
const ref = refOfPieceCore(coreMessages, startIdx, byRef);
|
|
3877
|
+
if (!ref) return { reject: `recovered ${r.startRef} @${startIdx} has no ref (protected piece)`, ...hinted ? { hint: true } : {} };
|
|
3878
|
+
remap.startRef = ref;
|
|
3879
|
+
}
|
|
3880
|
+
if (/^m\d+$/i.test(r.endRef.trim()) && rawEndIdx < 0) {
|
|
3881
|
+
const ref = refOfPieceCore(coreMessages, endIdx, byRef);
|
|
3882
|
+
if (!ref) return { reject: `recovered ${r.endRef} @${endIdx} has no ref (protected piece)`, ...hinted ? { hint: true } : {} };
|
|
3883
|
+
remap.endRef = ref;
|
|
3884
|
+
}
|
|
3885
|
+
if (!remap.startRef && !remap.endRef) return {};
|
|
3886
|
+
return { remap, recovered: { pos: pair, startIdx, endIdx } };
|
|
3887
|
+
}
|
|
3888
|
+
function rangePositionsCore(ranges, coreMessages, byRef, blocks) {
|
|
3889
|
+
return ranges.map((r) => {
|
|
3890
|
+
const s = boundaryIndexCore(r.startRef, byRef, blocks, coreMessages, "min");
|
|
3891
|
+
const e = s >= 0 ? boundaryIndexCore(r.endRef, byRef, blocks, coreMessages, "max") : -1;
|
|
3892
|
+
return s >= 0 && e >= 0 ? `${s}-${e}` : "-";
|
|
3893
|
+
});
|
|
3479
3894
|
}
|
|
3480
|
-
function
|
|
3895
|
+
function viewToCoreStream(view, systemText) {
|
|
3481
3896
|
const messages = [{ role: "system", content: systemText }];
|
|
3482
3897
|
for (const message of view) {
|
|
3483
3898
|
const m = message;
|
|
3484
3899
|
if (m.role === "user") {
|
|
3485
|
-
const text =
|
|
3900
|
+
const text = extractViewText(m.content);
|
|
3486
3901
|
if (text) messages.push({ role: "user", content: text });
|
|
3487
3902
|
} else if (m.role === "assistant") {
|
|
3488
3903
|
const blocks = Array.isArray(m.content) ? m.content : [];
|
|
3489
3904
|
const calls = blocks.filter(
|
|
3490
3905
|
(b) => b !== null && typeof b === "object" && b.type === "toolCall"
|
|
3491
3906
|
);
|
|
3492
|
-
const text =
|
|
3907
|
+
const text = extractViewText(m.content);
|
|
3493
3908
|
if (calls.length > 0) {
|
|
3494
3909
|
messages.push({
|
|
3495
3910
|
role: "assistant",
|
|
@@ -3504,13 +3919,63 @@ function viewToWireStream(view, systemText) {
|
|
|
3504
3919
|
messages.push({ role: "assistant", content: text });
|
|
3505
3920
|
}
|
|
3506
3921
|
} else if (m.role === "toolResult") {
|
|
3507
|
-
messages.push({ role: "tool", tool_call_id: m.toolCallId ?? "", content:
|
|
3922
|
+
messages.push({ role: "tool", tool_call_id: m.toolCallId ?? "", content: extractViewText(m.content) });
|
|
3508
3923
|
} else {
|
|
3509
|
-
const text =
|
|
3924
|
+
const text = extractViewText(m.content) || (typeof m.summary === "string" ? m.summary : "");
|
|
3510
3925
|
if (text) messages.push({ role: "developer", content: text });
|
|
3511
3926
|
}
|
|
3512
3927
|
}
|
|
3513
|
-
|
|
3928
|
+
const { msgs } = openaiToCore({ model: "prime-fold", messages });
|
|
3929
|
+
return msgs;
|
|
3930
|
+
}
|
|
3931
|
+
function viewToAnthropicCore(view) {
|
|
3932
|
+
const messages = [];
|
|
3933
|
+
for (const message of view) {
|
|
3934
|
+
const m = message;
|
|
3935
|
+
if (m.role === "user") {
|
|
3936
|
+
const text = extractViewText(m.content);
|
|
3937
|
+
if (text) messages.push({ role: "user", content: [{ type: "text", text }] });
|
|
3938
|
+
} else if (m.role === "assistant") {
|
|
3939
|
+
const blocks = Array.isArray(m.content) ? m.content : [];
|
|
3940
|
+
const calls = blocks.filter(
|
|
3941
|
+
(b) => b !== null && typeof b === "object" && b.type === "toolCall"
|
|
3942
|
+
);
|
|
3943
|
+
const text = extractViewText(m.content);
|
|
3944
|
+
const content = [];
|
|
3945
|
+
if (text) content.push({ type: "text", text });
|
|
3946
|
+
for (const c of calls) {
|
|
3947
|
+
let input = {};
|
|
3948
|
+
try {
|
|
3949
|
+
input = c.arguments && typeof c.arguments === "object" ? c.arguments : JSON.parse(JSON.stringify(c.arguments ?? {}));
|
|
3950
|
+
} catch {
|
|
3951
|
+
input = {};
|
|
3952
|
+
}
|
|
3953
|
+
content.push({ type: "tool_use", id: c.id, name: c.name ?? "", input });
|
|
3954
|
+
}
|
|
3955
|
+
if (content.length > 0) messages.push({ role: "assistant", content });
|
|
3956
|
+
} else if (m.role === "toolResult") {
|
|
3957
|
+
messages.push({
|
|
3958
|
+
role: "user",
|
|
3959
|
+
content: [{ type: "tool_result", tool_use_id: m.toolCallId ?? "", content: extractViewText(m.content) }]
|
|
3960
|
+
});
|
|
3961
|
+
} else {
|
|
3962
|
+
const text = extractViewText(m.content) || (typeof m.summary === "string" ? m.summary : "");
|
|
3963
|
+
if (text) messages.push({ role: "user", content: [{ type: "text", text }] });
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
const { msgs, cacheControls } = anthropicToCore({ model: "prime-fold", messages });
|
|
3967
|
+
void cacheControls;
|
|
3968
|
+
return msgs;
|
|
3969
|
+
}
|
|
3970
|
+
function extractViewText(content) {
|
|
3971
|
+
const clean = (s) => stripRefTag(s);
|
|
3972
|
+
if (typeof content === "string") return clean(content);
|
|
3973
|
+
if (!Array.isArray(content)) return "";
|
|
3974
|
+
const parts = [];
|
|
3975
|
+
for (const b of content) {
|
|
3976
|
+
if (b.type === "text" && typeof b.text === "string") parts.push(clean(b.text));
|
|
3977
|
+
}
|
|
3978
|
+
return parts.join("\n");
|
|
3514
3979
|
}
|
|
3515
3980
|
|
|
3516
3981
|
// src/runtime.ts
|
|
@@ -3538,6 +4003,7 @@ function createRuntime(adapter) {
|
|
|
3538
4003
|
const core = createCore({ countTokens: defaultCountTokens });
|
|
3539
4004
|
const locks = /* @__PURE__ */ new Map();
|
|
3540
4005
|
const slots = /* @__PURE__ */ new Map();
|
|
4006
|
+
const coreSlots = /* @__PURE__ */ new Map();
|
|
3541
4007
|
let adapterRef = adapter;
|
|
3542
4008
|
let promptsRef = defaultPrompts;
|
|
3543
4009
|
async function acquireLock(sid) {
|
|
@@ -3567,6 +4033,14 @@ function createRuntime(adapter) {
|
|
|
3567
4033
|
}
|
|
3568
4034
|
return slot;
|
|
3569
4035
|
}
|
|
4036
|
+
function coreSlotFor(sid) {
|
|
4037
|
+
let slot = coreSlots.get(sid);
|
|
4038
|
+
if (!slot) {
|
|
4039
|
+
slot = freshSlot();
|
|
4040
|
+
coreSlots.set(sid, slot);
|
|
4041
|
+
}
|
|
4042
|
+
return slot;
|
|
4043
|
+
}
|
|
3570
4044
|
function sidOf(ctx) {
|
|
3571
4045
|
return ctx.sessionManager.getSessionId();
|
|
3572
4046
|
}
|
|
@@ -3651,8 +4125,90 @@ function createRuntime(adapter) {
|
|
|
3651
4125
|
stream.forEach((message, i) => originalById.set(`p${i + 1}`, message));
|
|
3652
4126
|
return { state: slot.state, coreMessages, originalById, streamLen: stream.length };
|
|
3653
4127
|
}
|
|
4128
|
+
function foldStreamCore(ctx, stream) {
|
|
4129
|
+
const sid = sidOf(ctx);
|
|
4130
|
+
let slot = coreSlotFor(sid);
|
|
4131
|
+
if (slot.preview) {
|
|
4132
|
+
debug.event("fold-refold", { sid, foldedLen: slot.foldedLen, lcp: 0, streamLen: stream.length, reason: "preview" });
|
|
4133
|
+
slot = freshSlot(slot);
|
|
4134
|
+
coreSlots.set(sid, slot);
|
|
4135
|
+
}
|
|
4136
|
+
const ids = stream.map(coreIdentity);
|
|
4137
|
+
let lcp = 0;
|
|
4138
|
+
while (lcp < Math.min(ids.length, slot.identities.length) && ids[lcp] === slot.identities[lcp]) lcp++;
|
|
4139
|
+
if (lcp < slot.foldedLen) {
|
|
4140
|
+
const flip = isViewFlip(slot.foldedLen, lcp);
|
|
4141
|
+
debug.event("fold-refold", { sid, foldedLen: slot.foldedLen, lcp, streamLen: stream.length, flip, space: "core" });
|
|
4142
|
+
slot = flip ? preserveCompressedSlot(slot) : freshSlot(slot);
|
|
4143
|
+
coreSlots.set(sid, slot);
|
|
4144
|
+
lcp = 0;
|
|
4145
|
+
}
|
|
4146
|
+
const coreMessages = stream;
|
|
4147
|
+
const config = configFor(ctx);
|
|
4148
|
+
const names = toolCallNames(stream);
|
|
4149
|
+
const assigned = assignRefs(coreMessages, {
|
|
4150
|
+
existing: slot.state.messageRefs,
|
|
4151
|
+
nextIndex: highestUsedIndex(slot.state.messageRefs) + 1,
|
|
4152
|
+
isProtected: (m) => {
|
|
4153
|
+
if (m.role !== "tool" || !m.toolCallId) return false;
|
|
4154
|
+
const name = names.get(m.toolCallId);
|
|
4155
|
+
if (!name) return false;
|
|
4156
|
+
if (name === "compress") return true;
|
|
4157
|
+
return (config.protectedTools ?? []).includes(name);
|
|
4158
|
+
}
|
|
4159
|
+
});
|
|
4160
|
+
slot.state = { ...slot.state, messageRefs: assigned.map };
|
|
4161
|
+
const isFreshFold = slot.foldedLen === 0;
|
|
4162
|
+
const resultTexts = toolResultTextsCore(stream);
|
|
4163
|
+
let replayed = 0;
|
|
4164
|
+
for (let i = isFreshFold ? 0 : slot.foldedLen; i < stream.length; i++) {
|
|
4165
|
+
for (const call of findCompressCallsCore(stream[i])) {
|
|
4166
|
+
const resultText = resultTexts.get(call.id) ?? "";
|
|
4167
|
+
if (resultText.includes("No changes applied")) {
|
|
4168
|
+
debug.event("fold-replay-skipped", { sid, callId: call.id });
|
|
4169
|
+
continue;
|
|
4170
|
+
}
|
|
4171
|
+
if (slot.appliedCallIds.has(call.id) || stateHasCompressCall(slot.state, call.id)) continue;
|
|
4172
|
+
const verdicts = call.ranges.map((r, ri) => staleRangeCore(r, ri, resultText, coreMessages, i, slot.state.messageRefs.byRef, slot.state.blocks));
|
|
4173
|
+
const stale = verdicts.find((v) => v.reject);
|
|
4174
|
+
if (stale) {
|
|
4175
|
+
debug.event("fold-replay-stale", { sid, callId: call.id, reason: stale.reject });
|
|
4176
|
+
const failed = verdicts.find((v) => v.hint && v.reject);
|
|
4177
|
+
if (failed) logWarn("fold", { sid, event: "replay-recovery-failed", callId: call.id, reason: failed.reject });
|
|
4178
|
+
continue;
|
|
4179
|
+
}
|
|
4180
|
+
const recovered = verdicts.find((v) => v.recovered);
|
|
4181
|
+
const ranges = recovered ? call.ranges.map((r, ri) => {
|
|
4182
|
+
const m = verdicts[ri].remap;
|
|
4183
|
+
return m ? { ...r, startRef: m.startRef ?? r.startRef, endRef: m.endRef ?? r.endRef } : r;
|
|
4184
|
+
}) : call.ranges;
|
|
4185
|
+
if (recovered) {
|
|
4186
|
+
logWarn("fold", { sid, event: "replay-recovered", callId: call.id, pos: recovered.recovered.pos, startIdx: recovered.recovered.startIdx, endIdx: recovered.recovered.endIdx });
|
|
4187
|
+
}
|
|
4188
|
+
try {
|
|
4189
|
+
const applied = core.applyCompression({ ranges, messages: coreMessages, state: slot.state, config });
|
|
4190
|
+
if (applied.result.errors.length === 0) {
|
|
4191
|
+
slot.state = applied.state;
|
|
4192
|
+
replayed++;
|
|
4193
|
+
debug.event("fold-replay", { sid, callId: call.id, ranges: call.ranges.length });
|
|
4194
|
+
} else {
|
|
4195
|
+
logWarn("fold", { sid, event: "replay-rejected", callId: call.id, errors: applied.result.errors.slice(0, 3) });
|
|
4196
|
+
}
|
|
4197
|
+
} catch (e) {
|
|
4198
|
+
logWarn("fold", { sid, event: "replay-failed", callId: call.id, error: e instanceof Error ? e.message : String(e) });
|
|
4199
|
+
}
|
|
4200
|
+
slot.appliedCallIds.add(call.id);
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
if (replayed > 0) logWarn("fold", { sid, event: "replayed", calls: replayed });
|
|
4204
|
+
slot.identities = ids;
|
|
4205
|
+
slot.foldedLen = ids.length;
|
|
4206
|
+
slot.coreMessages = coreMessages;
|
|
4207
|
+
return { state: slot.state, coreMessages, streamLen: stream.length };
|
|
4208
|
+
}
|
|
3654
4209
|
function stateFor(ctx) {
|
|
3655
|
-
const
|
|
4210
|
+
const sid = sidOf(ctx);
|
|
4211
|
+
const slot = slotForMode(ctx, sid);
|
|
3656
4212
|
return Promise.resolve({ state: slot.state, coreMessages: slot.coreMessages });
|
|
3657
4213
|
}
|
|
3658
4214
|
function primeFold(ctx) {
|
|
@@ -3661,30 +4217,40 @@ function createRuntime(adapter) {
|
|
|
3661
4217
|
const sm = ctx.sessionManager;
|
|
3662
4218
|
const view = sm.buildSessionContext?.().messages ?? [];
|
|
3663
4219
|
if (view.length === 0) return;
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
4220
|
+
if (resolveTransformMode(adapterRef, ctx.model) === "provider") {
|
|
4221
|
+
const api = ctx.model?.api ?? "";
|
|
4222
|
+
let stream;
|
|
4223
|
+
if (api === "anthropic-messages") {
|
|
4224
|
+
stream = viewToAnthropicCore(view);
|
|
4225
|
+
} else {
|
|
4226
|
+
const base = getSystemPromptText(ctx);
|
|
4227
|
+
const acp = buildAcpSystemPrompt(promptsRef);
|
|
4228
|
+
stream = viewToCoreStream(view, base.includes(acp) ? base : `${base}
|
|
3670
4229
|
|
|
3671
4230
|
${acp}`);
|
|
3672
|
-
|
|
4231
|
+
}
|
|
4232
|
+
const r2 = foldStreamCore(ctx, stream);
|
|
4233
|
+
coreSlotFor(sid).preview = true;
|
|
4234
|
+
logInfo("fold", { sid, event: "prime-fold", msgs: stream.length, wire: true, blocks: r2.state.blocks.length });
|
|
4235
|
+
return;
|
|
3673
4236
|
}
|
|
3674
|
-
const r = foldStream(ctx,
|
|
4237
|
+
const r = foldStream(ctx, view);
|
|
3675
4238
|
slotFor(sid).preview = true;
|
|
3676
|
-
logInfo("fold", { sid, event: "prime-fold", msgs:
|
|
4239
|
+
logInfo("fold", { sid, event: "prime-fold", msgs: view.length, wire: false, blocks: r.state.blocks.length });
|
|
3677
4240
|
} catch (e) {
|
|
3678
4241
|
logWarn("fold", { sid, event: "prime-fold-failed", error: e instanceof Error ? e.message : String(e) });
|
|
3679
4242
|
}
|
|
3680
4243
|
}
|
|
3681
4244
|
function forgetSession(sid) {
|
|
3682
4245
|
slots.delete(sid);
|
|
4246
|
+
coreSlots.delete(sid);
|
|
3683
4247
|
locks.delete(sid);
|
|
3684
4248
|
}
|
|
4249
|
+
function slotForMode(ctx, sid) {
|
|
4250
|
+
return resolveTransformMode(adapterRef, ctx.model) === "provider" ? coreSlotFor(sid) : slotFor(sid);
|
|
4251
|
+
}
|
|
3685
4252
|
function commitFoldState(ctx, state, toolCallId) {
|
|
3686
|
-
const
|
|
3687
|
-
const slot = slotFor(sid);
|
|
4253
|
+
const slot = slotForMode(ctx, sidOf(ctx));
|
|
3688
4254
|
slot.state = state;
|
|
3689
4255
|
if (toolCallId) slot.appliedCallIds.add(toolCallId);
|
|
3690
4256
|
}
|
|
@@ -3693,7 +4259,7 @@ ${acp}`);
|
|
|
3693
4259
|
slot.lastRebuiltOutput = rebuilt.map(messageIdentity);
|
|
3694
4260
|
}
|
|
3695
4261
|
function noteCompressOutcome(ctx, ok) {
|
|
3696
|
-
const slot =
|
|
4262
|
+
const slot = slotForMode(ctx, sidOf(ctx));
|
|
3697
4263
|
slot.rejectStreak = ok ? 0 : slot.rejectStreak + 1;
|
|
3698
4264
|
return slot.rejectStreak;
|
|
3699
4265
|
}
|
|
@@ -3714,6 +4280,7 @@ ${acp}`);
|
|
|
3714
4280
|
liveContextLimit,
|
|
3715
4281
|
configFor,
|
|
3716
4282
|
foldStream,
|
|
4283
|
+
foldStreamCore,
|
|
3717
4284
|
stateFor,
|
|
3718
4285
|
commitFoldState,
|
|
3719
4286
|
recordRebuiltOutput,
|
|
@@ -3906,9 +4473,11 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
|
|
|
3906
4473
|
logError("compress", { sid: ctx.sessionManager.getSessionId(), event: "warnings", count: warnings.length, warnings: warnings.slice(0, 5) });
|
|
3907
4474
|
}
|
|
3908
4475
|
const fps = rangeFingerprints(rangeSpecs, coreMessages, applied.state.messageRefs.byRef, applied.state.blocks);
|
|
4476
|
+
const positions = rangePositionsCore(rangeSpecs, coreMessages, applied.state.messageRefs.byRef, applied.state.blocks);
|
|
3909
4477
|
const lines = [`\u25A3 ACP | ${formatTokens3(beforeTokens)} \u2192 ${formatTokens3(afterTokens)} tokens (~${formatTokens3(tokensCompressed)} reclaimed, ${blocksCreated} block${blocksCreated > 1 ? "s" : ""})`];
|
|
3910
4478
|
if (warnings.length > 0) lines.push("\u26A0\uFE0F " + warnings.join("; "));
|
|
3911
4479
|
if (fps.some((fp) => fp !== "-")) lines.push(`[fp=${fps.join(",")}]`);
|
|
4480
|
+
if (positions.some((p) => p !== "-")) lines.push(`[pos=${positions.join(",")}]`);
|
|
3912
4481
|
return lines.join("\n");
|
|
3913
4482
|
} finally {
|
|
3914
4483
|
releaseLock();
|
|
@@ -4280,7 +4849,7 @@ function renderMessage2(message, map, countTokens, strategy) {
|
|
|
4280
4849
|
if (!cleanText) return { ...message, text: prefix };
|
|
4281
4850
|
return { ...message, text: prefix + cleanText };
|
|
4282
4851
|
}
|
|
4283
|
-
function
|
|
4852
|
+
function renderVisibleRefs(messages, state, countTokens = (text) => Math.ceil(text.length / 4), strategy = "all") {
|
|
4284
4853
|
const map = state.messageRefs;
|
|
4285
4854
|
return messages.map(
|
|
4286
4855
|
(message) => renderMessage2(message, map, countTokens, strategy)
|
|
@@ -4292,7 +4861,7 @@ function createRenderRefsNode2(strategy) {
|
|
|
4292
4861
|
run(io, ctx) {
|
|
4293
4862
|
return {
|
|
4294
4863
|
...io,
|
|
4295
|
-
messages:
|
|
4864
|
+
messages: renderVisibleRefs(io.messages, io.state, ctx.countTokens, strategy)
|
|
4296
4865
|
};
|
|
4297
4866
|
}
|
|
4298
4867
|
};
|
|
@@ -4903,7 +5472,7 @@ async function statusReport(runtime, ctx) {
|
|
|
4903
5472
|
const coveredIds = collectCoveredMessageIds(state);
|
|
4904
5473
|
const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
|
|
4905
5474
|
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount: sentTokens });
|
|
4906
|
-
const versionStr = "0.2.
|
|
5475
|
+
const versionStr = "0.2.8" ? `billion-context-omp@${"0.2.8"}` : void 0;
|
|
4907
5476
|
return buildStatusPanel({
|
|
4908
5477
|
version: versionStr,
|
|
4909
5478
|
tokenCount: sessionTokens,
|
|
@@ -5033,6 +5602,10 @@ import { readFileSync, writeFileSync } from "fs";
|
|
|
5033
5602
|
import { join as join3 } from "path";
|
|
5034
5603
|
var MARKER_FILE = ".billion-context-omp-instance.json";
|
|
5035
5604
|
var FRESH_MS = 6e4;
|
|
5605
|
+
function normalizeLoadPath(p) {
|
|
5606
|
+
const q = p.indexOf("?");
|
|
5607
|
+
return q === -1 ? p : p.slice(0, q);
|
|
5608
|
+
}
|
|
5036
5609
|
function markerPath() {
|
|
5037
5610
|
return join3(homeDir(), ".omp", MARKER_FILE);
|
|
5038
5611
|
}
|
|
@@ -5047,7 +5620,7 @@ function readMarker() {
|
|
|
5047
5620
|
function detectDualInstance(selfPath, now = Date.now()) {
|
|
5048
5621
|
const m = readMarker();
|
|
5049
5622
|
if (!m) return void 0;
|
|
5050
|
-
if (m.path === selfPath) return void 0;
|
|
5623
|
+
if (normalizeLoadPath(m.path) === normalizeLoadPath(selfPath)) return void 0;
|
|
5051
5624
|
if (now - m.ts > FRESH_MS) return void 0;
|
|
5052
5625
|
return m;
|
|
5053
5626
|
}
|
|
@@ -5193,7 +5766,7 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
5193
5766
|
const data = await res.json();
|
|
5194
5767
|
const latest = data.version;
|
|
5195
5768
|
if (!latest) return;
|
|
5196
|
-
const current = runtimeVersion ?? "0.2.
|
|
5769
|
+
const current = runtimeVersion ?? "0.2.8";
|
|
5197
5770
|
const hasUpdate = isNewer(latest, current);
|
|
5198
5771
|
debug.event("update-check", {
|
|
5199
5772
|
current,
|
|
@@ -5450,7 +6023,6 @@ function createAcpExtension(adapter = {}) {
|
|
|
5450
6023
|
return (pi) => {
|
|
5451
6024
|
const runtime = createRuntime(adapter);
|
|
5452
6025
|
wireSessionLifecycle(pi, runtime);
|
|
5453
|
-
wireSessionLifecycle(pi, runtime);
|
|
5454
6026
|
wireContextTransform(pi, runtime);
|
|
5455
6027
|
wireSystemPrompt(pi, runtime);
|
|
5456
6028
|
wireProviderTransform(pi, runtime);
|
|
@@ -5469,9 +6041,9 @@ var index_default = createAcpExtension();
|
|
|
5469
6041
|
function wireSessionLifecycle(pi, runtime) {
|
|
5470
6042
|
pi.on("session_start", async (_event, ctx) => {
|
|
5471
6043
|
const sid = ctx.sessionManager.getSessionId();
|
|
5472
|
-
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.2.
|
|
6044
|
+
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.2.8" : null });
|
|
5473
6045
|
const selfPath = import.meta.url;
|
|
5474
|
-
const conflict = stampAndDetect(selfPath, true ? "0.2.
|
|
6046
|
+
const conflict = stampAndDetect(selfPath, true ? "0.2.8" : null);
|
|
5475
6047
|
if (conflict) {
|
|
5476
6048
|
logWarn("instance", { event: "dual-instance", self: selfPath, other: conflict.path, otherPid: conflict.pid, otherVersion: conflict.version });
|
|
5477
6049
|
try {
|
|
@@ -5495,9 +6067,9 @@ function wireSessionLifecycle(pi, runtime) {
|
|
|
5495
6067
|
runtime.setPrompts(defaultPrompts);
|
|
5496
6068
|
}
|
|
5497
6069
|
runtime.primeFold(ctx);
|
|
5498
|
-
|
|
6070
|
+
void checkForUpdate(runtime.adapter.autoUpdate ?? true, (msg) => {
|
|
5499
6071
|
if (ctx.hasUI) ctx.ui.notify(msg);
|
|
5500
|
-
});
|
|
6072
|
+
}).catch((e) => logThrow("update", e, { sid, phase: "session_start" }));
|
|
5501
6073
|
});
|
|
5502
6074
|
pi.on("session_shutdown", (_event, ctx) => {
|
|
5503
6075
|
try {
|
|
@@ -5631,14 +6203,14 @@ ${rendered.text}${example}`);
|
|
|
5631
6203
|
} finally {
|
|
5632
6204
|
release();
|
|
5633
6205
|
}
|
|
5634
|
-
|
|
6206
|
+
void checkForUpdate(runtime.adapter.autoUpdate ?? true, (msg) => {
|
|
5635
6207
|
if (ctx.hasUI) ctx.ui.notify(msg);
|
|
5636
|
-
});
|
|
6208
|
+
}).catch((e) => logThrow("update", e, { sid, phase: "context" }));
|
|
5637
6209
|
return result;
|
|
5638
6210
|
}
|
|
5639
6211
|
function wireContextTransform(pi, runtime) {
|
|
5640
6212
|
pi.on("context", async (event, ctx) => {
|
|
5641
|
-
if ((runtime.adapter.
|
|
6213
|
+
if (resolveTransformMode(runtime.adapter, ctx.model) === "provider") {
|
|
5642
6214
|
debug.event("context-observer-skip", { sid: ctx.sessionManager.getSessionId(), msgs: event.messages?.length ?? 0 });
|
|
5643
6215
|
return void 0;
|
|
5644
6216
|
}
|
|
@@ -5649,34 +6221,158 @@ function wireContextTransform(pi, runtime) {
|
|
|
5649
6221
|
}
|
|
5650
6222
|
function wireProviderTransform(pi, runtime) {
|
|
5651
6223
|
pi.on("before_provider_request", async (event, ctx) => {
|
|
5652
|
-
if ((runtime.adapter.
|
|
6224
|
+
if (resolveTransformMode(runtime.adapter, ctx.model) !== "provider") return void 0;
|
|
5653
6225
|
const payload = event.payload;
|
|
5654
6226
|
if (payload === null || typeof payload !== "object" || !Array.isArray(payload.messages)) return void 0;
|
|
5655
6227
|
const sid = ctx.sessionManager?.getSessionId?.() ?? "";
|
|
5656
|
-
const fmt2 =
|
|
5657
|
-
if (fmt2 ===
|
|
6228
|
+
const fmt2 = detectProviderWireFormat(payload);
|
|
6229
|
+
if (fmt2 === null) {
|
|
5658
6230
|
debug.event("provider-transform-unknown-format", { sid });
|
|
5659
6231
|
return void 0;
|
|
5660
6232
|
}
|
|
6233
|
+
const representable = payloadRepresentable(payload, fmt2);
|
|
6234
|
+
if (!representable.ok) {
|
|
6235
|
+
logInfo("provider-transform", { sid, fmt: fmt2, event: "unrepresentable", reason: representable.reason });
|
|
6236
|
+
debug.event("provider-transform-unrepresentable", { sid, fmt: fmt2, reason: representable.reason });
|
|
6237
|
+
return void 0;
|
|
6238
|
+
}
|
|
5661
6239
|
try {
|
|
5662
|
-
const
|
|
5663
|
-
if (
|
|
5664
|
-
const result = await
|
|
6240
|
+
const { msgs, cacheControls } = payloadToCore(payload, fmt2);
|
|
6241
|
+
if (msgs.length === 0) return void 0;
|
|
6242
|
+
const result = await transformStreamCore(ctx, runtime, msgs, fmt2);
|
|
5665
6243
|
if (!result) return void 0;
|
|
5666
|
-
const
|
|
5667
|
-
const outMsgs = wireOut.messages?.length ?? 0;
|
|
6244
|
+
const outMsgs = coreToPayloadMessages(result.coreOut, fmt2, cacheControls).length;
|
|
5668
6245
|
const inMsgs = payload.messages?.length ?? 0;
|
|
5669
|
-
if (outMsgs !== inMsgs
|
|
6246
|
+
if (outMsgs !== inMsgs) {
|
|
5670
6247
|
logInfo("provider-transform", { sid, fmt: fmt2, inMsgs, outMsgs, nudge: result.nudgeInjected ? "injected" : "idle" });
|
|
5671
6248
|
}
|
|
5672
6249
|
debug.event("provider-transform", { sid, fmt: fmt2, inMsgs, outMsgs, nudgeInjected: result.nudgeInjected });
|
|
5673
|
-
return
|
|
6250
|
+
return { ...payload, messages: coreToPayloadMessages(result.coreOut, fmt2, cacheControls) };
|
|
5674
6251
|
} catch (e) {
|
|
5675
6252
|
logThrow("provider-transform", e, { sid, fmt: fmt2 });
|
|
5676
6253
|
return void 0;
|
|
5677
6254
|
}
|
|
5678
6255
|
});
|
|
5679
6256
|
}
|
|
6257
|
+
async function transformStreamCore(ctx, runtime, wireMsgs, fmt2) {
|
|
6258
|
+
const sid = ctx.sessionManager.getSessionId();
|
|
6259
|
+
const release = await runtime.acquireLock(sid);
|
|
6260
|
+
let result;
|
|
6261
|
+
try {
|
|
6262
|
+
if (wireMsgs.length === 0) {
|
|
6263
|
+
debug.event("empty-stream-bypass", { sid, space: "core" });
|
|
6264
|
+
return void 0;
|
|
6265
|
+
}
|
|
6266
|
+
debug.event("context-in-raw", { sid, msgs: wireMsgs.length, mode: "provider" });
|
|
6267
|
+
const { state, coreMessages, streamLen } = runtime.foldStreamCore(ctx, wireMsgs);
|
|
6268
|
+
const preTurnNudgeBaseline = state.nudge.lastPerMessageNudgeTokens;
|
|
6269
|
+
const preTurnNudgeShownTokens = state.nudge.lastNudgeShownTokens;
|
|
6270
|
+
const preTurnNudgeShownByTier = state.nudge.lastShownByTier;
|
|
6271
|
+
const config = runtime.configFor(ctx);
|
|
6272
|
+
const coveredIds = collectCoveredMessageIds(state);
|
|
6273
|
+
const systemPromptTokens = estimateTextTokens2(getSystemPromptText(ctx) ?? "");
|
|
6274
|
+
const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
|
|
6275
|
+
const sessionTokens = ctx.getContextUsage?.()?.tokens ?? null;
|
|
6276
|
+
const tokenCount = sentTokens;
|
|
6277
|
+
debug.event("context-in", {
|
|
6278
|
+
sid,
|
|
6279
|
+
mode: "provider",
|
|
6280
|
+
fmt: fmt2,
|
|
6281
|
+
streamLen,
|
|
6282
|
+
coreMsgs: coreMessages.length,
|
|
6283
|
+
tokenCount,
|
|
6284
|
+
sessionTokens,
|
|
6285
|
+
limit: config.modelContextLimit,
|
|
6286
|
+
blocksBefore: state.blocks.length,
|
|
6287
|
+
activeBefore: state.blocks.filter((b) => b.active).length
|
|
6288
|
+
});
|
|
6289
|
+
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount, renderTags: "text-only" });
|
|
6290
|
+
runtime.commitFoldState(ctx, turn.state);
|
|
6291
|
+
logInfo("turn", {
|
|
6292
|
+
sid,
|
|
6293
|
+
inMsgs: coreMessages.length,
|
|
6294
|
+
outMsgs: turn.messages.length,
|
|
6295
|
+
tokens: tokenCount,
|
|
6296
|
+
sessionTokens,
|
|
6297
|
+
pct: config.modelContextLimit > 0 ? Math.round(tokenCount / config.modelContextLimit * 100) : null,
|
|
6298
|
+
limit: config.modelContextLimit,
|
|
6299
|
+
nudge: turn.nudge?.shouldInject ? turn.nudge.breakdown?.emergencyOverride === 1 ? "emergency" : "active" : "idle",
|
|
6300
|
+
nudgeReason: turn.nudge?.reason ?? null,
|
|
6301
|
+
blocks: turn.state.blocks.length,
|
|
6302
|
+
activeBlocks: turn.state.blocks.filter((b) => b.active).length
|
|
6303
|
+
});
|
|
6304
|
+
debug.event("processTurn", {
|
|
6305
|
+
outMsgs: turn.messages.length,
|
|
6306
|
+
summaryMsgs: turn.messages.filter((m) => m.id.startsWith("acp_summary")).length,
|
|
6307
|
+
prunedMsgs: coreMessages.length - turn.messages.length + turn.messages.filter((m) => m.id.startsWith("acp_summary")).length,
|
|
6308
|
+
nudgeShouldInject: turn.nudge?.shouldInject ?? false,
|
|
6309
|
+
nudgeReason: turn.nudge?.reason ?? null,
|
|
6310
|
+
nudgeVoice: turn.nudge ? renderNudgeText(turn.nudge, runtime.prompts).voice : null,
|
|
6311
|
+
nudgePct: turn.nudge ? Math.round(turn.nudge.contextUsage * 100) : null,
|
|
6312
|
+
nudgeTier: turn.nudge?.tier ?? null,
|
|
6313
|
+
nudgeCompressibleCount: turn.nudge?.compressibleRanges.length ?? 0,
|
|
6314
|
+
nudgeProtectedCount: turn.nudge?.protectedRanges?.length ?? 0,
|
|
6315
|
+
nothingToCompress: turn.nudge?.reason?.includes("nothing to compress") ?? false,
|
|
6316
|
+
blocksAfter: turn.state.blocks.length,
|
|
6317
|
+
activeAfter: turn.state.blocks.filter((b) => b.active).length
|
|
6318
|
+
});
|
|
6319
|
+
const coreOut = applyWireTagContract(
|
|
6320
|
+
turn.messages.filter((m) => !m.id.startsWith("acp_summary_")),
|
|
6321
|
+
turn.state,
|
|
6322
|
+
{ config, tokenCount }
|
|
6323
|
+
);
|
|
6324
|
+
let nudgeInjected = false;
|
|
6325
|
+
if (turn.nudge?.shouldInject) {
|
|
6326
|
+
const lastUser = [...wireMsgs].reverse().find((m) => m.role === "user");
|
|
6327
|
+
const tailText = lastUser ? lastUser.text ?? "" : "";
|
|
6328
|
+
const isFeedbackView = tailText.includes("efficiency nudge to compress early") || tailText.includes("Context limit reached");
|
|
6329
|
+
if (isFeedbackView) {
|
|
6330
|
+
debug.event("nudge-feedback-skip", { sid, msgs: wireMsgs.length });
|
|
6331
|
+
} else {
|
|
6332
|
+
const emergency = turn.nudge.breakdown?.emergencyOverride === 1;
|
|
6333
|
+
const epochReset = turn.state.nudge.lastPerMessageNudgeTokens !== preTurnNudgeBaseline;
|
|
6334
|
+
const prevShown = epochReset ? 0 : preTurnNudgeShownTokens;
|
|
6335
|
+
const cadenceFloor = turn.nudge.breakdown?.growthFloor ?? 0;
|
|
6336
|
+
const suppressed = !emergency && prevShown > 0 && tokenCount - prevShown < cadenceFloor;
|
|
6337
|
+
if (suppressed) {
|
|
6338
|
+
turn.state.nudge.lastNudgeShownTokens = prevShown;
|
|
6339
|
+
turn.state.nudge.lastShownByTier = preTurnNudgeShownByTier;
|
|
6340
|
+
logInfo("nudge", { sid, event: "cadence-suppressed", growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6341
|
+
debug.event("nudge-suppressed", { sid, growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6342
|
+
} else {
|
|
6343
|
+
nudgeInjected = true;
|
|
6344
|
+
turn.nudge.compressibleRanges = viableRanges(turn.nudge.compressibleRanges);
|
|
6345
|
+
const rendered = renderNudgeText(turn.nudge, runtime.prompts);
|
|
6346
|
+
const top = [...turn.nudge.compressibleRanges].sort((a, b) => b.tokens - a.tokens)[0];
|
|
6347
|
+
const example = top ? `
|
|
6348
|
+
|
|
6349
|
+
Example: compress({ content: [{ startId: "${top.startRef}", endId: "${top.endRef}", summary: "..." }] })` : "";
|
|
6350
|
+
if (emergency) {
|
|
6351
|
+
logWarn("nudge", { sid, event: "emergency-inject", pct: Math.round(turn.nudge.contextUsage * 100), voice: rendered.voice, compressible: turn.nudge.compressibleRanges.length });
|
|
6352
|
+
}
|
|
6353
|
+
const debugOn2 = debug.enabled;
|
|
6354
|
+
if (debugOn2 && ctx.hasUI) {
|
|
6355
|
+
ctx.ui.notify(`[ACP nudge \u2192 context]${emergency ? " [EMERGENCY]" : ""}
|
|
6356
|
+
${rendered.text}${example}`);
|
|
6357
|
+
}
|
|
6358
|
+
debug.event("nudge-injected", { sid, voice: rendered.voice, channels: ["wire", debugOn2 ? "terminal" : null].filter(Boolean), emergency, text: rendered.text + example });
|
|
6359
|
+
coreOut.push({ id: `acp_nudge_${Date.now()}`, role: "user", contentType: "text", text: nudgeText(turn.nudge, turn.state.blocks.filter((b) => b.active), runtime.prompts, example) });
|
|
6360
|
+
}
|
|
6361
|
+
}
|
|
6362
|
+
}
|
|
6363
|
+
debug.event("core-out", { sid, coreOutMsgs: coreOut.length, space: "core", fmt: fmt2 });
|
|
6364
|
+
result = { coreOut, nudgeInjected };
|
|
6365
|
+
} catch (e) {
|
|
6366
|
+
logThrow("context-core", e, { sid, phase: "transform" });
|
|
6367
|
+
throw e;
|
|
6368
|
+
} finally {
|
|
6369
|
+
release();
|
|
6370
|
+
}
|
|
6371
|
+
void checkForUpdate(runtime.adapter.autoUpdate ?? true, (msg) => {
|
|
6372
|
+
if (ctx.hasUI) ctx.ui.notify(msg);
|
|
6373
|
+
}).catch((e) => logThrow("update", e, { sid, phase: "provider" }));
|
|
6374
|
+
return result;
|
|
6375
|
+
}
|
|
5680
6376
|
function wireSystemPrompt(pi, runtime) {
|
|
5681
6377
|
pi.on("before_agent_start", (event) => {
|
|
5682
6378
|
const acp = buildAcpSystemPrompt(runtime.prompts);
|
|
@@ -5708,7 +6404,7 @@ function wireProviderDebug(pi) {
|
|
|
5708
6404
|
});
|
|
5709
6405
|
});
|
|
5710
6406
|
}
|
|
5711
|
-
function
|
|
6407
|
+
function nudgeText(nudge, blocks, prompts, example) {
|
|
5712
6408
|
const rendered = renderNudgeText(nudge, prompts);
|
|
5713
6409
|
const lines = [rendered.text];
|
|
5714
6410
|
if (blocks.length > 0) {
|
|
@@ -5727,9 +6423,12 @@ function nudgeMessage(nudge, blocks, prompts, example) {
|
|
|
5727
6423
|
lines.push(`Compressed blocks: ${blocks.length} active (${tierStr}) \u2014 ${fmt2(totalSummary)} summary, ${fmt2(totalCompressed)} original compressed. Blocks: ${ids}${extra}.`);
|
|
5728
6424
|
}
|
|
5729
6425
|
if (example) lines.push(example);
|
|
6426
|
+
return lines.join("\n");
|
|
6427
|
+
}
|
|
6428
|
+
function nudgeMessage(nudge, blocks, prompts, example) {
|
|
5730
6429
|
return {
|
|
5731
6430
|
role: "user",
|
|
5732
|
-
content: [{ type: "text", text:
|
|
6431
|
+
content: [{ type: "text", text: nudgeText(nudge, blocks, prompts, example) }],
|
|
5733
6432
|
timestamp: Date.now()
|
|
5734
6433
|
};
|
|
5735
6434
|
}
|