acp-kernel 0.0.35 → 0.0.36
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/chunk-MWXUJVMN.js +366 -0
- package/dist/chunk-MWXUJVMN.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -345
- package/dist/index.js.map +1 -1
- package/dist/panel/format.d.ts +5 -0
- package/dist/panel/format.d.ts.map +1 -0
- package/dist/panel/index.d.ts +5 -0
- package/dist/panel/index.d.ts.map +1 -0
- package/dist/panel/index.js +116 -0
- package/dist/panel/index.js.map +1 -0
- package/dist/panel/panel.d.ts +44 -0
- package/dist/panel/panel.d.ts.map +1 -0
- package/dist/panel/topic.d.ts +5 -0
- package/dist/panel/topic.d.ts.map +1 -0
- package/dist/viable.d.ts +13 -0
- package/dist/viable.d.ts.map +1 -0
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
COMPRESS_PHILOSOPHY,
|
|
3
|
+
HOW_TO_COMPRESS_RULES,
|
|
4
|
+
TIER2_DISTILL_RULES,
|
|
5
|
+
TIER3_CONDENSE_RULES,
|
|
6
|
+
VIABLE_RANGE_MIN_TOKENS,
|
|
7
|
+
createBpeTokenizer,
|
|
8
|
+
defaultCountTokens,
|
|
9
|
+
defaultPrompts,
|
|
10
|
+
estimateTokensFast,
|
|
11
|
+
formatRanges,
|
|
12
|
+
renderNudgeText,
|
|
13
|
+
resolvePrompts,
|
|
14
|
+
viableRanges
|
|
15
|
+
} from "./chunk-MWXUJVMN.js";
|
|
16
|
+
|
|
1
17
|
// src/refs.ts
|
|
2
18
|
var REF_WIDTH = 5;
|
|
3
19
|
var MIN_INDEX = 1;
|
|
@@ -298,38 +314,6 @@ function syncBlocks(messages, state) {
|
|
|
298
314
|
return { state: result, deactivated };
|
|
299
315
|
}
|
|
300
316
|
|
|
301
|
-
// src/tokenize.ts
|
|
302
|
-
import { createRequire } from "module";
|
|
303
|
-
var require2 = createRequire(import.meta.url);
|
|
304
|
-
function defaultCountTokens(text) {
|
|
305
|
-
if (!text) return 0;
|
|
306
|
-
const cjk = text.match(/[\u4e00-\u9fff\u3040-\u30ff\uac00-\ud7af]/g);
|
|
307
|
-
const cjkCount = cjk?.length ?? 0;
|
|
308
|
-
return cjkCount + Math.ceil((text.length - cjkCount) / 4);
|
|
309
|
-
}
|
|
310
|
-
function estimateTokensFast(text) {
|
|
311
|
-
if (!text) return 0;
|
|
312
|
-
return Math.ceil(text.length / 4);
|
|
313
|
-
}
|
|
314
|
-
var BPE_SIZE_GUARD = 1e5;
|
|
315
|
-
function createBpeTokenizer() {
|
|
316
|
-
try {
|
|
317
|
-
const mod = require2("@anthropic-ai/tokenizer");
|
|
318
|
-
const bpeCount = mod.countTokens ?? mod.default?.countTokens;
|
|
319
|
-
if (typeof bpeCount !== "function") return defaultCountTokens;
|
|
320
|
-
return (text) => {
|
|
321
|
-
if (text.length > BPE_SIZE_GUARD) return defaultCountTokens(text);
|
|
322
|
-
try {
|
|
323
|
-
return bpeCount(text);
|
|
324
|
-
} catch {
|
|
325
|
-
return defaultCountTokens(text);
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
} catch {
|
|
329
|
-
return defaultCountTokens;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
317
|
// src/config.ts
|
|
334
318
|
function defaultConfig(modelContextLimit, overrides = {}) {
|
|
335
319
|
const base = {
|
|
@@ -1996,318 +1980,6 @@ function countOccurrences(haystack, needle) {
|
|
|
1996
1980
|
return count;
|
|
1997
1981
|
}
|
|
1998
1982
|
|
|
1999
|
-
// src/compression-rules.ts
|
|
2000
|
-
var COMPRESS_PHILOSOPHY = `Compression Philosophy:
|
|
2001
|
-
- All compression serves the primary task, but be frugal.
|
|
2002
|
-
- Context capacity is precious. Save context by compressing consumed outputs, not by avoiding tools.
|
|
2003
|
-
- Compress by need, not by percentage.
|
|
2004
|
-
- Work from summaries, not raw tool outputs. All listed ranges (user prompts, tool outputs, code, logs, exploration, intermediate steps) should be compressed to summary format \u2014 the ONLY exceptions are protected content, content the current step is actively using, or critical content you cannot reconstruct.`;
|
|
2005
|
-
var HOW_TO_COMPRESS_RULES = `HOW TO COMPRESS
|
|
2006
|
-
|
|
2007
|
-
When you call \`compress\`, the summary you write becomes the only record of the replaced conversation. Make it self-contained and complete: every user request, experiment purpose, and work task in the range must be accurately captured. A later reader (or you, after decompressing) should be able to continue the task WITHOUT needing the original.
|
|
2008
|
-
|
|
2009
|
-
KEEP VERBATIM \u2014 never paraphrase or abbreviate these:
|
|
2010
|
-
- Full file paths with line numbers, directory prefix on every mention (\`lib/hooks.ts:347\`, \`src/index.ts:12-18\`, \`gatenet_v3/model.py:45\`). Never abbreviate to a bare filename (\`hooks.ts\`, \`model.py\`) \u2014 they are ambiguous and cannot be grepped or decompressed-to later.
|
|
2011
|
-
- Function, class, and type signatures (exact names, params, return types) AND critical code lines that encode logic \u2014 the line that IS the finding, not just the function name (e.g. \`kv_keys += define_gate * a_key[i](emb)\` is more useful than "see model_kvnet.py").
|
|
2012
|
-
- Error messages and stack traces (exact text \u2014 you need the literal string to grep for it later).
|
|
2013
|
-
- Key details from reports and analyses \u2014 not just the conclusion. Keep the comparison numbers and the mechanism, not "X is worse" alone (write "1.76\xD7 PPL gap because KV store is static", not "KVNet underperforms").
|
|
2014
|
-
- Decisions and their rationale ("chose X over Y because Z" \u2014 the "because" is load-bearing; without it the decision looks arbitrary).
|
|
2015
|
-
- Constraints discovered ("must support Node 22", "no new dependencies", "AGENTS.md forbids \`as any\`").
|
|
2016
|
-
- Exact values: versions, config keys, thresholds, magic numbers.
|
|
2017
|
-
- User intent \u2014 quote short user messages verbatim. When the message is too long to quote, preserve intent with extra care: do not change scope, constraints, priorities, acceptance criteria, or requested outcomes. Mark them clearly as past quotes (e.g., "User said: ..."), not as current directives. Losing these changes the task itself.
|
|
2018
|
-
- The user's overall goal and any changes to it \u2014 the big-picture objective plus how it evolved during the compressed range. Each summary must reflect the goal as it stood at the end of the range, including pivots (e.g., "initially: fix bug X \u2192 pivoted to: refactor module Y after discovering root cause"). Losing the goal or its evolution makes all subsequent work appear unmotivated.
|
|
2019
|
-
- Purpose behind each significant action \u2014 preserve not just what was done but why: the hypothesis behind each experiment, the question behind each exploration, the task goal behind each work action. Without purpose, the summary reads as disconnected technical steps with no through-line.
|
|
2020
|
-
- Open questions and unresolved TODOs \u2014 losing these changes what work appears to remain.
|
|
2021
|
-
- Message refs of key anchors (\`m00420\`, \`m00510\u2013m00520\`) \u2014 they let you or a later reader jump back via decompress to the exact original.
|
|
2022
|
-
|
|
2023
|
-
DROP \u2014 extract the signal, discard the vessel:
|
|
2024
|
-
- Verbose logs (build/test/\`npm\` output) once you have captured the error line or the result.
|
|
2025
|
-
- Duplicate file reads once the needed content is recorded.
|
|
2026
|
-
- Consumed exploration \u2014 search hits, agent return values, successful tool outputs \u2014 once you have extracted the facts you need (same rule as dead-ends, but nothing went wrong; the content is simply spent).
|
|
2027
|
-
- Dead-end exploration \u2014 but PRESERVE the lesson in one line: "tried X, failed because Y".
|
|
2028
|
-
- Back-and-forth discussion and self-corrections once the final position is captured (keep the outcome, drop the journey to it).
|
|
2029
|
-
- Repeated status checks (\`git status\`, \`ls\`) once state is known.
|
|
2030
|
-
|
|
2031
|
-
For each significant item you DROP (scripts, reports, large analyses, long tool outputs), add a one-line CONTENT description of what it covers \u2014 not where it lives. Bad: "probe script at /path/probe_kvnet.py". Good: "probe_kvnet.py: tests n-gram baseline, generation quality, long-range dependency, position sensitivity, op pipeline, QUERY attention." This lets a later decompress target the right block by relevance, not by guessing locations.
|
|
2032
|
-
|
|
2033
|
-
PRIORITY \u2014 when the summary must be compact, preserve in this order:
|
|
2034
|
-
1. User's overall goal, goal evolution, intent, and hard constraints (losing these changes the task).
|
|
2035
|
-
2. Decisions and rationale.
|
|
2036
|
-
3. Exact technical artifacts: paths, signatures, errors, values.
|
|
2037
|
-
4. Conclusions and key findings.
|
|
2038
|
-
5. Lessons learned: what failed and why.
|
|
2039
|
-
|
|
2040
|
-
Write dense, scannable bullets \u2014 not narrative prose. If the range spans distinct concerns (request \u2192 findings \u2192 decision), group bullets under short thematic headers so a reader can scan to the part they need. Every line must earn its place. Do not mimic the style of existing summaries in context; follow these rules.`;
|
|
2041
|
-
var TIER2_DISTILL_RULES = `TIER 2 COMPRESSION \u2014 DISTILLATION
|
|
2042
|
-
|
|
2043
|
-
You are compressing historical summaries (not raw conversation). These summaries have already captured the details. Your job is to DISTILL them: extract only what matters for future work, discard the process.
|
|
2044
|
-
|
|
2045
|
-
KEEP \u2014 these are the only things that survive distillation:
|
|
2046
|
-
- Decisions and their rationale ("chose X over Y because Z" \u2014 the "because" is load-bearing).
|
|
2047
|
-
- Final outcomes: version numbers shipped, PR numbers merged/closed, bugs fixed or deferred.
|
|
2048
|
-
- Key lessons: what failed and why ("tried X, failed because Y"). These prevent repeating mistakes.
|
|
2049
|
-
- Critical constraints discovered ("must support Node 22", "AGENTS.md forbids as any").
|
|
2050
|
-
- Design decisions with architectural impact ("chose compress-as-anchor over synthetic messages because prefix cache").
|
|
2051
|
-
- Whether content is OBSOLETE or SUPERSEDED \u2014 mark with one line: "[SUPERSEDED by PR #NNN]" or "[OBSOLETE: deleted in vX.Y.Z]". Do NOT keep the obsolete content's details \u2014 just the marker and reason.
|
|
2052
|
-
- Function/class/type names and module paths that are the SUBJECT of the work \u2014 e.g., "fixed filterCompressedRanges in prune.ts", "added SessionStateRegistry in state.ts". Not exact line numbers or full signatures \u2014 just enough to LOCATE the code without searching.
|
|
2053
|
-
- Exploration findings: if a block was exploratory with no decision, keep the CONCLUSION in one line ("explored X, not viable because Y"). Do not keep the exploration process.
|
|
2054
|
-
|
|
2055
|
-
DROP \u2014 these were useful during the work but are no longer needed:
|
|
2056
|
-
- Exact line numbers, diffs, verbose function signatures, full code listings.
|
|
2057
|
-
- Build/deploy process details, test execution steps.
|
|
2058
|
-
- Review process details (who reviewed, what rounds, test counts).
|
|
2059
|
-
- Verbose logs, command output, intermediate debugging steps.
|
|
2060
|
-
|
|
2061
|
-
FORMAT:
|
|
2062
|
-
- Start each distilled block with a source header line:
|
|
2063
|
-
\`Source: bN+bM+... (XK\u2192YK tok, Zx). [original topic]\`
|
|
2064
|
-
Example: \`Source: b5+b7 (56K+44K\u2192268 tok, 375x). [Tool-result recap + publish]\`
|
|
2065
|
-
- 3-5 bullet points per source block, each a self-contained fact.
|
|
2066
|
-
- Dense, scannable \u2014 no narrative prose.
|
|
2067
|
-
- Start with the outcome, not the process: "v1.13.0 shipped (7 PRs bundled)" not "implemented 7 PRs then reviewed then merged".
|
|
2068
|
-
- Cross-block synthesis: if multiple source blocks cover the same topic (same PR, same feature, same bug), MERGE them into a single group of bullets. Do not repeat the same fact from different blocks \u2014 keep it once under the most relevant source header.
|
|
2069
|
-
|
|
2070
|
-
SIZE TARGET: 50-150 tokens per source block (excluding the header). If you can't fit it in 150 tokens, you're keeping too much process. If a block has nothing worth keeping (pure noise), output just the header followed by "[no actionable content]."`;
|
|
2071
|
-
var TIER3_CONDENSE_RULES = `TIER 3 COMPRESSION \u2014 ULTRA-CONDENSATION
|
|
2072
|
-
|
|
2073
|
-
You are compressing distilled summaries (Tier 2) into ultra-condensed facts (Tier 3). The distilled summaries already contain only decisions and outcomes. Your job is to reduce them to bare factual references.
|
|
2074
|
-
|
|
2075
|
-
PRIORITY \u2014 when a source block has more facts than the size target allows, keep in this order:
|
|
2076
|
-
1. Shipped outcomes (versions released, PRs merged) \u2014 these are permanent record.
|
|
2077
|
-
2. Open work (PRs/issues still pending) \u2014 these may need follow-up.
|
|
2078
|
-
3. Key decisions with architectural impact ("chose X over Y because Z").
|
|
2079
|
-
4. Critical constraints ("must support Node 22").
|
|
2080
|
-
Drop everything else. Tier 3 is a lookup index, not a knowledge base.
|
|
2081
|
-
|
|
2082
|
-
FORMAT:
|
|
2083
|
-
- Start with a source header line:
|
|
2084
|
-
\`Source: bN+bM+... (XK\u2192YK tok, Zx). [original topic]\`
|
|
2085
|
-
- Output 1-3 facts per source block. Each fact is a single line: subject + outcome.
|
|
2086
|
-
- No explanations, no rationale, no process \u2014 just the fact.
|
|
2087
|
-
- Format: "[PR/Issue/Version] \u2014 [outcome in \u22648 words]"
|
|
2088
|
-
- Merge related facts from different source blocks if they concern the same topic.
|
|
2089
|
-
|
|
2090
|
-
EXAMPLES:
|
|
2091
|
-
- "v1.13.0 shipped \u2014 quality gate + GC fix (7 PRs)"
|
|
2092
|
-
- "PR #196 merged \u2014 preserve-first-user (supersedes #169)"
|
|
2093
|
-
- "Bug 1214 fixed \u2014 compress consumed all user messages"
|
|
2094
|
-
- "Chose compress-as-anchor \u2014 prefix cache benefit over synthetic injection"
|
|
2095
|
-
- "Constraint: AGENTS.md forbids as any \u2014 never suppress types"
|
|
2096
|
-
|
|
2097
|
-
DROP:
|
|
2098
|
-
- Multi-sentence context. If a fact needs >1 sentence, it's too detailed for Tier 3.
|
|
2099
|
-
- Lessons learned ("tried X, failed because Y") \u2014 drop UNLESS the failure is likely to recur and the block is <30 days old.
|
|
2100
|
-
- Design rationale details \u2014 keep the decision, drop the "because" unless it's a critical constraint.
|
|
2101
|
-
- Anything marked [OBSOLETE] or [SUPERSEDED] \u2014 drop entirely, note "[N blocks obsolete]" in the summary.
|
|
2102
|
-
|
|
2103
|
-
SIZE TARGET: 30-60 tokens per source block (including header). For a batch of N source blocks, total output \u2248 N \xD7 40 tokens. If a source block has only one trivial fact, output just the header + one line.`;
|
|
2104
|
-
|
|
2105
|
-
// src/prompts.ts
|
|
2106
|
-
var defaultPrompts = Object.freeze({
|
|
2107
|
-
compressPhilosophy: COMPRESS_PHILOSOPHY,
|
|
2108
|
-
howToCompressRules: HOW_TO_COMPRESS_RULES,
|
|
2109
|
-
tier2DistillRules: TIER2_DISTILL_RULES,
|
|
2110
|
-
tier3CondenseRules: TIER3_CONDENSE_RULES
|
|
2111
|
-
});
|
|
2112
|
-
function resolvePrompts(overrides, options = {}) {
|
|
2113
|
-
const clean = {};
|
|
2114
|
-
if (overrides) {
|
|
2115
|
-
for (const [key, value] of Object.entries(overrides)) {
|
|
2116
|
-
if (typeof value === "string") {
|
|
2117
|
-
clean[key] = value;
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2120
|
-
}
|
|
2121
|
-
const keys = Object.keys(clean);
|
|
2122
|
-
if (keys.length > 0 && !options.acknowledgeRisk) {
|
|
2123
|
-
throw new Error(
|
|
2124
|
-
`resolvePrompts: overriding compression rules requires { acknowledgeRisk: true }. Overridden keys: ${keys.join(", ")}. These rules are quality-critical (tuned over months of production use); changing them can degrade summary quality and break retrieval (summaries may lose paths, signatures, decisions).`
|
|
2125
|
-
);
|
|
2126
|
-
}
|
|
2127
|
-
return { ...defaultPrompts, ...clean };
|
|
2128
|
-
}
|
|
2129
|
-
|
|
2130
|
-
// src/nudge-text.ts
|
|
2131
|
-
function efficiencyNote(prompts) {
|
|
2132
|
-
return `This is an efficiency nudge to compress early and keep context lean \u2014 not an overflow warning. A separate, stronger alert will appear if the context is actually full.
|
|
2133
|
-
|
|
2134
|
-
${prompts.compressPhilosophy}`;
|
|
2135
|
-
}
|
|
2136
|
-
function emergencyHeader(prompts) {
|
|
2137
|
-
return `\u26A0\uFE0F Context limit reached \u2014 compress now. Prioritize consumed tool outputs.
|
|
2138
|
-
|
|
2139
|
-
${prompts.compressPhilosophy}`;
|
|
2140
|
-
}
|
|
2141
|
-
function formatK(n) {
|
|
2142
|
-
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
2143
|
-
return `${n}`;
|
|
2144
|
-
}
|
|
2145
|
-
function formatBreakdown(bd) {
|
|
2146
|
-
if (!bd) return "";
|
|
2147
|
-
const parts = [];
|
|
2148
|
-
if (bd.system > 0) parts.push(`${formatK(bd.system)} system`);
|
|
2149
|
-
if (bd.tool > 0) parts.push(`${formatK(bd.tool)} tool`);
|
|
2150
|
-
if (bd.summaries > 0) parts.push(`${formatK(bd.summaries)} summaries`);
|
|
2151
|
-
if (bd.code > 0) parts.push(`${formatK(bd.code)} code`);
|
|
2152
|
-
if (bd.text > 0) parts.push(`${formatK(bd.text)} text`);
|
|
2153
|
-
const growth = bd.growth > 0 ? `
|
|
2154
|
-
+${formatK(bd.growth)} since last nudge` : "";
|
|
2155
|
-
return `Context breakdown: ${parts.join(" | ")}${growth}`;
|
|
2156
|
-
}
|
|
2157
|
-
function formatTierTargetBlocks(blocks) {
|
|
2158
|
-
if (blocks.length === 0) {
|
|
2159
|
-
return "Target blocks: (none \u2014 no tier blocks found)";
|
|
2160
|
-
}
|
|
2161
|
-
const lines = blocks.map((b) => {
|
|
2162
|
-
const summaryTokens = Math.ceil((b.summary ?? "").length / 4);
|
|
2163
|
-
const topic = b.topic ? ` "${b.topic}"` : "";
|
|
2164
|
-
return ` ${b.blockId} ${b.effectiveMessageIds.length} msgs ${formatK(b.compressedTokens)}\u2192${formatK(summaryTokens)}${topic}`;
|
|
2165
|
-
});
|
|
2166
|
-
return `Target ${blocks[0].tier === 1 ? "tier-1" : "tier-2"} blocks to distill (${blocks.length}):
|
|
2167
|
-
${lines.join("\n")}`;
|
|
2168
|
-
}
|
|
2169
|
-
function formatRanges(compressible, protectedRanges) {
|
|
2170
|
-
if (compressible.length === 0 && protectedRanges.length === 0) {
|
|
2171
|
-
return "[No specific ranges detected \u2014 compress any consumed content.]";
|
|
2172
|
-
}
|
|
2173
|
-
const refNum2 = (ref) => {
|
|
2174
|
-
const m = ref.match(/\d+/);
|
|
2175
|
-
return m ? parseInt(m[0], 10) : 0;
|
|
2176
|
-
};
|
|
2177
|
-
const entries = [];
|
|
2178
|
-
for (const r of compressible) {
|
|
2179
|
-
entries.push({
|
|
2180
|
-
startRef: r.startRef,
|
|
2181
|
-
endRef: r.endRef,
|
|
2182
|
-
startNum: refNum2(r.startRef),
|
|
2183
|
-
endNum: refNum2(r.endRef),
|
|
2184
|
-
count: r.count,
|
|
2185
|
-
tokens: r.tokens,
|
|
2186
|
-
toolPct: r.toolPct,
|
|
2187
|
-
textPct: r.textPct,
|
|
2188
|
-
compressibleTokens: r.tokens,
|
|
2189
|
-
compressibleCount: r.count,
|
|
2190
|
-
protectedTokens: 0,
|
|
2191
|
-
protectedCount: 0,
|
|
2192
|
-
protectedTools: [],
|
|
2193
|
-
dangerous: r.dangerous ?? false
|
|
2194
|
-
});
|
|
2195
|
-
}
|
|
2196
|
-
for (const r of protectedRanges) {
|
|
2197
|
-
entries.push({
|
|
2198
|
-
startRef: r.startRef,
|
|
2199
|
-
endRef: r.endRef,
|
|
2200
|
-
startNum: refNum2(r.startRef),
|
|
2201
|
-
endNum: refNum2(r.endRef),
|
|
2202
|
-
count: r.count,
|
|
2203
|
-
tokens: r.tokens,
|
|
2204
|
-
toolPct: 0,
|
|
2205
|
-
textPct: 0,
|
|
2206
|
-
compressibleTokens: 0,
|
|
2207
|
-
compressibleCount: 0,
|
|
2208
|
-
protectedTokens: r.tokens,
|
|
2209
|
-
protectedCount: r.count,
|
|
2210
|
-
protectedTools: [...r.tools],
|
|
2211
|
-
dangerous: false
|
|
2212
|
-
});
|
|
2213
|
-
}
|
|
2214
|
-
entries.sort((a, b) => a.startNum - b.startNum);
|
|
2215
|
-
const merged = [];
|
|
2216
|
-
for (const e of entries) {
|
|
2217
|
-
const last = merged[merged.length - 1];
|
|
2218
|
-
if (last && e.startNum <= last.endNum + 1) {
|
|
2219
|
-
last.endRef = e.endRef;
|
|
2220
|
-
last.endNum = Math.max(last.endNum, e.endNum);
|
|
2221
|
-
last.count += e.count;
|
|
2222
|
-
last.tokens += e.tokens;
|
|
2223
|
-
last.compressibleTokens += e.compressibleTokens;
|
|
2224
|
-
last.compressibleCount += e.compressibleCount;
|
|
2225
|
-
last.protectedTokens += e.protectedTokens;
|
|
2226
|
-
last.protectedCount += e.protectedCount;
|
|
2227
|
-
if (e.dangerous) last.dangerous = true;
|
|
2228
|
-
for (const t of e.protectedTools) {
|
|
2229
|
-
if (!last.protectedTools.includes(t)) last.protectedTools.push(t);
|
|
2230
|
-
}
|
|
2231
|
-
} else {
|
|
2232
|
-
merged.push({ ...e });
|
|
2233
|
-
}
|
|
2234
|
-
}
|
|
2235
|
-
const lines = merged.map((e) => {
|
|
2236
|
-
const suffix = e.dangerous && e.compressibleTokens > 0 ? " \u26A0\uFE0F NOT recommended unless you are certain." : "";
|
|
2237
|
-
if (e.protectedTokens > 0 && e.compressibleTokens === 0) {
|
|
2238
|
-
return ` ${e.startRef}\u2013${e.endRef} ${e.count} msgs ${formatK(e.tokens)} [PROTECTED: ${e.protectedTools.join(", ")} \u2014 not compressible]${suffix}`;
|
|
2239
|
-
}
|
|
2240
|
-
if (e.protectedTokens > 0 && e.compressibleTokens > 0) {
|
|
2241
|
-
return ` ${e.startRef}\u2013${e.endRef} ${e.count} msgs ${formatK(e.tokens)} [${formatK(e.compressibleTokens)} compressible | ${formatK(e.protectedTokens)} protected: ${e.protectedTools.join(", ")}]${suffix}`;
|
|
2242
|
-
}
|
|
2243
|
-
return ` ${e.startRef}\u2013${e.endRef} ${e.count} msgs ${formatK(e.tokens)} [tool ${e.toolPct}% | text ${e.textPct}%]${suffix}`;
|
|
2244
|
-
});
|
|
2245
|
-
return `Compressible ranges (${merged.length}, oldest first):
|
|
2246
|
-
${lines.join("\n")}`;
|
|
2247
|
-
}
|
|
2248
|
-
function renderNudgeText(decision, prompts = defaultPrompts) {
|
|
2249
|
-
const breakdownStr = formatBreakdown(decision.contextBreakdown);
|
|
2250
|
-
const rangesStr = formatRanges(decision.compressibleRanges, decision.protectedRanges ?? []);
|
|
2251
|
-
const isEmergency = !!decision.breakdown?.emergencyOverride || !!decision.breakdown?.overLimit;
|
|
2252
|
-
if (decision.tier !== null && decision.tier >= 2) {
|
|
2253
|
-
const isT2 = decision.tier === 2;
|
|
2254
|
-
const targets = decision.tierTargetBlocks ?? [];
|
|
2255
|
-
const blockList = formatTierTargetBlocks(targets);
|
|
2256
|
-
const startId = targets[0]?.blockId ?? "b1";
|
|
2257
|
-
const endId = targets[targets.length - 1]?.blockId ?? "b5";
|
|
2258
|
-
const voice = isEmergency ? "emergency" : "gentle";
|
|
2259
|
-
const triggerLine = isEmergency ? `[EMERGENCY \u2014 TIER ${decision.tier} ${isT2 ? "DISTILLATION" : "CONDENSATION"}] Context limit reached \u2014 distill NOW into a denser summary to reclaim tokens.` : `[TIER ${decision.tier} ${isT2 ? "DISTILLATION" : "CONDENSATION"} TRIGGER]`;
|
|
2260
|
-
return {
|
|
2261
|
-
voice,
|
|
2262
|
-
text: [
|
|
2263
|
-
efficiencyNote(prompts),
|
|
2264
|
-
"",
|
|
2265
|
-
breakdownStr,
|
|
2266
|
-
"",
|
|
2267
|
-
triggerLine,
|
|
2268
|
-
isT2 ? `Your tier-1 compression summaries have accumulated. Distill them into a single denser tier-2 summary. Use block IDs as boundaries (startId and endId as bN). Any raw (uncompressed) messages sitting between the boundary blocks are absorbed into the tier-2 block as well \u2014 apply HOW TO COMPRESS to those raw messages and the TIER 2 distillation rules to the existing summaries, so the whole span is covered and nothing is lost.` : `Your tier-2 compression summaries have accumulated. Condense them further into a tier-3 ultra-condensed summary. Use block IDs as boundaries (startId and endId as bN). Any raw (uncompressed) messages sitting between the boundary blocks are absorbed into the tier-3 block as well \u2014 apply HOW TO COMPRESS to those raw messages and the TIER 3 condensation rules to the existing summaries, so the whole span is covered and nothing is lost.`,
|
|
2269
|
-
blockList,
|
|
2270
|
-
`Example: compress({ content: [{ startId: "${startId}", endId: "${endId}", summary: "..." }] })`,
|
|
2271
|
-
"",
|
|
2272
|
-
prompts.howToCompressRules,
|
|
2273
|
-
"",
|
|
2274
|
-
isT2 ? prompts.tier2DistillRules : prompts.tier3CondenseRules
|
|
2275
|
-
].join("\n")
|
|
2276
|
-
};
|
|
2277
|
-
}
|
|
2278
|
-
if (isEmergency) {
|
|
2279
|
-
return {
|
|
2280
|
-
voice: "emergency",
|
|
2281
|
-
text: [
|
|
2282
|
-
emergencyHeader(prompts),
|
|
2283
|
-
"",
|
|
2284
|
-
breakdownStr,
|
|
2285
|
-
"",
|
|
2286
|
-
prompts.howToCompressRules,
|
|
2287
|
-
"",
|
|
2288
|
-
`{ "topic": "...", "content": [{ "startId": "<ID>", "endId": "<ID>", "summary": "..." }] }`,
|
|
2289
|
-
"Only use IDs from visible messages above. Compress older work first.",
|
|
2290
|
-
"",
|
|
2291
|
-
rangesStr
|
|
2292
|
-
].join("\n")
|
|
2293
|
-
};
|
|
2294
|
-
}
|
|
2295
|
-
return {
|
|
2296
|
-
voice: "gentle",
|
|
2297
|
-
text: [
|
|
2298
|
-
efficiencyNote(prompts),
|
|
2299
|
-
"",
|
|
2300
|
-
breakdownStr,
|
|
2301
|
-
"",
|
|
2302
|
-
prompts.howToCompressRules,
|
|
2303
|
-
"",
|
|
2304
|
-
rangesStr,
|
|
2305
|
-
"",
|
|
2306
|
-
`\u{1F4A1} Compress all ranges in one call (pass multiple content entries: \`content: [{...}, {...}]\`).`
|
|
2307
|
-
].join("\n")
|
|
2308
|
-
};
|
|
2309
|
-
}
|
|
2310
|
-
|
|
2311
1983
|
// src/decompress.ts
|
|
2312
1984
|
function parseBlockIdArg(arg) {
|
|
2313
1985
|
const normalized = arg.trim().toLowerCase();
|
|
@@ -3101,6 +2773,7 @@ export {
|
|
|
3101
2773
|
SUMMARY_HEADER,
|
|
3102
2774
|
TIER2_DISTILL_RULES,
|
|
3103
2775
|
TIER3_CONDENSE_RULES,
|
|
2776
|
+
VIABLE_RANGE_MIN_TOKENS,
|
|
3104
2777
|
activeBlocks,
|
|
3105
2778
|
advanceSurvival,
|
|
3106
2779
|
allocateBlockId,
|
|
@@ -3164,6 +2837,7 @@ export {
|
|
|
3164
2837
|
setDocCacheCap,
|
|
3165
2838
|
syncBlocks,
|
|
3166
2839
|
truncateLargeToolOutputs,
|
|
3167
|
-
validateConfig
|
|
2840
|
+
validateConfig,
|
|
2841
|
+
viableRanges
|
|
3168
2842
|
};
|
|
3169
2843
|
//# sourceMappingURL=index.js.map
|