@agimon-ai/doompi-autocompact 0.0.1-alpha.57 → 0.0.1-alpha.63

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.
Files changed (36) hide show
  1. package/README.md +36 -3
  2. package/dist/adapters/compaction/modelOverrides.cjs +2 -0
  3. package/dist/adapters/compaction/modelOverrides.cjs.map +1 -0
  4. package/dist/adapters/compaction/modelOverrides.mjs +2 -0
  5. package/dist/adapters/compaction/modelOverrides.mjs.map +1 -0
  6. package/dist/adapters/compaction/policy.cjs +3 -3
  7. package/dist/adapters/compaction/policy.cjs.map +1 -1
  8. package/dist/adapters/compaction/policy.d.cts +1 -2
  9. package/dist/adapters/compaction/policy.d.cts.map +1 -1
  10. package/dist/adapters/compaction/policy.d.mts +1 -2
  11. package/dist/adapters/compaction/policy.d.mts.map +1 -1
  12. package/dist/adapters/compaction/policy.mjs +3 -3
  13. package/dist/adapters/compaction/policy.mjs.map +1 -1
  14. package/dist/adapters/pi/extension.cjs +8 -8
  15. package/dist/adapters/pi/extension.cjs.map +1 -1
  16. package/dist/adapters/pi/extension.d.cts +4 -4
  17. package/dist/adapters/pi/extension.d.cts.map +1 -1
  18. package/dist/adapters/pi/extension.d.mts +4 -4
  19. package/dist/adapters/pi/extension.d.mts.map +1 -1
  20. package/dist/adapters/pi/extension.mjs +4 -4
  21. package/dist/adapters/pi/extension.mjs.map +1 -1
  22. package/dist/adapters/telemetry/logSinkTelemetry.d.cts +4 -5
  23. package/dist/adapters/telemetry/logSinkTelemetry.d.cts.map +1 -1
  24. package/dist/adapters/telemetry/logSinkTelemetry.d.mts +4 -5
  25. package/dist/adapters/telemetry/logSinkTelemetry.d.mts.map +1 -1
  26. package/dist/services/summarizationModel.d.cts +1 -2
  27. package/dist/services/summarizationModel.d.cts.map +1 -1
  28. package/dist/services/summarizationModel.d.mts +1 -2
  29. package/dist/services/summarizationModel.d.mts.map +1 -1
  30. package/dist/types/index.d.cts +2 -3
  31. package/dist/types/index.d.cts.map +1 -1
  32. package/dist/types/index.d.mts +2 -3
  33. package/dist/types/index.d.mts.map +1 -1
  34. package/package.json +12 -11
  35. package/src/web/index.ts +1 -1
  36. package/src/web/{autocompactSettings.ts → lib/autocompactSettings.ts} +1 -1
package/README.md CHANGED
@@ -36,9 +36,42 @@ subject to token caps and Pi's native-compaction clamp:
36
36
  2. combine it with later messages and allow the model to decide whether compaction is ready;
37
37
  3. combine again and force compaction on the final pass.
38
38
 
39
- Summarization runs asynchronously in the background, on the session's own provider, so a model
40
- registered by a Pi provider extension summarizes through that extension. Checkpoints are
41
- persisted as hidden session entries and used for later steering.
39
+ ## Per-model token checkpoints
40
+
41
+ Ratios scale with the window, which is usually what you want. On a very large window they can
42
+ also mean the first checkpoint waits far longer than you would like: half of a one-million-token
43
+ window is 500,000 tokens. `modes.autocompact.overrides` pins individual passes to an absolute
44
+ token count for the models you name, and leaves every other model on the ratio ladder.
45
+
46
+ ```yaml
47
+ modes:
48
+ autocompact:
49
+ overrides:
50
+ - model: 'claude-opus-4-[6-9]'
51
+ tokens:
52
+ pass1: 75000
53
+ pass2: 150000
54
+ pass3: 200000
55
+ ```
56
+
57
+ - Entries are tried in file order and the first match wins. A model matching nothing behaves
58
+ exactly as it does without this key.
59
+ - `model` is a glob supporting `*` and character classes such as `[6-9]`. A pattern containing
60
+ `/` is matched against `provider/id`, anything else against the bare model id, because the
61
+ wildcard does not cross the separator. Matching ignores case.
62
+ - The lower of the ratio and the token count wins, so an override can only bring a checkpoint
63
+ forward, never push one past the point Pi compacts natively.
64
+ - Counts are compared against total context usage, not against growth since the last compaction.
65
+ - A count at or below the current cycle's baseline is ignored and the pass falls back to its
66
+ ratio. Without that, a compaction landing above the count would satisfy the pass as soon as
67
+ the next cycle opened and re-fire it every turn.
68
+ - A pass never fires before the one before it. A list that puts a later pass lower is raised to
69
+ match, the same way a ratio below the previous pass is.
70
+ - A repository config replaces the global list whole rather than merging entry by entry.
71
+ - These keys are not on the cockpit settings page; edit `.doom/config.yaml` directly.
72
+ Summarization runs asynchronously in the background, on the session's own provider, so a model
73
+ registered by a Pi provider extension summarizes through that extension. Checkpoints are
74
+ persisted as hidden session entries and used for later steering.
42
75
 
43
76
  DoomPi uses the configured planning subagent model and thinking level when available, then falls
44
77
  back to the active Pi model. Standalone Pi without DoomPi planning configuration uses the active
