billion-context-omp 0.2.6 → 0.2.7

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/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,7 +742,7 @@ 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 };
@@ -741,14 +754,27 @@ function renderVisibleRefs(messages, state, countTokens = (text) => Math.ceil(te
741
754
  (message) => renderMessage(message, map, countTokens, strategy)
742
755
  );
743
756
  }
757
+ function renderWithSnapshot(messages, state, countTokens = (text) => Math.ceil(text.length / 4), strategy = "all") {
758
+ const map = state.messageRefs;
759
+ const snapshot = { ...state.tokenSnapshot ?? {} };
760
+ const rendered = messages.map(
761
+ (message) => renderMessage(message, map, countTokens, strategy, snapshot)
762
+ );
763
+ return { messages: rendered, tokenSnapshot: snapshot };
764
+ }
744
765
  function createRenderRefsNode(strategy) {
745
766
  return {
746
767
  name: "render-refs",
747
768
  run(io, ctx) {
748
- return {
749
- ...io,
750
- messages: renderVisibleRefs(io.messages, io.state, ctx.countTokens, strategy)
751
- };
769
+ const { messages, tokenSnapshot } = renderWithSnapshot(
770
+ io.messages,
771
+ io.state,
772
+ ctx.countTokens,
773
+ strategy
774
+ );
775
+ const prev = io.state.tokenSnapshot;
776
+ const changed = !prev || Object.keys(tokenSnapshot).length !== Object.keys(prev).length;
777
+ return changed ? { ...io, messages, state: { ...io.state, tokenSnapshot } } : { ...io, messages };
752
778
  }
753
779
  };
754
780
  }
@@ -944,6 +970,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
944
970
  ref,
945
971
  refNum: rn,
946
972
  tokens: countTokens(msg.text ?? ""),
973
+ chars: (msg.text ?? "").length,
947
974
  isTool: isToolMessage(msg),
948
975
  isUser: msg.role === "user"
949
976
  });
@@ -964,6 +991,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
964
991
  endRef: info.ref,
965
992
  count: 1,
966
993
  tokens: info.tokens,
994
+ chars: info.chars,
967
995
  toolPct: info.isTool ? 100 : 0,
968
996
  textPct: info.isTool ? 0 : 100
969
997
  };
@@ -971,6 +999,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs, cou
971
999
  cur.endRef = info.ref;
972
1000
  cur.count++;
973
1001
  cur.tokens += info.tokens;
