billion-context-omp 0.2.9 → 0.3.0
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/compress-tool.d.ts +1 -0
- package/dist/index.js +360 -110
- package/dist/index.js.map +1 -1
- package/dist/messages.d.ts +8 -0
- package/dist/runtime.d.ts +4 -0
- package/dist/transform-mode.d.ts +15 -0
- package/dist/update.d.ts +19 -0
- package/dist/wire-fold.d.ts +12 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3005,6 +3005,27 @@ function resolveTransformMode(adapter, model, hostVersion = VERSION) {
|
|
|
3005
3005
|
if (api === "openai-completions" && hostVersionAtLeast(OPENAI_COMPLETIONS_VIABLE_FROM, hostVersion)) return "provider";
|
|
3006
3006
|
return "context";
|
|
3007
3007
|
}
|
|
3008
|
+
function providerDeliveryWarning(adapter, model, hostVersion = VERSION) {
|
|
3009
|
+
if (adapter.transformMode !== "provider") return void 0;
|
|
3010
|
+
const api = model?.api;
|
|
3011
|
+
const dropWarning = (target) => ({
|
|
3012
|
+
key: `drop:${target}`,
|
|
3013
|
+
reason: `host < 17.3.8 drops the before_provider_request replacement on ${target} (fixed upstream pi-ai 17.3.8, can1357/oh-my-pi#8717)`,
|
|
3014
|
+
message: `\u26A0 billion-context-omp: transformMode "provider" is set, but this host (pi-ai < 17.3.8) discards the rewritten payload on ${target} \u2014 compression is NOT applied. Upgrade the host (omp update) or remove the transformMode override.`
|
|
3015
|
+
});
|
|
3016
|
+
if (api === "openai-completions" && !hostVersionAtLeast(OPENAI_COMPLETIONS_VIABLE_FROM, hostVersion)) {
|
|
3017
|
+
return dropWarning(api);
|
|
3018
|
+
}
|
|
3019
|
+
if (api === "amazon-bedrock" || api === "cursor") {
|
|
3020
|
+
if (!hostVersionAtLeast(OPENAI_COMPLETIONS_VIABLE_FROM, hostVersion)) return dropWarning(api);
|
|
3021
|
+
return {
|
|
3022
|
+
key: `nocodec:${api}`,
|
|
3023
|
+
reason: `${api} honors the replacement from 17.3.8 but its wire body has no codec path yet (issue #83)`,
|
|
3024
|
+
message: `\u26A0 billion-context-omp: transformMode "provider" is set, but the ${api} wire body has no codec path yet (#83) \u2014 compression is NOT applied. Remove the transformMode override to use context mode.`
|
|
3025
|
+
};
|
|
3026
|
+
}
|
|
3027
|
+
return void 0;
|
|
3028
|
+
}
|
|
3008
3029
|
|
|
3009
3030
|
// node_modules/acp-kernel/dist/wire/index.js
|
|
3010
3031
|
import { createHash } from "crypto";
|
|
@@ -3399,6 +3420,22 @@ function toolResultTexts(stream) {
|
|
|
3399
3420
|
}
|
|
3400
3421
|
return results;
|
|
3401
3422
|
}
|
|
3423
|
+
function lastRejectedCompressPair(stream) {
|
|
3424
|
+
for (let i = stream.length - 1; i >= 0; i--) {
|
|
3425
|
+
const m = stream[i];
|
|
3426
|
+
if (m.role !== "toolResult" || m.toolName !== "compress" || !m.toolCallId) continue;
|
|
3427
|
+
if (!extractText(m.content).includes("No changes applied")) continue;
|
|
3428
|
+
for (let j = stream.length - 1; j >= 0; j--) {
|
|
3429
|
+
if (j === i) continue;
|
|
3430
|
+
const c = stream[j];
|
|
3431
|
+
if (c.role !== "assistant") continue;
|
|
3432
|
+
if (!allToolCalls(c.content).some((call) => call.id === m.toolCallId && compressToolArgs(call))) continue;
|
|
3433
|
+
return [stream[j], stream[i]];
|
|
3434
|
+
}
|
|
3435
|
+
return null;
|
|
3436
|
+
}
|
|
3437
|
+
return null;
|
|
3438
|
+
}
|
|
3402
3439
|
function findCompressCalls(message) {
|
|
3403
3440
|
const out = [];
|
|
3404
3441
|
for (const call of allToolCalls(message.content)) {
|
|
@@ -3817,6 +3854,13 @@ function unrepresentableOpenaiMessage(message) {
|
|
|
3817
3854
|
if (typeof role !== "string" || !OPENAI_CODEC_ROLES.has(role)) {
|
|
3818
3855
|
return `openai role ${JSON.stringify(role) ?? "missing"}`;
|
|
3819
3856
|
}
|
|
3857
|
+
for (const field of ["function_call", "audio", "annotations"]) {
|
|
3858
|
+
if (message[field] !== void 0) {
|
|
3859
|
+
return `openai ${field} field is dropped by the rebuild`;
|
|
3860
|
+
}
|
|
3861
|
+
}
|
|
3862
|
+
const refusal = message.refusal;
|
|
3863
|
+
if (refusal !== null && refusal !== void 0) return "openai refusal content is dropped by the rebuild";
|
|
3820
3864
|
const content = message.content;
|
|
3821
3865
|
if (content == null || typeof content === "string") return null;
|
|
3822
3866
|
if (!Array.isArray(content)) return "content neither string nor part array";
|
|
@@ -3833,6 +3877,39 @@ function unrepresentableOpenaiMessage(message) {
|
|
|
3833
3877
|
}
|
|
3834
3878
|
return null;
|
|
3835
3879
|
}
|
|
3880
|
+
function restoreOpenaiWireFidelity(originalMessages, rebuilt) {
|
|
3881
|
+
const detailsByCall = /* @__PURE__ */ new Map();
|
|
3882
|
+
for (const message of originalMessages) {
|
|
3883
|
+
if (message === null || typeof message !== "object") continue;
|
|
3884
|
+
const calls = message.tool_calls;
|
|
3885
|
+
const details = message.reasoning_details;
|
|
3886
|
+
if (!Array.isArray(calls) || !Array.isArray(details) || details.length === 0) continue;
|
|
3887
|
+
for (const call of calls) {
|
|
3888
|
+
const id = call?.id;
|
|
3889
|
+
if (typeof id === "string" && !detailsByCall.has(id)) detailsByCall.set(id, details);
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
return rebuilt.map((message) => {
|
|
3893
|
+
if (message === null || typeof message !== "object") return message;
|
|
3894
|
+
const m = message;
|
|
3895
|
+
if (m.role !== "assistant") return message;
|
|
3896
|
+
const calls = Array.isArray(m.tool_calls) ? m.tool_calls : [];
|
|
3897
|
+
const attached = [];
|
|
3898
|
+
for (const call of calls) {
|
|
3899
|
+
const id = call?.id;
|
|
3900
|
+
if (typeof id !== "string") continue;
|
|
3901
|
+
const d = detailsByCall.get(id);
|
|
3902
|
+
if (d) attached.push(...d);
|
|
3903
|
+
}
|
|
3904
|
+
const hasReasoningField = m.reasoning_content !== void 0 || m.reasoning !== void 0 || m.reasoning_text !== void 0;
|
|
3905
|
+
const emptyContent = m.content === null && (calls.length > 0 || hasReasoningField);
|
|
3906
|
+
if (attached.length === 0 && !emptyContent) return message;
|
|
3907
|
+
const out = { ...m };
|
|
3908
|
+
if (emptyContent) out.content = "";
|
|
3909
|
+
if (attached.length > 0) out.reasoning_details = attached;
|
|
3910
|
+
return out;
|
|
3911
|
+
});
|
|
3912
|
+
}
|
|
3836
3913
|
var renderRefsAll = createRenderRefsNode("all");
|
|
3837
3914
|
function applyWireTagContract(msgs, state, scope) {
|
|
3838
3915
|
const stripAssistantTags = (m) => m.contentType === "text" && m.role === "assistant" ? { ...m, text: stripRefTag(m.text ?? "") } : m;
|
|
@@ -3873,6 +3950,18 @@ function toolResultTextsCore(msgs) {
|
|
|
3873
3950
|
}
|
|
3874
3951
|
return results;
|
|
3875
3952
|
}
|
|
3953
|
+
function lastRejectedPairCore(msgs) {
|
|
3954
|
+
const names = toolCallNames(msgs);
|
|
3955
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
3956
|
+
const m = msgs[i];
|
|
3957
|
+
if (m.contentType !== "tool-result" || !m.toolCallId) continue;
|
|
3958
|
+
if (!(m.text ?? "").includes("No changes applied")) continue;
|
|
3959
|
+
if (names.get(m.toolCallId) !== "compress") continue;
|
|
3960
|
+
const call = msgs.find((c) => c.contentType === "tool-call" && c.toolCallId === m.toolCallId);
|
|
3961
|
+
return call ? [call, m] : null;
|
|
3962
|
+
}
|
|
3963
|
+
return null;
|
|
3964
|
+
}
|
|
3876
3965
|
function findCompressCallsCore(msg) {
|
|
3877
3966
|
if (msg.contentType !== "tool-call" || !msg.toolName) return [];
|
|
3878
3967
|
const args = compressToolArgs({ name: msg.toolName, arguments: msg.text });
|
|
@@ -3991,22 +4080,23 @@ function viewToCoreStream(view, systemText) {
|
|
|
3991
4080
|
if (text) messages.push({ role: "user", content: text });
|
|
3992
4081
|
} else if (m.role === "assistant") {
|
|
3993
4082
|
const blocks = Array.isArray(m.content) ? m.content : [];
|
|
3994
|
-
const
|
|
3995
|
-
|
|
3996
|
-
);
|
|
4083
|
+
const typed = blocks;
|
|
4084
|
+
const calls = typed.filter((b) => b !== null && typeof b === "object" && b.type === "toolCall");
|
|
4085
|
+
const reasoning = typed.filter((b) => b !== null && typeof b === "object" && b.type === "thinking" && typeof b.thinking === "string" && b.thinking.trim().length > 0).map((b) => b.thinking).join("\n");
|
|
3997
4086
|
const text = extractViewText(m.content);
|
|
3998
4087
|
if (calls.length > 0) {
|
|
3999
4088
|
messages.push({
|
|
4000
4089
|
role: "assistant",
|
|
4001
4090
|
content: text,
|
|
4091
|
+
...reasoning ? { reasoning_content: reasoning } : {},
|
|
4002
4092
|
tool_calls: calls.map((c) => ({
|
|
4003
4093
|
id: c.id,
|
|
4004
4094
|
type: "function",
|
|
4005
4095
|
function: { name: c.name ?? "", arguments: JSON.stringify(c.arguments ?? {}) }
|
|
4006
4096
|
}))
|
|
4007
4097
|
});
|
|
4008
|
-
} else if (text) {
|
|
4009
|
-
messages.push({ role: "assistant", content: text });
|
|
4098
|
+
} else if (text || reasoning) {
|
|
4099
|
+
messages.push({ role: "assistant", content: text, ...reasoning ? { reasoning_content: reasoning } : {} });
|
|
4010
4100
|
}
|
|
4011
4101
|
} else if (m.role === "toolResult") {
|
|
4012
4102
|
messages.push({ role: "tool", tool_call_id: m.toolCallId ?? "", content: extractViewText(m.content) });
|
|
@@ -4027,20 +4117,27 @@ function viewToAnthropicCore(view) {
|
|
|
4027
4117
|
if (text) messages.push({ role: "user", content: [{ type: "text", text }] });
|
|
4028
4118
|
} else if (m.role === "assistant") {
|
|
4029
4119
|
const blocks = Array.isArray(m.content) ? m.content : [];
|
|
4030
|
-
const
|
|
4031
|
-
(b) => b !== null && typeof b === "object" && b.type === "toolCall"
|
|
4032
|
-
);
|
|
4033
|
-
const text = extractViewText(m.content);
|
|
4120
|
+
const typed = blocks;
|
|
4034
4121
|
const content = [];
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4122
|
+
for (const b of typed) {
|
|
4123
|
+
if (b === null || typeof b !== "object") continue;
|
|
4124
|
+
if (b.type === "thinking" && typeof b.thinking === "string" && b.thinking.trim().length > 0) {
|
|
4125
|
+
content.push({
|
|
4126
|
+
type: "thinking",
|
|
4127
|
+
thinking: b.thinking,
|
|
4128
|
+
...typeof b.thinkingSignature === "string" && b.thinkingSignature ? { signature: b.thinkingSignature } : {}
|
|
4129
|
+
});
|
|
4130
|
+
} else if (b.type === "text" && typeof b.text === "string" && stripRefTag(b.text).trim().length > 0) {
|
|
4131
|
+
content.push({ type: "text", text: stripRefTag(b.text) });
|
|
4132
|
+
} else if (b.type === "toolCall") {
|
|
4133
|
+
let input = {};
|
|
4134
|
+
try {
|
|
4135
|
+
input = b.arguments && typeof b.arguments === "object" ? b.arguments : JSON.parse(JSON.stringify(b.arguments ?? {}));
|
|
4136
|
+
} catch {
|
|
4137
|
+
input = {};
|
|
4138
|
+
}
|
|
4139
|
+
content.push({ type: "tool_use", id: b.id, name: b.name ?? "", input });
|
|
4042
4140
|
}
|
|
4043
|
-
content.push({ type: "tool_use", id: c.id, name: c.name ?? "", input });
|
|
4044
4141
|
}
|
|
4045
4142
|
if (content.length > 0) messages.push({ role: "assistant", content });
|
|
4046
4143
|
} else if (m.role === "toolResult") {
|
|
@@ -4353,6 +4450,9 @@ ${acp}`);
|
|
|
4353
4450
|
slot.rejectStreak = ok ? 0 : slot.rejectStreak + 1;
|
|
4354
4451
|
return slot.rejectStreak;
|
|
4355
4452
|
}
|
|
4453
|
+
function rejectStreakFor(ctx) {
|
|
4454
|
+
return slotForMode(ctx, sidOf(ctx)).rejectStreak;
|
|
4455
|
+
}
|
|
4356
4456
|
return {
|
|
4357
4457
|
core,
|
|
4358
4458
|
get adapter() {
|
|
@@ -4375,6 +4475,7 @@ ${acp}`);
|
|
|
4375
4475
|
commitFoldState,
|
|
4376
4476
|
recordRebuiltOutput,
|
|
4377
4477
|
noteCompressOutcome,
|
|
4478
|
+
rejectStreakFor,
|
|
4378
4479
|
forgetSession,
|
|
4379
4480
|
primeFold,
|
|
4380
4481
|
acquireLock
|
|
@@ -5562,7 +5663,7 @@ async function statusReport(runtime, ctx) {
|
|
|
5562
5663
|
const coveredIds = collectCoveredMessageIds(state);
|
|
5563
5664
|
const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
|
|
5564
5665
|
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount: sentTokens });
|
|
5565
|
-
const versionStr = "0.
|
|
5666
|
+
const versionStr = "0.3.0" ? `billion-context-omp@${"0.3.0"}` : void 0;
|
|
5566
5667
|
return buildStatusPanel({
|
|
5567
5668
|
version: versionStr,
|
|
5568
5669
|
tokenCount: sessionTokens,
|
|
@@ -5727,7 +5828,7 @@ function stampAndDetect(selfPath, version, now = Date.now()) {
|
|
|
5727
5828
|
}
|
|
5728
5829
|
|
|
5729
5830
|
// src/update.ts
|
|
5730
|
-
import { readFile, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
5831
|
+
import { readFile, writeFile as writeFile2, mkdir as mkdir2, access } from "fs/promises";
|
|
5731
5832
|
import { join as join4, dirname as dirname3 } from "path";
|
|
5732
5833
|
import { fileURLToPath } from "url";
|
|
5733
5834
|
import { execFile } from "child_process";
|
|
@@ -5793,43 +5894,112 @@ async function findExtensionDir() {
|
|
|
5793
5894
|
dir = parent;
|
|
5794
5895
|
}
|
|
5795
5896
|
}
|
|
5796
|
-
|
|
5897
|
+
var runNpmImpl = (args, cwd) => new Promise((resolve2) => {
|
|
5898
|
+
execFile(
|
|
5899
|
+
"npm",
|
|
5900
|
+
args,
|
|
5901
|
+
{ cwd, timeout: 6e4, shell: process.platform === "win32", maxBuffer: 4 * 1024 * 1024 },
|
|
5902
|
+
(err, stdout, stderr) => {
|
|
5903
|
+
if (err) logWarn("update", { event: "install-exec-failed", error: err.message, stderr: String(stderr).slice(0, 300) });
|
|
5904
|
+
resolve2({ code: err ? 1 : 0, stdout: String(stdout), stderr: String(stderr) });
|
|
5905
|
+
}
|
|
5906
|
+
);
|
|
5907
|
+
});
|
|
5908
|
+
var runNpm = runNpmImpl;
|
|
5909
|
+
var runNodeImpl = (args) => new Promise((resolve2) => {
|
|
5910
|
+
execFile(
|
|
5911
|
+
process.execPath,
|
|
5912
|
+
args,
|
|
5913
|
+
{ timeout: 15e3, maxBuffer: 4 * 1024 * 1024, shell: false },
|
|
5914
|
+
(err, stdout, stderr) => {
|
|
5915
|
+
resolve2({ code: err ? 1 : 0, stdout: String(stdout), stderr: String(stderr) });
|
|
5916
|
+
}
|
|
5917
|
+
);
|
|
5918
|
+
});
|
|
5919
|
+
var runNode = runNodeImpl;
|
|
5920
|
+
function declaredEntries(pkg) {
|
|
5921
|
+
const entries = /* @__PURE__ */ new Set();
|
|
5922
|
+
for (const ext of pkg.omp?.extensions ?? []) {
|
|
5923
|
+
if (typeof ext === "string") entries.add(ext);
|
|
5924
|
+
}
|
|
5925
|
+
const dot = pkg.exports?.["."];
|
|
5926
|
+
if (typeof dot === "string") entries.add(dot);
|
|
5927
|
+
else if (dot && typeof dot.import === "string") entries.add(dot.import);
|
|
5928
|
+
if (typeof pkg.main === "string") entries.add(pkg.main);
|
|
5929
|
+
return [...entries];
|
|
5930
|
+
}
|
|
5931
|
+
async function verifyInstall(npmDir, latest) {
|
|
5932
|
+
const extDir = join4(npmDir, "node_modules", PACKAGE_NAME);
|
|
5933
|
+
const pkg = await readPackageJson(join4(extDir, "package.json"));
|
|
5934
|
+
if (!pkg) return { ok: false, reason: "package-json-missing" };
|
|
5935
|
+
if (pkg.version !== latest) return { ok: false, reason: `version-mismatch:${pkg.version ?? "none"}` };
|
|
5936
|
+
const entries = declaredEntries(pkg);
|
|
5937
|
+
if (entries.length === 0) return { ok: false, reason: "no-entry-declared" };
|
|
5938
|
+
for (const rel of entries) {
|
|
5939
|
+
try {
|
|
5940
|
+
await access(join4(extDir, rel));
|
|
5941
|
+
} catch {
|
|
5942
|
+
return { ok: false, reason: `entry-missing:${rel}` };
|
|
5943
|
+
}
|
|
5944
|
+
}
|
|
5945
|
+
const smokeEntry = pkg.omp?.extensions?.[0] ?? entries[0];
|
|
5946
|
+
if (!smokeEntry) return { ok: false, reason: "no-entry-declared" };
|
|
5947
|
+
const smoke = `const{pathToFileURL}=require("node:url");import(pathToFileURL(process.argv[1]).href).then(()=>{},(e)=>{console.error(e&&e.stack||e);process.exit(1)});`;
|
|
5948
|
+
const r = await runNode(["-e", smoke, join4(extDir, smokeEntry)]);
|
|
5949
|
+
if (r.code !== 0) return { ok: false, reason: `entry-import-failed:${r.stderr.slice(0, 500)}` };
|
|
5950
|
+
return { ok: true };
|
|
5951
|
+
}
|
|
5952
|
+
var installArgs = (version) => [
|
|
5953
|
+
"install",
|
|
5954
|
+
`${PACKAGE_NAME}@${version}`,
|
|
5955
|
+
// --no-save: the auto-updater must never mutate the host's package.json
|
|
5956
|
+
// or lockfile.
|
|
5957
|
+
"--no-save",
|
|
5958
|
+
"--silent",
|
|
5959
|
+
"--no-audit",
|
|
5960
|
+
"--no-fund"
|
|
5961
|
+
];
|
|
5962
|
+
async function autoInstallLatest(latest, npmDirOverride) {
|
|
5797
5963
|
if (!SEMVER_RE.test(latest)) {
|
|
5798
5964
|
logWarn("update", { event: "install-abort", reason: "semver", latest });
|
|
5799
|
-
return
|
|
5965
|
+
return "failed";
|
|
5800
5966
|
}
|
|
5801
5967
|
const extDir = await findExtensionDir();
|
|
5802
5968
|
if (!extDir) {
|
|
5803
5969
|
logWarn("update", { event: "install-abort", reason: "extdir-not-found", moduleUrl: import.meta.url });
|
|
5804
|
-
return
|
|
5970
|
+
return "failed";
|
|
5805
5971
|
}
|
|
5806
|
-
const npmDir = findNpmRoot(extDir);
|
|
5972
|
+
const npmDir = npmDirOverride ?? findNpmRoot(extDir);
|
|
5807
5973
|
if (!npmDir) {
|
|
5808
5974
|
logWarn("update", { event: "install-abort", reason: "npmroot-not-found", extDir });
|
|
5809
|
-
return
|
|
5975
|
+
return "failed";
|
|
5810
5976
|
}
|
|
5977
|
+
const prevVersion = (await readPackageJson(join4(npmDir, "node_modules", PACKAGE_NAME, "package.json")))?.version ?? "0.3.0";
|
|
5811
5978
|
try {
|
|
5812
5979
|
const keepAlive = setInterval(() => {
|
|
5813
5980
|
}, 500);
|
|
5814
5981
|
try {
|
|
5815
|
-
const
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
);
|
|
5825
|
-
|
|
5826
|
-
|
|
5982
|
+
const res = await runNpm(installArgs(latest), npmDir);
|
|
5983
|
+
if (res.code !== 0) {
|
|
5984
|
+
logWarn("update", { event: "auto-install-failed", latest, stderr: res.stderr.slice(0, 2e3) });
|
|
5985
|
+
return "failed";
|
|
5986
|
+
}
|
|
5987
|
+
const verify = await verifyInstall(npmDir, latest);
|
|
5988
|
+
if (!verify.ok) {
|
|
5989
|
+
const rollbackTo = SEMVER_RE.test(prevVersion) ? prevVersion : "0.3.0";
|
|
5990
|
+
logWarn("update", { event: "auto-install-verify-failed", latest, reason: verify.reason, rollbackTo });
|
|
5991
|
+
const rb = await runNpm(installArgs(rollbackTo), npmDir);
|
|
5992
|
+
logInfo("update", { event: "rollback", from: latest, to: rollbackTo, ok: rb.code === 0 });
|
|
5993
|
+
return "rolled-back";
|
|
5994
|
+
}
|
|
5995
|
+
logInfo("update", { event: "auto-installed", from: prevVersion, to: latest });
|
|
5996
|
+
return "ok";
|
|
5827
5997
|
} finally {
|
|
5828
5998
|
clearInterval(keepAlive);
|
|
5829
5999
|
}
|
|
5830
6000
|
} catch (e) {
|
|
5831
6001
|
logWarn("update", { event: "install-throw", error: e instanceof Error ? e.message : String(e) });
|
|
5832
|
-
return
|
|
6002
|
+
return "failed";
|
|
5833
6003
|
}
|
|
5834
6004
|
}
|
|
5835
6005
|
async function checkForUpdate(autoUpdate, notify) {
|
|
@@ -5856,7 +6026,7 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
5856
6026
|
const data = await res.json();
|
|
5857
6027
|
const latest = data.version;
|
|
5858
6028
|
if (!latest) return;
|
|
5859
|
-
const current = runtimeVersion ?? "0.
|
|
6029
|
+
const current = runtimeVersion ?? "0.3.0";
|
|
5860
6030
|
const hasUpdate = isNewer(latest, current);
|
|
5861
6031
|
debug.event("update-check", {
|
|
5862
6032
|
current,
|
|
@@ -5865,16 +6035,16 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
5865
6035
|
});
|
|
5866
6036
|
logInfo("update", { event: "check", current, latest, hasUpdate });
|
|
5867
6037
|
if (hasUpdate) {
|
|
5868
|
-
const
|
|
5869
|
-
if (
|
|
6038
|
+
const outcome = await autoInstallLatest(latest);
|
|
6039
|
+
if (!notify) return;
|
|
6040
|
+
if (outcome === "ok") {
|
|
6041
|
+
notify(`\x1B[32m\u2714 ACP auto-updated ${current} \u2192 ${latest}. Restart omp to finish.\x1B[0m`);
|
|
6042
|
+
} else if (outcome === "rolled-back") {
|
|
5870
6043
|
notify(
|
|
5871
|
-
`\x1B[
|
|
5872
|
-
);
|
|
5873
|
-
logInfo("update", { event: "auto-installed", from: current, to: latest });
|
|
5874
|
-
} else if (!installed && notify) {
|
|
5875
|
-
notify(
|
|
5876
|
-
`${PACKAGE_NAME} ${latest} available (you have ${current}). Run: omp install ${PACKAGE_NAME}@latest`
|
|
6044
|
+
`\x1B[33m\u26A0 ${PACKAGE_NAME} ${latest} failed verification and was rolled back. Keeping ${current}. A later release will auto-update.\x1B[0m`
|
|
5877
6045
|
);
|
|
6046
|
+
} else {
|
|
6047
|
+
notify(`${PACKAGE_NAME} ${latest} available (you have ${current}). Run: omp install ${PACKAGE_NAME}@latest`);
|
|
5878
6048
|
}
|
|
5879
6049
|
}
|
|
5880
6050
|
} catch (e) {
|
|
@@ -6112,10 +6282,11 @@ function applyUserConfig(adapter, user) {
|
|
|
6112
6282
|
function createAcpExtension(adapter = {}) {
|
|
6113
6283
|
return (pi) => {
|
|
6114
6284
|
const runtime = createRuntime(adapter);
|
|
6285
|
+
const warnDelivery = makeDeliveryWarner();
|
|
6115
6286
|
wireSessionLifecycle(pi, runtime);
|
|
6116
|
-
wireContextTransform(pi, runtime);
|
|
6287
|
+
wireContextTransform(pi, runtime, warnDelivery);
|
|
6117
6288
|
wireSystemPrompt(pi, runtime);
|
|
6118
|
-
wireProviderTransform(pi, runtime);
|
|
6289
|
+
wireProviderTransform(pi, runtime, warnDelivery);
|
|
6119
6290
|
wireProviderDebug(pi);
|
|
6120
6291
|
wireToolGuardrails(pi, runtime);
|
|
6121
6292
|
pi.registerTool(makeCompressTool(runtime));
|
|
@@ -6129,26 +6300,14 @@ function createAcpExtension(adapter = {}) {
|
|
|
6129
6300
|
}
|
|
6130
6301
|
var index_default = createAcpExtension();
|
|
6131
6302
|
function wireSessionLifecycle(pi, runtime) {
|
|
6132
|
-
|
|
6303
|
+
const prepareAndPrime = async (ctx, phase) => {
|
|
6133
6304
|
const sid = ctx.sessionManager.getSessionId();
|
|
6134
|
-
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.2.9" : null });
|
|
6135
|
-
const selfPath = import.meta.url;
|
|
6136
|
-
const conflict = stampAndDetect(selfPath, true ? "0.2.9" : null);
|
|
6137
|
-
if (conflict) {
|
|
6138
|
-
logWarn("instance", { event: "dual-instance", self: selfPath, other: conflict.path, otherPid: conflict.pid, otherVersion: conflict.version });
|
|
6139
|
-
try {
|
|
6140
|
-
if (ctx.hasUI) {
|
|
6141
|
-
ctx.ui.notify(`\u26A0 billion-context-omp loaded TWICE (also from ${conflict.path}). Two instances corrupt compression state \u2014 remove one (check 'omp plugin list' vs config.yml extensions).`);
|
|
6142
|
-
}
|
|
6143
|
-
} catch {
|
|
6144
|
-
}
|
|
6145
|
-
}
|
|
6146
6305
|
try {
|
|
6147
6306
|
const user = await loadUserConfig(ctx.cwd);
|
|
6148
6307
|
runtime.setAdapter(applyUserConfig(runtime.adapter, user));
|
|
6149
6308
|
if (runtime.adapter.debug !== void 0) setDebugEnabled(runtime.adapter.debug);
|
|
6150
6309
|
} catch (e) {
|
|
6151
|
-
logThrow("config", e, { sid, phase
|
|
6310
|
+
logThrow("config", e, { sid, phase });
|
|
6152
6311
|
}
|
|
6153
6312
|
try {
|
|
6154
6313
|
runtime.setPrompts(resolvePrompts(runtime.adapter.prompts, { acknowledgeRisk: runtime.adapter.acknowledgePromptsRisk === true }));
|
|
@@ -6157,10 +6316,35 @@ function wireSessionLifecycle(pi, runtime) {
|
|
|
6157
6316
|
runtime.setPrompts(defaultPrompts);
|
|
6158
6317
|
}
|
|
6159
6318
|
runtime.primeFold(ctx);
|
|
6319
|
+
};
|
|
6320
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
6321
|
+
const sid = ctx.sessionManager.getSessionId();
|
|
6322
|
+
const modelInfo = ctx.model;
|
|
6323
|
+
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.3.0" : null, model: modelInfo?.id ?? null, modelApi: modelInfo?.api ?? null, contextWindow: modelInfo?.contextWindow ?? null });
|
|
6324
|
+
const selfPath = import.meta.url;
|
|
6325
|
+
const conflict = stampAndDetect(selfPath, true ? "0.3.0" : null);
|
|
6326
|
+
if (conflict) {
|
|
6327
|
+
logWarn("instance", { event: "dual-instance", self: selfPath, other: conflict.path, otherPid: conflict.pid, otherVersion: conflict.version });
|
|
6328
|
+
try {
|
|
6329
|
+
if (ctx.hasUI) {
|
|
6330
|
+
ctx.ui.notify(`\u26A0 billion-context-omp loaded TWICE (also from ${conflict.path}). Two instances corrupt compression state \u2014 remove one (check 'omp plugin list' vs config.yml extensions).`);
|
|
6331
|
+
}
|
|
6332
|
+
} catch {
|
|
6333
|
+
}
|
|
6334
|
+
}
|
|
6335
|
+
await prepareAndPrime(ctx, "session_start");
|
|
6160
6336
|
void checkForUpdate(runtime.adapter.autoUpdate ?? true, (msg) => {
|
|
6161
6337
|
if (ctx.hasUI) ctx.ui.notify(msg);
|
|
6162
6338
|
}).catch((e) => logThrow("update", e, { sid, phase: "session_start" }));
|
|
6163
6339
|
});
|
|
6340
|
+
pi.on("session_switch", async (event, ctx) => {
|
|
6341
|
+
logInfo("session", { event: "switch", sid: ctx.sessionManager.getSessionId(), reason: event.reason, previous: event.previousSessionFile ?? null });
|
|
6342
|
+
await prepareAndPrime(ctx, "session_switch");
|
|
6343
|
+
});
|
|
6344
|
+
pi.on("session_branch", async (_event, ctx) => {
|
|
6345
|
+
logInfo("session", { event: "branch", sid: ctx.sessionManager.getSessionId() });
|
|
6346
|
+
await prepareAndPrime(ctx, "session_branch");
|
|
6347
|
+
});
|
|
6164
6348
|
pi.on("session_shutdown", (_event, ctx) => {
|
|
6165
6349
|
try {
|
|
6166
6350
|
runtime.forgetSession(ctx.sessionManager.getSessionId());
|
|
@@ -6204,6 +6388,7 @@ async function transformStream(ctx, runtime, input, mode) {
|
|
|
6204
6388
|
runtime.commitFoldState(ctx, turn.state);
|
|
6205
6389
|
logInfo("turn", {
|
|
6206
6390
|
sid,
|
|
6391
|
+
model: ctx.model?.id ?? null,
|
|
6207
6392
|
inMsgs: coreMessages.length,
|
|
6208
6393
|
outMsgs: turn.messages.length,
|
|
6209
6394
|
tokens: tokenCount,
|
|
@@ -6231,6 +6416,11 @@ async function transformStream(ctx, runtime, input, mode) {
|
|
|
6231
6416
|
activeAfter: turn.state.blocks.filter((b) => b.active).length
|
|
6232
6417
|
});
|
|
6233
6418
|
const rebuilt = coreOutToAgentMessages(turn.messages, originalById);
|
|
6419
|
+
const rejectedPair = lastRejectedCompressPair(input);
|
|
6420
|
+
if (rejectedPair) {
|
|
6421
|
+
rebuilt.push(...rejectedPair);
|
|
6422
|
+
debug.event("rejected-pair-visible", { sid, callId: rejectedPair[1].toolCallId ?? null });
|
|
6423
|
+
}
|
|
6234
6424
|
debug.event("core-out", {
|
|
6235
6425
|
sid,
|
|
6236
6426
|
coreOutMsgs: turn.messages.length,
|
|
@@ -6242,38 +6432,48 @@ async function transformStream(ctx, runtime, input, mode) {
|
|
|
6242
6432
|
if (turn.nudge?.shouldInject) {
|
|
6243
6433
|
const lastUser = [...input].reverse().find((m) => m.role === "user");
|
|
6244
6434
|
const tailText = lastUser ? JSON.stringify(lastUser.content ?? "") : "";
|
|
6245
|
-
const isFeedbackView = tailText.includes("efficiency nudge to compress early") || tailText.includes("Context limit reached");
|
|
6435
|
+
const isFeedbackView = tailText.includes("efficiency nudge to compress early") || tailText.includes("Context limit reached") || tailText.includes("compress calls were rejected in a row");
|
|
6246
6436
|
if (isFeedbackView) {
|
|
6247
6437
|
debug.event("nudge-feedback-skip", { sid: ctx.sessionManager.getSessionId(), msgs: input.length });
|
|
6248
6438
|
} else {
|
|
6249
6439
|
const emergency = turn.nudge.breakdown?.emergencyOverride === 1;
|
|
6440
|
+
const rejectStreak = runtime.rejectStreakFor(ctx);
|
|
6250
6441
|
const epochReset = turn.state.nudge.lastPerMessageNudgeTokens !== preTurnNudgeBaseline;
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
const suppressed = !emergency && prevShown > 0 && tokenCount - prevShown < cadenceFloor;
|
|
6254
|
-
if (suppressed) {
|
|
6255
|
-
turn.state.nudge.lastNudgeShownTokens = prevShown;
|
|
6442
|
+
if (rejectStreak >= LOOP_GUARD_STOP) {
|
|
6443
|
+
turn.state.nudge.lastNudgeShownTokens = epochReset ? 0 : preTurnNudgeShownTokens;
|
|
6256
6444
|
turn.state.nudge.lastShownByTier = preTurnNudgeShownByTier;
|
|
6257
|
-
logInfo("nudge", { sid, event: "cadence-suppressed", growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6258
|
-
debug.event("nudge-suppressed", { sid, growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6259
|
-
} else {
|
|
6260
6445
|
nudgeInjected = true;
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6265
|
-
|
|
6446
|
+
rebuilt.push(holdMessage(rejectStreak));
|
|
6447
|
+
logInfo("nudge", { sid, event: "hold-injected", streak: rejectStreak, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6448
|
+
debug.event("nudge-hold", { sid, streak: rejectStreak });
|
|
6449
|
+
} else {
|
|
6450
|
+
const prevShown = epochReset ? 0 : preTurnNudgeShownTokens;
|
|
6451
|
+
const cadenceFloor = turn.nudge.breakdown?.growthFloor ?? 0;
|
|
6452
|
+
const suppressed = !emergency && prevShown > 0 && tokenCount - prevShown < cadenceFloor;
|
|
6453
|
+
if (suppressed) {
|
|
6454
|
+
turn.state.nudge.lastNudgeShownTokens = prevShown;
|
|
6455
|
+
turn.state.nudge.lastShownByTier = preTurnNudgeShownByTier;
|
|
6456
|
+
logInfo("nudge", { sid, event: "cadence-suppressed", growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6457
|
+
debug.event("nudge-suppressed", { sid, growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6458
|
+
} else {
|
|
6459
|
+
nudgeInjected = true;
|
|
6460
|
+
{
|
|
6461
|
+
turn.nudge.compressibleRanges = viableRanges(turn.nudge.compressibleRanges);
|
|
6462
|
+
const rendered = renderNudgeText(turn.nudge, runtime.prompts);
|
|
6463
|
+
const top = [...turn.nudge.compressibleRanges].sort((a, b) => b.tokens - a.tokens)[0];
|
|
6464
|
+
const example = top ? `
|
|
6266
6465
|
|
|
6267
6466
|
Example: compress({ content: [{ startId: "${top.startRef}", endId: "${top.endRef}", summary: "..." }] })` : "";
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6467
|
+
rebuilt.push(nudgeMessage(turn.nudge, turn.state.blocks.filter((b) => b.active), runtime.prompts, example));
|
|
6468
|
+
if (emergency) {
|
|
6469
|
+
logWarn("nudge", { sid: ctx.sessionManager.getSessionId(), event: "emergency-inject", pct: Math.round(turn.nudge.contextUsage * 100), voice: rendered.voice, compressible: turn.nudge.compressibleRanges.length });
|
|
6470
|
+
}
|
|
6471
|
+
if (debugOn2 && ctx.hasUI) {
|
|
6472
|
+
ctx.ui.notify(`[ACP nudge \u2192 context]${emergency ? " [EMERGENCY]" : ""}
|
|
6274
6473
|
${rendered.text}${example}`);
|
|
6474
|
+
}
|
|
6475
|
+
debug.event("nudge-injected", { sid: ctx.sessionManager.getSessionId(), voice: rendered.voice, channels: ["context", debugOn2 ? "terminal" : null].filter(Boolean), emergency, text: rendered.text + example });
|
|
6275
6476
|
}
|
|
6276
|
-
debug.event("nudge-injected", { sid: ctx.sessionManager.getSessionId(), voice: rendered.voice, channels: ["context", debugOn2 ? "terminal" : null].filter(Boolean), emergency, text: rendered.text + example });
|
|
6277
6477
|
}
|
|
6278
6478
|
}
|
|
6279
6479
|
}
|
|
@@ -6298,10 +6498,13 @@ ${rendered.text}${example}`);
|
|
|
6298
6498
|
}).catch((e) => logThrow("update", e, { sid, phase: "context" }));
|
|
6299
6499
|
return result;
|
|
6300
6500
|
}
|
|
6301
|
-
function wireContextTransform(pi, runtime) {
|
|
6501
|
+
function wireContextTransform(pi, runtime, warnDelivery) {
|
|
6302
6502
|
pi.on("context", async (event, ctx) => {
|
|
6303
6503
|
if (resolveTransformMode(runtime.adapter, ctx.model) === "provider") {
|
|
6304
|
-
|
|
6504
|
+
const sid = ctx.sessionManager.getSessionId();
|
|
6505
|
+
debug.event("context-observer-skip", { sid, msgs: event.messages?.length ?? 0 });
|
|
6506
|
+
const warning = providerDeliveryWarning(runtime.adapter, ctx.model);
|
|
6507
|
+
if (warning) warnDelivery(ctx, sid, warning);
|
|
6305
6508
|
return void 0;
|
|
6306
6509
|
}
|
|
6307
6510
|
const result = await transformStream(ctx, runtime, event.messages ?? [], "context");
|
|
@@ -6309,7 +6512,20 @@ function wireContextTransform(pi, runtime) {
|
|
|
6309
6512
|
return { messages: result.rebuilt };
|
|
6310
6513
|
});
|
|
6311
6514
|
}
|
|
6312
|
-
function
|
|
6515
|
+
function makeDeliveryWarner() {
|
|
6516
|
+
const warned = /* @__PURE__ */ new Set();
|
|
6517
|
+
return (ctx, sid, warning) => {
|
|
6518
|
+
const dedup = `${sid}:${warning.key}`;
|
|
6519
|
+
if (warned.has(dedup)) return;
|
|
6520
|
+
warned.add(dedup);
|
|
6521
|
+
logWarn("provider-transform", { sid, event: "undelivered", reason: warning.reason });
|
|
6522
|
+
try {
|
|
6523
|
+
if (ctx.hasUI) ctx.ui.notify(warning.message);
|
|
6524
|
+
} catch {
|
|
6525
|
+
}
|
|
6526
|
+
};
|
|
6527
|
+
}
|
|
6528
|
+
function wireProviderTransform(pi, runtime, warnDelivery) {
|
|
6313
6529
|
pi.on("before_provider_request", async (event, ctx) => {
|
|
6314
6530
|
if (resolveTransformMode(runtime.adapter, ctx.model) !== "provider") return void 0;
|
|
6315
6531
|
const payload = event.payload;
|
|
@@ -6318,6 +6534,13 @@ function wireProviderTransform(pi, runtime) {
|
|
|
6318
6534
|
const fmt2 = detectProviderWireFormat(payload);
|
|
6319
6535
|
if (fmt2 === null) {
|
|
6320
6536
|
debug.event("provider-transform-unknown-format", { sid });
|
|
6537
|
+
if (runtime.adapter.transformMode === "provider") {
|
|
6538
|
+
warnDelivery(ctx, sid, {
|
|
6539
|
+
key: "unknown-wire-format",
|
|
6540
|
+
reason: "explicit provider mode but the wire body has no codec path (unknown format) \u2014 payload passes through",
|
|
6541
|
+
message: '\u26A0 billion-context-omp: transformMode "provider" is set, but this wire body has no codec path \u2014 compression is NOT applied here. Remove the override to use context mode.'
|
|
6542
|
+
});
|
|
6543
|
+
}
|
|
6321
6544
|
return void 0;
|
|
6322
6545
|
}
|
|
6323
6546
|
const representable = payloadRepresentable(payload, fmt2);
|
|
@@ -6331,13 +6554,15 @@ function wireProviderTransform(pi, runtime) {
|
|
|
6331
6554
|
if (msgs.length === 0) return void 0;
|
|
6332
6555
|
const result = await transformStreamCore(ctx, runtime, msgs, fmt2);
|
|
6333
6556
|
if (!result) return void 0;
|
|
6334
|
-
const
|
|
6335
|
-
const
|
|
6557
|
+
const inMessages = payload.messages ?? [];
|
|
6558
|
+
const rebuilt = fmt2 === "openai" ? restoreOpenaiWireFidelity(inMessages, coreToPayloadMessages(result.coreOut, fmt2, cacheControls)) : coreToPayloadMessages(result.coreOut, fmt2, cacheControls);
|
|
6559
|
+
const outMsgs = rebuilt.length;
|
|
6560
|
+
const inMsgs = inMessages.length;
|
|
6336
6561
|
if (outMsgs !== inMsgs) {
|
|
6337
6562
|
logInfo("provider-transform", { sid, fmt: fmt2, inMsgs, outMsgs, nudge: result.nudgeInjected ? "injected" : "idle" });
|
|
6338
6563
|
}
|
|
6339
6564
|
debug.event("provider-transform", { sid, fmt: fmt2, inMsgs, outMsgs, nudgeInjected: result.nudgeInjected });
|
|
6340
|
-
return { ...payload, messages:
|
|
6565
|
+
return { ...payload, messages: rebuilt };
|
|
6341
6566
|
} catch (e) {
|
|
6342
6567
|
logThrow("provider-transform", e, { sid, fmt: fmt2 });
|
|
6343
6568
|
return void 0;
|
|
@@ -6411,42 +6636,57 @@ async function transformStreamCore(ctx, runtime, wireMsgs, fmt2) {
|
|
|
6411
6636
|
turn.state,
|
|
6412
6637
|
{ config, tokenCount }
|
|
6413
6638
|
);
|
|
6639
|
+
const rejectedPair = lastRejectedPairCore(wireMsgs);
|
|
6640
|
+
if (rejectedPair) {
|
|
6641
|
+
coreOut.push(...rejectedPair);
|
|
6642
|
+
debug.event("rejected-pair-visible", { sid, space: "core", callId: rejectedPair[1]?.toolCallId ?? null });
|
|
6643
|
+
}
|
|
6414
6644
|
let nudgeInjected = false;
|
|
6415
6645
|
if (turn.nudge?.shouldInject) {
|
|
6416
6646
|
const lastUser = [...wireMsgs].reverse().find((m) => m.role === "user");
|
|
6417
6647
|
const tailText = lastUser ? lastUser.text ?? "" : "";
|
|
6418
|
-
const isFeedbackView = tailText.includes("efficiency nudge to compress early") || tailText.includes("Context limit reached");
|
|
6648
|
+
const isFeedbackView = tailText.includes("efficiency nudge to compress early") || tailText.includes("Context limit reached") || tailText.includes("compress calls were rejected in a row");
|
|
6419
6649
|
if (isFeedbackView) {
|
|
6420
6650
|
debug.event("nudge-feedback-skip", { sid, msgs: wireMsgs.length });
|
|
6421
6651
|
} else {
|
|
6422
6652
|
const emergency = turn.nudge.breakdown?.emergencyOverride === 1;
|
|
6423
6653
|
const epochReset = turn.state.nudge.lastPerMessageNudgeTokens !== preTurnNudgeBaseline;
|
|
6424
|
-
const
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
if (suppressed) {
|
|
6428
|
-
turn.state.nudge.lastNudgeShownTokens = prevShown;
|
|
6654
|
+
const rejectStreak = runtime.rejectStreakFor(ctx);
|
|
6655
|
+
if (rejectStreak >= LOOP_GUARD_STOP) {
|
|
6656
|
+
turn.state.nudge.lastNudgeShownTokens = epochReset ? 0 : preTurnNudgeShownTokens;
|
|
6429
6657
|
turn.state.nudge.lastShownByTier = preTurnNudgeShownByTier;
|
|
6430
|
-
logInfo("nudge", { sid, event: "cadence-suppressed", growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6431
|
-
debug.event("nudge-suppressed", { sid, growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6432
|
-
} else {
|
|
6433
6658
|
nudgeInjected = true;
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6659
|
+
coreOut.push({ id: `acp_hold_${Date.now()}`, role: "user", contentType: "text", text: holdText(rejectStreak) });
|
|
6660
|
+
logInfo("nudge", { sid, event: "hold-injected", streak: rejectStreak, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6661
|
+
debug.event("nudge-hold", { sid, streak: rejectStreak });
|
|
6662
|
+
} else {
|
|
6663
|
+
const prevShown = epochReset ? 0 : preTurnNudgeShownTokens;
|
|
6664
|
+
const cadenceFloor = turn.nudge.breakdown?.growthFloor ?? 0;
|
|
6665
|
+
const suppressed = !emergency && prevShown > 0 && tokenCount - prevShown < cadenceFloor;
|
|
6666
|
+
if (suppressed) {
|
|
6667
|
+
turn.state.nudge.lastNudgeShownTokens = prevShown;
|
|
6668
|
+
turn.state.nudge.lastShownByTier = preTurnNudgeShownByTier;
|
|
6669
|
+
logInfo("nudge", { sid, event: "cadence-suppressed", growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6670
|
+
debug.event("nudge-suppressed", { sid, growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
6671
|
+
} else {
|
|
6672
|
+
nudgeInjected = true;
|
|
6673
|
+
turn.nudge.compressibleRanges = viableRanges(turn.nudge.compressibleRanges);
|
|
6674
|
+
const rendered = renderNudgeText(turn.nudge, runtime.prompts);
|
|
6675
|
+
const top = [...turn.nudge.compressibleRanges].sort((a, b) => b.tokens - a.tokens)[0];
|
|
6676
|
+
const example = top ? `
|
|
6438
6677
|
|
|
6439
6678
|
Example: compress({ content: [{ startId: "${top.startRef}", endId: "${top.endRef}", summary: "..." }] })` : "";
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6679
|
+
if (emergency) {
|
|
6680
|
+
logWarn("nudge", { sid, event: "emergency-inject", pct: Math.round(turn.nudge.contextUsage * 100), voice: rendered.voice, compressible: turn.nudge.compressibleRanges.length });
|
|
6681
|
+
}
|
|
6682
|
+
const debugOn2 = debug.enabled;
|
|
6683
|
+
if (debugOn2 && ctx.hasUI) {
|
|
6684
|
+
ctx.ui.notify(`[ACP nudge \u2192 context]${emergency ? " [EMERGENCY]" : ""}
|
|
6446
6685
|
${rendered.text}${example}`);
|
|
6686
|
+
}
|
|
6687
|
+
debug.event("nudge-injected", { sid, voice: rendered.voice, channels: ["wire", debugOn2 ? "terminal" : null].filter(Boolean), emergency, text: rendered.text + example });
|
|
6688
|
+
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) });
|
|
6447
6689
|
}
|
|
6448
|
-
debug.event("nudge-injected", { sid, voice: rendered.voice, channels: ["wire", debugOn2 ? "terminal" : null].filter(Boolean), emergency, text: rendered.text + example });
|
|
6449
|
-
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) });
|
|
6450
6690
|
}
|
|
6451
6691
|
}
|
|
6452
6692
|
}
|
|
@@ -6522,6 +6762,16 @@ function nudgeMessage(nudge, blocks, prompts, example) {
|
|
|
6522
6762
|
timestamp: Date.now()
|
|
6523
6763
|
};
|
|
6524
6764
|
}
|
|
6765
|
+
function holdText(streak) {
|
|
6766
|
+
return `[ACP hold] Your last ${streak} compress calls were rejected in a row. Do NOT call compress again now and do NOT retry the same range \u2014 the compress reminder is suspended until context actually changes. Continue the actual task. If context still needs relief, run acp_status first and target ONLY a range that meets the minimum size.`;
|
|
6767
|
+
}
|
|
6768
|
+
function holdMessage(streak) {
|
|
6769
|
+
return {
|
|
6770
|
+
role: "user",
|
|
6771
|
+
content: [{ type: "text", text: holdText(streak) }],
|
|
6772
|
+
timestamp: Date.now()
|
|
6773
|
+
};
|
|
6774
|
+
}
|
|
6525
6775
|
export {
|
|
6526
6776
|
createAcpExtension,
|
|
6527
6777
|
index_default as default
|