@@ -0,0 +1,2 @@
1
+ let e=require("minimatch");function t(t,n){let r=t.includes(`/`)?`${n.provider}/${n.id}`:n.id;return(0,e.minimatch)(r,t,{nocase:!0})}function n(e,n){if(!e)return{};let r=n.find(n=>t(n.model,e));if(!r)return{};let{pass1:i,pass2:a,pass3:o}=r.tokens;return{...i===void 0?{}:{1:i},...a===void 0?{}:{2:a},...o===void 0?{}:{3:o}}}exports.resolveModelTokenOverrides=n;
2
+ //# sourceMappingURL=modelOverrides.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelOverrides.cjs","names":[],"sources":["../../../src/adapters/compaction/modelOverrides.ts"],"sourcesContent":["/**\n * Picks the absolute token checkpoints configured for the model a session is running.\n *\n * DESIGN PATTERNS:\n * - Pure decision function, so the matching rule is unit-testable without a session,\n * a config file or a filesystem\n * - First match in file order wins, so a reader resolves a model by reading down the\n * list rather than by working out which pattern is the most specific\n * - A model matching nothing returns no overrides at all, which leaves the ratio\n * ladder exactly as it behaves without this feature\n *\n * AVOID:\n * - Stripping a thinking suffix the way subagent model scope does. That matches\n * free-typed config strings; this matches a resolved `Model`, whose `id` carries\n * the level in a separate field and never in the id itself.\n * - Matching a bare pattern against `provider/id`. The glob wildcard does not cross\n * the separator, so the subject has to follow the pattern's own shape.\n */\n\nimport { minimatch } from 'minimatch';\nimport type { AutocompactOverrideConfig } from '@agimon-ai/doompi-config';\nimport type { AutocompactTokenOverrides } from '../../types/index.ts';\n\n/** The parts of a resolved model the rules match on. */\nexport interface AutocompactModelIdentity {\n id: string;\n provider: string;\n}\n\n/**\n * A pattern naming a provider is matched against `provider/id`, anything else\n * against the bare id. `*` does not cross `/`, so a bare pattern tested against a\n * qualified subject would never match and would read as a silently dead rule.\n */\nfunction matchesModelPattern(pattern: string, model: AutocompactModelIdentity): boolean {\n const subject = pattern.includes('/') ? `${model.provider}/${model.id}` : model.id;\n return minimatch(subject, pattern, { nocase: true });\n}\n\nexport function resolveModelTokenOverrides(\n model: AutocompactModelIdentity | undefined,\n overrides: readonly AutocompactOverrideConfig[],\n): AutocompactTokenOverrides {\n if (!model) return {};\n const matched = overrides.find((entry) => matchesModelPattern(entry.model, model));\n if (!matched) return {};\n const { pass1, pass2, pass3 } = matched.tokens;\n return {\n ...(pass1 === undefined ? {} : { 1: pass1 }),\n ...(pass2 === undefined ? {} : { 2: pass2 }),\n ...(pass3 === undefined ? {} : { 3: pass3 }),\n };\n}\n"],"mappings":"2BAkCA,SAAS,EAAoB,EAAiB,EAA0C,CACtF,IAAM,EAAU,EAAQ,SAAS,GAAG,EAAI,GAAG,EAAM,SAAS,GAAG,EAAM,KAAO,EAAM,GAChF,OAAA,EAAO,EAAA,UAAA,CAAU,EAAS,EAAS,CAAE,OAAQ,EAAK,CAAC,CACrD,CAEA,SAAgB,EACd,EACA,EAC2B,CAC3B,GAAI,CAAC,EAAO,MAAO,CAAC,EACpB,IAAM,EAAU,EAAU,KAAM,GAAU,EAAoB,EAAM,MAAO,CAAK,CAAC,EACjF,GAAI,CAAC,EAAS,MAAO,CAAC,EACtB,GAAM,CAAE,QAAO,QAAO,SAAU,EAAQ,OACxC,MAAO,CACL,GAAI,IAAU,IAAA,GAAY,CAAC,EAAI,CAAE,EAAG,CAAM,EAC1C,GAAI,IAAU,IAAA,GAAY,CAAC,EAAI,CAAE,EAAG,CAAM,EAC1C,GAAI,IAAU,IAAA,GAAY,CAAC,EAAI,CAAE,EAAG,CAAM,CAC5C,CACF"}
@@ -0,0 +1,2 @@
1
+ import{minimatch as e}from"minimatch";function t(t,n){let r=t.includes(`/`)?`${n.provider}/${n.id}`:n.id;return e(r,t,{nocase:!0})}function n(e,n){if(!e)return{};let r=n.find(n=>t(n.model,e));if(!r)return{};let{pass1:i,pass2:a,pass3:o}=r.tokens;return{...i===void 0?{}:{1:i},...a===void 0?{}:{2:a},...o===void 0?{}:{3:o}}}export{n as resolveModelTokenOverrides};
2
+ //# sourceMappingURL=modelOverrides.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelOverrides.mjs","names":[],"sources":["../../../src/adapters/compaction/modelOverrides.ts"],"sourcesContent":["/**\n * Picks the absolute token checkpoints configured for the model a session is running.\n *\n * DESIGN PATTERNS:\n * - Pure decision function, so the matching rule is unit-testable without a session,\n * a config file or a filesystem\n * - First match in file order wins, so a reader resolves a model by reading down the\n * list rather than by working out which pattern is the most specific\n * - A model matching nothing returns no overrides at all, which leaves the ratio\n * ladder exactly as it behaves without this feature\n *\n * AVOID:\n * - Stripping a thinking suffix the way subagent model scope does. That matches\n * free-typed config strings; this matches a resolved `Model`, whose `id` carries\n * the level in a separate field and never in the id itself.\n * - Matching a bare pattern against `provider/id`. The glob wildcard does not cross\n * the separator, so the subject has to follow the pattern's own shape.\n */\n\nimport { minimatch } from 'minimatch';\nimport type { AutocompactOverrideConfig } from '@agimon-ai/doompi-config';\nimport type { AutocompactTokenOverrides } from '../../types/index.ts';\n\n/** The parts of a resolved model the rules match on. */\nexport interface AutocompactModelIdentity {\n id: string;\n provider: string;\n}\n\n/**\n * A pattern naming a provider is matched against `provider/id`, anything else\n * against the bare id. `*` does not cross `/`, so a bare pattern tested against a\n * qualified subject would never match and would read as a silently dead rule.\n */\nfunction matchesModelPattern(pattern: string, model: AutocompactModelIdentity): boolean {\n const subject = pattern.includes('/') ? `${model.provider}/${model.id}` : model.id;\n return minimatch(subject, pattern, { nocase: true });\n}\n\nexport function resolveModelTokenOverrides(\n model: AutocompactModelIdentity | undefined,\n overrides: readonly AutocompactOverrideConfig[],\n): AutocompactTokenOverrides {\n if (!model) return {};\n const matched = overrides.find((entry) => matchesModelPattern(entry.model, model));\n if (!matched) return {};\n const { pass1, pass2, pass3 } = matched.tokens;\n return {\n ...(pass1 === undefined ? {} : { 1: pass1 }),\n ...(pass2 === undefined ? {} : { 2: pass2 }),\n ...(pass3 === undefined ? {} : { 3: pass3 }),\n };\n}\n"],"mappings":"sCAkCA,SAAS,EAAoB,EAAiB,EAA0C,CACtF,IAAM,EAAU,EAAQ,SAAS,GAAG,EAAI,GAAG,EAAM,SAAS,GAAG,EAAM,KAAO,EAAM,GAChF,OAAO,EAAU,EAAS,EAAS,CAAE,OAAQ,EAAK,CAAC,CACrD,CAEA,SAAgB,EACd,EACA,EAC2B,CAC3B,GAAI,CAAC,EAAO,MAAO,CAAC,EACpB,IAAM,EAAU,EAAU,KAAM,GAAU,EAAoB,EAAM,MAAO,CAAK,CAAC,EACjF,GAAI,CAAC,EAAS,MAAO,CAAC,EACtB,GAAM,CAAE,QAAO,QAAO,SAAU,EAAQ,OACxC,MAAO,CACL,GAAI,IAAU,IAAA,GAAY,CAAC,EAAI,CAAE,EAAG,CAAM,EAC1C,GAAI,IAAU,IAAA,GAAY,CAAC,EAAI,CAAE,EAAG,CAAM,EAC1C,GAAI,IAAU,IAAA,GAAY,CAAC,EAAI,CAAE,EAAG,CAAM,CAC5C,CACF"}
@@ -1,8 +1,8 @@
1
1
  const e=require("../../types/constants.cjs");let t=require("@earendil-works/pi-coding-agent");const n=/<shouldCompact>\s*(true|false)\s*<\/shouldCompact>/i,r=/\n*<(?:read-files|modified-files)>[\s\S]*?<\/(?:read-files|modified-files)>/g;function i(e){return typeof e==`object`&&!!e}function a(e){return Array.isArray(e)&&e.every(e=>typeof e==`string`)}function o(e){return e===1||e===2||e===3}function s(e){if(e.type===`message`&&e.message.role===`assistant`)return e.message.content.filter(e=>e.type===`text`).map(e=>e.text).join(`
2
- `).trim()||void 0}function c(e){return i(e)&&typeof e.role==`string`}function l(e){if(!i(e)||!a(e.readFiles)||!a(e.modifiedFiles)||!Array.isArray(e.retainedMessages)||!e.retainedMessages.every(c)||!i(e.doomAutocompact))return;let t=e.doomAutocompact;if(!(t.version!==2||t.pass!==2&&t.pass!==3||typeof t.cycle!=`number`||typeof t.requestId!=`string`||typeof t.snapshotLeafId!=`string`||typeof t.tokensBefore!=`number`))return{readFiles:[...e.readFiles],modifiedFiles:[...e.modifiedFiles],retainedMessages:[...e.retainedMessages],doomAutocompact:{version:2,cycle:t.cycle,pass:t.pass,requestId:t.requestId,snapshotLeafId:t.snapshotLeafId,tokensBefore:t.tokensBefore}}}function u(){return{version:2,cycle:1,pass:1,phase:`waiting`,checkpointQueue:[],exhaustedPasses:[],invalidAttempts:0,baselineTokens:0,baselinePending:!1,readFiles:[],modifiedFiles:[]}}function d(t={}){let n=0,r={};for(let i of[1,2,3]){let a=Math.max(t[i]??e.COMPACTION_THRESHOLDS[i].ratio,n);r[i]=a,n=a}return r}function f(n,r,i=0,a={}){let o=e.COMPACTION_THRESHOLDS[n],s=d(a)[n],c=Math.max(0,Math.min(i,r)),l=r-c,u=c+Math.min(Math.floor(l*s),o.capTokens),f=r-t.DEFAULT_COMPACTION_SETTINGS.reserveTokens;return f>c?Math.min(u,f):u}function p(e){return e.findLast(e=>e.type===`compaction`||e.type===`custom`&&e.customType===`doom-autocompact-checkpoint`||e.type===`custom_message`&&(e.customType===`doom-autocompact-checkpoint`||e.customType===`doom-autocompact-context`))}function m(e){let t=e.findLastIndex(e=>e.type===`compaction`||e.type===`custom_message`&&e.customType===`doom-autocompact-context`);return e.slice(t+1).some(e=>{if(e.type!==`message`||e.message.role!==`assistant`)return!1;let{stopReason:t,usage:n}=e.message;return t===`aborted`||t===`error`||!n?!1:(n.totalTokens||n.input+n.output+n.cacheRead+n.cacheWrite)>0})}function h(e,n){let r=e.findIndex(e=>e.id===n);return r===-1?[]:e.slice(r+1).filter(e=>e.type!==`custom_message`||e.customType!==`doom-autocompact-checkpoint`).flatMap(e=>(0,t.sessionEntryToContextMessages)(e))}function g(e,t){let n=t.findLastIndex(e=>e.type===`compaction`),r=t.slice(n+1).findLast(e=>e.type===`custom_message`&&e.customType===`doom-autocompact-context`);if(!r||r.type!==`custom_message`)return{messages:e,retainedMessageCount:0};let i=l(r.details),a=y(r);if(!i||!a)return{messages:e,invalidMarker:!0,retainedMessageCount:0};let o=e.findLastIndex(e=>e.role===`custom`&&e.customType===`doom-autocompact-context`&&l(e.details)?.doomAutocompact.requestId===i.doomAutocompact.requestId);return o===-1?{messages:e,invalidMarker:!0,retainedMessageCount:0}:{messages:[{role:`compactionSummary`,summary:a,tokensBefore:i.doomAutocompact.tokensBefore,timestamp:e[o]?.timestamp??Date.now()},...i.retainedMessages,...e.slice(o+1)],marker:i.doomAutocompact,retainedMessageCount:i.retainedMessages.length}}function _(e){let t={read:new Set,written:new Set,edited:new Set};for(let n of e)if(n.role===`assistant`)for(let e of n.content){if(e.type!==`toolCall`)continue;let n=typeof e.arguments.path==`string`?e.arguments.path:void 0;n&&(e.name===`read`?t.read.add(n):e.name===`write`?t.written.add(n):e.name===`edit`&&t.edited.add(n))}return t}function v(e){if(!i(e)||e.version!==2||typeof e.cycle!=`number`||!o(e.pass)||e.phase!==`waiting`&&e.phase!==`checkpoint_pending`&&e.phase!==`checkpoint_ready`&&e.phase!==`compacting`)return;let t=e.baselineTokens??0;if(typeof t!=`number`||t<0)return;let n=e.baselinePending??!1;if(typeof n!=`boolean`)return;let r=e.checkpointQueue??[];if(!Array.isArray(r)||!r.every(o)||r.some((e,t)=>t>0&&e<=r[t-1]))return;let s=e.exhaustedPasses??[];if(!Array.isArray(s)||!s.every(o))return;let c=e.invalidAttempts??0;if(!(typeof c!=`number`||c<0)&&!(!a(e.readFiles)||!a(e.modifiedFiles))&&(e.requestId===void 0||typeof e.requestId==`string`)&&(e.compactionPass===void 0||e.compactionPass===2||e.compactionPass===3)&&!(`latestCheckpointEntryId`in e)&&(e.latestCheckpointSnapshotLeafId===void 0||typeof e.latestCheckpointSnapshotLeafId==`string`)&&(e.lastAttemptLeafId===void 0||typeof e.lastAttemptLeafId==`string`)&&(e.snapshotLeafId===void 0||typeof e.snapshotLeafId==`string`)&&!(e.snapshotTokens!==void 0&&(typeof e.snapshotTokens!=`number`||e.snapshotTokens<0))&&(e.pendingCheckpoint===void 0||typeof e.pendingCheckpoint==`string`))return{version:2,cycle:e.cycle,pass:e.pass,phase:e.phase,checkpointQueue:[...r],exhaustedPasses:[...s],invalidAttempts:c,baselineTokens:t,baselinePending:n,readFiles:[...e.readFiles],modifiedFiles:[...e.modifiedFiles],...e.requestId?{requestId:e.requestId}:{},...e.compactionPass?{compactionPass:e.compactionPass}:{},...e.latestCheckpointSnapshotLeafId?{latestCheckpointSnapshotLeafId:e.latestCheckpointSnapshotLeafId}:{},...e.lastAttemptLeafId?{lastAttemptLeafId:e.lastAttemptLeafId}:{},...e.snapshotLeafId?{snapshotLeafId:e.snapshotLeafId}:{},...e.snapshotTokens===void 0?{}:{snapshotTokens:e.snapshotTokens},...e.pendingCheckpoint?{pendingCheckpoint:e.pendingCheckpoint}:{}}}function y(e){if(e)return e.type===`compaction`?e.summary.trim()||void 0:e.type===`custom`?i(e.data)&&typeof e.data.summary==`string`&&e.data.summary.trim()||void 0:e.type===`custom_message`?(typeof e.content==`string`?e.content:e.content.filter(e=>e.type===`text`).map(e=>e.text).join(`
3
- `)).trim()||void 0:s(e)}function b(e){let t=e.match(n),r=e.replace(n,``).trim();return t?{summary:r,shouldCompact:t[1]?.toLowerCase()===`true`}:{summary:r}}function x(t){return e.CHECKPOINT_HEADINGS.every(e=>t.includes(e))}function S(e,t,n,r){return`${e}:${t}:${n}:${r??`root`}`}function C(e,t,n){return{version:2,cycle:e,pass:t,requestId:n}}function w(e,t,n){let r=new Set([...e.modifiedFiles,...n?.modifiedFiles??[],...t?[...t.edited,...t.written]:[]]),i=new Set([...e.readFiles,...n?.readFiles??[],...t?[...t.read]:[]]);for(let e of r)i.delete(e);return{readFiles:[...i].sort(),modifiedFiles:[...r].sort()}}function T(e){if(!(!i(e)||!a(e.readFiles)||!a(e.modifiedFiles)))return{readFiles:e.readFiles,modifiedFiles:e.modifiedFiles}}function E(e,t){let n=[];t.readFiles.length>0&&n.push(`<read-files>\n${t.readFiles.join(`
2
+ `).trim()||void 0}function c(e){return i(e)&&typeof e.role==`string`}function l(e){if(!i(e)||!a(e.readFiles)||!a(e.modifiedFiles)||!Array.isArray(e.retainedMessages)||!e.retainedMessages.every(c)||!i(e.doomAutocompact))return;let t=e.doomAutocompact;if(!(t.version!==2||t.pass!==2&&t.pass!==3||typeof t.cycle!=`number`||typeof t.requestId!=`string`||typeof t.snapshotLeafId!=`string`||typeof t.tokensBefore!=`number`))return{readFiles:[...e.readFiles],modifiedFiles:[...e.modifiedFiles],retainedMessages:[...e.retainedMessages],doomAutocompact:{version:2,cycle:t.cycle,pass:t.pass,requestId:t.requestId,snapshotLeafId:t.snapshotLeafId,tokensBefore:t.tokensBefore}}}function u(){return{version:2,cycle:1,pass:1,phase:`waiting`,checkpointQueue:[],exhaustedPasses:[],invalidAttempts:0,baselineTokens:0,baselinePending:!1,readFiles:[],modifiedFiles:[]}}function d(t={}){let n=0,r={};for(let i of[1,2,3]){let a=Math.max(t[i]??e.COMPACTION_THRESHOLDS[i].ratio,n);r[i]=a,n=a}return r}function f(n,r,i=0,a={}){let o=e.COMPACTION_THRESHOLDS[n],s=d(a)[n],c=Math.max(0,Math.min(i,r)),l=r-c,u=c+Math.min(Math.floor(l*s),o.capTokens),f=r-t.DEFAULT_COMPACTION_SETTINGS.reserveTokens;return f>c?Math.min(u,f):u}function p(e,t=0,n={},r={}){let i=0,a={};for(let o of[1,2,3]){let s=f(o,e,t,n),c=r[o];a[o]=Math.max(c!==void 0&&c>t?Math.min(s,c):s,i),i=a[o]}return a}function m(e){return e.findLast(e=>e.type===`compaction`||e.type===`custom`&&e.customType===`doom-autocompact-checkpoint`||e.type===`custom_message`&&(e.customType===`doom-autocompact-checkpoint`||e.customType===`doom-autocompact-context`))}function h(e){let t=e.findLastIndex(e=>e.type===`compaction`||e.type===`custom_message`&&e.customType===`doom-autocompact-context`);return e.slice(t+1).some(e=>{if(e.type!==`message`||e.message.role!==`assistant`)return!1;let{stopReason:t,usage:n}=e.message;return t===`aborted`||t===`error`||!n?!1:(n.totalTokens||n.input+n.output+n.cacheRead+n.cacheWrite)>0})}function g(e,n){let r=e.findIndex(e=>e.id===n);return r===-1?[]:e.slice(r+1).filter(e=>e.type!==`custom_message`||e.customType!==`doom-autocompact-checkpoint`).flatMap(e=>(0,t.sessionEntryToContextMessages)(e))}function _(e,t){let n=t.findLastIndex(e=>e.type===`compaction`),r=t.slice(n+1).findLast(e=>e.type===`custom_message`&&e.customType===`doom-autocompact-context`);if(!r||r.type!==`custom_message`)return{messages:e,retainedMessageCount:0};let i=l(r.details),a=b(r);if(!i||!a)return{messages:e,invalidMarker:!0,retainedMessageCount:0};let o=e.findLastIndex(e=>e.role===`custom`&&e.customType===`doom-autocompact-context`&&l(e.details)?.doomAutocompact.requestId===i.doomAutocompact.requestId);return o===-1?{messages:e,invalidMarker:!0,retainedMessageCount:0}:{messages:[{role:`compactionSummary`,summary:a,tokensBefore:i.doomAutocompact.tokensBefore,timestamp:e[o]?.timestamp??Date.now()},...i.retainedMessages,...e.slice(o+1)],marker:i.doomAutocompact,retainedMessageCount:i.retainedMessages.length}}function v(e){let t={read:new Set,written:new Set,edited:new Set};for(let n of e)if(n.role===`assistant`)for(let e of n.content){if(e.type!==`toolCall`)continue;let n=typeof e.arguments.path==`string`?e.arguments.path:void 0;n&&(e.name===`read`?t.read.add(n):e.name===`write`?t.written.add(n):e.name===`edit`&&t.edited.add(n))}return t}function y(e){if(!i(e)||e.version!==2||typeof e.cycle!=`number`||!o(e.pass)||e.phase!==`waiting`&&e.phase!==`checkpoint_pending`&&e.phase!==`checkpoint_ready`&&e.phase!==`compacting`)return;let t=e.baselineTokens??0;if(typeof t!=`number`||t<0)return;let n=e.baselinePending??!1;if(typeof n!=`boolean`)return;let r=e.checkpointQueue??[];if(!Array.isArray(r)||!r.every(o)||r.some((e,t)=>t>0&&e<=r[t-1]))return;let s=e.exhaustedPasses??[];if(!Array.isArray(s)||!s.every(o))return;let c=e.invalidAttempts??0;if(!(typeof c!=`number`||c<0)&&a(e.readFiles)&&a(e.modifiedFiles)&&(e.requestId===void 0||typeof e.requestId==`string`)&&(e.compactionPass===void 0||e.compactionPass===2||e.compactionPass===3)&&!(`latestCheckpointEntryId`in e)&&(e.latestCheckpointSnapshotLeafId===void 0||typeof e.latestCheckpointSnapshotLeafId==`string`)&&(e.lastAttemptLeafId===void 0||typeof e.lastAttemptLeafId==`string`)&&(e.snapshotLeafId===void 0||typeof e.snapshotLeafId==`string`)&&!(e.snapshotTokens!==void 0&&(typeof e.snapshotTokens!=`number`||e.snapshotTokens<0))&&(e.pendingCheckpoint===void 0||typeof e.pendingCheckpoint==`string`))return{version:2,cycle:e.cycle,pass:e.pass,phase:e.phase,checkpointQueue:[...r],exhaustedPasses:[...s],invalidAttempts:c,baselineTokens:t,baselinePending:n,readFiles:[...e.readFiles],modifiedFiles:[...e.modifiedFiles],...e.requestId?{requestId:e.requestId}:{},...e.compactionPass?{compactionPass:e.compactionPass}:{},...e.latestCheckpointSnapshotLeafId?{latestCheckpointSnapshotLeafId:e.latestCheckpointSnapshotLeafId}:{},...e.lastAttemptLeafId?{lastAttemptLeafId:e.lastAttemptLeafId}:{},...e.snapshotLeafId?{snapshotLeafId:e.snapshotLeafId}:{},...e.snapshotTokens===void 0?{}:{snapshotTokens:e.snapshotTokens},...e.pendingCheckpoint?{pendingCheckpoint:e.pendingCheckpoint}:{}}}function b(e){if(e)return e.type===`compaction`?e.summary.trim()||void 0:e.type===`custom`?i(e.data)&&typeof e.data.summary==`string`&&e.data.summary.trim()||void 0:e.type===`custom_message`?(typeof e.content==`string`?e.content:e.content.filter(e=>e.type===`text`).map(e=>e.text).join(`
3
+ `)).trim()||void 0:s(e)}function x(e){let t=e.match(n),r=e.replace(n,``).trim();return t?{summary:r,shouldCompact:t[1]?.toLowerCase()===`true`}:{summary:r}}function S(t){return e.CHECKPOINT_HEADINGS.every(e=>t.includes(e))}function C(e,t,n,r){return`${e}:${t}:${n}:${r??`root`}`}function w(e,t,n){return{version:2,cycle:e,pass:t,requestId:n}}function T(e,t,n){let r=new Set([...e.modifiedFiles,...n?.modifiedFiles??[],...t?[...t.edited,...t.written]:[]]),i=new Set([...e.readFiles,...n?.readFiles??[],...t?[...t.read]:[]]);for(let e of r)i.delete(e);return{readFiles:[...i].sort(),modifiedFiles:[...r].sort()}}function E(e){if(i(e)&&a(e.readFiles)&&a(e.modifiedFiles))return{readFiles:e.readFiles,modifiedFiles:e.modifiedFiles}}function D(e,t){let n=[];t.readFiles.length>0&&n.push(`<read-files>\n${t.readFiles.join(`
4
4
  `)}\n</read-files>`),t.modifiedFiles.length>0&&n.push(`<modified-files>\n${t.modifiedFiles.join(`
5
5
  `)}\n</modified-files>`);let i=e.replace(r,``).trim();return n.length>0?`${i}\n\n${n.join(`
6
6
 
7
- `)}`:i}exports.baselineUsageIsSettled=m,exports.checkpointRequestDetails=C,exports.checkpointSummaryFromEntry=y,exports.compactionRatios=d,exports.contextDetailsFromUnknown=l,exports.createInitialState=u,exports.createRequestId=S,exports.fileDetailsFromUnknown=T,exports.fileOperationsFromMessages=_,exports.isStructuredCheckpoint=x,exports.latestCheckpointArtifactEntry=p,exports.mergeFileDetails=w,exports.parseCheckpointDecision=b,exports.parseState=v,exports.projectContextMessages=g,exports.retainedMessagesAfterSnapshot=h,exports.thresholdTokens=f,exports.withCanonicalFileSections=E;
7
+ `)}`:i}exports.baselineUsageIsSettled=h,exports.checkpointRequestDetails=w,exports.checkpointSummaryFromEntry=b,exports.compactionRatios=d,exports.contextDetailsFromUnknown=l,exports.createInitialState=u,exports.createRequestId=C,exports.effectiveThresholds=p,exports.fileDetailsFromUnknown=E,exports.fileOperationsFromMessages=v,exports.isStructuredCheckpoint=S,exports.latestCheckpointArtifactEntry=m,exports.mergeFileDetails=T,exports.parseCheckpointDecision=x,exports.parseState=y,exports.projectContextMessages=_,exports.retainedMessagesAfterSnapshot=g,exports.thresholdTokens=f,exports.withCanonicalFileSections=D;
8
8
  //# sourceMappingURL=policy.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"policy.cjs","names":["COMPACTION_THRESHOLDS","DEFAULT_COMPACTION_SETTINGS","sessionEntryToContextMessages","CHECKPOINT_HEADINGS"],"sources":["../../../src/adapters/compaction/policy.ts"],"sourcesContent":["import {\n DEFAULT_COMPACTION_SETTINGS,\n type FileOperations,\n type SessionEntry,\n sessionEntryToContextMessages,\n} from '@earendil-works/pi-coding-agent';\nimport {\n CHECKPOINT_HEADINGS,\n CHECKPOINT_MESSAGE_TYPE,\n COMPACTION_THRESHOLDS,\n CONTEXT_MESSAGE_TYPE,\n STATE_VERSION,\n} from '../../types/constants.ts';\nimport type {\n AutocompactContextDetails,\n AutocompactFileDetails,\n AutocompactRatioOverrides,\n AutocompactMessage,\n AutocompactPass,\n AutocompactState,\n CheckpointDecision,\n CheckpointRequestDetails,\n ContextProjection,\n} from '../../types/index.ts';\n\nconst SHOULD_COMPACT_PATTERN = /<shouldCompact>\\s*(true|false)\\s*<\\/shouldCompact>/i;\nconst FILE_SECTION_PATTERN = /\\n*<(?:read-files|modified-files)>[\\s\\S]*?<\\/(?:read-files|modified-files)>/g;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === 'string');\n}\n\nfunction isPass(value: unknown): value is AutocompactPass {\n return value === 1 || value === 2 || value === 3;\n}\n\nfunction assistantText(entry: SessionEntry): string | undefined {\n if (entry.type !== 'message' || entry.message.role !== 'assistant') return undefined;\n const text = entry.message.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('\\n')\n .trim();\n return text || undefined;\n}\n\nfunction isAutocompactMessage(value: unknown): value is AutocompactMessage {\n return isRecord(value) && typeof value.role === 'string';\n}\n\nexport function contextDetailsFromUnknown(value: unknown): AutocompactContextDetails | undefined {\n if (!isRecord(value) || !isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n if (!Array.isArray(value.retainedMessages) || !value.retainedMessages.every(isAutocompactMessage)) return undefined;\n if (!isRecord(value.doomAutocompact)) return undefined;\n const marker = value.doomAutocompact;\n if (\n marker.version !== STATE_VERSION ||\n (marker.pass !== 2 && marker.pass !== 3) ||\n typeof marker.cycle !== 'number' ||\n typeof marker.requestId !== 'string' ||\n typeof marker.snapshotLeafId !== 'string' ||\n typeof marker.tokensBefore !== 'number'\n )\n return undefined;\n return {\n readFiles: [...value.readFiles],\n modifiedFiles: [...value.modifiedFiles],\n retainedMessages: [...value.retainedMessages],\n doomAutocompact: {\n version: STATE_VERSION,\n cycle: marker.cycle,\n pass: marker.pass,\n requestId: marker.requestId,\n snapshotLeafId: marker.snapshotLeafId,\n tokensBefore: marker.tokensBefore,\n },\n };\n}\n\nexport function createInitialState(): AutocompactState {\n return {\n version: STATE_VERSION,\n cycle: 1,\n pass: 1,\n phase: 'waiting',\n checkpointQueue: [],\n exhaustedPasses: [],\n invalidAttempts: 0,\n baselineTokens: 0,\n baselinePending: false,\n readFiles: [],\n modifiedFiles: [],\n };\n}\n\n/**\n * The ratios each pass fires at, with configured values folded in.\n *\n * The ladder only works if it climbs, so a configured pass never sits below the\n * one before it: a file that says pass 2 fires earlier than pass 1 gets pass 1's\n * ratio for pass 2 rather than a pass that can never contribute.\n */\nexport function compactionRatios(configured: AutocompactRatioOverrides = {}): Record<AutocompactPass, number> {\n let previous = 0;\n const ratios = {} as Record<AutocompactPass, number>;\n for (const pass of [1, 2, 3] as const) {\n const ratio = Math.max(configured[pass] ?? COMPACTION_THRESHOLDS[pass].ratio, previous);\n ratios[pass] = ratio;\n previous = ratio;\n }\n return ratios;\n}\n\nexport function thresholdTokens(\n pass: AutocompactPass,\n contextWindow: number,\n baselineTokens = 0,\n configured: AutocompactRatioOverrides = {},\n): number {\n const threshold = COMPACTION_THRESHOLDS[pass];\n const ratio = compactionRatios(configured)[pass];\n const baseline = Math.max(0, Math.min(baselineTokens, contextWindow));\n const remaining = contextWindow - baseline;\n const staged = baseline + Math.min(Math.floor(remaining * ratio), threshold.capTokens);\n // Pi compacts natively above `contextWindow - reserveTokens`. A staged threshold above that\n // point can never fire, so the ladder would silently degrade into native compaction: on a\n // 200k window the raw pass 3 ratio lands at 190_000, while Pi already compacted at 183_616.\n const nativeTrigger = contextWindow - DEFAULT_COMPACTION_SETTINGS.reserveTokens;\n return nativeTrigger > baseline ? Math.min(staged, nativeTrigger) : staged;\n}\n\nexport function latestCheckpointArtifactEntry(branchEntries: SessionEntry[]): SessionEntry | undefined {\n return branchEntries.findLast(\n (entry) =>\n entry.type === 'compaction' ||\n // Staged checkpoints are plain entries so they stay out of the agent's LLM context.\n (entry.type === 'custom' && entry.customType === CHECKPOINT_MESSAGE_TYPE) ||\n // Legacy sessions staged checkpoints as custom messages; committed markers still are.\n (entry.type === 'custom_message' &&\n (entry.customType === CHECKPOINT_MESSAGE_TYPE || entry.customType === CONTEXT_MESSAGE_TYPE)),\n );\n}\n\nexport function baselineUsageIsSettled(branchEntries: SessionEntry[]): boolean {\n const boundaryIndex = branchEntries.findLastIndex(\n (entry) =>\n entry.type === 'compaction' || (entry.type === 'custom_message' && entry.customType === CONTEXT_MESSAGE_TYPE),\n );\n return branchEntries.slice(boundaryIndex + 1).some((entry) => {\n if (entry.type !== 'message' || entry.message.role !== 'assistant') return false;\n const { stopReason, usage } = entry.message;\n if (stopReason === 'aborted' || stopReason === 'error' || !usage) return false;\n return (usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite) > 0;\n });\n}\n\nexport function retainedMessagesAfterSnapshot(\n branchEntries: SessionEntry[],\n snapshotLeafId: string,\n): AutocompactMessage[] {\n const snapshotIndex = branchEntries.findIndex((entry) => entry.id === snapshotLeafId);\n if (snapshotIndex === -1) return [];\n return branchEntries\n .slice(snapshotIndex + 1)\n .filter((entry) => entry.type !== 'custom_message' || entry.customType !== CHECKPOINT_MESSAGE_TYPE)\n .flatMap((entry) => sessionEntryToContextMessages(entry));\n}\n\nexport function projectContextMessages(\n messages: AutocompactMessage[],\n branchEntries: SessionEntry[],\n): ContextProjection {\n const nativeCompactionIndex = branchEntries.findLastIndex((entry) => entry.type === 'compaction');\n const markerEntry = branchEntries\n .slice(nativeCompactionIndex + 1)\n .findLast((entry) => entry.type === 'custom_message' && entry.customType === CONTEXT_MESSAGE_TYPE);\n if (!markerEntry || markerEntry.type !== 'custom_message') {\n return { messages, retainedMessageCount: 0 };\n }\n\n const details = contextDetailsFromUnknown(markerEntry.details);\n const summary = checkpointSummaryFromEntry(markerEntry);\n if (!details || !summary) return { messages, invalidMarker: true, retainedMessageCount: 0 };\n\n const markerMessageIndex = messages.findLastIndex(\n (message) =>\n message.role === 'custom' &&\n message.customType === CONTEXT_MESSAGE_TYPE &&\n contextDetailsFromUnknown(message.details)?.doomAutocompact.requestId === details.doomAutocompact.requestId,\n );\n if (markerMessageIndex === -1) return { messages, invalidMarker: true, retainedMessageCount: 0 };\n\n const summaryMessage: AutocompactMessage = {\n role: 'compactionSummary',\n summary,\n tokensBefore: details.doomAutocompact.tokensBefore,\n timestamp: messages[markerMessageIndex]?.timestamp ?? Date.now(),\n };\n return {\n messages: [summaryMessage, ...details.retainedMessages, ...messages.slice(markerMessageIndex + 1)],\n marker: details.doomAutocompact,\n retainedMessageCount: details.retainedMessages.length,\n };\n}\n\nexport function fileOperationsFromMessages(messages: AutocompactMessage[]): FileOperations {\n const fileOps: FileOperations = { read: new Set(), written: new Set(), edited: new Set() };\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const block of message.content) {\n if (block.type !== 'toolCall') continue;\n const path = typeof block.arguments.path === 'string' ? block.arguments.path : undefined;\n if (!path) continue;\n if (block.name === 'read') fileOps.read.add(path);\n else if (block.name === 'write') fileOps.written.add(path);\n else if (block.name === 'edit') fileOps.edited.add(path);\n }\n }\n return fileOps;\n}\n\nexport function parseState(value: unknown): AutocompactState | undefined {\n if (!isRecord(value)) return undefined;\n if (value.version !== STATE_VERSION || typeof value.cycle !== 'number' || !isPass(value.pass)) return undefined;\n if (\n value.phase !== 'waiting' &&\n value.phase !== 'checkpoint_pending' &&\n value.phase !== 'checkpoint_ready' &&\n value.phase !== 'compacting'\n )\n return undefined;\n const baselineTokens = value.baselineTokens ?? 0;\n if (typeof baselineTokens !== 'number' || baselineTokens < 0) return undefined;\n const baselinePending = value.baselinePending ?? false;\n if (typeof baselinePending !== 'boolean') return undefined;\n const checkpointQueue = value.checkpointQueue ?? [];\n if (\n !Array.isArray(checkpointQueue) ||\n !checkpointQueue.every(isPass) ||\n checkpointQueue.some((pass, index) => index > 0 && pass <= checkpointQueue[index - 1]!)\n )\n return undefined;\n // Sessions persisted before bounded retry landed simply have no attempt history to restore.\n const exhaustedPasses = value.exhaustedPasses ?? [];\n if (!Array.isArray(exhaustedPasses) || !exhaustedPasses.every(isPass)) return undefined;\n const invalidAttempts = value.invalidAttempts ?? 0;\n if (typeof invalidAttempts !== 'number' || invalidAttempts < 0) return undefined;\n if (!isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n if (value.requestId !== undefined && typeof value.requestId !== 'string') return undefined;\n if (value.compactionPass !== undefined && value.compactionPass !== 2 && value.compactionPass !== 3) return undefined;\n if ('latestCheckpointEntryId' in value) return undefined;\n if (value.latestCheckpointSnapshotLeafId !== undefined && typeof value.latestCheckpointSnapshotLeafId !== 'string')\n return undefined;\n if (value.lastAttemptLeafId !== undefined && typeof value.lastAttemptLeafId !== 'string') return undefined;\n if (value.snapshotLeafId !== undefined && typeof value.snapshotLeafId !== 'string') return undefined;\n if (value.snapshotTokens !== undefined && (typeof value.snapshotTokens !== 'number' || value.snapshotTokens < 0))\n return undefined;\n if (value.pendingCheckpoint !== undefined && typeof value.pendingCheckpoint !== 'string') return undefined;\n\n return {\n version: STATE_VERSION,\n cycle: value.cycle,\n pass: value.pass,\n phase: value.phase,\n checkpointQueue: [...checkpointQueue],\n exhaustedPasses: [...exhaustedPasses],\n invalidAttempts,\n baselineTokens,\n baselinePending,\n readFiles: [...value.readFiles],\n modifiedFiles: [...value.modifiedFiles],\n ...(value.requestId ? { requestId: value.requestId } : {}),\n ...(value.compactionPass ? { compactionPass: value.compactionPass } : {}),\n ...(value.latestCheckpointSnapshotLeafId\n ? { latestCheckpointSnapshotLeafId: value.latestCheckpointSnapshotLeafId }\n : {}),\n ...(value.lastAttemptLeafId ? { lastAttemptLeafId: value.lastAttemptLeafId } : {}),\n ...(value.snapshotLeafId ? { snapshotLeafId: value.snapshotLeafId } : {}),\n ...(value.snapshotTokens !== undefined ? { snapshotTokens: value.snapshotTokens } : {}),\n ...(value.pendingCheckpoint ? { pendingCheckpoint: value.pendingCheckpoint } : {}),\n };\n}\n\nexport function checkpointSummaryFromEntry(entry: SessionEntry | undefined): string | undefined {\n if (!entry) return undefined;\n if (entry.type === 'compaction') return entry.summary.trim() || undefined;\n if (entry.type === 'custom') {\n return isRecord(entry.data) && typeof entry.data.summary === 'string'\n ? entry.data.summary.trim() || undefined\n : undefined;\n }\n if (entry.type === 'custom_message') {\n const content =\n typeof entry.content === 'string'\n ? entry.content\n : entry.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('\\n');\n return content.trim() || undefined;\n }\n return assistantText(entry);\n}\n\nexport function parseCheckpointDecision(response: string): CheckpointDecision {\n const match = response.match(SHOULD_COMPACT_PATTERN);\n const summary = response.replace(SHOULD_COMPACT_PATTERN, '').trim();\n if (!match) return { summary };\n return { summary, shouldCompact: match[1]?.toLowerCase() === 'true' };\n}\n\nexport function isStructuredCheckpoint(summary: string): boolean {\n return CHECKPOINT_HEADINGS.every((heading) => summary.includes(heading));\n}\n\nexport function createRequestId(\n sessionId: string,\n cycle: number,\n pass: AutocompactPass,\n leafId: string | null,\n): string {\n return `${sessionId}:${cycle}:${pass}:${leafId ?? 'root'}`;\n}\n\nexport function checkpointRequestDetails(\n cycle: number,\n pass: AutocompactPass,\n requestId: string,\n): CheckpointRequestDetails {\n return { version: STATE_VERSION, cycle, pass, requestId };\n}\n\nexport function mergeFileDetails(\n current: AutocompactFileDetails,\n fileOps?: FileOperations,\n additional?: AutocompactFileDetails,\n): AutocompactFileDetails {\n const modified = new Set([\n ...current.modifiedFiles,\n ...(additional?.modifiedFiles ?? []),\n ...(fileOps ? [...fileOps.edited, ...fileOps.written] : []),\n ]);\n const read = new Set([...current.readFiles, ...(additional?.readFiles ?? []), ...(fileOps ? [...fileOps.read] : [])]);\n for (const path of modified) read.delete(path);\n return { readFiles: [...read].sort(), modifiedFiles: [...modified].sort() };\n}\n\nexport function fileDetailsFromUnknown(value: unknown): AutocompactFileDetails | undefined {\n if (!isRecord(value) || !isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n return { readFiles: value.readFiles, modifiedFiles: value.modifiedFiles };\n}\n\nexport function withCanonicalFileSections(summary: string, details: AutocompactFileDetails): string {\n const sections: string[] = [];\n if (details.readFiles.length > 0) sections.push(`<read-files>\\n${details.readFiles.join('\\n')}\\n</read-files>`);\n if (details.modifiedFiles.length > 0) {\n sections.push(`<modified-files>\\n${details.modifiedFiles.join('\\n')}\\n</modified-files>`);\n }\n const normalized = summary.replace(FILE_SECTION_PATTERN, '').trim();\n return sections.length > 0 ? `${normalized}\\n\\n${sections.join('\\n\\n')}` : normalized;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"policy.cjs","names":["COMPACTION_THRESHOLDS","DEFAULT_COMPACTION_SETTINGS","sessionEntryToContextMessages","CHECKPOINT_HEADINGS"],"sources":["../../../src/adapters/compaction/policy.ts"],"sourcesContent":["import {\n DEFAULT_COMPACTION_SETTINGS,\n type FileOperations,\n type SessionEntry,\n sessionEntryToContextMessages,\n} from '@earendil-works/pi-coding-agent';\nimport {\n CHECKPOINT_HEADINGS,\n CHECKPOINT_MESSAGE_TYPE,\n COMPACTION_THRESHOLDS,\n CONTEXT_MESSAGE_TYPE,\n STATE_VERSION,\n} from '../../types/constants.ts';\nimport type {\n AutocompactContextDetails,\n AutocompactFileDetails,\n AutocompactRatioOverrides,\n AutocompactTokenOverrides,\n AutocompactMessage,\n AutocompactPass,\n AutocompactState,\n CheckpointDecision,\n CheckpointRequestDetails,\n ContextProjection,\n} from '../../types/index.ts';\n\nconst SHOULD_COMPACT_PATTERN = /<shouldCompact>\\s*(true|false)\\s*<\\/shouldCompact>/i;\nconst FILE_SECTION_PATTERN = /\\n*<(?:read-files|modified-files)>[\\s\\S]*?<\\/(?:read-files|modified-files)>/g;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === 'string');\n}\n\nfunction isPass(value: unknown): value is AutocompactPass {\n return value === 1 || value === 2 || value === 3;\n}\n\nfunction assistantText(entry: SessionEntry): string | undefined {\n if (entry.type !== 'message' || entry.message.role !== 'assistant') return undefined;\n const text = entry.message.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('\\n')\n .trim();\n return text || undefined;\n}\n\nfunction isAutocompactMessage(value: unknown): value is AutocompactMessage {\n return isRecord(value) && typeof value.role === 'string';\n}\n\nexport function contextDetailsFromUnknown(value: unknown): AutocompactContextDetails | undefined {\n if (!isRecord(value) || !isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n if (!Array.isArray(value.retainedMessages) || !value.retainedMessages.every(isAutocompactMessage)) return undefined;\n if (!isRecord(value.doomAutocompact)) return undefined;\n const marker = value.doomAutocompact;\n if (\n marker.version !== STATE_VERSION ||\n (marker.pass !== 2 && marker.pass !== 3) ||\n typeof marker.cycle !== 'number' ||\n typeof marker.requestId !== 'string' ||\n typeof marker.snapshotLeafId !== 'string' ||\n typeof marker.tokensBefore !== 'number'\n )\n return undefined;\n return {\n readFiles: [...value.readFiles],\n modifiedFiles: [...value.modifiedFiles],\n retainedMessages: [...value.retainedMessages],\n doomAutocompact: {\n version: STATE_VERSION,\n cycle: marker.cycle,\n pass: marker.pass,\n requestId: marker.requestId,\n snapshotLeafId: marker.snapshotLeafId,\n tokensBefore: marker.tokensBefore,\n },\n };\n}\n\nexport function createInitialState(): AutocompactState {\n return {\n version: STATE_VERSION,\n cycle: 1,\n pass: 1,\n phase: 'waiting',\n checkpointQueue: [],\n exhaustedPasses: [],\n invalidAttempts: 0,\n baselineTokens: 0,\n baselinePending: false,\n readFiles: [],\n modifiedFiles: [],\n };\n}\n\n/**\n * The ratios each pass fires at, with configured values folded in.\n *\n * The ladder only works if it climbs, so a configured pass never sits below the\n * one before it: a file that says pass 2 fires earlier than pass 1 gets pass 1's\n * ratio for pass 2 rather than a pass that can never contribute.\n */\nexport function compactionRatios(configured: AutocompactRatioOverrides = {}): Record<AutocompactPass, number> {\n let previous = 0;\n const ratios = {} as Record<AutocompactPass, number>;\n for (const pass of [1, 2, 3] as const) {\n const ratio = Math.max(configured[pass] ?? COMPACTION_THRESHOLDS[pass].ratio, previous);\n ratios[pass] = ratio;\n previous = ratio;\n }\n return ratios;\n}\n\nexport function thresholdTokens(\n pass: AutocompactPass,\n contextWindow: number,\n baselineTokens = 0,\n configured: AutocompactRatioOverrides = {},\n): number {\n const threshold = COMPACTION_THRESHOLDS[pass];\n const ratio = compactionRatios(configured)[pass];\n const baseline = Math.max(0, Math.min(baselineTokens, contextWindow));\n const remaining = contextWindow - baseline;\n const staged = baseline + Math.min(Math.floor(remaining * ratio), threshold.capTokens);\n // Pi compacts natively above `contextWindow - reserveTokens`. A staged threshold above that\n // point can never fire, so the ladder would silently degrade into native compaction: on a\n // 200k window the raw pass 3 ratio lands at 190_000, while Pi already compacted at 183_616.\n const nativeTrigger = contextWindow - DEFAULT_COMPACTION_SETTINGS.reserveTokens;\n return nativeTrigger > baseline ? Math.min(staged, nativeTrigger) : staged;\n}\n\n/**\n * Where every pass fires, with a matching model's absolute token checkpoints folded in.\n *\n * A configured token count replaces the ratio only when it fires earlier, so an\n * override can bring a checkpoint forward on a very large window without ever\n * pushing one past the point Pi compacts natively.\n *\n * Two rules keep the ladder usable. A token count at or below the baseline is\n * ignored, because a compaction that lands above it would otherwise satisfy that\n * pass the moment the next cycle opens and re-fire it every turn. And a pass never\n * sits below the one before it, for the same reason {@link compactionRatios}\n * climbs: `evaluateUsage` skips any pass below the one already reached, so a later\n * pass that fires first does not merely reorder the ladder, it locks the earlier\n * passes out of the cycle and forces compaction with no summary ever written.\n */\nexport function effectiveThresholds(\n contextWindow: number,\n baselineTokens = 0,\n configured: AutocompactRatioOverrides = {},\n tokenOverrides: AutocompactTokenOverrides = {},\n): Record<AutocompactPass, number> {\n let previous = 0;\n const thresholds = {} as Record<AutocompactPass, number>;\n for (const pass of [1, 2, 3] as const) {\n const ratioTokens = thresholdTokens(pass, contextWindow, baselineTokens, configured);\n const absolute = tokenOverrides[pass];\n const staged = absolute !== undefined && absolute > baselineTokens ? Math.min(ratioTokens, absolute) : ratioTokens;\n thresholds[pass] = Math.max(staged, previous);\n previous = thresholds[pass];\n }\n return thresholds;\n}\nexport function latestCheckpointArtifactEntry(branchEntries: SessionEntry[]): SessionEntry | undefined {\n return branchEntries.findLast(\n (entry) =>\n entry.type === 'compaction' ||\n // Staged checkpoints are plain entries so they stay out of the agent's LLM context.\n (entry.type === 'custom' && entry.customType === CHECKPOINT_MESSAGE_TYPE) ||\n // Legacy sessions staged checkpoints as custom messages; committed markers still are.\n (entry.type === 'custom_message' &&\n (entry.customType === CHECKPOINT_MESSAGE_TYPE || entry.customType === CONTEXT_MESSAGE_TYPE)),\n );\n}\n\nexport function baselineUsageIsSettled(branchEntries: SessionEntry[]): boolean {\n const boundaryIndex = branchEntries.findLastIndex(\n (entry) =>\n entry.type === 'compaction' || (entry.type === 'custom_message' && entry.customType === CONTEXT_MESSAGE_TYPE),\n );\n return branchEntries.slice(boundaryIndex + 1).some((entry) => {\n if (entry.type !== 'message' || entry.message.role !== 'assistant') return false;\n const { stopReason, usage } = entry.message;\n if (stopReason === 'aborted' || stopReason === 'error' || !usage) return false;\n return (usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite) > 0;\n });\n}\n\nexport function retainedMessagesAfterSnapshot(\n branchEntries: SessionEntry[],\n snapshotLeafId: string,\n): AutocompactMessage[] {\n const snapshotIndex = branchEntries.findIndex((entry) => entry.id === snapshotLeafId);\n if (snapshotIndex === -1) return [];\n return branchEntries\n .slice(snapshotIndex + 1)\n .filter((entry) => entry.type !== 'custom_message' || entry.customType !== CHECKPOINT_MESSAGE_TYPE)\n .flatMap((entry) => sessionEntryToContextMessages(entry));\n}\n\nexport function projectContextMessages(\n messages: AutocompactMessage[],\n branchEntries: SessionEntry[],\n): ContextProjection {\n const nativeCompactionIndex = branchEntries.findLastIndex((entry) => entry.type === 'compaction');\n const markerEntry = branchEntries\n .slice(nativeCompactionIndex + 1)\n .findLast((entry) => entry.type === 'custom_message' && entry.customType === CONTEXT_MESSAGE_TYPE);\n if (!markerEntry || markerEntry.type !== 'custom_message') {\n return { messages, retainedMessageCount: 0 };\n }\n\n const details = contextDetailsFromUnknown(markerEntry.details);\n const summary = checkpointSummaryFromEntry(markerEntry);\n if (!details || !summary) return { messages, invalidMarker: true, retainedMessageCount: 0 };\n\n const markerMessageIndex = messages.findLastIndex(\n (message) =>\n message.role === 'custom' &&\n message.customType === CONTEXT_MESSAGE_TYPE &&\n contextDetailsFromUnknown(message.details)?.doomAutocompact.requestId === details.doomAutocompact.requestId,\n );\n if (markerMessageIndex === -1) return { messages, invalidMarker: true, retainedMessageCount: 0 };\n\n const summaryMessage: AutocompactMessage = {\n role: 'compactionSummary',\n summary,\n tokensBefore: details.doomAutocompact.tokensBefore,\n timestamp: messages[markerMessageIndex]?.timestamp ?? Date.now(),\n };\n return {\n messages: [summaryMessage, ...details.retainedMessages, ...messages.slice(markerMessageIndex + 1)],\n marker: details.doomAutocompact,\n retainedMessageCount: details.retainedMessages.length,\n };\n}\n\nexport function fileOperationsFromMessages(messages: AutocompactMessage[]): FileOperations {\n const fileOps: FileOperations = { read: new Set(), written: new Set(), edited: new Set() };\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const block of message.content) {\n if (block.type !== 'toolCall') continue;\n const path = typeof block.arguments.path === 'string' ? block.arguments.path : undefined;\n if (!path) continue;\n if (block.name === 'read') fileOps.read.add(path);\n else if (block.name === 'write') fileOps.written.add(path);\n else if (block.name === 'edit') fileOps.edited.add(path);\n }\n }\n return fileOps;\n}\n\nexport function parseState(value: unknown): AutocompactState | undefined {\n if (!isRecord(value)) return undefined;\n if (value.version !== STATE_VERSION || typeof value.cycle !== 'number' || !isPass(value.pass)) return undefined;\n if (\n value.phase !== 'waiting' &&\n value.phase !== 'checkpoint_pending' &&\n value.phase !== 'checkpoint_ready' &&\n value.phase !== 'compacting'\n )\n return undefined;\n const baselineTokens = value.baselineTokens ?? 0;\n if (typeof baselineTokens !== 'number' || baselineTokens < 0) return undefined;\n const baselinePending = value.baselinePending ?? false;\n if (typeof baselinePending !== 'boolean') return undefined;\n const checkpointQueue = value.checkpointQueue ?? [];\n if (\n !Array.isArray(checkpointQueue) ||\n !checkpointQueue.every(isPass) ||\n checkpointQueue.some((pass, index) => index > 0 && pass <= checkpointQueue[index - 1]!)\n )\n return undefined;\n // Sessions persisted before bounded retry landed simply have no attempt history to restore.\n const exhaustedPasses = value.exhaustedPasses ?? [];\n if (!Array.isArray(exhaustedPasses) || !exhaustedPasses.every(isPass)) return undefined;\n const invalidAttempts = value.invalidAttempts ?? 0;\n if (typeof invalidAttempts !== 'number' || invalidAttempts < 0) return undefined;\n if (!isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n if (value.requestId !== undefined && typeof value.requestId !== 'string') return undefined;\n if (value.compactionPass !== undefined && value.compactionPass !== 2 && value.compactionPass !== 3) return undefined;\n if ('latestCheckpointEntryId' in value) return undefined;\n if (value.latestCheckpointSnapshotLeafId !== undefined && typeof value.latestCheckpointSnapshotLeafId !== 'string')\n return undefined;\n if (value.lastAttemptLeafId !== undefined && typeof value.lastAttemptLeafId !== 'string') return undefined;\n if (value.snapshotLeafId !== undefined && typeof value.snapshotLeafId !== 'string') return undefined;\n if (value.snapshotTokens !== undefined && (typeof value.snapshotTokens !== 'number' || value.snapshotTokens < 0))\n return undefined;\n if (value.pendingCheckpoint !== undefined && typeof value.pendingCheckpoint !== 'string') return undefined;\n\n return {\n version: STATE_VERSION,\n cycle: value.cycle,\n pass: value.pass,\n phase: value.phase,\n checkpointQueue: [...checkpointQueue],\n exhaustedPasses: [...exhaustedPasses],\n invalidAttempts,\n baselineTokens,\n baselinePending,\n readFiles: [...value.readFiles],\n modifiedFiles: [...value.modifiedFiles],\n ...(value.requestId ? { requestId: value.requestId } : {}),\n ...(value.compactionPass ? { compactionPass: value.compactionPass } : {}),\n ...(value.latestCheckpointSnapshotLeafId\n ? { latestCheckpointSnapshotLeafId: value.latestCheckpointSnapshotLeafId }\n : {}),\n ...(value.lastAttemptLeafId ? { lastAttemptLeafId: value.lastAttemptLeafId } : {}),\n ...(value.snapshotLeafId ? { snapshotLeafId: value.snapshotLeafId } : {}),\n ...(value.snapshotTokens !== undefined ? { snapshotTokens: value.snapshotTokens } : {}),\n ...(value.pendingCheckpoint ? { pendingCheckpoint: value.pendingCheckpoint } : {}),\n };\n}\n\nexport function checkpointSummaryFromEntry(entry: SessionEntry | undefined): string | undefined {\n if (!entry) return undefined;\n if (entry.type === 'compaction') return entry.summary.trim() || undefined;\n if (entry.type === 'custom') {\n return isRecord(entry.data) && typeof entry.data.summary === 'string'\n ? entry.data.summary.trim() || undefined\n : undefined;\n }\n if (entry.type === 'custom_message') {\n const content =\n typeof entry.content === 'string'\n ? entry.content\n : entry.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('\\n');\n return content.trim() || undefined;\n }\n return assistantText(entry);\n}\n\nexport function parseCheckpointDecision(response: string): CheckpointDecision {\n const match = response.match(SHOULD_COMPACT_PATTERN);\n const summary = response.replace(SHOULD_COMPACT_PATTERN, '').trim();\n if (!match) return { summary };\n return { summary, shouldCompact: match[1]?.toLowerCase() === 'true' };\n}\n\nexport function isStructuredCheckpoint(summary: string): boolean {\n return CHECKPOINT_HEADINGS.every((heading) => summary.includes(heading));\n}\n\nexport function createRequestId(\n sessionId: string,\n cycle: number,\n pass: AutocompactPass,\n leafId: string | null,\n): string {\n return `${sessionId}:${cycle}:${pass}:${leafId ?? 'root'}`;\n}\n\nexport function checkpointRequestDetails(\n cycle: number,\n pass: AutocompactPass,\n requestId: string,\n): CheckpointRequestDetails {\n return { version: STATE_VERSION, cycle, pass, requestId };\n}\n\nexport function mergeFileDetails(\n current: AutocompactFileDetails,\n fileOps?: FileOperations,\n additional?: AutocompactFileDetails,\n): AutocompactFileDetails {\n const modified = new Set([\n ...current.modifiedFiles,\n ...(additional?.modifiedFiles ?? []),\n ...(fileOps ? [...fileOps.edited, ...fileOps.written] : []),\n ]);\n const read = new Set([...current.readFiles, ...(additional?.readFiles ?? []), ...(fileOps ? [...fileOps.read] : [])]);\n for (const path of modified) read.delete(path);\n return { readFiles: [...read].sort(), modifiedFiles: [...modified].sort() };\n}\n\nexport function fileDetailsFromUnknown(value: unknown): AutocompactFileDetails | undefined {\n if (!isRecord(value) || !isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n return { readFiles: value.readFiles, modifiedFiles: value.modifiedFiles };\n}\n\nexport function withCanonicalFileSections(summary: string, details: AutocompactFileDetails): string {\n const sections: string[] = [];\n if (details.readFiles.length > 0) sections.push(`<read-files>\\n${details.readFiles.join('\\n')}\\n</read-files>`);\n if (details.modifiedFiles.length > 0) {\n sections.push(`<modified-files>\\n${details.modifiedFiles.join('\\n')}\\n</modified-files>`);\n }\n const normalized = summary.replace(FILE_SECTION_PATTERN, '').trim();\n return sections.length > 0 ? `${normalized}\\n\\n${sections.join('\\n\\n')}` : normalized;\n}\n"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  import { AutocompactPass, AutocompactRatioOverrides } from "../../types/index.cjs";
2
2
  import "@earendil-works/pi-coding-agent";
3
3
  //#region src/adapters/compaction/policy.d.ts
4
- declare function thresholdTokens(pass: AutocompactPass, contextWindow: number, baselineTokens?: number, configured?: AutocompactRatioOverrides): number;
4
+ export declare function thresholdTokens(pass: AutocompactPass, contextWindow: number, baselineTokens?: number, configured?: AutocompactRatioOverrides): number;
5
5
  //#endregion
6
- export { thresholdTokens };
7
6
  //# sourceMappingURL=policy.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"policy.d.cts","names":[],"sources":["../../../src/adapters/compaction/policy.ts"],"mappings":";;;iBAqHgB,gBACd,MAAM,iBACN,uBACA,yBACA,aAAY"}
1
+ {"version":3,"file":"policy.d.cts","names":[],"sources":["../../../src/adapters/compaction/policy.ts"],"mappings":";;;wBAsHgB,gBACd,MAAM,iBACN,uBACA,yBACA,aAAY"}
@@ -1,7 +1,6 @@
1
1
  import { AutocompactPass, AutocompactRatioOverrides } from "../../types/index.mjs";
2
2
  import "@earendil-works/pi-coding-agent";
3
3
  //#region src/adapters/compaction/policy.d.ts
4
- declare function thresholdTokens(pass: AutocompactPass, contextWindow: number, baselineTokens?: number, configured?: AutocompactRatioOverrides): number;
4
+ export declare function thresholdTokens(pass: AutocompactPass, contextWindow: number, baselineTokens?: number, configured?: AutocompactRatioOverrides): number;
5
5
  //#endregion
6
- export { thresholdTokens };
7
6
  //# sourceMappingURL=policy.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"policy.d.mts","names":[],"sources":["../../../src/adapters/compaction/policy.ts"],"mappings":";;;iBAqHgB,gBACd,MAAM,iBACN,uBACA,yBACA,aAAY"}
1
+ {"version":3,"file":"policy.d.mts","names":[],"sources":["../../../src/adapters/compaction/policy.ts"],"mappings":";;;wBAsHgB,gBACd,MAAM,iBACN,uBACA,yBACA,aAAY"}
@@ -1,8 +1,8 @@
1
1
  import{CHECKPOINT_HEADINGS as e,COMPACTION_THRESHOLDS as t}from"../../types/constants.mjs";import{DEFAULT_COMPACTION_SETTINGS as n,sessionEntryToContextMessages as r}from"@earendil-works/pi-coding-agent";const i=/<shouldCompact>\s*(true|false)\s*<\/shouldCompact>/i,a=/\n*<(?:read-files|modified-files)>[\s\S]*?<\/(?:read-files|modified-files)>/g;function o(e){return typeof e==`object`&&!!e}function s(e){return Array.isArray(e)&&e.every(e=>typeof e==`string`)}function c(e){return e===1||e===2||e===3}function l(e){if(e.type===`message`&&e.message.role===`assistant`)return e.message.content.filter(e=>e.type===`text`).map(e=>e.text).join(`
