billion-context-omp 0.1.9 → 0.2.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/README.md +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/index.js +394 -118
- package/dist/index.js.map +1 -1
- package/dist/user-config.d.ts +1 -0
- package/dist/wire-transform.d.ts +53 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -145,6 +145,7 @@ Create `~/.omp/acp-omp.json` (global) and/or `<project>/.omp/acp-omp.json` (proj
|
|
|
145
145
|
| Key | Default | Description |
|
|
146
146
|
|-----|---------|-------------|
|
|
147
147
|
| `debug` | `false` | Enable verbose **debug-level** events in the log. The always-on log (lifecycle events, errors, warnings) is written regardless; `debug` only adds extra diagnostics. Also enabled by env `ACP_DEBUG=1`. |
|
|
148
|
+
| `transformMode` | `"context"` (default) or `"provider"` — where the compression surgery intercepts. `provider` transforms the provider wire payload (no feedback re-entry; experimental). |
|
|
148
149
|
| `autoUpdate` | `true` | On session start (throttled to one check per 3 minutes), check npm for a newer version and auto-install it. Disable to avoid all startup network calls. |
|
|
149
150
|
| `modelContextLimit` | *(auto)* | Override the context limit (in tokens). Defaults to the model's `contextWindow`. |
|
|
150
151
|
| `compressModel` | *(session model)* | `provider:modelId` used for `/compact` model-summarized compaction (e.g. `"zhipuai:glm-5.2"`). Defaults to the current session model when omitted. |
|
package/dist/config.d.ts
CHANGED
|
@@ -27,6 +27,13 @@ export interface CompressConfig {
|
|
|
27
27
|
* (live model context window, protected tools, state persistence).
|
|
28
28
|
*/
|
|
29
29
|
export interface AdapterConfig {
|
|
30
|
+
/** Where the compression surgery intercepts (issue #52). "context" (default)
|
|
31
|
+
* rewrites the context event — battle-tested, but omp's recap/subagent
|
|
32
|
+
* pipelines can re-feed our output as input (feedback-view loops).
|
|
33
|
+
* "provider" leaves the agent array untouched and transforms the WIRE
|
|
34
|
+
* payload at before_provider_request — request-local, no re-entry; unknown
|
|
35
|
+
* provider formats pass through untransformed (fail-open). */
|
|
36
|
+
transformMode?: "context" | "provider";
|
|
30
37
|
/** When omitted, the adapter reads `ctx.model.contextWindow` live each turn.
|
|
31
38
|
* Set explicitly for tests/headless runs. */
|
|
32
39
|
modelContextLimit?: number;
|
package/dist/index.js
CHANGED
|
@@ -3425,6 +3425,11 @@ function makeCompressTool(runtime) {
|
|
|
3425
3425
|
async function handleCompress(args, runtime, ctx, toolCallId) {
|
|
3426
3426
|
const ranges = args.content ?? [];
|
|
3427
3427
|
if (ranges.length === 0) return "No ranges provided.";
|
|
3428
|
+
const invalid = ranges.filter((r) => !r || typeof r.summary !== "string" || !r.summary.trim() || !r.startId || !r.endId);
|
|
3429
|
+
if (invalid.length > 0) {
|
|
3430
|
+
logWarn("compress", { sid: ctx.sessionManager.getSessionId(), event: "invalid-ranges", count: invalid.length });
|
|
3431
|
+
return `Every range needs startId, endId and a summary (min 50 chars) \u2014 got ${invalid.length} range(s) missing fields. Re-send the FULL ranges array with summaries included.`;
|
|
3432
|
+
}
|
|
3428
3433
|
const releaseLock = await runtime.acquireLock(ctx.sessionManager.getSessionId());
|
|
3429
3434
|
try {
|
|
3430
3435
|
const { state: initialState, coreMessages } = await runtime.stateFor(ctx);
|
|
@@ -4492,7 +4497,7 @@ async function statusReport(runtime, ctx) {
|
|
|
4492
4497
|
const coveredIds = collectCoveredMessageIds(state);
|
|
4493
4498
|
const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
|
|
4494
4499
|
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount: sentTokens });
|
|
4495
|
-
const versionStr = "0.
|
|
4500
|
+
const versionStr = "0.2.0" ? `billion-context-omp@${"0.2.0"}` : void 0;
|
|
4496
4501
|
return buildStatusPanel({
|
|
4497
4502
|
version: versionStr,
|
|
4498
4503
|
tokenCount: sessionTokens,
|
|
@@ -4504,6 +4509,237 @@ async function statusReport(runtime, ctx) {
|
|
|
4504
4509
|
});
|
|
4505
4510
|
}
|
|
4506
4511
|
|
|
4512
|
+
// src/wire-transform.ts
|
|
4513
|
+
var AI = /* @__PURE__ */ Symbol("acp.streamIndex");
|
|
4514
|
+
function detectWireFormat(payload) {
|
|
4515
|
+
if (payload === null || typeof payload !== "object") return "unknown";
|
|
4516
|
+
const p = payload;
|
|
4517
|
+
const messages = p.messages;
|
|
4518
|
+
if (!Array.isArray(messages)) return "unknown";
|
|
4519
|
+
if ("system" in p || "anthropic_version" in p) return "anthropic";
|
|
4520
|
+
for (const m of messages) {
|
|
4521
|
+
if (m === null || typeof m !== "object") continue;
|
|
4522
|
+
const c = m.content;
|
|
4523
|
+
if (Array.isArray(c)) {
|
|
4524
|
+
for (const b of c) {
|
|
4525
|
+
if (b && typeof b === "object" && typeof b.type === "string") {
|
|
4526
|
+
if (b.type === "tool_use" || b.type === "tool_result" || b.type === "thinking") return "anthropic";
|
|
4527
|
+
if (b.type === "text" && "cache_control" in b) return "anthropic";
|
|
4528
|
+
}
|
|
4529
|
+
}
|
|
4530
|
+
}
|
|
4531
|
+
if (Array.isArray(m.tool_calls)) return "openai";
|
|
4532
|
+
if (m.role === "tool" && typeof m.tool_call_id === "string") return "openai";
|
|
4533
|
+
if (m.role === "system" || m.role === "developer") return "openai";
|
|
4534
|
+
}
|
|
4535
|
+
return "openai";
|
|
4536
|
+
}
|
|
4537
|
+
function anthropicBlocks(m) {
|
|
4538
|
+
return typeof m.content === "string" ? [{ type: "text", text: m.content }] : m.content ?? [];
|
|
4539
|
+
}
|
|
4540
|
+
var assistantBase = () => ({
|
|
4541
|
+
api: "anthropic",
|
|
4542
|
+
provider: "anthropic",
|
|
4543
|
+
model: "wire",
|
|
4544
|
+
usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } },
|
|
4545
|
+
stopReason: "stop",
|
|
4546
|
+
timestamp: Date.now()
|
|
4547
|
+
});
|
|
4548
|
+
function synthesizeStream(payload, format) {
|
|
4549
|
+
const messages = payload.messages ?? [];
|
|
4550
|
+
const stream = [];
|
|
4551
|
+
const back = [];
|
|
4552
|
+
const push = (msg, wi, kind) => {
|
|
4553
|
+
msg[AI] = stream.length;
|
|
4554
|
+
stream.push(msg);
|
|
4555
|
+
back.push({ wi, kind });
|
|
4556
|
+
};
|
|
4557
|
+
if (format === "anthropic") {
|
|
4558
|
+
const toolNames = /* @__PURE__ */ new Map();
|
|
4559
|
+
for (const raw of messages) {
|
|
4560
|
+
if (raw === null || typeof raw !== "object") continue;
|
|
4561
|
+
const m = raw;
|
|
4562
|
+
if (m.role !== "assistant") continue;
|
|
4563
|
+
for (const b of anthropicBlocks(m)) if (b.type === "tool_use" && b.id) toolNames.set(b.id, b.name ?? "");
|
|
4564
|
+
}
|
|
4565
|
+
messages.forEach((raw, wi) => {
|
|
4566
|
+
if (raw === null || typeof raw !== "object") return;
|
|
4567
|
+
const m = raw;
|
|
4568
|
+
const blocks = anthropicBlocks(m);
|
|
4569
|
+
if (m.role === "user") {
|
|
4570
|
+
let texts = [];
|
|
4571
|
+
for (const b of blocks) {
|
|
4572
|
+
if (b.type === "text" && typeof b.text === "string") texts.push(b.text);
|
|
4573
|
+
else if (b.type === "tool_result") {
|
|
4574
|
+
if (texts.length > 0) {
|
|
4575
|
+
push({ role: "user", content: texts.map((t2) => ({ type: "text", text: t2 })), timestamp: Date.now() }, wi, "text");
|
|
4576
|
+
texts = [];
|
|
4577
|
+
}
|
|
4578
|
+
const trText = typeof b.content === "string" ? b.content : Array.isArray(b.content) ? b.content.map((c) => c.text ?? "").join("\n") : "";
|
|
4579
|
+
push({
|
|
4580
|
+
role: "toolResult",
|
|
4581
|
+
content: [{ type: "text", text: trText }],
|
|
4582
|
+
toolName: toolNames.get(b.tool_use_id ?? "") ?? "",
|
|
4583
|
+
toolCallId: b.tool_use_id ?? "",
|
|
4584
|
+
isError: b.is_error === true,
|
|
4585
|
+
timestamp: Date.now()
|
|
4586
|
+
}, wi, "toolResult");
|
|
4587
|
+
}
|
|
4588
|
+
}
|
|
4589
|
+
if (texts.length > 0) push({ role: "user", content: texts.map((t2) => ({ type: "text", text: t2 })), timestamp: Date.now() }, wi, "text");
|
|
4590
|
+
return;
|
|
4591
|
+
}
|
|
4592
|
+
if (m.role === "assistant") {
|
|
4593
|
+
const content = [];
|
|
4594
|
+
for (const b of blocks) {
|
|
4595
|
+
if (b.type === "text" && typeof b.text === "string" && b.text.length > 0) content.push({ type: "text", text: b.text });
|
|
4596
|
+
else if (b.type === "tool_use") content.push({ type: "toolCall", id: b.id, name: b.name, arguments: b.input ?? {} });
|
|
4597
|
+
}
|
|
4598
|
+
if (content.length > 0) push({ role: "assistant", ...assistantBase(), content }, wi, "toolCall");
|
|
4599
|
+
return;
|
|
4600
|
+
}
|
|
4601
|
+
const t = blocks.map((b) => typeof b.text === "string" ? b.text : "").join("\n");
|
|
4602
|
+
if (t) push({ role: "user", content: [{ type: "text", text: t }], timestamp: Date.now() }, wi, "text");
|
|
4603
|
+
});
|
|
4604
|
+
return { stream, back, format };
|
|
4605
|
+
}
|
|
4606
|
+
messages.forEach((raw, wi) => {
|
|
4607
|
+
if (raw === null || typeof raw !== "object") return;
|
|
4608
|
+
const m = raw;
|
|
4609
|
+
const textOf = () => {
|
|
4610
|
+
const c = m.content;
|
|
4611
|
+
if (typeof c === "string") return c;
|
|
4612
|
+
if (Array.isArray(c)) return c.map((p) => p.type === "text" ? p.text ?? "" : "").join("\n");
|
|
4613
|
+
return "";
|
|
4614
|
+
};
|
|
4615
|
+
if (m.role === "system" || m.role === "developer") {
|
|
4616
|
+
const t2 = textOf();
|
|
4617
|
+
if (t2) push({ role: "user", content: [{ type: "text", text: t2 }], timestamp: Date.now() }, wi, "text");
|
|
4618
|
+
return;
|
|
4619
|
+
}
|
|
4620
|
+
if (m.role === "tool") {
|
|
4621
|
+
push({
|
|
4622
|
+
role: "toolResult",
|
|
4623
|
+
content: [{ type: "text", text: textOf() }],
|
|
4624
|
+
toolName: "",
|
|
4625
|
+
toolCallId: m.tool_call_id ?? "",
|
|
4626
|
+
isError: false,
|
|
4627
|
+
timestamp: Date.now()
|
|
4628
|
+
}, wi, "toolResult");
|
|
4629
|
+
return;
|
|
4630
|
+
}
|
|
4631
|
+
if (m.role === "assistant") {
|
|
4632
|
+
const calls = m.tool_calls ?? [];
|
|
4633
|
+
if (calls.length > 0) {
|
|
4634
|
+
const content = [];
|
|
4635
|
+
const t3 = textOf();
|
|
4636
|
+
if (t3) content.push({ type: "text", text: t3 });
|
|
4637
|
+
for (const c of calls) {
|
|
4638
|
+
let args = {};
|
|
4639
|
+
try {
|
|
4640
|
+
args = c.function?.arguments ? JSON.parse(c.function.arguments) : {};
|
|
4641
|
+
} catch {
|
|
4642
|
+
args = { raw: c.function?.arguments ?? "" };
|
|
4643
|
+
}
|
|
4644
|
+
content.push({ type: "toolCall", id: c.id, name: c.function?.name ?? "", arguments: args });
|
|
4645
|
+
}
|
|
4646
|
+
push({ role: "assistant", ...assistantBase(), content }, wi, "toolCall");
|
|
4647
|
+
return;
|
|
4648
|
+
}
|
|
4649
|
+
const t2 = textOf();
|
|
4650
|
+
if (t2) push({ role: "assistant", ...assistantBase(), content: [{ type: "text", text: t2 }] }, wi, "text");
|
|
4651
|
+
return;
|
|
4652
|
+
}
|
|
4653
|
+
const t = textOf();
|
|
4654
|
+
if (t) push({ role: "user", content: [{ type: "text", text: t }], timestamp: Date.now() }, wi, "text");
|
|
4655
|
+
});
|
|
4656
|
+
return { stream, back, format };
|
|
4657
|
+
}
|
|
4658
|
+
function rebuildWirePayload(rebuilt, payload, synth) {
|
|
4659
|
+
const messages = (payload.messages ?? []).slice();
|
|
4660
|
+
const out = [];
|
|
4661
|
+
const agentIndexOf = (m) => m[AI];
|
|
4662
|
+
for (const agent of rebuilt) {
|
|
4663
|
+
const ai = agentIndexOf(agent);
|
|
4664
|
+
if (ai === void 0 || ai >= synth.back.length) {
|
|
4665
|
+
const text2 = extractText(agent.content);
|
|
4666
|
+
const role = agent.role === "assistant" ? "assistant" : "user";
|
|
4667
|
+
if (synth.format === "anthropic") {
|
|
4668
|
+
out.push({ role, content: [{ type: "text", text: text2 }] });
|
|
4669
|
+
} else {
|
|
4670
|
+
out.push({ role, content: text2 });
|
|
4671
|
+
}
|
|
4672
|
+
continue;
|
|
4673
|
+
}
|
|
4674
|
+
const { wi, kind } = synth.back[ai];
|
|
4675
|
+
const src = messages[wi];
|
|
4676
|
+
if (!src) {
|
|
4677
|
+
out.push(agent);
|
|
4678
|
+
continue;
|
|
4679
|
+
}
|
|
4680
|
+
if (synth.format === "anthropic") {
|
|
4681
|
+
const srcMsg2 = src;
|
|
4682
|
+
const blocks = anthropicBlocks(srcMsg2);
|
|
4683
|
+
if (kind === "toolResult") {
|
|
4684
|
+
const block2 = blocks.find((b) => b.type === "tool_result" && b.tool_use_id === agent.toolCallId);
|
|
4685
|
+
const text3 = extractText(agent.content);
|
|
4686
|
+
if (block2) {
|
|
4687
|
+
out.push({ role: "user", content: [{ ...block2, content: [{ type: "text", text: text3 }] }] });
|
|
4688
|
+
continue;
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
if (kind === "toolCall") {
|
|
4692
|
+
const callIds = new Set(
|
|
4693
|
+
(agent.content ?? []).filter((b) => b.type === "toolCall" && b.id).map((b) => b.id)
|
|
4694
|
+
);
|
|
4695
|
+
const agentText = extractText(agent.content);
|
|
4696
|
+
const outBlocks = [];
|
|
4697
|
+
let textSeen = false;
|
|
4698
|
+
for (const b of blocks) {
|
|
4699
|
+
if (b.type === "tool_use") {
|
|
4700
|
+
if (callIds.has(b.id ?? "")) outBlocks.push(b);
|
|
4701
|
+
continue;
|
|
4702
|
+
}
|
|
4703
|
+
if (b.type === "text") {
|
|
4704
|
+
if (!textSeen && typeof b.text === "string") {
|
|
4705
|
+
outBlocks.push(b);
|
|
4706
|
+
textSeen = true;
|
|
4707
|
+
}
|
|
4708
|
+
continue;
|
|
4709
|
+
}
|
|
4710
|
+
outBlocks.push(b);
|
|
4711
|
+
}
|
|
4712
|
+
if (agentText && !textSeen) outBlocks.unshift({ type: "text", text: agentText });
|
|
4713
|
+
out.push({ role: "assistant", content: outBlocks });
|
|
4714
|
+
continue;
|
|
4715
|
+
}
|
|
4716
|
+
const text2 = extractText(agent.content);
|
|
4717
|
+
const block = blocks.find((b) => b.type === "text");
|
|
4718
|
+
if (block) out.push({ role: srcMsg2.role, content: [{ ...block, text: text2 }] });
|
|
4719
|
+
else out.push({ role: srcMsg2.role, content: [{ type: "text", text: text2 }] });
|
|
4720
|
+
continue;
|
|
4721
|
+
}
|
|
4722
|
+
const srcMsg = src;
|
|
4723
|
+
const text = extractText(agent.content);
|
|
4724
|
+
if (kind === "toolResult") {
|
|
4725
|
+
out.push({ role: "tool", tool_call_id: agent.toolCallId ?? srcMsg.tool_call_id, content: text });
|
|
4726
|
+
continue;
|
|
4727
|
+
}
|
|
4728
|
+
if (kind === "toolCall") {
|
|
4729
|
+
const callIds = new Set(
|
|
4730
|
+
(agent.content ?? []).filter((b) => b.type === "toolCall" && b.id).map((b) => b.id)
|
|
4731
|
+
);
|
|
4732
|
+
const surviving = (srcMsg.tool_calls ?? []).filter((c) => callIds.has(c.id));
|
|
4733
|
+
const entry = { role: "assistant", content: text };
|
|
4734
|
+
if (surviving.length > 0) entry.tool_calls = surviving;
|
|
4735
|
+
out.push(entry);
|
|
4736
|
+
continue;
|
|
4737
|
+
}
|
|
4738
|
+
out.push({ role: srcMsg.role === "assistant" ? "assistant" : srcMsg.role, content: text });
|
|
4739
|
+
}
|
|
4740
|
+
return { ...payload, messages: out };
|
|
4741
|
+
}
|
|
4742
|
+
|
|
4507
4743
|
// src/auto-compress.ts
|
|
4508
4744
|
import { readFileSync } from "fs";
|
|
4509
4745
|
import { join as join3 } from "path";
|
|
@@ -4934,7 +5170,7 @@ async function checkForUpdate(autoUpdate, notify) {
|
|
|
4934
5170
|
const data = await res.json();
|
|
4935
5171
|
const latest = data.version;
|
|
4936
5172
|
if (!latest) return;
|
|
4937
|
-
const current = runtimeVersion ?? "0.
|
|
5173
|
+
const current = runtimeVersion ?? "0.2.0";
|
|
4938
5174
|
const hasUpdate = isNewer(latest, current);
|
|
4939
5175
|
debug.event("update-check", {
|
|
4940
5176
|
current,
|
|
@@ -5149,6 +5385,7 @@ var KNOWN = /* @__PURE__ */ new Set([
|
|
|
5149
5385
|
"debug",
|
|
5150
5386
|
"autoUpdate",
|
|
5151
5387
|
"modelContextLimit",
|
|
5388
|
+
"transformMode",
|
|
5152
5389
|
"toolBashDefaultTimeout",
|
|
5153
5390
|
"toolOutputMaxBytes",
|
|
5154
5391
|
"delegate",
|
|
@@ -5192,6 +5429,7 @@ function createAcpExtension(adapter = {}) {
|
|
|
5192
5429
|
wireSessionLifecycle(pi, runtime);
|
|
5193
5430
|
wireContextTransform(pi, runtime);
|
|
5194
5431
|
wireSystemPrompt(pi, runtime);
|
|
5432
|
+
wireProviderTransform(pi, runtime);
|
|
5195
5433
|
wireProviderDebug(pi);
|
|
5196
5434
|
wireToolGuardrails(pi, runtime);
|
|
5197
5435
|
pi.registerTool(makeCompressTool(runtime));
|
|
@@ -5248,7 +5486,7 @@ function wireCompactionDisable(pi, runtime) {
|
|
|
5248
5486
|
function wireSessionLifecycle(pi, runtime) {
|
|
5249
5487
|
pi.on("session_start", async (_event, ctx) => {
|
|
5250
5488
|
const sid = ctx.sessionManager.getSessionId();
|
|
5251
|
-
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.
|
|
5489
|
+
logInfo("session", { event: "start", sid, cwd: ctx.cwd, debug: runtime.adapter.debug ?? null, version: true ? "0.2.0" : null });
|
|
5252
5490
|
try {
|
|
5253
5491
|
const user = await loadUserConfig(ctx.cwd);
|
|
5254
5492
|
runtime.setAdapter(applyUserConfig(runtime.adapter, user));
|
|
@@ -5275,130 +5513,168 @@ function wireSessionLifecycle(pi, runtime) {
|
|
|
5275
5513
|
closeLogStream();
|
|
5276
5514
|
});
|
|
5277
5515
|
}
|
|
5278
|
-
function
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5289
|
-
|
|
5290
|
-
|
|
5291
|
-
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5516
|
+
async function transformStream(ctx, runtime, input, mode) {
|
|
5517
|
+
const sid = ctx.sessionManager.getSessionId();
|
|
5518
|
+
const release = await runtime.acquireLock(sid);
|
|
5519
|
+
try {
|
|
5520
|
+
if (input.length === 0) {
|
|
5521
|
+
debug.event("empty-stream-bypass", { sid });
|
|
5522
|
+
return void 0;
|
|
5523
|
+
}
|
|
5524
|
+
debug.event("context-in-raw", { sid, msgs: input.length, mode });
|
|
5525
|
+
const { state, coreMessages, originalById, streamLen } = runtime.foldStream(ctx, input);
|
|
5526
|
+
const preTurnNudgeBaseline = state.nudge.lastPerMessageNudgeTokens;
|
|
5527
|
+
const preTurnNudgeShownTokens = state.nudge.lastNudgeShownTokens;
|
|
5528
|
+
const preTurnNudgeShownByTier = state.nudge.lastShownByTier;
|
|
5529
|
+
const config = runtime.configFor(ctx);
|
|
5530
|
+
const coveredIds = collectCoveredMessageIds(state);
|
|
5531
|
+
const systemPromptTokens = estimateTextTokens2(getSystemPromptText(ctx) ?? "");
|
|
5532
|
+
const sentTokens = estimateTokens(coreMessages, coveredIds) + systemPromptTokens;
|
|
5533
|
+
const sessionTokens = ctx.getContextUsage?.()?.tokens ?? null;
|
|
5534
|
+
const tokenCount = sentTokens;
|
|
5535
|
+
debug.event("context-in", {
|
|
5536
|
+
sid,
|
|
5537
|
+
mode,
|
|
5538
|
+
streamLen,
|
|
5539
|
+
coreMsgs: coreMessages.length,
|
|
5540
|
+
tokenCount,
|
|
5541
|
+
sessionTokens,
|
|
5542
|
+
limit: config.modelContextLimit,
|
|
5543
|
+
blocksBefore: state.blocks.length,
|
|
5544
|
+
activeBefore: state.blocks.filter((b) => b.active).length
|
|
5545
|
+
});
|
|
5546
|
+
const turn = runtime.core.processTurn({ messages: coreMessages, state, config, tokenCount });
|
|
5547
|
+
runtime.commitFoldState(ctx, turn.state);
|
|
5548
|
+
logInfo("turn", {
|
|
5549
|
+
sid,
|
|
5550
|
+
inMsgs: coreMessages.length,
|
|
5551
|
+
outMsgs: turn.messages.length,
|
|
5552
|
+
tokens: tokenCount,
|
|
5553
|
+
sessionTokens,
|
|
5554
|
+
pct: config.modelContextLimit > 0 ? Math.round(tokenCount / config.modelContextLimit * 100) : null,
|
|
5555
|
+
limit: config.modelContextLimit,
|
|
5556
|
+
nudge: turn.nudge?.shouldInject ? turn.nudge.breakdown?.emergencyOverride === 1 ? "emergency" : "active" : "idle",
|
|
5557
|
+
nudgeReason: turn.nudge?.reason ?? null,
|
|
5558
|
+
blocks: turn.state.blocks.length,
|
|
5559
|
+
activeBlocks: turn.state.blocks.filter((b) => b.active).length
|
|
5560
|
+
});
|
|
5561
|
+
debug.event("processTurn", {
|
|
5562
|
+
outMsgs: turn.messages.length,
|
|
5563
|
+
summaryMsgs: turn.messages.filter((m) => m.id.startsWith("acp_summary")).length,
|
|
5564
|
+
prunedMsgs: coreMessages.length - turn.messages.length + turn.messages.filter((m) => m.id.startsWith("acp_summary")).length,
|
|
5565
|
+
nudgeShouldInject: turn.nudge?.shouldInject ?? false,
|
|
5566
|
+
nudgeReason: turn.nudge?.reason ?? null,
|
|
5567
|
+
nudgeVoice: turn.nudge ? renderNudgeText(turn.nudge, runtime.prompts).voice : null,
|
|
5568
|
+
nudgePct: turn.nudge ? Math.round(turn.nudge.contextUsage * 100) : null,
|
|
5569
|
+
nudgeTier: turn.nudge?.tier ?? null,
|
|
5570
|
+
nudgeCompressibleCount: turn.nudge?.compressibleRanges.length ?? 0,
|
|
5571
|
+
nudgeProtectedCount: turn.nudge?.protectedRanges?.length ?? 0,
|
|
5572
|
+
nothingToCompress: turn.nudge?.reason?.includes("nothing to compress") ?? false,
|
|
5573
|
+
blocksAfter: turn.state.blocks.length,
|
|
5574
|
+
activeAfter: turn.state.blocks.filter((b) => b.active).length
|
|
5575
|
+
});
|
|
5576
|
+
const rebuilt = coreOutToAgentMessages(turn.messages, originalById);
|
|
5577
|
+
debug.event("core-out", {
|
|
5578
|
+
sid,
|
|
5579
|
+
coreOutMsgs: turn.messages.length,
|
|
5580
|
+
originalByIdSize: originalById.size,
|
|
5581
|
+
rebuiltMsgs: rebuilt.length
|
|
5582
|
+
});
|
|
5583
|
+
const debugOn2 = debug.enabled;
|
|
5584
|
+
let nudgeInjected = false;
|
|
5585
|
+
if (turn.nudge?.shouldInject) {
|
|
5586
|
+
const lastUser = [...input].reverse().find((m) => m.role === "user");
|
|
5587
|
+
const tailText = lastUser ? JSON.stringify(lastUser.content ?? "") : "";
|
|
5588
|
+
const isFeedbackView = tailText.includes("efficiency nudge to compress early") || tailText.includes("Context limit reached");
|
|
5589
|
+
if (isFeedbackView) {
|
|
5590
|
+
debug.event("nudge-feedback-skip", { sid: ctx.sessionManager.getSessionId(), msgs: input.length });
|
|
5591
|
+
} else {
|
|
5592
|
+
const emergency = turn.nudge.breakdown?.emergencyOverride === 1;
|
|
5593
|
+
const epochReset = turn.state.nudge.lastPerMessageNudgeTokens !== preTurnNudgeBaseline;
|
|
5594
|
+
const prevShown = epochReset ? 0 : preTurnNudgeShownTokens;
|
|
5595
|
+
const cadenceFloor = turn.nudge.breakdown?.growthFloor ?? 0;
|
|
5596
|
+
const suppressed = !emergency && prevShown > 0 && tokenCount - prevShown < cadenceFloor;
|
|
5597
|
+
if (suppressed) {
|
|
5598
|
+
turn.state.nudge.lastNudgeShownTokens = prevShown;
|
|
5599
|
+
turn.state.nudge.lastShownByTier = preTurnNudgeShownByTier;
|
|
5600
|
+
logInfo("nudge", { sid, event: "cadence-suppressed", growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
5601
|
+
debug.event("nudge-suppressed", { sid, growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
5355
5602
|
} else {
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
turn.state.nudge.lastNudgeShownTokens = prevShown;
|
|
5363
|
-
turn.state.nudge.lastShownByTier = preTurnNudgeShownByTier;
|
|
5364
|
-
logInfo("nudge", { sid, event: "cadence-suppressed", growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
5365
|
-
debug.event("nudge-suppressed", { sid, growth: tokenCount - prevShown, floor: cadenceFloor, pct: Math.round(turn.nudge.contextUsage * 100), reason: turn.nudge.reason });
|
|
5366
|
-
} else {
|
|
5367
|
-
nudgeInjected = true;
|
|
5368
|
-
{
|
|
5369
|
-
turn.nudge.compressibleRanges = viableRanges(turn.nudge.compressibleRanges);
|
|
5370
|
-
const rendered = renderNudgeText(turn.nudge, runtime.prompts);
|
|
5371
|
-
const top = [...turn.nudge.compressibleRanges].sort((a, b) => b.tokens - a.tokens)[0];
|
|
5372
|
-
const example = top ? `
|
|
5603
|
+
nudgeInjected = true;
|
|
5604
|
+
{
|
|
5605
|
+
turn.nudge.compressibleRanges = viableRanges(turn.nudge.compressibleRanges);
|
|
5606
|
+
const rendered = renderNudgeText(turn.nudge, runtime.prompts);
|
|
5607
|
+
const top = [...turn.nudge.compressibleRanges].sort((a, b) => b.tokens - a.tokens)[0];
|
|
5608
|
+
const example = top ? `
|
|
5373
5609
|
|
|
5374
5610
|
Example: compress({ content: [{ startId: "${top.startRef}", endId: "${top.endRef}", summary: "..." }] })` : "";
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5611
|
+
rebuilt.push(nudgeMessage(turn.nudge, turn.state.blocks.filter((b) => b.active), runtime.prompts, example));
|
|
5612
|
+
if (emergency) {
|
|
5613
|
+
logWarn("nudge", { sid: ctx.sessionManager.getSessionId(), event: "emergency-inject", pct: Math.round(turn.nudge.contextUsage * 100), voice: rendered.voice, compressible: turn.nudge.compressibleRanges.length });
|
|
5614
|
+
}
|
|
5615
|
+
if (debugOn2 && ctx.hasUI) {
|
|
5616
|
+
ctx.ui.notify(`[ACP nudge \u2192 context]${emergency ? " [EMERGENCY]" : ""}
|
|
5381
5617
|
${rendered.text}${example}`);
|
|
5382
|
-
}
|
|
5383
|
-
debug.event("nudge-injected", { sid: ctx.sessionManager.getSessionId(), voice: rendered.voice, channels: ["context", debugOn2 ? "terminal" : null].filter(Boolean), emergency, text: rendered.text + example });
|
|
5384
5618
|
}
|
|
5619
|
+
debug.event("nudge-injected", { sid: ctx.sessionManager.getSessionId(), voice: rendered.voice, channels: ["context", debugOn2 ? "terminal" : null].filter(Boolean), emergency, text: rendered.text + example });
|
|
5385
5620
|
}
|
|
5386
5621
|
}
|
|
5387
5622
|
}
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5623
|
+
}
|
|
5624
|
+
dumpContextMessages(rebuilt, {
|
|
5625
|
+
sid,
|
|
5626
|
+
injected: nudgeInjected,
|
|
5627
|
+
emergency: turn.nudge?.breakdown?.emergencyOverride === 1
|
|
5628
|
+
});
|
|
5629
|
+
await checkForUpdate(runtime.adapter.autoUpdate ?? true, (msg) => {
|
|
5630
|
+
if (ctx.hasUI) ctx.ui.notify(msg);
|
|
5631
|
+
});
|
|
5632
|
+
return { rebuilt, nudgeInjected };
|
|
5633
|
+
} catch (e) {
|
|
5634
|
+
logThrow("context", e, { sid, phase: "transform", mode });
|
|
5635
|
+
throw e;
|
|
5636
|
+
} finally {
|
|
5637
|
+
release();
|
|
5638
|
+
}
|
|
5639
|
+
}
|
|
5640
|
+
function wireContextTransform(pi, runtime) {
|
|
5641
|
+
pi.on("context", async (event, ctx) => {
|
|
5642
|
+
if ((runtime.adapter.transformMode ?? "context") === "provider") {
|
|
5643
|
+
debug.event("context-observer-skip", { sid: ctx.sessionManager.getSessionId(), msgs: event.messages?.length ?? 0 });
|
|
5644
|
+
return void 0;
|
|
5645
|
+
}
|
|
5646
|
+
const result = await transformStream(ctx, runtime, event.messages ?? [], "context");
|
|
5647
|
+
if (!result) return void 0;
|
|
5648
|
+
return { messages: result.rebuilt };
|
|
5649
|
+
});
|
|
5650
|
+
}
|
|
5651
|
+
function wireProviderTransform(pi, runtime) {
|
|
5652
|
+
pi.on("before_provider_request", async (event, ctx) => {
|
|
5653
|
+
if ((runtime.adapter.transformMode ?? "context") !== "provider") return void 0;
|
|
5654
|
+
const payload = event.payload;
|
|
5655
|
+
if (payload === null || typeof payload !== "object" || !Array.isArray(payload.messages)) return void 0;
|
|
5656
|
+
const sid = ctx.sessionManager?.getSessionId?.() ?? "";
|
|
5657
|
+
const fmt2 = detectWireFormat(payload);
|
|
5658
|
+
if (fmt2 === "unknown") {
|
|
5659
|
+
debug.event("provider-transform-unknown-format", { sid });
|
|
5660
|
+
return void 0;
|
|
5661
|
+
}
|
|
5662
|
+
try {
|
|
5663
|
+
const synth = synthesizeStream(payload, fmt2);
|
|
5664
|
+
if (synth.stream.length === 0) return void 0;
|
|
5665
|
+
const result = await transformStream(ctx, runtime, synth.stream, "provider");
|
|
5666
|
+
if (!result) return void 0;
|
|
5667
|
+
const wireOut = rebuildWirePayload(result.rebuilt, payload, synth);
|
|
5668
|
+
const outMsgs = wireOut.messages?.length ?? 0;
|
|
5669
|
+
const inMsgs = payload.messages?.length ?? 0;
|
|
5670
|
+
if (outMsgs !== inMsgs || wireOut !== payload) {
|
|
5671
|
+
logInfo("provider-transform", { sid, fmt: fmt2, inMsgs, outMsgs, nudge: result.nudgeInjected ? "injected" : "idle" });
|
|
5672
|
+
}
|
|
5673
|
+
debug.event("provider-transform", { sid, fmt: fmt2, inMsgs, outMsgs, nudgeInjected: result.nudgeInjected });
|
|
5674
|
+
return wireOut === payload ? void 0 : wireOut;
|
|
5397
5675
|
} catch (e) {
|
|
5398
|
-
logThrow("
|
|
5399
|
-
|
|
5400
|
-
} finally {
|
|
5401
|
-
release();
|
|
5676
|
+
logThrow("provider-transform", e, { sid, fmt: fmt2 });
|
|
5677
|
+
return void 0;
|
|
5402
5678
|
}
|
|
5403
5679
|
});
|
|
5404
5680
|
}
|