1002
+ cur.chars = (cur.chars ?? 0) + info.chars;
974
1003
  if (info.isTool) {
975
1004
  cur.toolPct = Math.round((cur.toolPct * (cur.count - 1) + 100) / cur.count);
976
1005
  } else {
@@ -1018,6 +1047,7 @@ function mergeBatch(batch) {
1018
1047
  const last = batch[batch.length - 1];
1019
1048
  const count = batch.reduce((s, r) => s + r.count, 0);
1020
1049
  const tokens = batch.reduce((s, r) => s + r.tokens, 0);
1050
+ const chars = batch.reduce((s, r) => s + rangeChars(r), 0);
1021
1051
  const toolPct = Math.round(
1022
1052
  batch.reduce((s, r) => s + r.toolPct * r.count, 0) / count
1023
1053
  );
@@ -1026,6 +1056,7 @@ function mergeBatch(batch) {
1026
1056
  endRef: last.endRef,
1027
1057
  count,
1028
1058
  tokens,
1059
+ chars,
1029
1060
  toolPct,
1030
1061
  textPct: 100 - toolPct
1031
1062
  };
@@ -1034,16 +1065,21 @@ function mergeBatch(batch) {
1034
1065
  }
1035
1066
  return merged;
1036
1067
  }
1068
+ function rangeChars(r) {
1069
+ return r.chars ?? r.tokens * 4;
1070
+ }
1037
1071
  function mergeRangesToThreshold(ranges, minChars) {
1038
1072
  if (minChars <= 0 || ranges.length === 0) return ranges;
1039
1073
  const result = [];
1040
1074
  let batch = [];
1075
+ let batchChars = 0;
1041
1076
  for (const r of ranges) {
1042
1077
  batch.push(r);
1043
- const batchTokens = batch.reduce((s, x) => s + x.tokens, 0);
1044
- if (batchTokens * 4 >= minChars) {
1078
+ batchChars += rangeChars(r);
1079
+ if (batchChars >= minChars) {
1045
1080
  result.push(mergeBatch(batch));
1046
1081
  batch = [];
1082
+ batchChars = 0;
1047
1083
  }
1048
1084
  }
1049
1085
  if (batch.length > 0) {
@@ -1631,7 +1667,7 @@ function resolveAdaptiveGrowth(modelContextLimit, nudge) {
1631
1667
  function pendingByTier(state, recommendation, countTokens, minCompressRange) {
1632
1668
  const out = {};
1633
1669
  const merged = recommendation?.recommendedRanges ?? [];
1634
- const effective = minCompressRange > 0 ? merged.filter((r) => r.tokens * 4 >= minCompressRange) : merged;
1670
+ const effective = minCompressRange > 0 ? merged.filter((r) => (r.chars ?? r.tokens * 4) >= minCompressRange) : merged;
1635
1671
  out[1] = { pending: effective.reduce((s, r) => s + r.tokens, 0), targetBlocks: [] };
1636
1672
  const active = activeBlocks(state);
1637
1673
  const t1 = active.filter((b) => b.tier === 1);
@@ -1793,6 +1829,7 @@ function cloneState(state) {
1793
1829
  byRaw: { ...state.messageRefs.byRaw },
1794
1830
  byRef: { ...state.messageRefs.byRef }
1795
1831
  },
1832
+ tokenSnapshot: { ...state.tokenSnapshot ?? {} },
1796
1833
  nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },
1797
1834
  stats: { ...state.stats },
1798
1835
  nextBlockId: state.nextBlockId,
@@ -2757,8 +2794,12 @@ function resolveConfig(adapter, liveContextLimit) {
2757
2794
  if (c?.maxContextLimit !== void 0) config.nudge.maxContextLimitPct = parsePercent(c.maxContextLimit);
2758
2795
  if (c?.emergencyThresholdPercent !== void 0) {
2759
2796
  const pct2 = parsePercent(c.emergencyThresholdPercent);
2760
- config.nudge.emergencyThresholdPct = pct2;
2761
- config.truncate.threshold = pct2;
2797
+ if (pct2 <= 0) {
2798
+ logWarn("config", { event: "emergency-threshold-ignored", value: String(c.emergencyThresholdPercent), reason: "zero threshold would truncate every turn" });
2799
+ } else {
2800
+ config.nudge.emergencyThresholdPct = pct2;
2801
+ config.truncate.threshold = pct2;
2802
+ }
2762
2803
  }
2763
2804
  if (c?.nudgeGrowthTokens !== void 0) {
2764
2805
  config.nudge.growthFloor = c.nudgeGrowthTokens;
@@ -2863,8 +2904,396 @@ When context usage passes a threshold, the system appends a breakdown showing wh
2863
2904
  `;
2864
2905
  }
2865
2906
 
2866
- // src/messages.ts
2907
+ // src/transform-mode.ts
2908
+ import { VERSION } from "@oh-my-pi/pi-utils";
2909
+ var PROVIDER_VIABLE_APIS = /* @__PURE__ */ new Set(["anthropic-messages", "ollama-chat"]);
2910
+ var OPENAI_COMPLETIONS_VIABLE_FROM = [17, 3, 8];
2911
+ function hostVersionAtLeast(min, version = VERSION) {
2912
+ const m = /^(\d+)\.(\d+)\.(\d+)/.exec(version ?? "");
2913
+ if (!m) return false;
2914
+ const v = [Number(m[1]), Number(m[2]), Number(m[3])];
2915
+ return v[0] > min[0] || v[0] === min[0] && (v[1] > min[1] || v[1] === min[1] && v[2] >= min[2]);
2916
+ }
2917
+ function resolveTransformMode(adapter, model, hostVersion = VERSION) {
2918
+ if (adapter.transformMode) return adapter.transformMode;
2919
+ const api = model?.api;
2920
+ if (api == null) return "context";
2921
+ if (PROVIDER_VIABLE_APIS.has(api)) return "provider";
2922
+ if (api === "openai-completions" && hostVersionAtLeast(OPENAI_COMPLETIONS_VIABLE_FROM, hostVersion)) return "provider";
2923
+ return "context";
2924
+ }
2925
+
2926
+ // node_modules/acp-kernel/dist/wire/index.js
2867
2927
  import { createHash } from "crypto";
2928
+ function hashId(s) {
2929
+ return createHash("sha256").update(s, "utf8").digest("hex").slice(0, 16);
2930
+ }
2931
+ function deriveMessageId(role, contentType, text, options = {}) {
2932
+ const seed = `${role}|${contentType}|${options.toolCallId ?? ""}|${options.toolName ?? ""}|${text}`;
2933
+ return "h_" + hashId(seed);
2934
+ }
2935
+ var ClusterCounter = class {
2936
+ counts = /* @__PURE__ */ new Map();
2937
+ next(baseId) {
2938
+ const n = this.counts.get(baseId) ?? 0;
2939
+ this.counts.set(baseId, n + 1);
2940
+ return n === 0 ? baseId : `${baseId}_${n}`;
2941
+ }
2942
+ };
2943
+ function anthropicToCore(body) {
2944
+ const msgs = [];
2945
+ const cacheControls = /* @__PURE__ */ new Map();
2946
+ const clusters = new ClusterCounter();
2947
+ for (const m of body.messages) {
2948
+ const blocks = typeof m.content === "string" ? [{ type: "text", text: m.content }] : m.content;
2949
+ for (const b of blocks) {
2950
+ switch (b.type) {
2951
+ case "text": {
2952
+ const base = deriveMessageId(m.role, "text", b.text);
2953
+ const id = clusters.next(base);
2954
+ msgs.push({ id, role: m.role, contentType: "text", text: b.text });
2955
+ if (b.cache_control) cacheControls.set(id, b.cache_control);
2956
+ break;
2957
+ }
2958
+ case "tool_use": {
2959
+ const base = deriveMessageId("assistant", "tool-call", safeStringify(b.input), {
2960
+ toolCallId: b.id,
2961
+ toolName: b.name
2962
+ });
2963
+ const id = clusters.next(base);
2964
+ msgs.push({
2965
+ id,
2966
+ role: "assistant",
2967
+ contentType: "tool-call",
2968
+ toolName: b.name,
2969
+ toolCallId: b.id,
2970
+ text: safeStringify(b.input)
2971
+ });
2972
+ if (b.cache_control) cacheControls.set(id, b.cache_control);
2973
+ break;
2974
+ }
2975
+ case "tool_result": {
2976
+ const text = typeof b.content === "string" ? b.content : b.content.map((c) => c.text).join("\n");
2977
+ const base = deriveMessageId("tool", "tool-result", text, { toolCallId: b.tool_use_id });
2978
+ const id = clusters.next(base);
2979
+ msgs.push({
2980
+ id,
2981
+ role: "tool",
2982
+ contentType: "tool-result",
2983
+ toolCallId: b.tool_use_id,
2984
+ text,
2985
+ ...b.is_error === true ? { toolIsError: true } : {}
2986
+ });
2987
+ if (b.cache_control) cacheControls.set(id, b.cache_control);
2988
+ break;
2989
+ }
2990
+ case "thinking": {
2991
+ const base = deriveMessageId("assistant", "reasoning", b.thinking);
2992
+ msgs.push({
2993
+ id: clusters.next(base),
2994
+ role: "assistant",
2995
+ contentType: "reasoning",
2996
+ text: b.thinking,
2997
+ ...b.signature ? { thinkingSignature: b.signature } : {}
2998
+ });
2999
+ break;
3000
+ }
3001
+ case "image": {
3002
+ const base = deriveMessageId(m.role, "text", "[image]");
3003
+ msgs.push({
3004
+ id: clusters.next(base),
3005
+ role: m.role,
3006
+ contentType: "text",
3007
+ text: "[image]",
3008
+ rawAnthropicBlock: b
3009
+ });
3010
+ break;
3011
+ }
3012
+ }
3013
+ }
3014
+ }
3015
+ return { msgs, cacheControls };
3016
+ }
3017
+ function coreToAnthropic(messages, cacheControls) {
3018
+ const out = [];
3019
+ let current = null;
3020
+ const flush = () => {
3021
+ if (current && current.blocks.length > 0) {
3022
+ out.push({ role: current.role, content: current.blocks });
3023
+ }
3024
+ current = null;
3025
+ };
3026
+ const cc = (id) => {
3027
+ const v = cacheControls?.get(id);
3028
+ return v ? { cache_control: v } : {};
3029
+ };
3030
+ for (const m of messages) {
3031
+ const target = m.role === "assistant" ? "assistant" : "user";
3032
+ if (!current || current.role !== target) {
3033
+ flush();
3034
+ current = { role: target, blocks: [] };
3035
+ }
3036
+ switch (m.contentType) {
3037
+ case "text": {
3038
+ if (m.rawAnthropicBlock) {
3039
+ current.blocks.push(m.rawAnthropicBlock);
3040
+ break;
3041
+ }
3042
+ current.blocks.push({ type: "text", text: m.text ?? "", ...cc(m.id) });
3043
+ break;
3044
+ }
3045
+ case "tool-call":
3046
+ current.blocks.push({
3047
+ type: "tool_use",
3048
+ id: m.toolCallId ?? `call_${m.id}`,
3049
+ name: m.toolName ?? "unknown",
3050
+ input: safeParse(m.text),
3051
+ ...cc(m.id)
3052
+ });
3053
+ break;
3054
+ case "tool-result":
3055
+ current.blocks.push({
3056
+ type: "tool_result",
3057
+ tool_use_id: m.toolCallId ?? "",
3058
+ content: m.text ?? "",
3059
+ ...m.toolIsError ? { is_error: true } : {},
3060
+ ...cc(m.id)
3061
+ });
3062
+ break;
3063
+ case "reasoning":
3064
+ current.blocks.push({
3065
+ type: "thinking",
3066
+ thinking: m.text ?? "",
3067
+ ...m.thinkingSignature ? { signature: m.thinkingSignature } : {}
3068
+ });
3069
+ break;
3070
+ }
3071
+ }
3072
+ flush();
3073
+ return out;
3074
+ }
3075
+ function safeStringify(v) {
3076
+ try {
3077
+ return JSON.stringify(v ?? {});
3078
+ } catch {
3079
+ return "{}";
3080
+ }
3081
+ }
3082
+ function safeParse(s) {
3083
+ if (!s) return {};
3084
+ try {
3085
+ return JSON.parse(s);
3086
+ } catch {
3087
+ return {};
3088
+ }
3089
+ }
3090
+ function parseDataUrl(url) {
3091
+ const m = /^data:([^;,]+)(?:;base64)?,(.+)$/i.exec(url);
3092
+ if (!m) return void 0;
3093
+ return { mediaType: m[1], base64: m[2] };
3094
+ }
3095
+ function openaiToCore(body) {
3096
+ const msgs = [];
3097
+ const clusters = new ClusterCounter();
3098
+ for (const m of body.messages) {
3099
+ switch (m.role) {
3100
+ case "system":
3101
+ case "developer": {
3102
+ const base = deriveMessageId(m.role, "text", stringContent(m.content));
3103
+ msgs.push({ id: clusters.next(base), role: "system", contentType: "text", text: stringContent(m.content), originalRole: m.role });
3104
+ break;
3105
+ }
3106
+ case "user": {
3107
+ const text = stringContent(m.content);
3108
+ const img = firstImagePart(m.content);
3109
+ const base = deriveMessageId("user", "text", text);
3110
+ msgs.push({
3111
+ id: clusters.next(base),
3112
+ role: "user",
3113
+ contentType: "text",
3114
+ text,
3115
+ ...img ? { rawOpenaiContent: img.part, imageMediaType: img.mediaType, imageBase64: img.base64 } : {}
3116
+ });
3117
+ break;
3118
+ }
3119
+ case "assistant": {
3120
+ const reasoning = typeof m.reasoning_content === "string" ? m.reasoning_content : "";
3121
+ if (reasoning) {
3122
+ const base = deriveMessageId("assistant", "reasoning", reasoning);
3123
+ msgs.push({
3124
+ id: clusters.next(base),
3125
+ role: "assistant",
3126
+ contentType: "reasoning",
3127
+ text: reasoning,
3128
+ reasoningContent: reasoning
3129
+ });
3130
+ }
3131
+ const text = stringContent(m.content);
3132
+ if (text) {
3133
+ const base = deriveMessageId("assistant", "text", text);
3134
+ msgs.push({ id: clusters.next(base), role: "assistant", contentType: "text", text });
3135
+ }
3136
+ if (Array.isArray(m.tool_calls)) {
3137
+ for (const tc of m.tool_calls) {
3138
+ const base = deriveMessageId("assistant", "tool-call", tc.function.arguments ?? "", {
3139
+ toolCallId: tc.id,
3140
+ toolName: tc.function.name
3141
+ });
3142
+ msgs.push({
3143
+ id: clusters.next(base),
3144
+ role: "assistant",
3145
+ contentType: "tool-call",
3146
+ toolName: tc.function.name,
3147
+ toolCallId: tc.id,
3148
+ text: tc.function.arguments ?? ""
3149
+ });
3150
+ }
3151
+ }
3152
+ break;
3153
+ }
3154
+ case "tool": {
3155
+ const base = deriveMessageId("tool", "tool-result", stringContent(m.content), {
3156
+ toolCallId: m.tool_call_id ?? ""
3157
+ });
3158
+ msgs.push({
3159
+ id: clusters.next(base),
3160
+ role: "tool",
3161
+ contentType: "tool-result",
3162
+ toolCallId: m.tool_call_id ?? "",
3163
+ text: stringContent(m.content)
3164
+ });
3165
+ break;
3166
+ }
3167
+ }
3168
+ }
3169
+ return { msgs };
3170
+ }
3171
+ function coreToOpenai(messages) {
3172
+ const out = [];
3173
+ let pending = null;
3174
+ const flush = () => {
3175
+ if (!pending) return;
3176
+ const reasoning = pending.reasoning !== null && pending.reasoning.length > 0 ? pending.reasoning : void 0;
3177
+ if (pending.toolCalls.length > 0) {
3178
+ out.push({
3179
+ role: "assistant",
3180
+ content: pending.text ?? null,
3181
+ tool_calls: pending.toolCalls,
3182
+ ...reasoning ? { reasoning_content: reasoning } : {}
3183
+ });
3184
+ } else if (pending.text !== null) {
3185
+ out.push({ role: "assistant", content: pending.text, ...reasoning ? { reasoning_content: reasoning } : {} });
3186
+ } else if (reasoning) {
3187
+ out.push({ role: "assistant", content: null, reasoning_content: reasoning });
3188
+ }
3189
+ pending = null;
3190
+ };
3191
+ for (const m of messages) {
3192
+ if (m.role === "assistant") {
3193
+ if (!pending) pending = { text: null, toolCalls: [], reasoning: null };
3194
+ if (m.contentType === "reasoning") {
3195
+ pending.reasoning = (pending.reasoning ?? "") + (m.reasoningContent ?? m.text ?? "");
3196
+ } else if (m.contentType === "text") {
3197
+ pending.text = (pending.text ?? "") + (m.text ?? "");
3198
+ } else if (m.contentType === "tool-call") {
3199
+ pending.toolCalls.push({
3200
+ id: m.toolCallId ?? `call_${m.id}`,
3201
+ type: "function",
3202
+ function: { name: m.toolName ?? "unknown", arguments: m.text ?? "" }
3203
+ });
3204
+ }
3205
+ } else {
3206
+ flush();
3207
+ if (m.role === "system") {
3208
+ out.push({ role: m.originalRole === "developer" ? "developer" : "system", content: m.text ?? "" });
3209
+ } else if (m.role === "user") {
3210
+ if (m.rawOpenaiContent || m.imageBase64) {
3211
+ const parts = [];
3212
+ if (m.text) parts.push({ type: "text", text: m.text });
3213
+ if (m.rawOpenaiContent) {
3214
+ parts.push(m.rawOpenaiContent);
3215
+ } else if (m.imageBase64 && m.imageMediaType) {
3216
+ parts.push({ type: "image_url", image_url: { url: `data:${m.imageMediaType};base64,${m.imageBase64}` } });
3217
+ }
3218
+ out.push({ role: "user", content: parts });
3219
+ } else {
3220
+ out.push({ role: "user", content: m.text ?? "" });
3221
+ }
3222
+ } else if (m.role === "tool") {
3223
+ out.push({ role: "tool", tool_call_id: m.toolCallId ?? "", content: m.text ?? "" });
3224
+ }
3225
+ }
3226
+ }
3227
+ flush();
3228
+ return out;
3229
+ }
3230
+ function stringContent(content) {
3231
+ if (content == null) return "";
3232
+ if (typeof content === "string") return content;
3233
+ if (Array.isArray(content)) {
3234
+ return content.map((p) => typeof p === "string" ? p : p.type === "text" ? p.text ?? "" : "").join("\n");
3235
+ }
3236
+ return "";
3237
+ }
3238
+ function firstImagePart(content) {
3239
+ if (!Array.isArray(content)) return void 0;
3240
+ for (const p of content) {
3241
+ if (p && typeof p === "object" && p.type === "image_url") {
3242
+ const iu = p.image_url;
3243
+ const url = iu?.url;
3244
+ if (typeof url === "string") {
3245
+ const parsed = parseDataUrl(url);
3246
+ if (parsed) return { part: p, mediaType: parsed.mediaType, base64: parsed.base64 };
3247
+ }
3248
+ }
3249
+ }
3250
+ return void 0;
3251
+ }
3252
+ function createSubagentNamespaces() {
3253
+ const anchors = /* @__PURE__ */ new Map();
3254
+ return {
3255
+ namespaceFor(identityValue, instructions) {
3256
+ if (typeof instructions !== "string" || instructions.trim().length === 0) return identityValue;
3257
+ const fp = hashId(instructions);
3258
+ const anchor = anchors.get(identityValue);
3259
+ if (anchor === void 0) {
3260
+ anchors.set(identityValue, fp);
3261
+ return identityValue;
3262
+ }
3263
+ return anchor === fp ? identityValue : `${identityValue}|sub:${fp}`;
3264
+ }
3265
+ };
3266
+ }
3267
+ var defaultNamespaces = createSubagentNamespaces();
3268
+ function detectWireFormat(payload) {
3269
+ if (payload === null || typeof payload !== "object") return void 0;
3270
+ const p = payload;
3271
+ if (Array.isArray(p.input)) return "responses";
3272
+ const messages = p.messages;
3273
+ if (!Array.isArray(messages)) return void 0;
3274
+ if ("system" in p || "anthropic_version" in p) return "anthropic";
3275
+ for (const m of messages) {
3276
+ if (m === null || typeof m !== "object") continue;
3277
+ const c = m.content;
3278
+ if (Array.isArray(c)) {
3279
+ for (const b of c) {
3280
+ if (b && typeof b === "object" && typeof b.type === "string") {
3281
+ if (b.type === "tool_use" || b.type === "tool_result" || b.type === "thinking")
3282
+ return "anthropic";
3283
+ if (b.type === "text" && "cache_control" in b) return "anthropic";
3284
+ }
3285
+ }
3286
+ }
3287
+ if (Array.isArray(m.tool_calls)) return "openai";
3288
+ if (m.role === "tool" && typeof m.tool_call_id === "string")
3289
+ return "openai";
3290
+ if (m.role === "system" || m.role === "developer") return "openai";
3291
+ }
3292
+ return "openai";
3293
+ }
3294
+
3295
+ // src/messages.ts
3296
+ import { createHash as createHash2 } from "crypto";
2868
3297
  var REF_TAG_SOURCE = "(?:<acp\\s[^>]*>m\\d+</acp>|\\[m\\d+\\])";
2869
3298
  var REF_TAG = new RegExp(`^${REF_TAG_SOURCE}\\s?\\n?`);
2870
3299
  var TRAILING_REF_TAG = new RegExp(`\\n*${REF_TAG_SOURCE}\\s*$`);
@@ -3004,7 +3433,7 @@ function fallbackText(msg) {
3004
3433
  function stringifyArgs(args) {
3005
3434
  if (!args) return "";
3006
3435
  if (typeof args === "string") return args;
3007
- return safeStringify(args);
3436
+ return safeStringify2(args);
3008
3437
  }
3009
3438
  function extractText(content, stripTags = true) {
3010
3439
  const clean = stripTags ? stripRefTag : (s) => s;
@@ -3060,7 +3489,7 @@ function allToolCalls(content) {
3060
3489
  }
3061
3490
  return calls;
3062
3491
  }
3063
- function safeStringify(value) {
3492
+ function safeStringify2(value) {
3064
3493
  try {
3065
3494
  return JSON.stringify(value);
3066
3495
  } catch {
@@ -3218,7 +3647,7 @@ function spanFingerprint(coreMessages, startId, endId) {
3218
3647
  const first = find(startId);
3219
3648
  const last = find(endId);
3220
3649
  if (!first || !last) return "";
3221
- return createHash("sha1").update(`${key(first)}\0${key(last)}`).digest("hex").slice(0, 8);
3650
+ return createHash2("sha1").update(`${key(first)}\0${key(last)}`).digest("hex").slice(0, 8);
3222
3651
  }
3223
3652
  function isBlockRef(ref) {
3224
3653
  return /^b\d+$/i.test(ref.trim());
@@ -3247,249 +3676,179 @@ function rangeFingerprints(ranges, coreMessages, byRef, blocks) {
3247
3676
  });
3248
3677
  }
3249
3678
 
3250
- // src/wire-transform.ts
3251
- var AI = /* @__PURE__ */ Symbol("acp.streamIndex");
3252
- function detectWireFormat(payload) {
3253
- if (payload === null || typeof payload !== "object") return "unknown";
3254
- const p = payload;
3255
- const messages = p.messages;
3256
- if (!Array.isArray(messages)) return "unknown";
3257
- if ("system" in p || "anthropic_version" in p) return "anthropic";
3258
- for (const m of messages) {
3259
- if (m === null || typeof m !== "object") continue;
3260
- const c = m.content;
3261
- if (Array.isArray(c)) {
3262
- for (const b of c) {
3263
- if (b && typeof b === "object" && typeof b.type === "string") {
3264
- if (b.type === "tool_use" || b.type === "tool_result" || b.type === "thinking") return "anthropic";
3265
- if (b.type === "text" && "cache_control" in b) return "anthropic";
3266
- }
3267
- }
3268
- }
3269
- if (Array.isArray(m.tool_calls)) return "openai";
3270
- if (m.role === "tool" && typeof m.tool_call_id === "string") return "openai";
3271
- if (m.role === "system" || m.role === "developer") return "openai";
3679
+ // src/wire-fold.ts
3680
+ import { createHash as createHash3 } from "crypto";
3681
+ function detectProviderWireFormat(payload) {
3682
+ const fmt2 = detectWireFormat(payload);
3683
+ return fmt2 === "anthropic" || fmt2 === "openai" ? fmt2 : null;
3684
+ }
3685
+ function payloadToCore(payload, fmt2) {
3686
+ if (fmt2 === "anthropic") {
3687
+ const { msgs: msgs2, cacheControls } = anthropicToCore(payload);
3688
+ return { msgs: msgs2, cacheControls };
3689
+ }
3690
+ const { msgs } = openaiToCore(payload);
3691
+ return { msgs };
3692
+ }
3693
+ function coreToPayloadMessages(msgs, fmt2, cacheControls) {
3694
+ return fmt2 === "anthropic" ? coreToAnthropic(msgs, cacheControls) : coreToOpenai(msgs);
3695
+ }
3696
+ function applyWireTagContract(msgs, state) {
3697
+ const toolResults = msgs.filter((m) => m.contentType === "tool-result");
3698
+ const taggedTools = toolResults.length > 0 ? renderVisibleRefs(toolResults, state, defaultCountTokens, "all") : [];
3699
+ const bySource = new Map(toolResults.map((m, i) => [m, taggedTools[i]]));
3700
+ return msgs.map((m) => {
3701
+ if (m.contentType === "tool-result") return bySource.get(m) ?? m;
3702
+ if (m.contentType === "text" && m.role === "assistant") return { ...m, text: stripRefTag(m.text ?? "") };
3703
+ return m;
3704
+ });
3705
+ }
3706
+ function coreIdentity(msg) {
3707
+ return JSON.stringify({
3708
+ role: msg.role,
3709
+ contentType: msg.contentType,
3710
+ toolName: msg.toolName ?? null,
3711
+ toolCallId: msg.toolCallId ?? null,
3712
+ text: stripRefTag(msg.text ?? "")
3713
+ });
3714
+ }
3715
+ function toolCallNames(msgs) {
3716
+ const names = /* @__PURE__ */ new Map();
3717
+ for (const m of msgs) {
3718
+ if (m.contentType === "tool-call" && m.toolCallId && m.toolName) names.set(m.toolCallId, m.toolName);
3272
3719
  }
3273
- return "openai";
3720
+ return names;
3274
3721
  }
3275
- function anthropicBlocks(m) {
3276
- return typeof m.content === "string" ? [{ type: "text", text: m.content }] : m.content ?? [];
3722
+ function toolResultTextsCore(msgs) {
3723
+ const results = /* @__PURE__ */ new Map();
3724
+ for (const m of msgs) {
3725
+ if (m.contentType !== "tool-result" || !m.toolCallId) continue;
3726
+ results.set(m.toolCallId, m.text ?? "");
3727
+ }
3728
+ return results;
3277
3729
  }
3278
- var assistantBase = () => ({
3279
- api: "anthropic",
3280
- provider: "anthropic",
3281
- model: "wire",
3282
- usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
3283
- stopReason: "stop",
3284
- timestamp: Date.now()
3285
- });
3286
- function synthesizeStream(payload, format) {
3287
- const messages = payload.messages ?? [];
3288
- const stream = [];
3289
- const back = [];
3290
- const push = (msg, wi, kind) => {
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;
3338
- }
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");
3730
+ function findCompressCallsCore(msg) {
3731
+ if (msg.contentType !== "tool-call" || !msg.toolName) return [];
3732
+ const args = compressToolArgs({ name: msg.toolName, arguments: msg.text });
3733
+ if (!args) return [];
3734
+ const content = args.content;
3735
+ if (!Array.isArray(content)) return [];
3736
+ const ranges = [];
3737
+ const callTopic = typeof args.topic === "string" ? args.topic : void 0;
3738
+ for (const item of content) {
3739
+ const r = item;
3740
+ if (typeof r.startId !== "string" || typeof r.endId !== "string" || typeof r.summary !== "string" || r.summary.length === 0) continue;
3741
+ ranges.push({
3742
+ startRef: r.startId,
3743
+ endRef: r.endId,
3744
+ summary: r.summary,
3745
+ topic: typeof r.topic === "string" ? r.topic : callTopic,
3746
+ summaryMaxChars: typeof args.summaryMaxChars === "number" ? args.summaryMaxChars : void 0,
3747
+ compressCallId: msg.toolCallId ?? ""
3341
3748
  });
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
- }
3358
- if (m.role === "tool") {
3359
- push({
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;
3390
- }
3391
- const t = textOf();
3392
- if (t) push({ role: "user", content: [{ type: "text", text: t }], timestamp: Date.now() }, wi, "text");
3393
- });
3394
- return { stream, back, format };
3749
+ }
3750
+ return ranges.length > 0 ? [{ id: msg.toolCallId ?? "", ranges }] : [];
3395
3751
  }
3396
- function rebuildWirePayload(rebuilt, payload, synth) {
3397
- const messages = (payload.messages ?? []).slice();
3398
- const out = [];
3399
- const agentIndexOf = (m) => m[AI];
3400
- for (const agent of rebuilt) {
3401
- const ai = agentIndexOf(agent);
3402
- if (ai === void 0 || ai >= synth.back.length) {
3403
- const text2 = extractText(agent.content, false);
3404
- const role = agent.role === "assistant" ? "assistant" : "user";
3405
- if (synth.format === "anthropic") {
3406
- out.push({ role, content: [{ type: "text", text: text2 }] });
3407
- } else {
3408
- out.push({ role, content: text2 });
3409
- }
3410
- continue;
3411
- }
3412
- const { wi, kind } = synth.back[ai];
3413
- const src = messages[wi];
3414
- if (!src) {
3415
- out.push(agent);
3416
- continue;
3417
- }
3418
- if (synth.format === "anthropic") {
3419
- const srcMsg2 = src;
3420
- const blocks = anthropicBlocks(srcMsg2);
3421
- if (kind === "toolResult") {
3422
- const block2 = blocks.find((b) => b.type === "tool_result" && b.tool_use_id === agent.toolCallId);
3423
- const text3 = extractText(agent.content, false);
3424
- if (block2) {
3425
- out.push({ role: "user", content: [{ ...block2, content: [{ type: "text", text: text3 }] }] });
3426
- continue;
3427
- }
3428
- }
3429
- if (kind === "toolCall") {
3430
- const callIds = new Set(
3431
- (agent.content ?? []).filter((b) => b.type === "toolCall" && b.id).map((b) => b.id)
3432
- );
3433
- const agentText = extractText(agent.content, false);
3434
- const outBlocks = [];
3435
- let textSeen = false;
3436
- for (const b of blocks) {
3437
- if (b.type === "tool_use") {
3438
- if (callIds.has(b.id ?? "")) outBlocks.push(b);
3439
- continue;
3440
- }
3441
- if (b.type === "text") {
3442
- if (!textSeen && typeof b.text === "string") {
3443
- outBlocks.push(b);
3444
- textSeen = true;
3445
- }
3446
- continue;
3447
- }
3448
- outBlocks.push(b);
3449
- }
3450
- if (agentText && !textSeen) outBlocks.unshift({ type: "text", text: agentText });
3451
- out.push({ role: "assistant", content: outBlocks });
3452
- continue;
3453
- }
3454
- const text2 = extractText(agent.content, false);
3455
- const block = blocks.find((b) => b.type === "text");
3456
- if (block) out.push({ role: srcMsg2.role, content: [{ ...block, text: text2 }] });
3457
- else out.push({ role: srcMsg2.role, content: [{ type: "text", text: text2 }] });
3458
- continue;
3459
- }
3460
- const srcMsg = src;
3461
- const text = extractText(agent.content, false);
3462
- if (kind === "toolResult") {
3463
- out.push({ role: "tool", tool_call_id: agent.toolCallId ?? srcMsg.tool_call_id, content: text });
3464
- continue;
3465
- }
3466
- if (kind === "toolCall") {
3467
- const callIds = new Set(
3468
- (agent.content ?? []).filter((b) => b.type === "toolCall" && b.id).map((b) => b.id)
3469
- );
3470
- const surviving = (srcMsg.tool_calls ?? []).filter((c) => callIds.has(c.id));
3471
- const entry = { role: "assistant", content: text };
3472
- if (surviving.length > 0) entry.tool_calls = surviving;
3473
- out.push(entry);
3474
- continue;
3752
+ function corePieceKey(cm) {
3753
+ return `${cm.role}|${cm.contentType}|${cm.toolName ?? ""}|${(cm.text ?? "").slice(0, 4096)}`;
3754
+ }
3755
+ function spanFingerprintCoreIdx(coreMessages, startIdx, endIdx) {
3756
+ const first = coreMessages[startIdx];
3757
+ const last = coreMessages[endIdx];
3758
+ if (!first || !last) return "";
3759
+ return createHash3("sha1").update(`${corePieceKey(first)}\0${corePieceKey(last)}`).digest("hex").slice(0, 8);
3760
+ }
3761
+ function boundaryRawCore(ref, byRef, blocks, coreMessages, pick) {
3762
+ const raw = byRef[ref];
3763
+ if (raw) return raw;
3764
+ const m = /^b(\d+)$/i.exec(ref.trim());
3765
+ if (!m) return "";
3766
+ const block = blocks.find((b) => b.blockId.toLowerCase() === `b${m[1]}`);
3767
+ if (!block) return "";
3768
+ const idx = (id) => coreMessages.findIndex((cm) => cm.id === (byRef[id] ?? id));
3769
+ let best = -1;
3770
+ for (const id of block.effectiveMessageIds) {
3771
+ const i = idx(id);
3772
+ if (i < 0) continue;
3773
+ if (best < 0 || (pick === "min" ? i < best : i > best)) best = i;
3774
+ }
3775
+ return best < 0 ? "" : coreMessages[best]?.id ?? "";
3776
+ }
3777
+ function boundaryIndexCore(ref, byRef, blocks, coreMessages, pick, fallbackIdx = -1) {
3778
+ const id = boundaryRawCore(ref, byRef, blocks, coreMessages, pick);
3779
+ if (id) {
3780
+ const i = coreMessages.findIndex((cm) => cm.id === id);
3781
+ if (i >= 0) return i;
3782
+ }
3783
+ return fallbackIdx >= 0 && fallbackIdx < coreMessages.length ? fallbackIdx : -1;
3784
+ }
3785
+ function refOfPieceCore(coreMessages, idx, byRef) {
3786
+ const id = coreMessages[idx]?.id;
3787
+ if (!id) return "";
3788
+ for (const [ref, mapped] of Object.entries(byRef)) if (mapped === id) return ref;
3789
+ return "";
3790
+ }
3791
+ function staleRangeCore(r, rangeIndex, resultText, coreMessages, callIndex, byRef, blocks) {
3792
+ const pm = resultText.match(/\[pos=([0-9,-]+)\]/);
3793
+ const pair = pm ? pm[1].split(",")[rangeIndex] ?? "-" : "-";
3794
+ const hinted = pair !== "-";
3795
+ const [ps, pe] = pair === "-" ? ["", ""] : pair.split("-");
3796
+ const fbStart = ps && ps !== "" ? Number.parseInt(ps, 10) : -1;
3797
+ const fbEnd = pe && pe !== "" ? Number.parseInt(pe, 10) : -1;
3798
+ const startRaw = boundaryRawCore(r.startRef, byRef, blocks, coreMessages, "min");
3799
+ const endRaw = boundaryRawCore(r.endRef, byRef, blocks, coreMessages, "max");
3800
+ const rawStartIdx = startRaw ? coreMessages.findIndex((cm) => cm.id === startRaw) : -1;
3801
+ const rawEndIdx = endRaw ? coreMessages.findIndex((cm) => cm.id === endRaw) : -1;
3802
+ const startIdx = rawStartIdx >= 0 ? rawStartIdx : fbStart >= 0 && fbStart < coreMessages.length ? fbStart : -1;
3803
+ const endIdx = rawEndIdx >= 0 ? rawEndIdx : fbEnd >= 0 && fbEnd < coreMessages.length ? fbEnd : -1;
3804
+ if (startIdx < 0 || endIdx < 0) {
3805
+ if (!/^b\d+$/i.test(r.startRef.trim()) && !/^b\d+$/i.test(r.endRef.trim()))
3806
+ return { reject: `unresolved ${r.startRef}..${r.endRef} -> ${startIdx}..${endIdx}`, ...hinted ? { hint: true } : {} };
3807
+ return {};
3808
+ }
3809
+ if (endIdx > callIndex) return { reject: `end idx ${endIdx} > callIndex ${callIndex}`, ...hinted ? { hint: true } : {} };
3810
+ const m = resultText.match(/\[fp=([0-9a-f,-]+)\]/);
3811
+ if (m) {
3812
+ const want = m[1].split(",")[rangeIndex];
3813
+ if (want !== void 0 && want !== "-") {
3814
+ const got = spanFingerprintCoreIdx(coreMessages, startIdx, endIdx);
3815
+ if (want !== got) return { reject: `fp ${r.startRef}..${r.endRef} want ${want} got ${got} @${startIdx}..${endIdx}`, ...hinted ? { hint: true } : {} };
3475
3816
  }
3476
- out.push({ role: srcMsg.role === "assistant" ? "assistant" : srcMsg.role, content: text });
3477
3817
  }
3478
- return { ...payload, messages: out };
3818
+ const remap = {};
3819
+ if (/^m\d+$/i.test(r.startRef.trim()) && rawStartIdx < 0) {
3820
+ const ref = refOfPieceCore(coreMessages, startIdx, byRef);
3821
+ if (!ref) return { reject: `recovered ${r.startRef} @${startIdx} has no ref (protected piece)`, ...hinted ? { hint: true } : {} };
3822
+ remap.startRef = ref;
3823
+ }
3824
+ if (/^m\d+$/i.test(r.endRef.trim()) && rawEndIdx < 0) {
3825
+ const ref = refOfPieceCore(coreMessages, endIdx, byRef);
3826
+ if (!ref) return { reject: `recovered ${r.endRef} @${endIdx} has no ref (protected piece)`, ...hinted ? { hint: true } : {} };
3827
+ remap.endRef = ref;
3828
+ }
3829
+ if (!remap.startRef && !remap.endRef) return {};
3830
+ return { remap, recovered: { pos: pair, startIdx, endIdx } };
3479
3831
  }
3480
- function viewToWireStream(view, systemText) {
3832
+ function rangePositionsCore(ranges, coreMessages, byRef, blocks) {
3833
+ return ranges.map((r) => {
3834
+ const s = boundaryIndexCore(r.startRef, byRef, blocks, coreMessages, "min");
3835
+ const e = s >= 0 ? boundaryIndexCore(r.endRef, byRef, blocks, coreMessages, "max") : -1;
3836
+ return s >= 0 && e >= 0 ? `${s}-${e}` : "-";
3837
+ });
3838
+ }
3839
+ function viewToCoreStream(view, systemText) {
3481
3840
  const messages = [{ role: "system", content: systemText }];
3482
3841
  for (const message of view) {
3483
3842
  const m = message;
3484
3843
  if (m.role === "user") {
3485
- const text = extractText(m.content);
3844
+ const text = extractViewText(m.content);
3486
3845
  if (text) messages.push({ role: "user", content: text });
3487
3846
  } else if (m.role === "assistant") {
3488
3847
  const blocks = Array.isArray(m.content) ? m.content : [];
3489
3848
  const calls = blocks.filter(
3490
3849
  (b) => b !== null && typeof b === "object" && b.type === "toolCall"
3491
3850
  );
3492
- const text = extractText(m.content);
3851
+ const text = extractViewText(m.content);
3493
3852
  if (calls.length > 0) {
3494
3853
  messages.push({
3495
3854
  role: "assistant",
@@ -3504,13 +3863,63 @@ function viewToWireStream(view, systemText) {
3504
3863
  messages.push({ role: "assistant", content: text });
3505
3864
  }
3506
3865
  } else if (m.role === "toolResult") {
3507
- messages.push({ role: "tool", tool_call_id: m.toolCallId ?? "", content: extractText(m.content) });
3866
+ messages.push({ role: "tool", tool_call_id: m.toolCallId ?? "", content: extractViewText(m.content) });
3508
3867
  } else {
3509
- const text = extractText(m.content) || (typeof m.summary === "string" ? m.summary : "");
3868
+ const text = extractViewText(m.content) || (typeof m.summary === "string" ? m.summary : "");
3510
3869
  if (text) messages.push({ role: "developer", content: text });
3511
3870
  }
3512
3871
  }
3513
- return synthesizeStream({ model: "prime-fold", messages }, "openai").stream;
3872
+ const { msgs } = openaiToCore({ model: "prime-fold", messages });
3873
+ return msgs;
3874
+ }
3875
+ function viewToAnthropicCore(view) {
3876
+ const messages = [];
3877
+ for (const message of view) {
3878
+ const m = message;
3879
+ if (m.role === "user") {
3880
+ const text = extractViewText(m.content);
3881
+ if (text) messages.push({ role: "user", content: [{ type: "text", text }] });
3882
+ } else if (m.role === "assistant") {
3883
+ const blocks = Array.isArray(m.content) ? m.content : [];
3884
+ const calls = blocks.filter(
3885
+ (b) => b !== null && typeof b === "object" && b.type === "toolCall"
3886
+ );
3887
+ const text = extractViewText(m.content);
3888
+ const content = [];
3889
+ if (text) content.push({ type: "text", text });
3890
+ for (const c of calls) {
3891
+ let input = {};
3892
+ try {
3893
+ input = c.arguments && typeof c.arguments === "object" ? c.arguments : JSON.parse(JSON.stringify(c.arguments ?? {}));
3894
+ } catch {
3895
+ input = {};
3896
+ }
3897
+ content.push({ type: "tool_use", id: c.id, name: c.name ?? "", input });
3898
+ }
3899
+ if (content.length > 0) messages.push({ role: "assistant", content });
3900
+ } else if (m.role === "toolResult") {
3901
+ messages.push({
3902
+ role: "user",
3903
+ content: [{ type: "tool_result", tool_use_id: m.toolCallId ?? "", content: extractViewText(m.content) }]
3904
+ });
3905
+ } else {
3906
+ const text = extractViewText(m.content) || (typeof m.summary === "string" ? m.summary : "");
3907
+ if (text) messages.push({ role: "user", content: [{ type: "text", text }] });
3908
+ }
3909
+ }
3910
+ const { msgs, cacheControls } = anthropicToCore({ model: "prime-fold", messages });
3911
+ void cacheControls;
3912
+ return msgs;
3913
+ }
3914
+ function extractViewText(content) {
3915
+ const clean = (s) => stripRefTag(s);
3916
+ if (typeof content === "string") return clean(content);
3917
+ if (!Array.isArray(content)) return "";
3918
+ const parts = [];
3919
+ for (const b of content) {
3920
+ if (b.type === "text" && typeof b.text === "string") parts.push(clean(b.text));
3921
+ }
3922
+ return parts.join("\n");
3514
3923
  }
3515
3924
 
3516
3925
  // src/runtime.ts
@@ -3538,6 +3947,7 @@ function createRuntime(adapter) {
3538
3947
  const core = createCore({ countTokens: defaultCountTokens });
3539
3948
  const locks = /* @__PURE__ */ new Map();
3540
3949
  const slots = /* @__PURE__ */ new Map();
3950
+ const coreSlots = /* @__PURE__ */ new Map();
3541
3951
  let adapterRef = adapter;
3542
3952
  let promptsRef = defaultPrompts;
3543
3953
  async function acquireLock(sid) {
@@ -3567,6 +3977,14 @@ function createRuntime(adapter) {
3567
3977
  }
3568
3978
  return slot;
3569
3979
  }
3980
+ function coreSlotFor(sid) {
3981
+ let slot = coreSlots.get(sid);
3982
+ if (!slot) {
3983
+ slot = freshSlot();
3984
+ coreSlots.set(sid, slot);
3985
+ }
3986
+ return slot;
3987
+ }
3570
3988
  function sidOf(ctx) {
3571
3989
  return ctx.sessionManager.getSessionId();
3572
3990
  }
@@ -3651,8 +4069,90 @@ function createRuntime(adapter) {
3651
4069
  stream.forEach((message, i) => originalById.set(`p${i + 1}`, message));
3652
4070
  return { state: slot.state, coreMessages, originalById, streamLen: stream.length };
3653
4071
  }
4072
+ function foldStreamCore(ctx, stream) {
4073
+ const sid = sidOf(ctx);
4074
+ let slot = coreSlotFor(sid);
4075
+ if (slot.preview) {
4076
+ debug.event("fold-refold", { sid, foldedLen: slot.foldedLen, lcp: 0, streamLen: stream.length, reason: "preview" });
4077
+ slot = freshSlot(slot);
4078
+ coreSlots.set(sid, slot);
4079
+ }
4080
+ const ids = stream.map(coreIdentity);
4081
+ let lcp = 0;
4082
+ while (lcp < Math.min(ids.length, slot.identities.length) && ids[lcp] === slot.identities[lcp]) lcp++;
4083
+ if (lcp < slot.foldedLen) {
4084
+ const flip = isViewFlip(slot.foldedLen, lcp);
4085
+ debug.event("fold-refold", { sid, foldedLen: slot.foldedLen, lcp, streamLen: stream.length, flip, space: "core" });
4086
+ slot = flip ? preserveCompressedSlot(slot) : freshSlot(slot);
4087
+ coreSlots.set(sid, slot);
4088
+ lcp = 0;
4089
+ }
4090
+ const coreMessages = stream;
4091
+ const config = configFor(ctx);
4092
+ const names = toolCallNames(stream);
4093
+ const assigned = assignRefs(coreMessages, {
4094
+ existing: slot.state.messageRefs,
4095
+ nextIndex: highestUsedIndex(slot.state.messageRefs) + 1,
4096
+ isProtected: (m) => {
4097
+ if (m.role !== "tool" || !m.toolCallId) return false;
4098
+ const name = names.get(m.toolCallId);
4099
+ if (!name) return false;
4100
+ if (name === "compress") return true;
4101
+ return (config.protectedTools ?? []).includes(name);
4102
+ }
4103
+ });
4104
+ slot.state = { ...slot.state, messageRefs: assigned.map };
4105
+ const isFreshFold = slot.foldedLen === 0;
4106
+ const resultTexts = toolResultTextsCore(stream);
4107
+ let replayed = 0;
4108
+ for (let i = isFreshFold ? 0 : slot.foldedLen; i < stream.length; i++) {
4109
+ for (const call of findCompressCallsCore(stream[i])) {
4110
+ const resultText = resultTexts.get(call.id) ?? "";
4111
+ if (resultText.includes("No changes applied")) {
4112
+ debug.event("fold-replay-skipped", { sid, callId: call.id });
4113
+ continue;
4114
+ }
4115
+ if (slot.appliedCallIds.has(call.id) || stateHasCompressCall(slot.state, call.id)) continue;
4116
+ const verdicts = call.ranges.map((r, ri) => staleRangeCore(r, ri, resultText, coreMessages, i, slot.state.messageRefs.byRef, slot.state.blocks));
4117
+ const stale = verdicts.find((v) => v.reject);
4118
+ if (stale) {
4119
+ debug.event("fold-replay-stale", { sid, callId: call.id, reason: stale.reject });
4120
+ const failed = verdicts.find((v) => v.hint && v.reject);
4121
+ if (failed) logWarn("fold", { sid, event: "replay-recovery-failed", callId: call.id, reason: failed.reject });
4122
+ continue;
4123
+ }
4124
+ const recovered = verdicts.find((v) => v.recovered);
4125
+ const ranges = recovered ? call.ranges.map((r, ri) => {
4126
+ const m = verdicts[ri].remap;
4127
+ return m ? { ...r, startRef: m.startRef ?? r.startRef, endRef: m.endRef ?? r.endRef } : r;
4128
+ }) : call.ranges;
4129
+ if (recovered) {
4130
+ logWarn("fold", { sid, event: "replay-recovered", callId: call.id, pos: recovered.recovered.pos, startIdx: recovered.recovered.startIdx, endIdx: recovered.recovered.endIdx });
4131
+ }
4132
+ try {
4133
+ const applied = core.applyCompression({ ranges, messages: coreMessages, state: slot.state, config });
4134
+ if (applied.result.errors.length === 0) {
4135
+ slot.state = applied.state;
4136
+ replayed++;
4137
+ debug.event("fold-replay", { sid, callId: call.id, ranges: call.ranges.length });
4138
+ } else {
4139
+ logWarn("fold", { sid, event: "replay-rejected", callId: call.id, errors: applied.result.errors.slice(0, 3) });
4140
+ }
4141
+ } catch (e) {
4142
+ logWarn("fold", { sid, event: "replay-failed", callId: call.id, error: e instanceof Error ? e.message : String(e) });
4143
+ }
4144
+ slot.appliedCallIds.add(call.id);
4145
+ }
4146
+ }
4147
+ if (replayed > 0) logWarn("fold", { sid, event: "replayed", calls: replayed });
4148
+ slot.identities = ids;
4149
+ slot.foldedLen = ids.length;
4150
+ slot.coreMessages = coreMessages;
4151
+ return { state: slot.state, coreMessages, streamLen: stream.length };
4152
+ }
3654
4153
  function stateFor(ctx) {
3655
- const slot = slotFor(sidOf(ctx));
4154
+ const sid = sidOf(ctx);
4155
+ const slot = slotForMode(ctx, sid);
3656
4156
  return Promise.resolve({ state: slot.state, coreMessages: slot.coreMessages });
3657
4157
  }
3658
4158
  function primeFold(ctx) {
@@ -3661,30 +4161,40 @@ function createRuntime(adapter) {
3661
4161
  const sm = ctx.sessionManager;
3662
4162
  const view = sm.buildSessionContext?.().messages ?? [];
3663
4163
  if (view.length === 0) return;
3664
- let stream = view;
3665
- let wire = false;
3666
- if ((adapterRef.transformMode ?? "provider") === "provider" && ctx.model?.api === "openai-completions") {
3667
- const base = getSystemPromptText(ctx);
3668
- const acp = buildAcpSystemPrompt(promptsRef);
3669
- stream = viewToWireStream(view, base.includes(acp) ? base : `${base}
4164
+ if (resolveTransformMode(adapterRef, ctx.model) === "provider") {
4165
+ const api = ctx.model?.api ?? "";
4166
+ let stream;
4167
+ if (api === "anthropic-messages") {
4168
+ stream = viewToAnthropicCore(view);
4169
+ } else {
4170
+ const base = getSystemPromptText(ctx);
4171
+ const acp = buildAcpSystemPrompt(promptsRef);
4172
+ stream = viewToCoreStream(view, base.includes(acp) ? base : `${base}
3670
4173
 
3671
4174
  ${acp}`);
3672
- wire = true;
4175
+ }
4176
+ const r2 = foldStreamCore(ctx, stream);
4177
+ coreSlotFor(sid).preview = true;
4178
+ logInfo("fold", { sid, event: "prime-fold", msgs: stream.length, wire: true, blocks: r2.state.blocks.length });
4179
+ return;
3673
4180
  }
3674
- const r = foldStream(ctx, stream);
4181
+ const r = foldStream(ctx, view);
3675
4182
  slotFor(sid).preview = true;
3676
- logInfo("fold", { sid, event: "prime-fold", msgs: stream.length, wire, blocks: r.state.blocks.length });
4183
+ logInfo("fold", { sid, event: "prime-fold", msgs: view.length, wire: false, blocks: r.state.blocks.length });
3677
4184
  } catch (e) {
3678
4185
  logWarn("fold", { sid, event: "prime-fold-failed", error: e instanceof Error ? e.message : String(e) });
3679
4186
  }
3680
4187
  }
3681
4188
  function forgetSession(sid) {
3682
4189
  slots.delete(sid);
4190
+ coreSlots.delete(sid);
3683
4191
  locks.delete(sid);
3684
4192
  }
4193
+ function slotForMode(ctx, sid) {
4194
+ return resolveTransformMode(adapterRef, ctx.model) === "provider" ? coreSlotFor(sid) : slotFor(sid);
4195
+ }
3685
4196
  function commitFoldState(ctx, state, toolCallId) {
3686
- const sid = sidOf(ctx);
3687
- const slot = slotFor(sid);
4197
+ const slot = slotForMode(ctx, sidOf(ctx));
3688
4198
  slot.state = state;
3689
4199
  if (toolCallId) slot.appliedCallIds.add(toolCallId);
3690
4200
  }
@@ -3693,7 +4203,7 @@ ${acp}`);
3693
4203
  slot.lastRebuiltOutput = rebuilt.map(messageIdentity);
3694
4204
  }
3695
4205
  function noteCompressOutcome(ctx, ok) {
3696
- const slot = slotFor(sidOf(ctx));
4206
+ const slot = slotForMode(ctx, sidOf(ctx));
3697
4207
  slot.rejectStreak = ok ? 0 : slot.rejectStreak + 1;
3698
4208
  return slot.rejectStreak;
3699
4209
  }
@@ -3714,6 +4224,7 @@ ${acp}`);
3714
4224
  liveContextLimit,
3715
4225
  configFor,
3716
4226
  foldStream,
4227
+ foldStreamCore,
3717
4228
  stateFor,
3718
4229
  commitFoldState,
3719
4230
  recordRebuiltOutput,
@@ -3906,9 +4417,11 @@ async function handleCompress(args, runtime, ctx, toolCallId) {
3906
4417
  logError("compress", { sid: ctx.sessionManager.getSessionId(), event: "warnings", count: warnings.length, warnings: warnings.slice(0, 5) });
3907
4418
  }
3908
4419
  const fps = rangeFingerprints(rangeSpecs, coreMessages, applied.state.messageRefs.byRef, applied.state.blocks);
4420
+ const positions = rangePositionsCore(rangeSpecs, coreMessages, applied.state.messageRefs.byRef, applied.state.blocks);
3909
4421
  const lines = [`\u25A3 ACP | ${formatTokens3(beforeTokens)} \u2192 ${formatTokens3(afterTokens)} tokens (~${formatTokens3(tokensCompressed)} reclaimed, ${blocksCreated} block${blocksCreated > 1 ? "s" : ""})`];
3910
4422
  if (warnings.length > 0) lines.push("\u26A0\uFE0F " + warnings.join("; "));
3911
4423
  if (fps.some((fp) => fp !== "-")) lines.push(`[fp=${fps.join(",")}]`);
4424
+ if (positions.some((p) => p !== "-")) lines.push(`[pos=${positions.join(",")}]`);
3912
4425
  return lines.join("\n");
3913
4426
  } finally {
3914
4427
  releaseLock();
@@ -4903,7 +5416,7 @@ async function statusReport(runtime, ctx) {
4903
5416
  const coveredIds = collectCoveredMessageIds(state);
4904
5417
  const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
4905
5418
  const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount: sentTokens });
4906
- const versionStr = "0.2.6" ? `billion-context-omp@${"0.2.6"}` : void 0;
5419
+ const versionStr = "0.2.7" ? `billion-context-omp@${"0.2.7"}` : void 0;
4907
5420
  return buildStatusPanel({
4908
5421
  version: versionStr,
4909
5422
  tokenCount: sessionTokens,
@@ -5033,6 +5546,10 @@ import { readFileSync, writeFileSync } from "fs";
5033
5546
  import { join as join3 } from "path";
5034
5547
  var MARKER_FILE = ".billion-context-omp-instance.json";
5035
5548
  var FRESH_MS = 6e4;
5549
+ function normalizeLoadPath(p) {
5550
+ const q = p.indexOf("?");
5551
+ return q === -1 ? p : p.slice(0, q);
5552
+ }
5036
5553
  function markerPath() {
5037
5554
  return join3(homeDir(), ".omp", MARKER_FILE);
5038
5555
  }
@@ -5047,7 +5564,7 @@ function readMarker() {
5047
5564
  function detectDualInstance(selfPath, now = Date.now()) {
5048
5565
  const m = readMarker();
5049
5566
  if (!m) return void 0;
5050
- if (m.path === selfPath) return void 0;
5567
+ if (normalizeLoadPath(m.path) === normalizeLoadPath(selfPath)) return void 0;
5051
5568
  if (now - m.ts > FRESH_MS) return void 0;
5052
5569
  return m;
5053
5570
  }
@@ -5193,7 +5710,7 @@ async function checkForUpdate(autoUpdate, notify) {
5193
5710
  const data = await res.json();
5194
5711
  const latest = data.version;
5195
5712
  if (!latest) return;
5196
- const current = runtimeVersion ?? "0.2.6";
5713
+ const current = runtimeVersion ?? "0.2.7";
5197
5714
  const hasUpdate = isNewer(latest, current);
5198
5715
  debug.event("update-check", {
5199
5716
  current,
@@ -5450,7 +5967,6 @@ function createAcpExtension(adapter = {}) {
5450
5967
  return (pi) => {
5451
5968
  const runtime = createRuntime(adapter);
5452
5969
  wireSessionLifecycle(pi, runtime);
5453
- wireSessionLifecycle(pi, runtime);
5454
5970
  wireContextTransform(pi, runtime);
5455
5971
  wireSystemPrompt(pi, runtime);
5456
5972
  wireProviderTransform(pi, runtime);
@@ -5469,9 +5985,9 @@ var index_default = createAcpExtension();
5469
5985
  function wireSessionLifecycle(pi, runtime) {
5470
5986
  pi.on("session_start", async (_event, ctx) => {
5471
5987
  const sid = ctx.sessionManager.getSessionId();
5472
- logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.2.6" : null });
5988
+ logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.2.7" : null });
5473
5989
  const selfPath = import.meta.url;
5474
- const conflict = stampAndDetect(selfPath, true ? "0.2.6" : null);
5990
+ const conflict = stampAndDetect(selfPath, true ? "0.2.7" : null);
5475
5991
  if (conflict) {
5476
5992
  logWarn("instance", { event: "dual-instance", self: selfPath, other: conflict.path, otherPid: conflict.pid, otherVersion: conflict.version });
5477
5993
  try {
@@ -5495,9 +6011,9 @@ function wireSessionLifecycle(pi, runtime) {
5495
6011
  runtime.setPrompts(defaultPrompts);
5496
6012
  }
5497
6013
  runtime.primeFold(ctx);
5498
- await checkForUpdate(runtime.adapter.autoUpdate ?? true, (msg) => {
6014
+ void checkForUpdate(runtime.adapter.autoUpdate ?? true, (msg) => {
5499
6015
  if (ctx.hasUI) ctx.ui.notify(msg);
5500
- });
6016
+ }).catch((e) => logThrow("update", e, { sid, phase: "session_start" }));
5501
6017
  });
5502
6018
  pi.on("session_shutdown", (_event, ctx) => {
5503
6019
  try {
@@ -5631,14 +6147,14 @@ ${rendered.text}${example}`);
5631
6147
  } finally {
5632
6148
  release();
5633
6149
  }
5634
- await checkForUpdate(runtime.adapter.autoUpdate ?? true, (msg) => {
6150
+ void checkForUpdate(runtime.adapter.autoUpdate ?? true, (msg) => {
5635
6151
  if (ctx.hasUI) ctx.ui.notify(msg);
5636
- });
6152
+ }).catch((e) => logThrow("update", e, { sid, phase: "context" }));
5637
6153
  return result;
5638
6154
  }
5639
6155
  function wireContextTransform(pi, runtime) {
5640
6156
  pi.on("context", async (event, ctx) => {
5641
- if ((runtime.adapter.transformMode ?? "provider") === "provider") {
6157
+ if (resolveTransformMode(runtime.adapter, ctx.model) === "provider") {
5642
6158
  debug.event("context-observer-skip", { sid: ctx.sessionManager.getSessionId(), msgs: event.messages?.length ?? 0 });
5643
6159
  return void 0;
5644
6160
  }
@@ -5649,34 +6165,151 @@ function wireContextTransform(pi, runtime) {
5649
6165
  }
5650
6166
  function wireProviderTransform(pi, runtime) {
5651
6167
  pi.on("before_provider_request", async (event, ctx) => {
5652
- if ((runtime.adapter.transformMode ?? "provider") !== "provider") return void 0;
6168
+ if (resolveTransformMode(runtime.adapter, ctx.model) !== "provider") return void 0;
5653
6169
  const payload = event.payload;
5654
6170
  if (payload === null || typeof payload !== "object" || !Array.isArray(payload.messages)) return void 0;
5655
6171
  const sid = ctx.sessionManager?.getSessionId?.() ?? "";
5656
- const fmt2 = detectWireFormat(payload);
5657
- if (fmt2 === "unknown") {
6172
+ const fmt2 = detectProviderWireFormat(payload);
6173
+ if (fmt2 === null) {
5658
6174
  debug.event("provider-transform-unknown-format", { sid });
5659
6175
  return void 0;
5660
6176
  }
5661
6177
  try {
5662
- const synth = synthesizeStream(payload, fmt2);
5663
- if (synth.stream.length === 0) return void 0;
5664
- const result = await transformStream(ctx, runtime, synth.stream, "provider");
6178
+ const { msgs, cacheControls } = payloadToCore(payload, fmt2);
6179
+ if (msgs.length === 0) return void 0;
6180
+ const result = await transformStreamCore(ctx, runtime, msgs, fmt2);
5665
6181
  if (!result) return void 0;
5666
- const wireOut = rebuildWirePayload(result.rebuilt, payload, synth);
5667
- const outMsgs = wireOut.messages?.length ?? 0;
6182
+ const outMsgs = coreToPayloadMessages(result.coreOut, fmt2, cacheControls).length;
5668
6183
  const inMsgs = payload.messages?.length ?? 0;
5669
- if (outMsgs !== inMsgs || wireOut !== payload) {
6184
+ if (outMsgs !== inMsgs) {
5670
6185
  logInfo("provider-transform", { sid, fmt: fmt2, inMsgs, outMsgs, nudge: result.nudgeInjected ? "injected" : "idle" });
5671
6186
  }
5672
6187
  debug.event("provider-transform", { sid, fmt: fmt2, inMsgs, outMsgs, nudgeInjected: result.nudgeInjected });
5673
- return wireOut === payload ? void 0 : wireOut;
6188
+ return { ...payload, messages: coreToPayloadMessages(result.coreOut, fmt2, cacheControls) };
5674
6189
  } catch (e) {
5675
6190
  logThrow("provider-transform", e, { sid, fmt: fmt2 });
5676
6191
  return void 0;
5677
6192
  }
5678
6193
  });
5679
6194
  }
6195
+ async function transformStreamCore(ctx, runtime, wireMsgs, fmt2) {
6196
+ const sid = ctx.sessionManager.getSessionId();
6197
+ const release = await runtime.acquireLock(sid);
6198
+ let result;
6199
+ try {
6200
+ if (wireMsgs.length === 0) {
6201
+ debug.event("empty-stream-bypass", { sid, space: "core" });
6202
+ return void 0;
6203
+ }
6204
+ debug.event("context-in-raw", { sid, msgs: wireMsgs.length, mode: "provider" });
6205
+ const { state, coreMessages, streamLen } = runtime.foldStreamCore(ctx, wireMsgs);
6206
+ const preTurnNudgeBaseline = state.nudge.lastPerMessageNudgeTokens;
6207
+ const preTurnNudgeShownTokens = state.nudge.lastNudgeShownTokens;
6208
+ const preTurnNudgeShownByTier = state.nudge.lastShownByTier;
6209
+ const config = runtime.configFor(ctx);
6210
+ const coveredIds = collectCoveredMessageIds(state);
6211
+ const systemPromptTokens = estimateTextTokens2(getSystemPromptText(ctx) ?? "");
6212
+ const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
6213
+ const sessionTokens = ctx.getContextUsage?.()?.tokens ?? null;
6214
+ const tokenCount = sentTokens;
6215
+ debug.event("context-in", {
6216
+ sid,
6217
+ mode: "provider",
6218
+ fmt: fmt2,
6219
+ streamLen,
6220
+ coreMsgs: coreMessages.length,
6221
+ tokenCount,
6222
+ sessionTokens,
6223
+ limit: config.modelContextLimit,
6224
+ blocksBefore: state.blocks.length,
6225
+ activeBefore: state.blocks.filter((b) => b.active).length
6226
+ });
6227
+ const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount, renderTags: "text-only" });
6228
+ runtime.commitFoldState(ctx, turn.state);
6229
+ logInfo("turn", {
6230
+ sid,
6231
+ inMsgs: coreMessages.length,
6232
+ outMsgs: turn.messages.length,
6233
+ tokens: tokenCount,
6234
+ sessionTokens,
6235
+ pct: config.modelContextLimit > 0 ? Math.round(tokenCount / config.modelContextLimit * 100) : null,
6236
+ limit: config.modelContextLimit,
6237
+ nudge: turn.nudge?.shouldInject ? turn.nudge.breakdown?.emergencyOverride === 1 ? "emergency" : "active" : "idle",
6238
+ nudgeReason: turn.nudge?.reason ?? null,
6239
+ blocks: turn.state.blocks.length,
6240
+ activeBlocks: turn.state.blocks.filter((b) => b.active).length
6241
+ });
6242
+ debug.event("processTurn", {
6243
+ outMsgs: turn.messages.length,
6244
+ summaryMsgs: turn.messages.filter((m) => m.id.startsWith("acp_summary")).length,
6245
+ prunedMsgs: coreMessages.length - turn.messages.length + turn.messages.filter((m) => m.id.startsWith("acp_summary")).length,
6246
+ nudgeShouldInject: turn.nudge?.shouldInject ?? false,
6247
+ nudgeReason: turn.nudge?.reason ?? null,
6248
+ nudgeVoice: turn.nudge ? renderNudgeText(turn.nudge, runtime.prompts).voice : null,
6249
+ nudgePct: turn.nudge ? Math.round(turn.nudge.contextUsage * 100) : null,
6250
+ nudgeTier: turn.nudge?.tier ?? null,
6251
+ nudgeCompressibleCount: turn.nudge?.compressibleRanges.length ?? 0,
6252
+ nudgeProtectedCount: turn.nudge?.protectedRanges?.length ?? 0,
6253
+ nothingToCompress: turn.nudge?.reason?.includes("nothing to compress") ?? false,
6254
+ blocksAfter: turn.state.blocks.length,
6255
+ activeAfter: turn.state.blocks.filter((b) => b.active).length
6256
+ });
6257
+ const coreOut = applyWireTagContract(
6258
+ turn.messages.filter((m) => !m.id.startsWith("acp_summary_")),
6259
+ turn.state
6260
+ );
6261
+ let nudgeInjected = false;
6262
+ if (turn.nudge?.shouldInject) {
6263
+ const lastUser = [...wireMsgs].reverse().find((m) => m.role === "user");
6264
+ const tailText = lastUser ? lastUser.text ?? "" : "";
6265
+ const isFeedbackView = tailText.includes("efficiency nudge to compress early") || tailText.includes("Context limit reached");
6266
+ if (isFeedbackView) {
6267
+ debug.event("nudge-feedback-skip", { sid, msgs: wireMsgs.length });
6268
+ } else {
6269
+ const emergency = turn.nudge.breakdown?.emergencyOverride === 1;
6270
+ const epochReset = turn.state.nudge.lastPerMessageNudgeTokens !== preTurnNudgeBaseline;
6271
+ const prevShown = epochReset ? 0 : preTurnNudgeShownTokens;
6272
+ const cadenceFloor = turn.nudge.breakdown?.growthFloor ?? 0;
6273
+ const suppressed = !emergency && prevShown > 0 && tokenCount - prevShown < cadenceFloor;
6274
+ if (suppressed) {
6275
+ turn.state.nudge.lastNudgeShownTokens = prevShown;
6276
+ turn.state.nudge.lastShownByTier = preTurnNudgeShownByTier;
6277
+ logInfo("nudge", { sid, event: "cadence-suppressed", growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
6278
+ debug.event("nudge-suppressed", { sid, growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
6279
+ } else {
6280
+ nudgeInjected = true;
6281
+ turn.nudge.compressibleRanges = viableRanges(turn.nudge.compressibleRanges);
6282
+ const rendered = renderNudgeText(turn.nudge, runtime.prompts);
6283
+ const top = [...turn.nudge.compressibleRanges].sort((a, b) => b.tokens - a.tokens)[0];
6284
+ const example = top ? `
6285
+
6286
+ Example: compress({ content: [{ startId: "${top.startRef}", endId: "${top.endRef}", summary: "..." }] })` : "";
6287
+ if (emergency) {
6288
+ logWarn("nudge", { sid, event: "emergency-inject", pct: Math.round(turn.nudge.contextUsage * 100), voice: rendered.voice, compressible: turn.nudge.compressibleRanges.length });
6289
+ }
6290
+ const debugOn2 = debug.enabled;
6291
+ if (debugOn2 && ctx.hasUI) {
6292
+ ctx.ui.notify(`[ACP nudge \u2192 context]${emergency ? " [EMERGENCY]" : ""}
6293
+ ${rendered.text}${example}`);
6294
+ }
6295
+ debug.event("nudge-injected", { sid, voice: rendered.voice, channels: ["wire", debugOn2 ? "terminal" : null].filter(Boolean), emergency, text: rendered.text + example });
6296
+ 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) });
6297
+ }
6298
+ }
6299
+ }
6300
+ debug.event("core-out", { sid, coreOutMsgs: coreOut.length, space: "core", fmt: fmt2 });
6301
+ result = { coreOut, nudgeInjected };
6302
+ } catch (e) {
6303
+ logThrow("context-core", e, { sid, phase: "transform" });
6304
+ throw e;
6305
+ } finally {
6306
+ release();
6307
+ }
6308
+ void checkForUpdate(runtime.adapter.autoUpdate ?? true, (msg) => {
6309
+ if (ctx.hasUI) ctx.ui.notify(msg);
6310
+ }).catch((e) => logThrow("update", e, { sid, phase: "provider" }));
6311
+ return result;
6312
+ }
5680
6313
  function wireSystemPrompt(pi, runtime) {
5681
6314
  pi.on("before_agent_start", (event) => {
5682
6315
  const acp = buildAcpSystemPrompt(runtime.prompts);
@@ -5708,7 +6341,7 @@ function wireProviderDebug(pi) {
5708
6341
  });
5709
6342
  });
5710
6343
  }
5711
- function nudgeMessage(nudge, blocks, prompts, example) {
6344
+ function nudgeText(nudge, blocks, prompts, example) {
5712
6345
  const rendered = renderNudgeText(nudge, prompts);
5713
6346
  const lines = [rendered.text];
5714
6347
  if (blocks.length > 0) {
@@ -5727,9 +6360,12 @@ function nudgeMessage(nudge, blocks, prompts, example) {
5727
6360
  lines.push(`Compressed blocks: ${blocks.length} active (${tierStr}) \u2014 ${fmt2(totalSummary)} summary, ${fmt2(totalCompressed)} original compressed. Blocks: ${ids}${extra}.`);
5728
6361
  }
5729
6362
  if (example) lines.push(example);
6363
+ return lines.join("\n");
6364
+ }
6365
+ function nudgeMessage(nudge, blocks, prompts, example) {
5730
6366
  return {
5731
6367
  role: "user",
5732
- content: [{ type: "text", text: lines.join("\n") }],
6368
+ content: [{ type: "text", text: nudgeText(nudge, blocks, prompts, example) }],
5733
6369
  timestamp: Date.now()
5734
6370
  };
5735
6371
  }