2
- `).trim()||void 0}function u(e){return o(e)&&typeof e.role==`string`}function d(e){if(!o(e)||!s(e.readFiles)||!s(e.modifiedFiles)||!Array.isArray(e.retainedMessages)||!e.retainedMessages.every(u)||!o(e.doomAutocompact))return;let t=e.doomAutocompact;if(!(t.version!==2||t.pass!==2&&t.pass!==3||typeof t.cycle!=`number`||typeof t.requestId!=`string`||typeof t.snapshotLeafId!=`string`||typeof t.tokensBefore!=`number`))return{readFiles:[...e.readFiles],modifiedFiles:[...e.modifiedFiles],retainedMessages:[...e.retainedMessages],doomAutocompact:{version:2,cycle:t.cycle,pass:t.pass,requestId:t.requestId,snapshotLeafId:t.snapshotLeafId,tokensBefore:t.tokensBefore}}}function f(){return{version:2,cycle:1,pass:1,phase:`waiting`,checkpointQueue:[],exhaustedPasses:[],invalidAttempts:0,baselineTokens:0,baselinePending:!1,readFiles:[],modifiedFiles:[]}}function p(e={}){let n=0,r={};for(let i of[1,2,3]){let a=Math.max(e[i]??t[i].ratio,n);r[i]=a,n=a}return r}function m(e,r,i=0,a={}){let o=t[e],s=p(a)[e],c=Math.max(0,Math.min(i,r)),l=r-c,u=c+Math.min(Math.floor(l*s),o.capTokens),d=r-n.reserveTokens;return d>c?Math.min(u,d):u}function h(e){return e.findLast(e=>e.type===`compaction`||e.type===`custom`&&e.customType===`doom-autocompact-checkpoint`||e.type===`custom_message`&&(e.customType===`doom-autocompact-checkpoint`||e.customType===`doom-autocompact-context`))}function g(e){let t=e.findLastIndex(e=>e.type===`compaction`||e.type===`custom_message`&&e.customType===`doom-autocompact-context`);return e.slice(t+1).some(e=>{if(e.type!==`message`||e.message.role!==`assistant`)return!1;let{stopReason:t,usage:n}=e.message;return t===`aborted`||t===`error`||!n?!1:(n.totalTokens||n.input+n.output+n.cacheRead+n.cacheWrite)>0})}function _(e,t){let n=e.findIndex(e=>e.id===t);return n===-1?[]:e.slice(n+1).filter(e=>e.type!==`custom_message`||e.customType!==`doom-autocompact-checkpoint`).flatMap(e=>r(e))}function v(e,t){let n=t.findLastIndex(e=>e.type===`compaction`),r=t.slice(n+1).findLast(e=>e.type===`custom_message`&&e.customType===`doom-autocompact-context`);if(!r||r.type!==`custom_message`)return{messages:e,retainedMessageCount:0};let i=d(r.details),a=x(r);if(!i||!a)return{messages:e,invalidMarker:!0,retainedMessageCount:0};let o=e.findLastIndex(e=>e.role===`custom`&&e.customType===`doom-autocompact-context`&&d(e.details)?.doomAutocompact.requestId===i.doomAutocompact.requestId);return o===-1?{messages:e,invalidMarker:!0,retainedMessageCount:0}:{messages:[{role:`compactionSummary`,summary:a,tokensBefore:i.doomAutocompact.tokensBefore,timestamp:e[o]?.timestamp??Date.now()},...i.retainedMessages,...e.slice(o+1)],marker:i.doomAutocompact,retainedMessageCount:i.retainedMessages.length}}function y(e){let t={read:new Set,written:new Set,edited:new Set};for(let n of e)if(n.role===`assistant`)for(let e of n.content){if(e.type!==`toolCall`)continue;let n=typeof e.arguments.path==`string`?e.arguments.path:void 0;n&&(e.name===`read`?t.read.add(n):e.name===`write`?t.written.add(n):e.name===`edit`&&t.edited.add(n))}return t}function b(e){if(!o(e)||e.version!==2||typeof e.cycle!=`number`||!c(e.pass)||e.phase!==`waiting`&&e.phase!==`checkpoint_pending`&&e.phase!==`checkpoint_ready`&&e.phase!==`compacting`)return;let t=e.baselineTokens??0;if(typeof t!=`number`||t<0)return;let n=e.baselinePending??!1;if(typeof n!=`boolean`)return;let r=e.checkpointQueue??[];if(!Array.isArray(r)||!r.every(c)||r.some((e,t)=>t>0&&e<=r[t-1]))return;let i=e.exhaustedPasses??[];if(!Array.isArray(i)||!i.every(c))return;let a=e.invalidAttempts??0;if(!(typeof a!=`number`||a<0)&&!(!s(e.readFiles)||!s(e.modifiedFiles))&&(e.requestId===void 0||typeof e.requestId==`string`)&&(e.compactionPass===void 0||e.compactionPass===2||e.compactionPass===3)&&!(`latestCheckpointEntryId`in e)&&(e.latestCheckpointSnapshotLeafId===void 0||typeof e.latestCheckpointSnapshotLeafId==`string`)&&(e.lastAttemptLeafId===void 0||typeof e.lastAttemptLeafId==`string`)&&(e.snapshotLeafId===void 0||typeof e.snapshotLeafId==`string`)&&!(e.snapshotTokens!==void 0&&(typeof e.snapshotTokens!=`number`||e.snapshotTokens<0))&&(e.pendingCheckpoint===void 0||typeof e.pendingCheckpoint==`string`))return{version:2,cycle:e.cycle,pass:e.pass,phase:e.phase,checkpointQueue:[...r],exhaustedPasses:[...i],invalidAttempts:a,baselineTokens:t,baselinePending:n,readFiles:[...e.readFiles],modifiedFiles:[...e.modifiedFiles],...e.requestId?{requestId:e.requestId}:{},...e.compactionPass?{compactionPass:e.compactionPass}:{},...e.latestCheckpointSnapshotLeafId?{latestCheckpointSnapshotLeafId:e.latestCheckpointSnapshotLeafId}:{},...e.lastAttemptLeafId?{lastAttemptLeafId:e.lastAttemptLeafId}:{},...e.snapshotLeafId?{snapshotLeafId:e.snapshotLeafId}:{},...e.snapshotTokens===void 0?{}:{snapshotTokens:e.snapshotTokens},...e.pendingCheckpoint?{pendingCheckpoint:e.pendingCheckpoint}:{}}}function x(e){if(e)return e.type===`compaction`?e.summary.trim()||void 0:e.type===`custom`?o(e.data)&&typeof e.data.summary==`string`&&e.data.summary.trim()||void 0:e.type===`custom_message`?(typeof e.content==`string`?e.content:e.content.filter(e=>e.type===`text`).map(e=>e.text).join(`
3
- `)).trim()||void 0:l(e)}function S(e){let t=e.match(i),n=e.replace(i,``).trim();return t?{summary:n,shouldCompact:t[1]?.toLowerCase()===`true`}:{summary:n}}function C(t){return e.every(e=>t.includes(e))}function w(e,t,n,r){return`${e}:${t}:${n}:${r??`root`}`}function T(e,t,n){return{version:2,cycle:e,pass:t,requestId:n}}function E(e,t,n){let r=new Set([...e.modifiedFiles,...n?.modifiedFiles??[],...t?[...t.edited,...t.written]:[]]),i=new Set([...e.readFiles,...n?.readFiles??[],...t?[...t.read]:[]]);for(let e of r)i.delete(e);return{readFiles:[...i].sort(),modifiedFiles:[...r].sort()}}function D(e){if(!(!o(e)||!s(e.readFiles)||!s(e.modifiedFiles)))return{readFiles:e.readFiles,modifiedFiles:e.modifiedFiles}}function O(e,t){let n=[];t.readFiles.length>0&&n.push(`<read-files>\n${t.readFiles.join(`
2
+ `).trim()||void 0}function u(e){return o(e)&&typeof e.role==`string`}function d(e){if(!o(e)||!s(e.readFiles)||!s(e.modifiedFiles)||!Array.isArray(e.retainedMessages)||!e.retainedMessages.every(u)||!o(e.doomAutocompact))return;let t=e.doomAutocompact;if(!(t.version!==2||t.pass!==2&&t.pass!==3||typeof t.cycle!=`number`||typeof t.requestId!=`string`||typeof t.snapshotLeafId!=`string`||typeof t.tokensBefore!=`number`))return{readFiles:[...e.readFiles],modifiedFiles:[...e.modifiedFiles],retainedMessages:[...e.retainedMessages],doomAutocompact:{version:2,cycle:t.cycle,pass:t.pass,requestId:t.requestId,snapshotLeafId:t.snapshotLeafId,tokensBefore:t.tokensBefore}}}function f(){return{version:2,cycle:1,pass:1,phase:`waiting`,checkpointQueue:[],exhaustedPasses:[],invalidAttempts:0,baselineTokens:0,baselinePending:!1,readFiles:[],modifiedFiles:[]}}function p(e={}){let n=0,r={};for(let i of[1,2,3]){let a=Math.max(e[i]??t[i].ratio,n);r[i]=a,n=a}return r}function m(e,r,i=0,a={}){let o=t[e],s=p(a)[e],c=Math.max(0,Math.min(i,r)),l=r-c,u=c+Math.min(Math.floor(l*s),o.capTokens),d=r-n.reserveTokens;return d>c?Math.min(u,d):u}function h(e,t=0,n={},r={}){let i=0,a={};for(let o of[1,2,3]){let s=m(o,e,t,n),c=r[o];a[o]=Math.max(c!==void 0&&c>t?Math.min(s,c):s,i),i=a[o]}return a}function g(e){return e.findLast(e=>e.type===`compaction`||e.type===`custom`&&e.customType===`doom-autocompact-checkpoint`||e.type===`custom_message`&&(e.customType===`doom-autocompact-checkpoint`||e.customType===`doom-autocompact-context`))}function _(e){let t=e.findLastIndex(e=>e.type===`compaction`||e.type===`custom_message`&&e.customType===`doom-autocompact-context`);return e.slice(t+1).some(e=>{if(e.type!==`message`||e.message.role!==`assistant`)return!1;let{stopReason:t,usage:n}=e.message;return t===`aborted`||t===`error`||!n?!1:(n.totalTokens||n.input+n.output+n.cacheRead+n.cacheWrite)>0})}function v(e,t){let n=e.findIndex(e=>e.id===t);return n===-1?[]:e.slice(n+1).filter(e=>e.type!==`custom_message`||e.customType!==`doom-autocompact-checkpoint`).flatMap(e=>r(e))}function y(e,t){let n=t.findLastIndex(e=>e.type===`compaction`),r=t.slice(n+1).findLast(e=>e.type===`custom_message`&&e.customType===`doom-autocompact-context`);if(!r||r.type!==`custom_message`)return{messages:e,retainedMessageCount:0};let i=d(r.details),a=S(r);if(!i||!a)return{messages:e,invalidMarker:!0,retainedMessageCount:0};let o=e.findLastIndex(e=>e.role===`custom`&&e.customType===`doom-autocompact-context`&&d(e.details)?.doomAutocompact.requestId===i.doomAutocompact.requestId);return o===-1?{messages:e,invalidMarker:!0,retainedMessageCount:0}:{messages:[{role:`compactionSummary`,summary:a,tokensBefore:i.doomAutocompact.tokensBefore,timestamp:e[o]?.timestamp??Date.now()},...i.retainedMessages,...e.slice(o+1)],marker:i.doomAutocompact,retainedMessageCount:i.retainedMessages.length}}function b(e){let t={read:new Set,written:new Set,edited:new Set};for(let n of e)if(n.role===`assistant`)for(let e of n.content){if(e.type!==`toolCall`)continue;let n=typeof e.arguments.path==`string`?e.arguments.path:void 0;n&&(e.name===`read`?t.read.add(n):e.name===`write`?t.written.add(n):e.name===`edit`&&t.edited.add(n))}return t}function x(e){if(!o(e)||e.version!==2||typeof e.cycle!=`number`||!c(e.pass)||e.phase!==`waiting`&&e.phase!==`checkpoint_pending`&&e.phase!==`checkpoint_ready`&&e.phase!==`compacting`)return;let t=e.baselineTokens??0;if(typeof t!=`number`||t<0)return;let n=e.baselinePending??!1;if(typeof n!=`boolean`)return;let r=e.checkpointQueue??[];if(!Array.isArray(r)||!r.every(c)||r.some((e,t)=>t>0&&e<=r[t-1]))return;let i=e.exhaustedPasses??[];if(!Array.isArray(i)||!i.every(c))return;let a=e.invalidAttempts??0;if(!(typeof a!=`number`||a<0)&&s(e.readFiles)&&s(e.modifiedFiles)&&(e.requestId===void 0||typeof e.requestId==`string`)&&(e.compactionPass===void 0||e.compactionPass===2||e.compactionPass===3)&&!(`latestCheckpointEntryId`in e)&&(e.latestCheckpointSnapshotLeafId===void 0||typeof e.latestCheckpointSnapshotLeafId==`string`)&&(e.lastAttemptLeafId===void 0||typeof e.lastAttemptLeafId==`string`)&&(e.snapshotLeafId===void 0||typeof e.snapshotLeafId==`string`)&&!(e.snapshotTokens!==void 0&&(typeof e.snapshotTokens!=`number`||e.snapshotTokens<0))&&(e.pendingCheckpoint===void 0||typeof e.pendingCheckpoint==`string`))return{version:2,cycle:e.cycle,pass:e.pass,phase:e.phase,checkpointQueue:[...r],exhaustedPasses:[...i],invalidAttempts:a,baselineTokens:t,baselinePending:n,readFiles:[...e.readFiles],modifiedFiles:[...e.modifiedFiles],...e.requestId?{requestId:e.requestId}:{},...e.compactionPass?{compactionPass:e.compactionPass}:{},...e.latestCheckpointSnapshotLeafId?{latestCheckpointSnapshotLeafId:e.latestCheckpointSnapshotLeafId}:{},...e.lastAttemptLeafId?{lastAttemptLeafId:e.lastAttemptLeafId}:{},...e.snapshotLeafId?{snapshotLeafId:e.snapshotLeafId}:{},...e.snapshotTokens===void 0?{}:{snapshotTokens:e.snapshotTokens},...e.pendingCheckpoint?{pendingCheckpoint:e.pendingCheckpoint}:{}}}function S(e){if(e)return e.type===`compaction`?e.summary.trim()||void 0:e.type===`custom`?o(e.data)&&typeof e.data.summary==`string`&&e.data.summary.trim()||void 0:e.type===`custom_message`?(typeof e.content==`string`?e.content:e.content.filter(e=>e.type===`text`).map(e=>e.text).join(`
3
+ `)).trim()||void 0:l(e)}function C(e){let t=e.match(i),n=e.replace(i,``).trim();return t?{summary:n,shouldCompact:t[1]?.toLowerCase()===`true`}:{summary:n}}function w(t){return e.every(e=>t.includes(e))}function T(e,t,n,r){return`${e}:${t}:${n}:${r??`root`}`}function E(e,t,n){return{version:2,cycle:e,pass:t,requestId:n}}function D(e,t,n){let r=new Set([...e.modifiedFiles,...n?.modifiedFiles??[],...t?[...t.edited,...t.written]:[]]),i=new Set([...e.readFiles,...n?.readFiles??[],...t?[...t.read]:[]]);for(let e of r)i.delete(e);return{readFiles:[...i].sort(),modifiedFiles:[...r].sort()}}function O(e){if(o(e)&&s(e.readFiles)&&s(e.modifiedFiles))return{readFiles:e.readFiles,modifiedFiles:e.modifiedFiles}}function k(e,t){let n=[];t.readFiles.length>0&&n.push(`<read-files>\n${t.readFiles.join(`
4
4
  `)}\n</read-files>`),t.modifiedFiles.length>0&&n.push(`<modified-files>\n${t.modifiedFiles.join(`
5
5
  `)}\n</modified-files>`);let r=e.replace(a,``).trim();return n.length>0?`${r}\n\n${n.join(`
6
6
 
7
- `)}`:r}export{g as baselineUsageIsSettled,T as checkpointRequestDetails,x as checkpointSummaryFromEntry,p as compactionRatios,d as contextDetailsFromUnknown,f as createInitialState,w as createRequestId,D as fileDetailsFromUnknown,y as fileOperationsFromMessages,C as isStructuredCheckpoint,h as latestCheckpointArtifactEntry,E as mergeFileDetails,S as parseCheckpointDecision,b as parseState,v as projectContextMessages,_ as retainedMessagesAfterSnapshot,m as thresholdTokens,O as withCanonicalFileSections};
7
+ `)}`:r}export{_ as baselineUsageIsSettled,E as checkpointRequestDetails,S as checkpointSummaryFromEntry,p as compactionRatios,d as contextDetailsFromUnknown,f as createInitialState,T as createRequestId,h as effectiveThresholds,O as fileDetailsFromUnknown,b as fileOperationsFromMessages,w as isStructuredCheckpoint,g as latestCheckpointArtifactEntry,D as mergeFileDetails,C as parseCheckpointDecision,x as parseState,y as projectContextMessages,v as retainedMessagesAfterSnapshot,m as thresholdTokens,k as withCanonicalFileSections};
8
8
  //# sourceMappingURL=policy.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"policy.mjs","names":[],"sources":["../../../src/adapters/compaction/policy.ts"],"sourcesContent":["import {\n DEFAULT_COMPACTION_SETTINGS,\n type FileOperations,\n type SessionEntry,\n sessionEntryToContextMessages,\n} from '@earendil-works/pi-coding-agent';\nimport {\n CHECKPOINT_HEADINGS,\n CHECKPOINT_MESSAGE_TYPE,\n COMPACTION_THRESHOLDS,\n CONTEXT_MESSAGE_TYPE,\n STATE_VERSION,\n} from '../../types/constants.ts';\nimport type {\n AutocompactContextDetails,\n AutocompactFileDetails,\n AutocompactRatioOverrides,\n AutocompactMessage,\n AutocompactPass,\n AutocompactState,\n CheckpointDecision,\n CheckpointRequestDetails,\n ContextProjection,\n} from '../../types/index.ts';\n\nconst SHOULD_COMPACT_PATTERN = /<shouldCompact>\\s*(true|false)\\s*<\\/shouldCompact>/i;\nconst FILE_SECTION_PATTERN = /\\n*<(?:read-files|modified-files)>[\\s\\S]*?<\\/(?:read-files|modified-files)>/g;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === 'string');\n}\n\nfunction isPass(value: unknown): value is AutocompactPass {\n return value === 1 || value === 2 || value === 3;\n}\n\nfunction assistantText(entry: SessionEntry): string | undefined {\n if (entry.type !== 'message' || entry.message.role !== 'assistant') return undefined;\n const text = entry.message.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('\\n')\n .trim();\n return text || undefined;\n}\n\nfunction isAutocompactMessage(value: unknown): value is AutocompactMessage {\n return isRecord(value) && typeof value.role === 'string';\n}\n\nexport function contextDetailsFromUnknown(value: unknown): AutocompactContextDetails | undefined {\n if (!isRecord(value) || !isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n if (!Array.isArray(value.retainedMessages) || !value.retainedMessages.every(isAutocompactMessage)) return undefined;\n if (!isRecord(value.doomAutocompact)) return undefined;\n const marker = value.doomAutocompact;\n if (\n marker.version !== STATE_VERSION ||\n (marker.pass !== 2 && marker.pass !== 3) ||\n typeof marker.cycle !== 'number' ||\n typeof marker.requestId !== 'string' ||\n typeof marker.snapshotLeafId !== 'string' ||\n typeof marker.tokensBefore !== 'number'\n )\n return undefined;\n return {\n readFiles: [...value.readFiles],\n modifiedFiles: [...value.modifiedFiles],\n retainedMessages: [...value.retainedMessages],\n doomAutocompact: {\n version: STATE_VERSION,\n cycle: marker.cycle,\n pass: marker.pass,\n requestId: marker.requestId,\n snapshotLeafId: marker.snapshotLeafId,\n tokensBefore: marker.tokensBefore,\n },\n };\n}\n\nexport function createInitialState(): AutocompactState {\n return {\n version: STATE_VERSION,\n cycle: 1,\n pass: 1,\n phase: 'waiting',\n checkpointQueue: [],\n exhaustedPasses: [],\n invalidAttempts: 0,\n baselineTokens: 0,\n baselinePending: false,\n readFiles: [],\n modifiedFiles: [],\n };\n}\n\n/**\n * The ratios each pass fires at, with configured values folded in.\n *\n * The ladder only works if it climbs, so a configured pass never sits below the\n * one before it: a file that says pass 2 fires earlier than pass 1 gets pass 1's\n * ratio for pass 2 rather than a pass that can never contribute.\n */\nexport function compactionRatios(configured: AutocompactRatioOverrides = {}): Record<AutocompactPass, number> {\n let previous = 0;\n const ratios = {} as Record<AutocompactPass, number>;\n for (const pass of [1, 2, 3] as const) {\n const ratio = Math.max(configured[pass] ?? COMPACTION_THRESHOLDS[pass].ratio, previous);\n ratios[pass] = ratio;\n previous = ratio;\n }\n return ratios;\n}\n\nexport function thresholdTokens(\n pass: AutocompactPass,\n contextWindow: number,\n baselineTokens = 0,\n configured: AutocompactRatioOverrides = {},\n): number {\n const threshold = COMPACTION_THRESHOLDS[pass];\n const ratio = compactionRatios(configured)[pass];\n const baseline = Math.max(0, Math.min(baselineTokens, contextWindow));\n const remaining = contextWindow - baseline;\n const staged = baseline + Math.min(Math.floor(remaining * ratio), threshold.capTokens);\n // Pi compacts natively above `contextWindow - reserveTokens`. A staged threshold above that\n // point can never fire, so the ladder would silently degrade into native compaction: on a\n // 200k window the raw pass 3 ratio lands at 190_000, while Pi already compacted at 183_616.\n const nativeTrigger = contextWindow - DEFAULT_COMPACTION_SETTINGS.reserveTokens;\n return nativeTrigger > baseline ? Math.min(staged, nativeTrigger) : staged;\n}\n\nexport function latestCheckpointArtifactEntry(branchEntries: SessionEntry[]): SessionEntry | undefined {\n return branchEntries.findLast(\n (entry) =>\n entry.type === 'compaction' ||\n // Staged checkpoints are plain entries so they stay out of the agent's LLM context.\n (entry.type === 'custom' && entry.customType === CHECKPOINT_MESSAGE_TYPE) ||\n // Legacy sessions staged checkpoints as custom messages; committed markers still are.\n (entry.type === 'custom_message' &&\n (entry.customType === CHECKPOINT_MESSAGE_TYPE || entry.customType === CONTEXT_MESSAGE_TYPE)),\n );\n}\n\nexport function baselineUsageIsSettled(branchEntries: SessionEntry[]): boolean {\n const boundaryIndex = branchEntries.findLastIndex(\n (entry) =>\n entry.type === 'compaction' || (entry.type === 'custom_message' && entry.customType === CONTEXT_MESSAGE_TYPE),\n );\n return branchEntries.slice(boundaryIndex + 1).some((entry) => {\n if (entry.type !== 'message' || entry.message.role !== 'assistant') return false;\n const { stopReason, usage } = entry.message;\n if (stopReason === 'aborted' || stopReason === 'error' || !usage) return false;\n return (usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite) > 0;\n });\n}\n\nexport function retainedMessagesAfterSnapshot(\n branchEntries: SessionEntry[],\n snapshotLeafId: string,\n): AutocompactMessage[] {\n const snapshotIndex = branchEntries.findIndex((entry) => entry.id === snapshotLeafId);\n if (snapshotIndex === -1) return [];\n return branchEntries\n .slice(snapshotIndex + 1)\n .filter((entry) => entry.type !== 'custom_message' || entry.customType !== CHECKPOINT_MESSAGE_TYPE)\n .flatMap((entry) => sessionEntryToContextMessages(entry));\n}\n\nexport function projectContextMessages(\n messages: AutocompactMessage[],\n branchEntries: SessionEntry[],\n): ContextProjection {\n const nativeCompactionIndex = branchEntries.findLastIndex((entry) => entry.type === 'compaction');\n const markerEntry = branchEntries\n .slice(nativeCompactionIndex + 1)\n .findLast((entry) => entry.type === 'custom_message' && entry.customType === CONTEXT_MESSAGE_TYPE);\n if (!markerEntry || markerEntry.type !== 'custom_message') {\n return { messages, retainedMessageCount: 0 };\n }\n\n const details = contextDetailsFromUnknown(markerEntry.details);\n const summary = checkpointSummaryFromEntry(markerEntry);\n if (!details || !summary) return { messages, invalidMarker: true, retainedMessageCount: 0 };\n\n const markerMessageIndex = messages.findLastIndex(\n (message) =>\n message.role === 'custom' &&\n message.customType === CONTEXT_MESSAGE_TYPE &&\n contextDetailsFromUnknown(message.details)?.doomAutocompact.requestId === details.doomAutocompact.requestId,\n );\n if (markerMessageIndex === -1) return { messages, invalidMarker: true, retainedMessageCount: 0 };\n\n const summaryMessage: AutocompactMessage = {\n role: 'compactionSummary',\n summary,\n tokensBefore: details.doomAutocompact.tokensBefore,\n timestamp: messages[markerMessageIndex]?.timestamp ?? Date.now(),\n };\n return {\n messages: [summaryMessage, ...details.retainedMessages, ...messages.slice(markerMessageIndex + 1)],\n marker: details.doomAutocompact,\n retainedMessageCount: details.retainedMessages.length,\n };\n}\n\nexport function fileOperationsFromMessages(messages: AutocompactMessage[]): FileOperations {\n const fileOps: FileOperations = { read: new Set(), written: new Set(), edited: new Set() };\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const block of message.content) {\n if (block.type !== 'toolCall') continue;\n const path = typeof block.arguments.path === 'string' ? block.arguments.path : undefined;\n if (!path) continue;\n if (block.name === 'read') fileOps.read.add(path);\n else if (block.name === 'write') fileOps.written.add(path);\n else if (block.name === 'edit') fileOps.edited.add(path);\n }\n }\n return fileOps;\n}\n\nexport function parseState(value: unknown): AutocompactState | undefined {\n if (!isRecord(value)) return undefined;\n if (value.version !== STATE_VERSION || typeof value.cycle !== 'number' || !isPass(value.pass)) return undefined;\n if (\n value.phase !== 'waiting' &&\n value.phase !== 'checkpoint_pending' &&\n value.phase !== 'checkpoint_ready' &&\n value.phase !== 'compacting'\n )\n return undefined;\n const baselineTokens = value.baselineTokens ?? 0;\n if (typeof baselineTokens !== 'number' || baselineTokens < 0) return undefined;\n const baselinePending = value.baselinePending ?? false;\n if (typeof baselinePending !== 'boolean') return undefined;\n const checkpointQueue = value.checkpointQueue ?? [];\n if (\n !Array.isArray(checkpointQueue) ||\n !checkpointQueue.every(isPass) ||\n checkpointQueue.some((pass, index) => index > 0 && pass <= checkpointQueue[index - 1]!)\n )\n return undefined;\n // Sessions persisted before bounded retry landed simply have no attempt history to restore.\n const exhaustedPasses = value.exhaustedPasses ?? [];\n if (!Array.isArray(exhaustedPasses) || !exhaustedPasses.every(isPass)) return undefined;\n const invalidAttempts = value.invalidAttempts ?? 0;\n if (typeof invalidAttempts !== 'number' || invalidAttempts < 0) return undefined;\n if (!isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n if (value.requestId !== undefined && typeof value.requestId !== 'string') return undefined;\n if (value.compactionPass !== undefined && value.compactionPass !== 2 && value.compactionPass !== 3) return undefined;\n if ('latestCheckpointEntryId' in value) return undefined;\n if (value.latestCheckpointSnapshotLeafId !== undefined && typeof value.latestCheckpointSnapshotLeafId !== 'string')\n return undefined;\n if (value.lastAttemptLeafId !== undefined && typeof value.lastAttemptLeafId !== 'string') return undefined;\n if (value.snapshotLeafId !== undefined && typeof value.snapshotLeafId !== 'string') return undefined;\n if (value.snapshotTokens !== undefined && (typeof value.snapshotTokens !== 'number' || value.snapshotTokens < 0))\n return undefined;\n if (value.pendingCheckpoint !== undefined && typeof value.pendingCheckpoint !== 'string') return undefined;\n\n return {\n version: STATE_VERSION,\n cycle: value.cycle,\n pass: value.pass,\n phase: value.phase,\n checkpointQueue: [...checkpointQueue],\n exhaustedPasses: [...exhaustedPasses],\n invalidAttempts,\n baselineTokens,\n baselinePending,\n readFiles: [...value.readFiles],\n modifiedFiles: [...value.modifiedFiles],\n ...(value.requestId ? { requestId: value.requestId } : {}),\n ...(value.compactionPass ? { compactionPass: value.compactionPass } : {}),\n ...(value.latestCheckpointSnapshotLeafId\n ? { latestCheckpointSnapshotLeafId: value.latestCheckpointSnapshotLeafId }\n : {}),\n ...(value.lastAttemptLeafId ? { lastAttemptLeafId: value.lastAttemptLeafId } : {}),\n ...(value.snapshotLeafId ? { snapshotLeafId: value.snapshotLeafId } : {}),\n ...(value.snapshotTokens !== undefined ? { snapshotTokens: value.snapshotTokens } : {}),\n ...(value.pendingCheckpoint ? { pendingCheckpoint: value.pendingCheckpoint } : {}),\n };\n}\n\nexport function checkpointSummaryFromEntry(entry: SessionEntry | undefined): string | undefined {\n if (!entry) return undefined;\n if (entry.type === 'compaction') return entry.summary.trim() || undefined;\n if (entry.type === 'custom') {\n return isRecord(entry.data) && typeof entry.data.summary === 'string'\n ? entry.data.summary.trim() || undefined\n : undefined;\n }\n if (entry.type === 'custom_message') {\n const content =\n typeof entry.content === 'string'\n ? entry.content\n : entry.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('\\n');\n return content.trim() || undefined;\n }\n return assistantText(entry);\n}\n\nexport function parseCheckpointDecision(response: string): CheckpointDecision {\n const match = response.match(SHOULD_COMPACT_PATTERN);\n const summary = response.replace(SHOULD_COMPACT_PATTERN, '').trim();\n if (!match) return { summary };\n return { summary, shouldCompact: match[1]?.toLowerCase() === 'true' };\n}\n\nexport function isStructuredCheckpoint(summary: string): boolean {\n return CHECKPOINT_HEADINGS.every((heading) => summary.includes(heading));\n}\n\nexport function createRequestId(\n sessionId: string,\n cycle: number,\n pass: AutocompactPass,\n leafId: string | null,\n): string {\n return `${sessionId}:${cycle}:${pass}:${leafId ?? 'root'}`;\n}\n\nexport function checkpointRequestDetails(\n cycle: number,\n pass: AutocompactPass,\n requestId: string,\n): CheckpointRequestDetails {\n return { version: STATE_VERSION, cycle, pass, requestId };\n}\n\nexport function mergeFileDetails(\n current: AutocompactFileDetails,\n fileOps?: FileOperations,\n additional?: AutocompactFileDetails,\n): AutocompactFileDetails {\n const modified = new Set([\n ...current.modifiedFiles,\n ...(additional?.modifiedFiles ?? []),\n ...(fileOps ? [...fileOps.edited, ...fileOps.written] : []),\n ]);\n const read = new Set([...current.readFiles, ...(additional?.readFiles ?? []), ...(fileOps ? [...fileOps.read] : [])]);\n for (const path of modified) read.delete(path);\n return { readFiles: [...read].sort(), modifiedFiles: [...modified].sort() };\n}\n\nexport function fileDetailsFromUnknown(value: unknown): AutocompactFileDetails | undefined {\n if (!isRecord(value) || !isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n return { readFiles: value.readFiles, modifiedFiles: value.modifiedFiles };\n}\n\nexport function withCanonicalFileSections(summary: string, details: AutocompactFileDetails): string {\n const sections: string[] = [];\n if (details.readFiles.length > 0) sections.push(`<read-files>\\n${details.readFiles.join('\\n')}\\n</read-files>`);\n if (details.modifiedFiles.length > 0) {\n sections.push(`<modified-files>\\n${details.modifiedFiles.join('\\n')}\\n</modified-files>`);\n }\n const normalized = summary.replace(FILE_SECTION_PATTERN, '').trim();\n return sections.length > 0 ? `${normalized}\\n\\n${sections.join('\\n\\n')}` : normalized;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"policy.mjs","names":[],"sources":["../../../src/adapters/compaction/policy.ts"],"sourcesContent":["import {\n DEFAULT_COMPACTION_SETTINGS,\n type FileOperations,\n type SessionEntry,\n sessionEntryToContextMessages,\n} from '@earendil-works/pi-coding-agent';\nimport {\n CHECKPOINT_HEADINGS,\n CHECKPOINT_MESSAGE_TYPE,\n COMPACTION_THRESHOLDS,\n CONTEXT_MESSAGE_TYPE,\n STATE_VERSION,\n} from '../../types/constants.ts';\nimport type {\n AutocompactContextDetails,\n AutocompactFileDetails,\n AutocompactRatioOverrides,\n AutocompactTokenOverrides,\n AutocompactMessage,\n AutocompactPass,\n AutocompactState,\n CheckpointDecision,\n CheckpointRequestDetails,\n ContextProjection,\n} from '../../types/index.ts';\n\nconst SHOULD_COMPACT_PATTERN = /<shouldCompact>\\s*(true|false)\\s*<\\/shouldCompact>/i;\nconst FILE_SECTION_PATTERN = /\\n*<(?:read-files|modified-files)>[\\s\\S]*?<\\/(?:read-files|modified-files)>/g;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === 'string');\n}\n\nfunction isPass(value: unknown): value is AutocompactPass {\n return value === 1 || value === 2 || value === 3;\n}\n\nfunction assistantText(entry: SessionEntry): string | undefined {\n if (entry.type !== 'message' || entry.message.role !== 'assistant') return undefined;\n const text = entry.message.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('\\n')\n .trim();\n return text || undefined;\n}\n\nfunction isAutocompactMessage(value: unknown): value is AutocompactMessage {\n return isRecord(value) && typeof value.role === 'string';\n}\n\nexport function contextDetailsFromUnknown(value: unknown): AutocompactContextDetails | undefined {\n if (!isRecord(value) || !isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n if (!Array.isArray(value.retainedMessages) || !value.retainedMessages.every(isAutocompactMessage)) return undefined;\n if (!isRecord(value.doomAutocompact)) return undefined;\n const marker = value.doomAutocompact;\n if (\n marker.version !== STATE_VERSION ||\n (marker.pass !== 2 && marker.pass !== 3) ||\n typeof marker.cycle !== 'number' ||\n typeof marker.requestId !== 'string' ||\n typeof marker.snapshotLeafId !== 'string' ||\n typeof marker.tokensBefore !== 'number'\n )\n return undefined;\n return {\n readFiles: [...value.readFiles],\n modifiedFiles: [...value.modifiedFiles],\n retainedMessages: [...value.retainedMessages],\n doomAutocompact: {\n version: STATE_VERSION,\n cycle: marker.cycle,\n pass: marker.pass,\n requestId: marker.requestId,\n snapshotLeafId: marker.snapshotLeafId,\n tokensBefore: marker.tokensBefore,\n },\n };\n}\n\nexport function createInitialState(): AutocompactState {\n return {\n version: STATE_VERSION,\n cycle: 1,\n pass: 1,\n phase: 'waiting',\n checkpointQueue: [],\n exhaustedPasses: [],\n invalidAttempts: 0,\n baselineTokens: 0,\n baselinePending: false,\n readFiles: [],\n modifiedFiles: [],\n };\n}\n\n/**\n * The ratios each pass fires at, with configured values folded in.\n *\n * The ladder only works if it climbs, so a configured pass never sits below the\n * one before it: a file that says pass 2 fires earlier than pass 1 gets pass 1's\n * ratio for pass 2 rather than a pass that can never contribute.\n */\nexport function compactionRatios(configured: AutocompactRatioOverrides = {}): Record<AutocompactPass, number> {\n let previous = 0;\n const ratios = {} as Record<AutocompactPass, number>;\n for (const pass of [1, 2, 3] as const) {\n const ratio = Math.max(configured[pass] ?? COMPACTION_THRESHOLDS[pass].ratio, previous);\n ratios[pass] = ratio;\n previous = ratio;\n }\n return ratios;\n}\n\nexport function thresholdTokens(\n pass: AutocompactPass,\n contextWindow: number,\n baselineTokens = 0,\n configured: AutocompactRatioOverrides = {},\n): number {\n const threshold = COMPACTION_THRESHOLDS[pass];\n const ratio = compactionRatios(configured)[pass];\n const baseline = Math.max(0, Math.min(baselineTokens, contextWindow));\n const remaining = contextWindow - baseline;\n const staged = baseline + Math.min(Math.floor(remaining * ratio), threshold.capTokens);\n // Pi compacts natively above `contextWindow - reserveTokens`. A staged threshold above that\n // point can never fire, so the ladder would silently degrade into native compaction: on a\n // 200k window the raw pass 3 ratio lands at 190_000, while Pi already compacted at 183_616.\n const nativeTrigger = contextWindow - DEFAULT_COMPACTION_SETTINGS.reserveTokens;\n return nativeTrigger > baseline ? Math.min(staged, nativeTrigger) : staged;\n}\n\n/**\n * Where every pass fires, with a matching model's absolute token checkpoints folded in.\n *\n * A configured token count replaces the ratio only when it fires earlier, so an\n * override can bring a checkpoint forward on a very large window without ever\n * pushing one past the point Pi compacts natively.\n *\n * Two rules keep the ladder usable. A token count at or below the baseline is\n * ignored, because a compaction that lands above it would otherwise satisfy that\n * pass the moment the next cycle opens and re-fire it every turn. And a pass never\n * sits below the one before it, for the same reason {@link compactionRatios}\n * climbs: `evaluateUsage` skips any pass below the one already reached, so a later\n * pass that fires first does not merely reorder the ladder, it locks the earlier\n * passes out of the cycle and forces compaction with no summary ever written.\n */\nexport function effectiveThresholds(\n contextWindow: number,\n baselineTokens = 0,\n configured: AutocompactRatioOverrides = {},\n tokenOverrides: AutocompactTokenOverrides = {},\n): Record<AutocompactPass, number> {\n let previous = 0;\n const thresholds = {} as Record<AutocompactPass, number>;\n for (const pass of [1, 2, 3] as const) {\n const ratioTokens = thresholdTokens(pass, contextWindow, baselineTokens, configured);\n const absolute = tokenOverrides[pass];\n const staged = absolute !== undefined && absolute > baselineTokens ? Math.min(ratioTokens, absolute) : ratioTokens;\n thresholds[pass] = Math.max(staged, previous);\n previous = thresholds[pass];\n }\n return thresholds;\n}\nexport function latestCheckpointArtifactEntry(branchEntries: SessionEntry[]): SessionEntry | undefined {\n return branchEntries.findLast(\n (entry) =>\n entry.type === 'compaction' ||\n // Staged checkpoints are plain entries so they stay out of the agent's LLM context.\n (entry.type === 'custom' && entry.customType === CHECKPOINT_MESSAGE_TYPE) ||\n // Legacy sessions staged checkpoints as custom messages; committed markers still are.\n (entry.type === 'custom_message' &&\n (entry.customType === CHECKPOINT_MESSAGE_TYPE || entry.customType === CONTEXT_MESSAGE_TYPE)),\n );\n}\n\nexport function baselineUsageIsSettled(branchEntries: SessionEntry[]): boolean {\n const boundaryIndex = branchEntries.findLastIndex(\n (entry) =>\n entry.type === 'compaction' || (entry.type === 'custom_message' && entry.customType === CONTEXT_MESSAGE_TYPE),\n );\n return branchEntries.slice(boundaryIndex + 1).some((entry) => {\n if (entry.type !== 'message' || entry.message.role !== 'assistant') return false;\n const { stopReason, usage } = entry.message;\n if (stopReason === 'aborted' || stopReason === 'error' || !usage) return false;\n return (usage.totalTokens || usage.input + usage.output + usage.cacheRead + usage.cacheWrite) > 0;\n });\n}\n\nexport function retainedMessagesAfterSnapshot(\n branchEntries: SessionEntry[],\n snapshotLeafId: string,\n): AutocompactMessage[] {\n const snapshotIndex = branchEntries.findIndex((entry) => entry.id === snapshotLeafId);\n if (snapshotIndex === -1) return [];\n return branchEntries\n .slice(snapshotIndex + 1)\n .filter((entry) => entry.type !== 'custom_message' || entry.customType !== CHECKPOINT_MESSAGE_TYPE)\n .flatMap((entry) => sessionEntryToContextMessages(entry));\n}\n\nexport function projectContextMessages(\n messages: AutocompactMessage[],\n branchEntries: SessionEntry[],\n): ContextProjection {\n const nativeCompactionIndex = branchEntries.findLastIndex((entry) => entry.type === 'compaction');\n const markerEntry = branchEntries\n .slice(nativeCompactionIndex + 1)\n .findLast((entry) => entry.type === 'custom_message' && entry.customType === CONTEXT_MESSAGE_TYPE);\n if (!markerEntry || markerEntry.type !== 'custom_message') {\n return { messages, retainedMessageCount: 0 };\n }\n\n const details = contextDetailsFromUnknown(markerEntry.details);\n const summary = checkpointSummaryFromEntry(markerEntry);\n if (!details || !summary) return { messages, invalidMarker: true, retainedMessageCount: 0 };\n\n const markerMessageIndex = messages.findLastIndex(\n (message) =>\n message.role === 'custom' &&\n message.customType === CONTEXT_MESSAGE_TYPE &&\n contextDetailsFromUnknown(message.details)?.doomAutocompact.requestId === details.doomAutocompact.requestId,\n );\n if (markerMessageIndex === -1) return { messages, invalidMarker: true, retainedMessageCount: 0 };\n\n const summaryMessage: AutocompactMessage = {\n role: 'compactionSummary',\n summary,\n tokensBefore: details.doomAutocompact.tokensBefore,\n timestamp: messages[markerMessageIndex]?.timestamp ?? Date.now(),\n };\n return {\n messages: [summaryMessage, ...details.retainedMessages, ...messages.slice(markerMessageIndex + 1)],\n marker: details.doomAutocompact,\n retainedMessageCount: details.retainedMessages.length,\n };\n}\n\nexport function fileOperationsFromMessages(messages: AutocompactMessage[]): FileOperations {\n const fileOps: FileOperations = { read: new Set(), written: new Set(), edited: new Set() };\n for (const message of messages) {\n if (message.role !== 'assistant') continue;\n for (const block of message.content) {\n if (block.type !== 'toolCall') continue;\n const path = typeof block.arguments.path === 'string' ? block.arguments.path : undefined;\n if (!path) continue;\n if (block.name === 'read') fileOps.read.add(path);\n else if (block.name === 'write') fileOps.written.add(path);\n else if (block.name === 'edit') fileOps.edited.add(path);\n }\n }\n return fileOps;\n}\n\nexport function parseState(value: unknown): AutocompactState | undefined {\n if (!isRecord(value)) return undefined;\n if (value.version !== STATE_VERSION || typeof value.cycle !== 'number' || !isPass(value.pass)) return undefined;\n if (\n value.phase !== 'waiting' &&\n value.phase !== 'checkpoint_pending' &&\n value.phase !== 'checkpoint_ready' &&\n value.phase !== 'compacting'\n )\n return undefined;\n const baselineTokens = value.baselineTokens ?? 0;\n if (typeof baselineTokens !== 'number' || baselineTokens < 0) return undefined;\n const baselinePending = value.baselinePending ?? false;\n if (typeof baselinePending !== 'boolean') return undefined;\n const checkpointQueue = value.checkpointQueue ?? [];\n if (\n !Array.isArray(checkpointQueue) ||\n !checkpointQueue.every(isPass) ||\n checkpointQueue.some((pass, index) => index > 0 && pass <= checkpointQueue[index - 1]!)\n )\n return undefined;\n // Sessions persisted before bounded retry landed simply have no attempt history to restore.\n const exhaustedPasses = value.exhaustedPasses ?? [];\n if (!Array.isArray(exhaustedPasses) || !exhaustedPasses.every(isPass)) return undefined;\n const invalidAttempts = value.invalidAttempts ?? 0;\n if (typeof invalidAttempts !== 'number' || invalidAttempts < 0) return undefined;\n if (!isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n if (value.requestId !== undefined && typeof value.requestId !== 'string') return undefined;\n if (value.compactionPass !== undefined && value.compactionPass !== 2 && value.compactionPass !== 3) return undefined;\n if ('latestCheckpointEntryId' in value) return undefined;\n if (value.latestCheckpointSnapshotLeafId !== undefined && typeof value.latestCheckpointSnapshotLeafId !== 'string')\n return undefined;\n if (value.lastAttemptLeafId !== undefined && typeof value.lastAttemptLeafId !== 'string') return undefined;\n if (value.snapshotLeafId !== undefined && typeof value.snapshotLeafId !== 'string') return undefined;\n if (value.snapshotTokens !== undefined && (typeof value.snapshotTokens !== 'number' || value.snapshotTokens < 0))\n return undefined;\n if (value.pendingCheckpoint !== undefined && typeof value.pendingCheckpoint !== 'string') return undefined;\n\n return {\n version: STATE_VERSION,\n cycle: value.cycle,\n pass: value.pass,\n phase: value.phase,\n checkpointQueue: [...checkpointQueue],\n exhaustedPasses: [...exhaustedPasses],\n invalidAttempts,\n baselineTokens,\n baselinePending,\n readFiles: [...value.readFiles],\n modifiedFiles: [...value.modifiedFiles],\n ...(value.requestId ? { requestId: value.requestId } : {}),\n ...(value.compactionPass ? { compactionPass: value.compactionPass } : {}),\n ...(value.latestCheckpointSnapshotLeafId\n ? { latestCheckpointSnapshotLeafId: value.latestCheckpointSnapshotLeafId }\n : {}),\n ...(value.lastAttemptLeafId ? { lastAttemptLeafId: value.lastAttemptLeafId } : {}),\n ...(value.snapshotLeafId ? { snapshotLeafId: value.snapshotLeafId } : {}),\n ...(value.snapshotTokens !== undefined ? { snapshotTokens: value.snapshotTokens } : {}),\n ...(value.pendingCheckpoint ? { pendingCheckpoint: value.pendingCheckpoint } : {}),\n };\n}\n\nexport function checkpointSummaryFromEntry(entry: SessionEntry | undefined): string | undefined {\n if (!entry) return undefined;\n if (entry.type === 'compaction') return entry.summary.trim() || undefined;\n if (entry.type === 'custom') {\n return isRecord(entry.data) && typeof entry.data.summary === 'string'\n ? entry.data.summary.trim() || undefined\n : undefined;\n }\n if (entry.type === 'custom_message') {\n const content =\n typeof entry.content === 'string'\n ? entry.content\n : entry.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('\\n');\n return content.trim() || undefined;\n }\n return assistantText(entry);\n}\n\nexport function parseCheckpointDecision(response: string): CheckpointDecision {\n const match = response.match(SHOULD_COMPACT_PATTERN);\n const summary = response.replace(SHOULD_COMPACT_PATTERN, '').trim();\n if (!match) return { summary };\n return { summary, shouldCompact: match[1]?.toLowerCase() === 'true' };\n}\n\nexport function isStructuredCheckpoint(summary: string): boolean {\n return CHECKPOINT_HEADINGS.every((heading) => summary.includes(heading));\n}\n\nexport function createRequestId(\n sessionId: string,\n cycle: number,\n pass: AutocompactPass,\n leafId: string | null,\n): string {\n return `${sessionId}:${cycle}:${pass}:${leafId ?? 'root'}`;\n}\n\nexport function checkpointRequestDetails(\n cycle: number,\n pass: AutocompactPass,\n requestId: string,\n): CheckpointRequestDetails {\n return { version: STATE_VERSION, cycle, pass, requestId };\n}\n\nexport function mergeFileDetails(\n current: AutocompactFileDetails,\n fileOps?: FileOperations,\n additional?: AutocompactFileDetails,\n): AutocompactFileDetails {\n const modified = new Set([\n ...current.modifiedFiles,\n ...(additional?.modifiedFiles ?? []),\n ...(fileOps ? [...fileOps.edited, ...fileOps.written] : []),\n ]);\n const read = new Set([...current.readFiles, ...(additional?.readFiles ?? []), ...(fileOps ? [...fileOps.read] : [])]);\n for (const path of modified) read.delete(path);\n return { readFiles: [...read].sort(), modifiedFiles: [...modified].sort() };\n}\n\nexport function fileDetailsFromUnknown(value: unknown): AutocompactFileDetails | undefined {\n if (!isRecord(value) || !isStringArray(value.readFiles) || !isStringArray(value.modifiedFiles)) return undefined;\n return { readFiles: value.readFiles, modifiedFiles: value.modifiedFiles };\n}\n\nexport function withCanonicalFileSections(summary: string, details: AutocompactFileDetails): string {\n const sections: string[] = [];\n if (details.readFiles.length > 0) sections.push(`<read-files>\\n${details.readFiles.join('\\n')}\\n</read-files>`);\n if (details.modifiedFiles.length > 0) {\n sections.push(`<modified-files>\\n${details.modifiedFiles.join('\\n')}\\n</modified-files>`);\n }\n const normalized = summary.replace(FILE_SECTION_PATTERN, '').trim();\n return sections.length > 0 ? `${normalized}\\n\\n${sections.join('\\n\\n')}` : normalized;\n}\n"],"mappings":"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"}
@@ -1,14 +1,14 @@
1
- const e=require("../../types/constants.cjs"),t=require("../compaction/policy.cjs"),n=require("../../services/summarizationModel.cjs"),r=require("../telemetry/logSinkTelemetry.cjs");let i=require("@agimon-ai/doompi-config"),a=require("@agimon-ai/doompi-extension-contracts/cordis-host"),o=require("@agimon-ai/doompi-extension-contracts/context-contributions"),s=require("@agimon-ai/doompi-extension-contracts/ui-hub"),c=require("@earendil-works/pi-coding-agent");const l=`@root`,u=`doom-autocompact`,d={waiting:`waiting`,checkpointPending:`checkpoint_pending`,checkpointReady:`checkpoint_ready`,compacting:`compacting`};function f(e,t={}){return{"pi.session.id":e.sessionManager.getSessionId(),...t}}function p(e){for(let n=e.length-1;n>=0;--n){let r=e[n];if(r?.type!==`custom`||r.customType!==`doom-autocompact-state`)continue;let i=t.parseState(r.data);if(i)return i}}function m(e){for(let t of e.sessionManager.getBranch().toReversed())if((t.type!==`custom`||t.customType!==`doom-autocompact-state`)&&t.type!==`label`)return t.id;return l}function h(e){return e instanceof Error?e.message:String(e)}function g(e){for(let t of e.toReversed()){if(t.type!==`custom`||t.customType!==`agent-harness-plan-document`)continue;if(!t.data||typeof t.data!=`object`)return;let e=t.data;return typeof e.content!=`string`||typeof e.path!=`string`?void 0:{content:e.content,path:e.path}}}const _=Object.freeze({entries:Object.freeze([]),errors:Object.freeze([])});function v(e){if(!e)return _;try{return e.snapshot()}catch(e){return{entries:[],errors:[{source:o.DOOM_CONTEXT_CONTRIBUTIONS_SERVICE,id:`service-snapshot`,label:`Context contributions`,order:0,message:h(e)}]}}}function y(e){let t=e.entries.map(e=>`### ${e.label}\n${e.text}`);return t.push(...e.errors.map(e=>`### ${e.label}\n(unavailable: ${e.message})`)),t.length>0?t.join(`
1
+ const e=require("../../types/constants.cjs"),t=require("../compaction/policy.cjs"),n=require("../compaction/modelOverrides.cjs"),r=require("../../services/summarizationModel.cjs"),i=require("../telemetry/logSinkTelemetry.cjs");let a=require("@agimon-ai/doompi-config"),o=require("@agimon-ai/doompi-extension-contracts/cordis-host"),s=require("@agimon-ai/doompi-extension-contracts/context-contributions"),c=require("@agimon-ai/doompi-extension-contracts/ui-hub"),l=require("@earendil-works/pi-coding-agent");const u=`@root`,d=`doom-autocompact`,f={waiting:`waiting`,checkpointPending:`checkpoint_pending`,checkpointReady:`checkpoint_ready`,compacting:`compacting`};function p(e,t={}){return{"pi.session.id":e.sessionManager.getSessionId(),...t}}function m(e){for(let n=e.length-1;n>=0;--n){let r=e[n];if(r?.type!==`custom`||r.customType!==`doom-autocompact-state`)continue;let i=t.parseState(r.data);if(i)return i}}function h(e){for(let t of e.sessionManager.getBranch().toReversed())if((t.type!==`custom`||t.customType!==`doom-autocompact-state`)&&t.type!==`label`)return t.id;return u}function g(e){return e instanceof Error?e.message:String(e)}function _(e){for(let t of e.toReversed()){if(t.type!==`custom`||t.customType!==`agent-harness-plan-document`)continue;if(!t.data||typeof t.data!=`object`)return;let e=t.data;return typeof e.content!=`string`||typeof e.path!=`string`?void 0:{content:e.content,path:e.path}}}const v=Object.freeze({entries:Object.freeze([]),errors:Object.freeze([])});function y(e){if(!e)return v;try{return e.snapshot()}catch(e){return{entries:[],errors:[{source:s.DOOM_CONTEXT_CONTRIBUTIONS_SERVICE,id:`service-snapshot`,label:`Context contributions`,order:0,message:g(e)}]}}}function b(e){let t=e.entries.map(e=>`### ${e.label}\n${e.text}`);return t.push(...e.errors.map(e=>`### ${e.label}\n(unavailable: ${e.message})`)),t.length>0?t.join(`
2
2
 
3
- `):`(no registered context contributions)`}function b(e,t){let n=g(e);return{...n?{planPath:n.path}:{},contributions:t.entries,contributionErrors:t.errors}}function x(e){return`<compaction-runtime-state>
3
+ `):`(no registered context contributions)`}function x(e,t){let n=_(e);return{...n?{planPath:n.path}:{},contributions:t.entries,contributionErrors:t.errors}}function S(e){return`<compaction-runtime-state>
4
4
  Authoritative runtime state captured when compaction committed. Use it to resume coordination without reconstructing state from the summary.
5
5
  <active-plan>
6
6
  ${e.planPath?`Source: ${e.planPath}\nExact plan content is restored separately by Doom Plan.`:`(no active plan document)`}
7
7
  </active-plan>
8
8
  <context-contributions>
9
- ${y({entries:e.contributions,errors:e.contributionErrors})}
9
+ ${b({entries:e.contributions,errors:e.contributionErrors})}
10
10
  </context-contributions>
11
- </compaction-runtime-state>`}function S(e){return{"autocompact.runtime.plan_present":!!e.planPath,"autocompact.runtime.contribution_count":e.contributions.length,"autocompact.runtime.contribution_error_count":e.contributionErrors.length}}function C(e){let t=e.plan?`Source: ${e.plan.path}\n\n${e.plan.content}`:`(no active plan document)`,n=[e.readFiles.length>0?`Read files: ${e.readFiles.join(`, `)}`:void 0,e.modifiedFiles.length>0?`Modified files: ${e.modifiedFiles.join(`, `)}`:void 0].filter(e=>!!e);return`<compaction-steering priority="user,plan,context-contributions,important-context,recent-messages">
11
+ </compaction-runtime-state>`}function C(e){return{"autocompact.runtime.plan_present":!!e.planPath,"autocompact.runtime.contribution_count":e.contributions.length,"autocompact.runtime.contribution_error_count":e.contributionErrors.length}}function w(e){let t=e.plan?`Source: ${e.plan.path}\n\n${e.plan.content}`:`(no active plan document)`,n=[e.readFiles.length>0?`Read files: ${e.readFiles.join(`, `)}`:void 0,e.modifiedFiles.length>0?`Modified files: ${e.modifiedFiles.join(`, `)}`:void 0].filter(e=>!!e);return`<compaction-steering priority="user,plan,context-contributions,important-context,recent-messages">
12
12
  <user-prompt source="conversation">
13
13
  Treat the user's explicit goals, constraints, corrections, and preferences in the conversation as authoritative. Newer user instructions override older ones.
14
14
  </user-prompt>
@@ -16,17 +16,17 @@ Treat the user's explicit goals, constraints, corrections, and preferences in th
16
16
  ${t}
17
17
  </active-plan>
18
18
  <context-contributions>
19
- ${y(e.contextContributions)}
19
+ ${b(e.contextContributions)}
20
20
  </context-contributions>
21
21
  <important-context>
22
22
  ${n.length>0?n.join(`
23
23
  `):`(none recorded outside the conversation)`}
24
24
  </important-context>
25
- </compaction-steering>`}function w(e,t){let n=e===2?`Start with exactly <shouldCompact>true</shouldCompact> or <shouldCompact>false</shouldCompact>. Use true when the staged summary safely retains the important parent context. Use false only when it is not yet sufficient for safe compaction.
25
+ </compaction-steering>`}function T(e,t){let n=e===2?`Start with exactly <shouldCompact>true</shouldCompact> or <shouldCompact>false</shouldCompact>. Use true when the staged summary safely retains the important parent context. Use false only when it is not yet sufficient for safe compaction.
26
26
 
27
27
  `:``;return`Create Doom autocompact checkpoint pass ${e}.
28
28
 
29
- ${C(t)}
29
+ ${w(t)}
30
30
 
31
31
  Apply the steering evidence in priority order. Do not invent plan or contributed runtime state. Preserve verified facts and mark unresolved inference explicitly. Newer evidence replaces superseded information.
32
32
 
@@ -40,5 +40,5 @@ ${n}Return only the decision tag when required, followed by a concise structured
40
40
  ### Blocked
41
41
  ## Key Decisions
42
42
  ## Next Steps
43
- ## Critical Context`}function T(e,n,r){let i=t.projectContextMessages((0,c.buildSessionContext)(n).messages,n).messages;if(e===1||!r)return i;let a=n.findIndex(e=>e.id===r);return a===-1?i:n.slice(a+1).filter(e=>e.type!==`custom_message`||e.customType!==`doom-autocompact-checkpoint`).flatMap(e=>(0,c.sessionEntryToContextMessages)(e))}const E={enabled:!0,ratios:{}};function D(e,t){let n;try{n=(0,i.loadDoomConfig)((0,i.getHarnessState)().root??e).modes}catch(e){return process.emitWarning(`Doom autocompact configuration could not be loaded; using the active session model instead.`),t?.(e),E}let r=n?.autocompact,a=(r&&(r.model!==void 0||r.thinking!==void 0)?{...r.model?{model:r.model}:{},...r.thinking?{thinking:r.thinking}:{}}:void 0)??n?.planning?.subagents,o=r?.thresholds;return{enabled:r?.enabled??!0,...a?{agent:a}:{},ratios:{...o?.pass1===void 0?{}:{1:o.pass1},...o?.pass2===void 0?{}:{2:o.pass2},...o?.pass3===void 0?{}:{3:o.pass3}}}}function O(e){let t=D(e.cwd).agent,r=t?.model?n.parseModelReference(t.model):void 0,i=r?e.modelRegistry.find(r.provider,r.modelId):void 0,a=i??e.model;if(!a)return;let o=t?.thinking??(i?r?.thinking:void 0)??e.thinkingLevel;return{model:a,...o?{thinkingLevel:o}:{}}}async function k(e,t){let n=t(e.context);if(!n)throw Error(`No active model is available for autocompact summarization.`);let r=await e.context.modelRegistry.getApiKeyAndHeaders(n.model);if(!r.ok)throw Error(r.error);let i=e.context.modelRegistry.getProvider(n.model.provider);if(!i)throw Error(`No provider is registered for "${n.model.provider}" in this session.`);return(0,c.generateSummary)(e.messages,n.model,c.DEFAULT_COMPACTION_SETTINGS.reserveTokens,r.apiKey,r.headers,e.signal,e.instructions,e.previousCheckpoint,n.thinkingLevel,(e,t,n)=>i.streamSimple(e,t,n),r.env)}function A(e,t,n=`info`){e?.hasUI&&e.ui.notify(t,n)}function j(n,i,a={}){let h=a.resolveModel??O,_=a.generateCheckpoint??(e=>k(e,h)),y=a.telemetry??r.createAutocompactTelemetry(),C=a.doomIntegrations??!0,E=new Set,j=new Set,M=new Set,N=!0,P=0,F=t.createInitialState(),I,L,R,z,B=!1;n.effect(()=>async()=>{N=!1,P+=1,L?.abort(Error(`Autocompact runtime is shutting down.`)),L=void 0,await Promise.allSettled(M),R=void 0,z=void 0,I=void 0,E.clear(),j.clear(),F=t.createInitialState(),B=!1,await y.shutdown()},`${u}/runtime`),n.inject([o.DOOM_CONTEXT_CONTRIBUTIONS_SERVICE],e=>{let t=(0,o.requireDoomContextContributions)(e);return z=t,()=>{z===t&&(z=void 0)}}),C&&n.inject([s.DOOM_UI_HUB_SERVICE],e=>{let t=(0,s.requireDoomUiHub)(e).registerFooter({source:u,id:`autocompact`,order:20});return R=t,()=>{t.dispose(),R===t&&(R=void 0)}});let V=e=>{if(!N)return;let t=F.phase===d.checkpointPending?`summarizing`:F.phase===d.checkpointReady?`applying`:void 0;R?.update(t?{fullText:`Compacting p${F.pass}`,compactText:`C${F.pass}`}:void 0);let n=e??I;n?.hasUI&&n.ui.setStatus(`doom-autocompact`,t?`Compacting pass ${F.pass} (${t})…`:void 0)},H=()=>{N&&(i.appendEntry(e.STATE_CUSTOM_TYPE,{...F}),V())},U=()=>{delete F.requestId,delete F.snapshotLeafId,delete F.snapshotTokens,delete F.pendingCheckpoint,delete F.compactionPass},W=e=>{F.checkpointQueue=F.checkpointQueue.filter(t=>t!==e)},G=e=>{N&&(F=p(e.sessionManager.getBranch())??t.createInitialState(),!(F.phase===d.checkpointReady&&F.requestId&&F.snapshotLeafId&&F.pendingCheckpoint||F.phase===d.waiting)&&(L?.abort(),L=void 0,F.phase=d.waiting,U(),H()))},ee=t=>{N&&i.sendMessage({customType:e.RESUME_MESSAGE_TYPE,content:`${t} Continue from the compacted checkpoint's immediate next action without repeating completed work.`,display:!1,details:{version:2,cycle:F.cycle,pass:F.pass}},{triggerTurn:!0,deliverAs:`steer`})},K=(e,t)=>{let n=F.invalidAttempts+1,r=n>=3;return F.phase=d.waiting,t&&(F.lastAttemptLeafId=t),r?(W(e),F.exhaustedPasses=[...F.exhaustedPasses,e],F.invalidAttempts=0):F.invalidAttempts=n,U(),H(),{attempts:n,exhausted:r}},te=(e,t)=>{if(!N||e!==F.requestId||F.phase!==d.checkpointPending)return;let n=F.pass,{attempts:r,exhausted:i}=K(n,F.snapshotLeafId),a=t instanceof Error?t.message:String(t);A(I,i?`Doom autocompact summarization pass ${n} failed ${r} times and was abandoned: ${a}`:`Doom autocompact summarization pass ${n} failed: ${a}`,`error`)},ne=(e,t)=>{!N||B||(B=!0,y.recordWarning(r.AUTOCOMPACT_EVENT.configurationLoadFailed,t,f(e,{"autocompact.cycle":F.cycle,"autocompact.pass":F.pass})))},q=(e,t,n)=>{if(N)for(let i of t.errors)A(e,`Doom autocompact context contribution degraded (${i.source}/${i.id}): ${i.message}`,`warning`),y.recordWarning(r.AUTOCOMPACT_EVENT.contextContributionDegraded,Error(i.message),{...n,"autocompact.context_contribution.source":i.source,"autocompact.context_contribution.id":i.id,"autocompact.context_contribution.order":i.order})},J=(t,n,r)=>{if(!N)return{contributions:[],contributionErrors:[]};let a=v(z);q(t,a,r);let o=b(n,a);return i.sendMessage({customType:e.RUNTIME_STATE_MESSAGE_TYPE,content:x(o),display:!1,details:{version:2,...o}}),o},re=(n,a)=>{if(!N||!F.requestId||!F.snapshotLeafId||!F.pendingCheckpoint)return!1;let o=a.sessionManager.getBranch(),s=t.projectContextMessages((0,c.buildSessionContext)(o).messages,o).messages,l=t.mergeFileDetails(F,t.fileOperationsFromMessages(s)),u=F.requestId,p=F.cycle,h=t.withCanonicalFileSections(F.pendingCheckpoint,l),g={...l,doomAutocompact:{version:2,cycle:p,pass:n,requestId:u,snapshotLeafId:F.snapshotLeafId,tokensBefore:F.snapshotTokens??a.getContextUsage()?.tokens??0},retainedMessages:t.retainedMessagesAfterSnapshot(o,F.snapshotLeafId)},_=a.isIdle();i.sendMessage({customType:e.CONTEXT_MESSAGE_TYPE,content:h,display:!1,details:g});let v=m(a),b=f(a,{"autocompact.request.id":u,"autocompact.cycle":p,"autocompact.pass":n}),x=J(a,o,b);return _&&i.setLabel(v,`autocompact:c${p}:p${n}`),F.readFiles=l.readFiles,F.modifiedFiles=l.modifiedFiles,delete F.latestCheckpointSnapshotLeafId,F.phase=d.waiting,F.checkpointQueue=[],F.exhaustedPasses=[],F.invalidAttempts=0,F.baselinePending=!0,delete F.lastAttemptLeafId,U(),F.cycle+=1,F.pass=1,H(),y.recordEvent(r.AUTOCOMPACT_EVENT.contextCommitted,f(a,{"autocompact.request.id":u,"autocompact.cycle":p,"autocompact.pass":n,"autocompact.snapshot_leaf_id":g.doomAutocompact.snapshotLeafId,"autocompact.tokens_before":g.doomAutocompact.tokensBefore,"autocompact.message_count.before":s.length,"autocompact.message_count.retained":g.retainedMessages.length,"autocompact.apply_mode":_?`idle`:`turn_end`,...S(x)})),_&&ee(`Asynchronous compaction completed.`),!0},ie=(e,n,i)=>{if(!N)return;let a=P,o=n.sessionManager.getBranch(),s=m(n),c=t.createRequestId(n.sessionManager.getSessionId(),F.cycle,e,s),l=e>1?t.checkpointSummaryFromEntry(t.latestCheckpointArtifactEntry(o)):void 0,u=T(e,o,F.latestCheckpointSnapshotLeafId),p=v(z),h=f(n,{"autocompact.request.id":c,"autocompact.cycle":F.cycle,"autocompact.pass":e,"autocompact.snapshot_leaf_id":s,"autocompact.tokens_before":i,"autocompact.message_count.before":u.length});q(n,p,h),F.phase=d.checkpointPending,F.pass=e,F.requestId=c,F.snapshotLeafId=s,F.snapshotTokens=i,delete F.pendingCheckpoint,delete F.compactionPass,delete F.lastAttemptLeafId,H(),L?.abort(),L=new AbortController;let b=L.signal,x=y.runInSpan(`doom_autocompact.checkpoint`,h,async()=>{await y.recordEvent(r.AUTOCOMPACT_EVENT.checkpointStarted,h);try{let t=await _({messages:u,instructions:w(e,{plan:g(o),contextContributions:p,readFiles:F.readFiles,modifiedFiles:F.modifiedFiles}),...l?{previousCheckpoint:l}:{},context:n,signal:b});if(!N||a!==P)throw b.reason??Error(`Autocompact checkpoint became stale.`);if(!t.trim())throw Error(`Summarization returned an empty checkpoint.`);return await y.recordEvent(r.AUTOCOMPACT_EVENT.checkpointCompleted,{...h,"autocompact.checkpoint.characters":t.length}),t}catch(e){throw N&&a===P&&await y.recordError(r.AUTOCOMPACT_EVENT.checkpointFailed,e,h),e}}).then(e=>{!N||a!==P||c!==F.requestId||F.phase!==d.checkpointPending||(F.phase=d.checkpointReady,F.pendingCheckpoint=e.trim(),H(),I&&Q(I))}).catch(e=>{N&&a===P&&te(c,e)});M.add(x),x.finally(()=>M.delete(x))},Y=e=>{if(!N||F.phase!==d.waiting||e.hasPendingMessages())return!1;let n=D(e.cwd,t=>ne(e,t));if(!n.enabled)return!1;let r=e.getContextUsage();if(!r||r.tokens===null)return!1;if(F.baselinePending)return t.baselineUsageIsSettled(e.sessionManager.getBranch())?(F.baselineTokens=r.tokens,F.baselinePending=!1,H(),!1):!1;let i=m(e);if(F.lastAttemptLeafId===i)return!1;for(let e of[1,2,3])e<F.pass||F.checkpointQueue.includes(e)||F.exhaustedPasses.includes(e)||r.tokens>=t.thresholdTokens(e,r.contextWindow,F.baselineTokens,n.ratios)&&F.checkpointQueue.push(e);let a=F.checkpointQueue[0];return a?(ie(a,e,r.tokens),!0):!1},X=(n,r)=>{if(!N)return;let a=F.snapshotLeafId;i.appendEntry(e.CHECKPOINT_MESSAGE_TYPE,{...t.checkpointRequestDetails(F.cycle,n,F.requestId??`completed`),summary:r}),a&&(F.latestCheckpointSnapshotLeafId=a)},Z=e=>{if(!N||F.phase!==d.checkpointReady||!F.requestId||!F.pendingCheckpoint)return`none`;let n=F.pass,i=t.parseCheckpointDecision(F.pendingCheckpoint);if(!t.isStructuredCheckpoint(i.summary)){let t=F.snapshotLeafId,i=F.requestId,{attempts:a,exhausted:o}=K(n,t),s=Error(`Summarization pass ${n} returned an incomplete checkpoint.`);return A(e,o?`Doom autocompact summarization pass ${n} returned an incomplete checkpoint ${a} times and was abandoned.`:`Doom autocompact summarization pass ${n} returned an incomplete checkpoint.`,`error`),y.recordError(r.AUTOCOMPACT_EVENT.checkpointInvalid,s,f(e,{"autocompact.cycle":F.cycle,"autocompact.pass":n,"autocompact.checkpoint.attempts":a,"autocompact.checkpoint.exhausted":o,...i?{"autocompact.request.id":i}:{}})),`invalid`}return F.invalidAttempts=0,n===1?(X(1,i.summary),W(1),F.phase=d.waiting,F.pass=2,U(),H(),`pass1`):n===2&&i.shouldCompact!==!0?(X(2,i.summary),W(2),F.phase=d.waiting,F.pass=3,U(),H(),`deferred`):(F.pendingCheckpoint=i.summary,re(n,e)?`committed`:`invalid`)};function Q(e){N&&(I=e,e.isIdle()&&Z(e)!==`committed`&&Y(e))}i.on(`context`,(e,n)=>{if(!N)return;let i=t.projectContextMessages(e.messages,n.sessionManager.getBranch());if(i.invalidMarker){let e=n.sessionManager.getLeafId()??l;j.has(e)||(j.add(e),y.recordError(r.AUTOCOMPACT_EVENT.contextMarkerInvalid,Error(`Doom autocompact context marker is malformed.`),f(n,{"autocompact.leaf_id":e})));return}if(i.marker)return E.has(i.marker.requestId)||(E.add(i.marker.requestId),y.recordEvent(r.AUTOCOMPACT_EVENT.contextApplied,f(n,{"autocompact.request.id":i.marker.requestId,"autocompact.cycle":i.marker.cycle,"autocompact.pass":i.marker.pass,"autocompact.snapshot_leaf_id":i.marker.snapshotLeafId,"autocompact.tokens_before":i.marker.tokensBefore,"autocompact.message_count.before":e.messages.length,"autocompact.message_count.after":i.messages.length,"autocompact.message_count.retained":i.retainedMessageCount}))),{messages:i.messages}});let $=e=>{N&&(P+=1,L?.abort(Error(`Autocompact session generation was replaced.`)),L=void 0,E.clear(),j.clear(),I=e,G(e),Q(e))};i.on(`session_start`,(e,t)=>$(t)),i.on(`session_tree`,(e,t)=>$(t)),i.on(`turn_end`,(e,t)=>{if(N){if(I=t,t.isIdle()){Q(t);return}F.phase===d.checkpointReady&&(e.toolResults?.length??0)>0&&!t.hasPendingMessages()&&Z(t)!==`none`||Y(t)}}),i.on(`agent_settled`,(e,t)=>{N&&Q(t)}),i.on(`session_before_compact`,e=>{if(!(!N||e.reason!==`threshold`))return F.phase===d.checkpointPending||F.phase===d.checkpointReady||F.baselinePending?{cancel:!0}:void 0}),i.on(`session_compact`,(e,n)=>{if(!N)return;P+=1,L?.abort(),L=void 0;let a=t.fileDetailsFromUnknown(e.compactionEntry.details),o=t.mergeFileDetails(F,void 0,a);F.readFiles=o.readFiles,F.modifiedFiles=o.modifiedFiles,delete F.latestCheckpointSnapshotLeafId,F.baselinePending=!0,F.phase=d.waiting,U(),F.checkpointQueue=[],F.exhaustedPasses=[],F.invalidAttempts=0,delete F.lastAttemptLeafId,i.setLabel(e.compactionEntry.id,`autocompact:c${F.cycle}:external`);let s=F.cycle,c=f(n,{"autocompact.cycle":s,"autocompact.native.reason":e.reason}),l=J(n,n.sessionManager.getBranch(),c);F.cycle+=1,F.pass=1,H(),y.recordEvent(r.AUTOCOMPACT_EVENT.nativeCompactionCompleted,f(n,{"autocompact.cycle":s,"autocompact.native.reason":e.reason,"autocompact.native.from_extension":e.fromExtension,"autocompact.tokens_before":e.compactionEntry.tokensBefore,...S(l)}))})}async function M(e){let t=await(0,a.connectDoomCordisHost)(e,`@agimon-ai/doompi-autocompact`),n=t.root.plugin(N,{pi:e});try{await n}catch(e){try{await n.dispose()}finally{await t.dispose()}throw e}let r;e.on(`session_shutdown`,()=>r??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}function N(e,t){j(e,t.pi)}exports.autocompactExtension=M,exports.default=M,exports.autocompactRuntimeConfig=D,exports.generateCheckpointWithPi=k,exports.installAutocompactRuntime=j,exports.resolveDoomSummarizationModel=O;
43
+ ## Critical Context`}function E(e,n,r){let i=t.projectContextMessages((0,l.buildSessionContext)(n).messages,n).messages;if(e===1||!r)return i;let a=n.findIndex(e=>e.id===r);return a===-1?i:n.slice(a+1).filter(e=>e.type!==`custom_message`||e.customType!==`doom-autocompact-checkpoint`).flatMap(e=>(0,l.sessionEntryToContextMessages)(e))}const D={enabled:!0,ratios:{},overrides:[]};function O(e,t){let n;try{n=(0,a.loadDoomConfig)((0,a.getHarnessState)().root??e).modes}catch(e){return process.emitWarning(`Doom autocompact configuration could not be loaded; using the active session model instead.`),t?.(e),D}let r=n?.autocompact,i=(r&&(r.model!==void 0||r.thinking!==void 0)?{...r.model?{model:r.model}:{},...r.thinking?{thinking:r.thinking}:{}}:void 0)??n?.planning?.subagents,o=r?.thresholds;return{enabled:r?.enabled??!0,...i?{agent:i}:{},ratios:{...o?.pass1===void 0?{}:{1:o.pass1},...o?.pass2===void 0?{}:{2:o.pass2},...o?.pass3===void 0?{}:{3:o.pass3}},overrides:r?.overrides??[]}}function k(e){let t=O(e.cwd).agent,n=t?.model?r.parseModelReference(t.model):void 0,i=n?e.modelRegistry.find(n.provider,n.modelId):void 0,a=i??e.model;if(!a)return;let o=t?.thinking??(i?n?.thinking:void 0)??e.thinkingLevel;return{model:a,...o?{thinkingLevel:o}:{}}}async function A(e,t){let n=t(e.context);if(!n)throw Error(`No active model is available for autocompact summarization.`);let r=await e.context.modelRegistry.getApiKeyAndHeaders(n.model);if(!r.ok)throw Error(r.error);let i=e.context.modelRegistry.getProvider(n.model.provider);if(!i)throw Error(`No provider is registered for "${n.model.provider}" in this session.`);return(0,l.generateSummary)(e.messages,n.model,l.DEFAULT_COMPACTION_SETTINGS.reserveTokens,r.apiKey,r.headers,e.signal,e.instructions,e.previousCheckpoint,n.thinkingLevel,(e,t,n)=>i.streamSimple(e,t,n),r.env)}function j(e,t,n=`info`){e?.hasUI&&e.ui.notify(t,n)}function M(r,a,o={}){let g=o.resolveModel??k,v=o.generateCheckpoint??(e=>A(e,g)),b=o.telemetry??i.createAutocompactTelemetry(),w=o.doomIntegrations??!0,D=new Set,M=new Set,N=new Set,P=!0,F=0,I=t.createInitialState(),L,R,z,B,V=!1;r.effect(()=>async()=>{P=!1,F+=1,R?.abort(Error(`Autocompact runtime is shutting down.`)),R=void 0,await Promise.allSettled(N),z=void 0,B=void 0,L=void 0,D.clear(),M.clear(),I=t.createInitialState(),V=!1,await b.shutdown()},`${d}/runtime`),r.inject([s.DOOM_CONTEXT_CONTRIBUTIONS_SERVICE],e=>{let t=(0,s.requireDoomContextContributions)(e);return B=t,()=>{B===t&&(B=void 0)}}),w&&r.inject([c.DOOM_UI_HUB_SERVICE],e=>{let t=(0,c.requireDoomUiHub)(e).registerFooter({source:d,id:`autocompact`,order:20});return z=t,()=>{t.dispose(),z===t&&(z=void 0)}});let H=e=>{if(!P)return;let t=I.phase===f.checkpointPending?`summarizing`:I.phase===f.checkpointReady?`applying`:void 0;z?.update(t?{fullText:`Compacting p${I.pass}`,compactText:`C${I.pass}`}:void 0);let n=e??L;n?.hasUI&&n.ui.setStatus(`doom-autocompact`,t?`Compacting pass ${I.pass} (${t})…`:void 0)},U=()=>{P&&(a.appendEntry(e.STATE_CUSTOM_TYPE,{...I}),H())},W=()=>{delete I.requestId,delete I.snapshotLeafId,delete I.snapshotTokens,delete I.pendingCheckpoint,delete I.compactionPass},G=e=>{I.checkpointQueue=I.checkpointQueue.filter(t=>t!==e)},ee=e=>{P&&(I=m(e.sessionManager.getBranch())??t.createInitialState(),!(I.phase===f.checkpointReady&&I.requestId&&I.snapshotLeafId&&I.pendingCheckpoint||I.phase===f.waiting)&&(R?.abort(),R=void 0,I.phase=f.waiting,W(),U()))},te=t=>{P&&a.sendMessage({customType:e.RESUME_MESSAGE_TYPE,content:`${t} Continue from the compacted checkpoint's immediate next action without repeating completed work.`,display:!1,details:{version:2,cycle:I.cycle,pass:I.pass}},{triggerTurn:!0,deliverAs:`steer`})},K=(e,t)=>{let n=I.invalidAttempts+1,r=n>=3;return I.phase=f.waiting,t&&(I.lastAttemptLeafId=t),r?(G(e),I.exhaustedPasses=[...I.exhaustedPasses,e],I.invalidAttempts=0):I.invalidAttempts=n,W(),U(),{attempts:n,exhausted:r}},ne=(e,t)=>{if(!P||e!==I.requestId||I.phase!==f.checkpointPending)return;let n=I.pass,{attempts:r,exhausted:i}=K(n,I.snapshotLeafId),a=t instanceof Error?t.message:String(t);j(L,i?`Doom autocompact summarization pass ${n} failed ${r} times and was abandoned: ${a}`:`Doom autocompact summarization pass ${n} failed: ${a}`,`error`)},re=(e,t)=>{P&&!V&&(V=!0,b.recordWarning(i.AUTOCOMPACT_EVENT.configurationLoadFailed,t,p(e,{"autocompact.cycle":I.cycle,"autocompact.pass":I.pass})))},q=(e,t,n)=>{if(P)for(let r of t.errors)j(e,`Doom autocompact context contribution degraded (${r.source}/${r.id}): ${r.message}`,`warning`),b.recordWarning(i.AUTOCOMPACT_EVENT.contextContributionDegraded,Error(r.message),{...n,"autocompact.context_contribution.source":r.source,"autocompact.context_contribution.id":r.id,"autocompact.context_contribution.order":r.order})},J=(t,n,r)=>{if(!P)return{contributions:[],contributionErrors:[]};let i=y(B);q(t,i,r);let o=x(n,i);return a.sendMessage({customType:e.RUNTIME_STATE_MESSAGE_TYPE,content:S(o),display:!1,details:{version:2,...o}}),o},ie=(n,r)=>{if(!P||!I.requestId||!I.snapshotLeafId||!I.pendingCheckpoint)return!1;let o=r.sessionManager.getBranch(),s=t.projectContextMessages((0,l.buildSessionContext)(o).messages,o).messages,c=t.mergeFileDetails(I,t.fileOperationsFromMessages(s)),u=I.requestId,d=I.cycle,m=t.withCanonicalFileSections(I.pendingCheckpoint,c),g={...c,doomAutocompact:{version:2,cycle:d,pass:n,requestId:u,snapshotLeafId:I.snapshotLeafId,tokensBefore:I.snapshotTokens??r.getContextUsage()?.tokens??0},retainedMessages:t.retainedMessagesAfterSnapshot(o,I.snapshotLeafId)},_=r.isIdle();a.sendMessage({customType:e.CONTEXT_MESSAGE_TYPE,content:m,display:!1,details:g});let v=h(r),y=p(r,{"autocompact.request.id":u,"autocompact.cycle":d,"autocompact.pass":n}),x=J(r,o,y);return _&&a.setLabel(v,`autocompact:c${d}:p${n}`),I.readFiles=c.readFiles,I.modifiedFiles=c.modifiedFiles,delete I.latestCheckpointSnapshotLeafId,I.phase=f.waiting,I.checkpointQueue=[],I.exhaustedPasses=[],I.invalidAttempts=0,I.baselinePending=!0,delete I.lastAttemptLeafId,W(),I.cycle+=1,I.pass=1,U(),b.recordEvent(i.AUTOCOMPACT_EVENT.contextCommitted,p(r,{"autocompact.request.id":u,"autocompact.cycle":d,"autocompact.pass":n,"autocompact.snapshot_leaf_id":g.doomAutocompact.snapshotLeafId,"autocompact.tokens_before":g.doomAutocompact.tokensBefore,"autocompact.message_count.before":s.length,"autocompact.message_count.retained":g.retainedMessages.length,"autocompact.apply_mode":_?`idle`:`turn_end`,...C(x)})),_&&te(`Asynchronous compaction completed.`),!0},ae=(e,n,r)=>{if(!P)return;let a=F,o=n.sessionManager.getBranch(),s=h(n),c=t.createRequestId(n.sessionManager.getSessionId(),I.cycle,e,s),l=e>1?t.checkpointSummaryFromEntry(t.latestCheckpointArtifactEntry(o)):void 0,u=E(e,o,I.latestCheckpointSnapshotLeafId),d=y(B),m=p(n,{"autocompact.request.id":c,"autocompact.cycle":I.cycle,"autocompact.pass":e,"autocompact.snapshot_leaf_id":s,"autocompact.tokens_before":r,"autocompact.message_count.before":u.length});q(n,d,m),I.phase=f.checkpointPending,I.pass=e,I.requestId=c,I.snapshotLeafId=s,I.snapshotTokens=r,delete I.pendingCheckpoint,delete I.compactionPass,delete I.lastAttemptLeafId,U(),R?.abort(),R=new AbortController;let g=R.signal,x=b.runInSpan(`doom_autocompact.checkpoint`,m,async()=>{await b.recordEvent(i.AUTOCOMPACT_EVENT.checkpointStarted,m);try{let t=await v({messages:u,instructions:T(e,{plan:_(o),contextContributions:d,readFiles:I.readFiles,modifiedFiles:I.modifiedFiles}),...l?{previousCheckpoint:l}:{},context:n,signal:g});if(!P||a!==F)throw g.reason??Error(`Autocompact checkpoint became stale.`);if(!t.trim())throw Error(`Summarization returned an empty checkpoint.`);return await b.recordEvent(i.AUTOCOMPACT_EVENT.checkpointCompleted,{...m,"autocompact.checkpoint.characters":t.length}),t}catch(e){throw P&&a===F&&await b.recordError(i.AUTOCOMPACT_EVENT.checkpointFailed,e,m),e}}).then(e=>{P&&a===F&&c===I.requestId&&I.phase===f.checkpointPending&&(I.phase=f.checkpointReady,I.pendingCheckpoint=e.trim(),U(),L&&Q(L))}).catch(e=>{P&&a===F&&ne(c,e)});N.add(x),x.finally(()=>N.delete(x))},Y=e=>{if(!P||I.phase!==f.waiting||e.hasPendingMessages())return!1;let r=O(e.cwd,t=>re(e,t));if(!r.enabled)return!1;let i=e.getContextUsage();if(!i||i.tokens===null)return!1;if(I.baselinePending)return t.baselineUsageIsSettled(e.sessionManager.getBranch())?(I.baselineTokens=i.tokens,I.baselinePending=!1,U(),!1):!1;let a=h(e);if(I.lastAttemptLeafId===a)return!1;let o=n.resolveModelTokenOverrides(e.model,r.overrides),s=t.effectiveThresholds(i.contextWindow,I.baselineTokens,r.ratios,o);for(let e of[1,2,3])e<I.pass||I.checkpointQueue.includes(e)||I.exhaustedPasses.includes(e)||i.tokens>=s[e]&&I.checkpointQueue.push(e);let c=I.checkpointQueue[0];return c?(ae(c,e,i.tokens),!0):!1},X=(n,r)=>{if(!P)return;let i=I.snapshotLeafId;a.appendEntry(e.CHECKPOINT_MESSAGE_TYPE,{...t.checkpointRequestDetails(I.cycle,n,I.requestId??`completed`),summary:r}),i&&(I.latestCheckpointSnapshotLeafId=i)},Z=e=>{if(!P||I.phase!==f.checkpointReady||!I.requestId||!I.pendingCheckpoint)return`none`;let n=I.pass,r=t.parseCheckpointDecision(I.pendingCheckpoint);if(!t.isStructuredCheckpoint(r.summary)){let t=I.snapshotLeafId,r=I.requestId,{attempts:a,exhausted:o}=K(n,t),s=Error(`Summarization pass ${n} returned an incomplete checkpoint.`);return j(e,o?`Doom autocompact summarization pass ${n} returned an incomplete checkpoint ${a} times and was abandoned.`:`Doom autocompact summarization pass ${n} returned an incomplete checkpoint.`,`error`),b.recordError(i.AUTOCOMPACT_EVENT.checkpointInvalid,s,p(e,{"autocompact.cycle":I.cycle,"autocompact.pass":n,"autocompact.checkpoint.attempts":a,"autocompact.checkpoint.exhausted":o,...r?{"autocompact.request.id":r}:{}})),`invalid`}return I.invalidAttempts=0,n===1?(X(1,r.summary),G(1),I.phase=f.waiting,I.pass=2,W(),U(),`pass1`):n===2&&r.shouldCompact!==!0?(X(2,r.summary),G(2),I.phase=f.waiting,I.pass=3,W(),U(),`deferred`):(I.pendingCheckpoint=r.summary,ie(n,e)?`committed`:`invalid`)};function Q(e){P&&(L=e,e.isIdle()&&Z(e)!==`committed`&&Y(e))}a.on(`context`,(e,n)=>{if(!P)return;let r=t.projectContextMessages(e.messages,n.sessionManager.getBranch());if(r.invalidMarker){let e=n.sessionManager.getLeafId()??u;M.has(e)||(M.add(e),b.recordError(i.AUTOCOMPACT_EVENT.contextMarkerInvalid,Error(`Doom autocompact context marker is malformed.`),p(n,{"autocompact.leaf_id":e})));return}if(r.marker)return D.has(r.marker.requestId)||(D.add(r.marker.requestId),b.recordEvent(i.AUTOCOMPACT_EVENT.contextApplied,p(n,{"autocompact.request.id":r.marker.requestId,"autocompact.cycle":r.marker.cycle,"autocompact.pass":r.marker.pass,"autocompact.snapshot_leaf_id":r.marker.snapshotLeafId,"autocompact.tokens_before":r.marker.tokensBefore,"autocompact.message_count.before":e.messages.length,"autocompact.message_count.after":r.messages.length,"autocompact.message_count.retained":r.retainedMessageCount}))),{messages:r.messages}});let $=e=>{P&&(F+=1,R?.abort(Error(`Autocompact session generation was replaced.`)),R=void 0,D.clear(),M.clear(),L=e,ee(e),Q(e))};a.on(`session_start`,(e,t)=>$(t)),a.on(`session_tree`,(e,t)=>$(t)),a.on(`turn_end`,(e,t)=>{if(P){if(L=t,t.isIdle()){Q(t);return}I.phase===f.checkpointReady&&(e.toolResults?.length??0)>0&&!t.hasPendingMessages()&&Z(t)!==`none`||Y(t)}}),a.on(`agent_settled`,(e,t)=>{P&&Q(t)}),a.on(`session_before_compact`,e=>{if(P&&e.reason===`threshold`)return I.phase===f.checkpointPending||I.phase===f.checkpointReady||I.baselinePending?{cancel:!0}:void 0}),a.on(`session_compact`,(e,n)=>{if(!P)return;F+=1,R?.abort(),R=void 0;let r=t.fileDetailsFromUnknown(e.compactionEntry.details),o=t.mergeFileDetails(I,void 0,r);I.readFiles=o.readFiles,I.modifiedFiles=o.modifiedFiles,delete I.latestCheckpointSnapshotLeafId,I.baselinePending=!0,I.phase=f.waiting,W(),I.checkpointQueue=[],I.exhaustedPasses=[],I.invalidAttempts=0,delete I.lastAttemptLeafId,a.setLabel(e.compactionEntry.id,`autocompact:c${I.cycle}:external`);let s=I.cycle,c=p(n,{"autocompact.cycle":s,"autocompact.native.reason":e.reason}),l=J(n,n.sessionManager.getBranch(),c);I.cycle+=1,I.pass=1,U(),b.recordEvent(i.AUTOCOMPACT_EVENT.nativeCompactionCompleted,p(n,{"autocompact.cycle":s,"autocompact.native.reason":e.reason,"autocompact.native.from_extension":e.fromExtension,"autocompact.tokens_before":e.compactionEntry.tokensBefore,...C(l)}))})}async function N(e){let t=await(0,o.connectDoomCordisHost)(e,`@agimon-ai/doompi-autocompact`),n=t.root.plugin(P,{pi:e});try{await n}catch(e){try{await n.dispose()}finally{await t.dispose()}throw e}let r;e.on(`session_shutdown`,()=>r??=(async()=>{try{await n.dispose()}finally{await t.dispose()}})())}function P(e,t){M(e,t.pi)}exports.autocompactExtension=N,exports.default=N,exports.autocompactRuntimeConfig=O,exports.generateCheckpointWithPi=A,exports.installAutocompactRuntime=M,exports.resolveDoomSummarizationModel=k;
44
44
  //# sourceMappingURL=extension.cjs.map