billion-context-pi-lean 0.1.83-lean.10 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,23 +9,18 @@
9
9
 
10
10
  Context management for the [Pi coding agent](https://github.com/earendil-works/pi-coding-agent) that lets long sessions keep going: as context fills up, the model folds finished work into summary blocks, and the originals stay recoverable on demand.
11
11
 
12
- This is a fork of [`billion-context-pi`](https://github.com/ranxianglei/billion-context-pi) **v0.1.83** that focuses on runtime stability and on spending fewer tokens. It keeps upstream's compression engine (ACP); the main additions are that **a cheap model can write the summaries** and that **context management itself costs fewer tokens**. Upstream has moved on to [`billion-context`](https://github.com/ranxianglei/billion-context); this fork stays on 0.1.83 and picks upstream fixes by hand. It is not affiliated with upstream.
12
+ This is a fork of [`billion-context-pi`](https://github.com/ranxianglei/billion-context-pi) **v0.1.83** that focuses on runtime stability and on spending fewer tokens. It keeps upstream's compression engine (ACP); the main additions are that **a cheap model can write the summaries**, that **context management itself costs fewer tokens**, and that **a long session is compressed while you are away**, before the prompt cache expires. Upstream has moved on to [`billion-context`](https://github.com/ranxianglei/billion-context); this fork stays on 0.1.83 and picks upstream fixes by hand. It is not affiliated with upstream.
13
13
 
14
- ## Context footprint benchmark
15
-
16
- With only this extension enabled, its recurring model-facing initialization contribution is:
14
+ ## How it works
17
15
 
18
- | Variant | Tool and prompt contribution | Total |
19
- | --- | --- | ---: |
20
- | Lean `billion-context-pi-lean@0.1.83-lean.10` | `compress` (231) + `acp_context` (87) + prompt (168) | **486** |
21
- | Upstream `billion-context-pi@0.1.83` with `promptPack: "lean"` | `compress` (389) + `decompress` (271) + `search_context` (90) + `acp_status` (227) + `acp_cache` (204) + `acp_delegate` (1,452) + `acp_delegate_wait` (342) + `acp_delegate_cancel` (83) + prompt (1,819) | **4,877** |
22
- | Upstream `billion-context-pi@0.1.83` | `compress` (549) + `decompress` (546) + `search_context` (210) + `acp_status` (339) + `acp_cache` (204) + `acp_delegate` (1,452) + `acp_delegate_wait` (342) + `acp_delegate_cancel` (83) + prompt (4,945) | **8,670** |
16
+ ACP does not compress on its own. When old, finished work piles up, it adds a short **compress nudge** to the next request, listing the message ranges that could be folded. The main model picks ranges and calls `compress`; the **summary model** (the main model itself unless you choose another) writes the summaries, and each range is replaced by its summary block. The originals stay in the session and can be brought back.
23
17
 
24
- This saves **8,184 tokens (94.4%)** against upstream's default, and 4,391 tokens (90.0%) against its `lean` prompt pack. The three `acp_delegate*` tools (1,877 tokens) belong to sub-agent delegation, which this fork removed; leaving them out, the savings are 92.8% and 83.8%.
18
+ The model sees two tools:
25
19
 
26
- Compression nudges come on top of this and only when context fills up. With a dedicated summary model, the rules in each nudge drop from about 1,460 tokens to about 220 ([setup](#use-a-cheap-model-for-summaries)).
20
+ - `compress`: fold finished message ranges into summary blocks.
21
+ - `acp_context`: `decompress`, `search_context`, `acp_status`, `acp_cache` and `help`, e.g. `{ "op": "search_context", "args": { "query": "authentication" } }`, to bring originals back or look things up.
27
22
 
28
- Measured with `npm run measure` on Pi 1.3.0, each variant in a separate temporary process with an empty working directory and configuration. Built-in tools, skills, context files, session history, user messages, unrelated extensions, runtime UI, and slash commands are excluded; `before_agent_start` additions are included. Tokens are a fixed character-proxy estimate using `ceil(characters / 4)`, not provider tokenizer billing.
23
+ With **Idle compact** on, the same nudge is also shown once when you step away, while the prompt cache is still warm, so you come back to a shorter context. When the [settings](#settings) make the nudge appear is up to you; as a last resort, at 95% of the window ACP cuts large tool outputs regardless.
29
24
 
30
25
  ## Main differences from upstream 0.1.83
31
26
 
@@ -34,6 +29,8 @@ Measured with `npm run measure` on Pi 1.3.0, each variant in a separate temporar
34
29
  | Who writes summaries | The main model, usually the expensive one | A **dedicated summary model** of your choice, e.g. a cheap one; the main model only picks the ranges |
35
30
  | Compression rules | Sent to the main model in every compression nudge (about 1,460 tokens; 720 with `promptPack: "lean"`) | Sent only to the summary model, so they no longer take up the main model's context; its nudge carries only a short range-picking note (about 220 tokens)\* |
36
31
  | Summary quality | General compression rules; only length is checked | Also: user requests are kept apart from what tools showed; open items are split into user objectives, suggestions and unverified risks. A failed or malformed summary is not folded; the range waits for a later attempt |
32
+ | Coming back after a break | The first request rewrites the whole long context at uncached prices | **[Idle compact](#idle-compact)**: before the cache expires, the model gets one chance to compress, so the request you send on return is shorter |
33
+ | Settings | Edit `acp.json` by hand | **[`/acp-config`](#configuration) panel**: pick values in the TUI, applied at once without restarting; `acp.json` still works |
37
34
  | Tools and resident prompt | 5 context tools + 3 delegation tools, about 8,700 tokens (4,900 with `promptPack: "lean"`) | `compress` + `acp_context`, 486 tokens ([benchmark](#context-footprint-benchmark)). The resident prompt keeps only rules needed before a call; the rest arrives with nudges, errors and tool results |
38
35
  | System prompt | Returns a whole system prompt, which on Pi 1.x drops prompt additions from extensions loaded after it | Added as its own section; other extensions keep theirs |
39
36
  | Sub-agent delegation, auto-update | Built in | Removed. Use a dedicated sub-agent extension; ACP still manages their sessions |
@@ -56,6 +53,22 @@ Details: [CHANGELOG.md](CHANGELOG.md), [MAINTENANCE.md](MAINTENANCE.md) (Chinese
56
53
 
57
54
  </details>
58
55
 
56
+ ## Context footprint benchmark
57
+
58
+ With only this extension enabled, its recurring model-facing initialization contribution is:
59
+
60
+ | Variant | Tool and prompt contribution | Total |
61
+ | --- | --- | ---: |
62
+ | Lean `billion-context-pi-lean@0.2.0` | `compress` (231) + `acp_context` (87) + prompt (168) | **486** |
63
+ | Upstream `billion-context-pi@0.1.83` with `promptPack: "lean"` | `compress` (389) + `decompress` (271) + `search_context` (90) + `acp_status` (227) + `acp_cache` (204) + `acp_delegate` (1,452) + `acp_delegate_wait` (342) + `acp_delegate_cancel` (83) + prompt (1,819) | **4,877** |
64
+ | Upstream `billion-context-pi@0.1.83` | `compress` (549) + `decompress` (546) + `search_context` (210) + `acp_status` (339) + `acp_cache` (204) + `acp_delegate` (1,452) + `acp_delegate_wait` (342) + `acp_delegate_cancel` (83) + prompt (4,945) | **8,670** |
65
+
66
+ This saves **8,184 tokens (94.4%)** against upstream's default, and 4,391 tokens (90.0%) against its `lean` prompt pack. The three `acp_delegate*` tools (1,877 tokens) belong to sub-agent delegation, which this fork removed; leaving them out, the savings are 92.8% and 83.8%.
67
+
68
+ Compression nudges come on top of this and only when context fills up. With a dedicated summary model, the rules in each nudge drop from about 1,460 tokens to about 220 ([setup](#settings)).
69
+
70
+ Measured with `npm run measure` on Pi 1.3.0, each variant in a separate temporary process with an empty working directory and configuration. Built-in tools, skills, context files, session history, user messages, unrelated extensions, runtime UI, and slash commands are excluded; `before_agent_start` additions are included. Tokens are a fixed character-proxy estimate using `ceil(characters / 4)`, not provider tokenizer billing.
71
+
59
72
  ## Install
60
73
 
61
74
  ```bash
@@ -68,51 +81,50 @@ Append `@<version>` to pin a version from [Releases](https://github.com/kunkun95
68
81
  - Do not enable it together with `billion-context-pi` or `billion-context`: tools and hooks would register twice.
69
82
  - Pi's built-in compaction is turned off while this extension is active.
70
83
 
71
- ## Use a cheap model for summaries
84
+ ## Configuration
72
85
 
73
- ```text
74
- /acp compact # show the current setting
75
- /acp compact <provider/model> # any model in Pi's model registry
76
- /acp compact session # the session's own model, in a separate call
77
- /acp compact reset # the main model writes summaries again
78
- ```
86
+ Type `/acp-config` in Pi to open the settings panel. Up/Down picks a setting, Enter or Space changes it, Esc closes. Changes apply at once, no restart needed.
79
87
 
80
- The choice is saved as `compressionModelId` in `~/.pi/acp.json` (a project's `.pi/acp.json` takes precedence).
88
+ ### Settings
81
89
 
82
- - Write `provider/id`. A bare id shared by several providers is rejected as ambiguous.
83
- - Models come from Pi's live registry, so providers registered by other extensions work too.
84
- - A model being listed does not mean its provider can serve it. If the call fails, that range stays uncompressed and is retried next time; `~/.pi/acp.log` records `compression-model-failed`. Only when the model cannot be resolved at all, or the host cannot make nested calls, does the main model's short summary get used, with a warning.
90
+ The panel lists these, most used first.
85
91
 
86
- ## Configuration
92
+ | Setting | What it does | Default |
93
+ |---|---|---|
94
+ | Summary model | Who writes the summaries. `main model`: the main model writes them itself. `session`: the current model, in a separate call that reuses its cached prefix. Or pick any model Pi can use (Enter opens the list; type to filter), e.g. a cheap one. If that model's call fails, the range stays uncompressed and is tried again next time. | `main model` |
95
+ | Idle compact | Compress once while you are away, before the prompt cache expires ([how it works](#idle-compact)). | `off` |
96
+ | Idle minutes | How long the session must be idle first. Keep it a little under your models' cache lifetime: 29 fits a 30-minute cache. | 29 |
97
+ | Context threshold | Share of the model's window above which the compress nudge no longer waits for Nudge interval and appears whenever Minimum benefit could be reclaimed. Lower keeps the context small; higher lets it run fuller. Not a hard cap. | 75% |
98
+ | Nudge interval | Below Context threshold, the nudge waits until about this many tokens of old, compressible content have piled up. Bigger: fewer nudges, more folded at once. Smaller: frequent small compressions, a leaner context. | 50K |
99
+ | Minimum benefit | No nudge, and no idle compact, when less than this could be reclaimed: rewriting a few thousand tokens is not worth breaking the cache. | larger of 5K and 1% of the window |
100
+ | Tool output cap | A single tool result larger than this is cut, with a note telling the model where the full output is. Pi's own bash and read already stop at 50KB, so this mainly catches MCP and other extensions' tools, which can return hundreds of KB at once. `off` keeps everything. | 50K bytes |
101
+ | bash default timeout | Seconds a bash command may run when the model gave no timeout. Pi has no default, so a stuck command would make the session wait forever; on timeout the model is told to re-run with a larger one. `off` means no limit. | 60 |
102
+ | Debug log | Writes detailed events to `~/.pi/acp.log` for troubleshooting. Errors and the main events are always logged. | `off` |
87
103
 
88
- Config files are `~/.pi/acp.json` and `<project>/.pi/acp.json`. Upstream options in [CONFIGURATION.md](CONFIGURATION.md) still apply, except:
89
-
90
- - `autoUpdate` is always off.
91
- - The removed delegation keys (`delegate.*`, `displayUsage`, `delegatePrompt`) are ignored.
92
- - `promptSections.*` is ignored because the fork injects its own prompt; you get a one-time warning.
93
-
94
- Compression timing can be tuned per provider and model:
95
-
96
- ```json
97
- {
98
- "compressionModelId": "<provider>/<cheap-model>",
99
- "compress": {
100
- "promptPack": "lean",
101
- "providers": {
102
- "<provider>": {
103
- "models": {
104
- "<main-model>": { "maxContextLimit": 0.4, "nudgeGrowthTokens": 70000, "minPressureBenefitTokens": 30000 }
105
- }
106
- }
107
- }
108
- }
109
- }
110
- ```
104
+ Context threshold, Nudge interval and Minimum benefit depend on the model's window and price, so the panel sets them for the **current model only**; switch models to set another one. `inherit` drops the model's own value; a provider-wide or global value from `acp.json`, or else the default, applies.
111
105
 
112
- ## Tools the model sees
106
+ Regardless of these settings, at 95% of the window ACP cuts large tool outputs as a last resort.
113
107
 
114
- - `compress`: fold finished message ranges into summary blocks.
115
- - `acp_context`: `decompress`, `search_context`, `acp_status`, `acp_cache` and `help`, e.g. `{ "op": "search_context", "args": { "query": "authentication" } }`.
108
+ ### Idle compact
109
+
110
+ Coming back to a long session after the prompt cache expired means the first request rewrites the whole context uncached. With Idle compact on, after Idle minutes without activity ACP starts one turn that shows the main model the compress nudge; the model decides whether to compress.
111
+
112
+ - Activity means a real model request: your messages, and also a sub-agent waking the session, so long background work does not count as idle.
113
+ - At most one such turn per idle period. Skipped when less than Minimum benefit could be reclaimed, outside the TUI and RPC modes, or when the timer fires more than a minute late (the machine slept).
114
+ - During that turn only ACP tools may run. If you type or a sub-agent result arrives, it becomes a normal turn.
115
+ - Idle minutes applies to every model. With a shorter cache (e.g. 5 minutes) that turn itself reads the long context uncached once.
116
+
117
+ ### Editing acp.json
118
+
119
+ The panel saves to `~/.pi/acp.json` and keeps every other key there. Edit the file yourself only for what the panel cannot do:
120
+
121
+ - **Per project:** `<project>/.pi/acp.json` overrides the global file. The panel shows the value in effect and warns when the project file overrides it.
122
+ - **Per provider:** the three compression timing settings can also be set for a whole provider or globally, not only for one model ([how](CONFIGURATION.md#compressproviders--per-provider--per-model-overrides)).
123
+ - **Options not in the panel**, e.g. `compress.emergencyThresholdPercent`. The full list is in [CONFIGURATION.md](CONFIGURATION.md), with these exceptions: `autoUpdate` and `ACP_AUTO_UPDATE` are gone (update with `pi install`); the removed delegation keys (`delegate.*`, `displayUsage`, `delegatePrompt`) are ignored; `promptSections.*` is ignored with a one-time warning, because this fork injects its own prompt.
124
+
125
+ Panel settings map to these keys: Summary model `compressionModelId`, Idle compact `idleCompact.enabled`, Idle minutes `idleCompact.idleMinutes`, Tool output cap `toolOutputMaxBytes`, bash default timeout `toolBashDefaultTimeout`, Debug log `debug`.
126
+
127
+ `/acp compact <provider/model>` sets the summary model from the command line (`/acp compact` shows it, `reset` returns to the main model).
116
128
 
117
129
  ## Development
118
130
 
@@ -7,7 +7,7 @@ var __export = (target, all) => {
7
7
  // src/contract.ts
8
8
  var SIDECAR_SCHEMA_VERSION = 1;
9
9
  function sidecarProducer() {
10
- return `billion-context-pi@${true ? "0.1.83-lean.10" : "dev"}`;
10
+ return `billion-context-pi@${true ? "0.2.0" : "dev"}`;
11
11
  }
12
12
 
13
13
  export {
@@ -15,4 +15,4 @@ export {
15
15
  SIDECAR_SCHEMA_VERSION,
16
16
  sidecarProducer
17
17
  };
18
- //# sourceMappingURL=chunk-HTPJ5GG7.js.map
18
+ //# sourceMappingURL=chunk-PPYOZRUP.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/contract.ts"],"sourcesContent":["/**\n * Machine-readable contract for the `<sessionFile>.acp.json` sidecar (#368).\n *\n * Downstream tools (e.g. pi-billion-memory) glob the sidecar directly instead\n * of running inside pi. To keep that stable across releases:\n *\n * - `schemaVersion` is written on every save. A MISSING version means v1\n * (pre-contract files). An unknown NEWER version means \"fields may have\n * changed\" — skip it, log once, never rewrite the file.\n * - `producer` identifies the writer (`billion-context-pi@x.y.z`).\n * - The file is replaced atomically (tmp + rename), so a reader either sees\n * the previous or the next complete file, never a torn write.\n * - Blocks are stored verbatim as the kernel's CompressionBlock; unknown\n * extra fields are additive and must be ignored by readers.\n */\nexport const SIDECAR_SCHEMA_VERSION = 1;\n\n/**\n * One compressed block, as persisted in the sidecar's `blocks[]`. Mirrors the\n * kernel's CompressionBlock (acp-kernel 0.0.81) — inlined rather than aliased\n * so this subpath carries no type dependency on acp-kernel (dev-only, bundled\n * at build time). Fields the kernel adds later are additive; tests assert the\n * kernel shape still covers this one.\n */\nexport interface BcpBlockV1 {\n blockId: string;\n runId: string;\n tier: 1 | 2 | 3;\n topic?: string;\n summary: string;\n directMessageIds: string[];\n effectiveMessageIds: string[];\n directBlockIds: string[];\n compressedTokens: number;\n createdAt: number;\n survivedCount: number;\n generation: \"young\" | \"old\";\n active: boolean;\n expanded?: boolean;\n durationMs?: number;\n compressCallId?: string;\n startRef?: string;\n endRef?: string;\n}\n\n/** Top-level shape of the sidecar (state fields beyond the contract allowed). */\nexport interface BcpSidecarV1 {\n schemaVersion: number;\n producer: string;\n blocks: BcpBlockV1[];\n [extra: string]: unknown;\n}\n\nexport function sidecarProducer(): string {\n return `billion-context-pi@${typeof CURRENT_VERSION !== \"undefined\" ? CURRENT_VERSION : \"dev\"}`;\n}\n\ndeclare const CURRENT_VERSION: string;\n"],"mappings":";;;;;;;AAeO,IAAM,yBAAyB;AAsC/B,SAAS,kBAA0B;AACxC,SAAO,sBAAsB,OAAyC,mBAAkB,KAAK;AAC/F;","names":[]}
1
+ {"version":3,"sources":["../src/contract.ts"],"sourcesContent":["/**\n * Machine-readable contract for the `<sessionFile>.acp.json` sidecar (#368).\n *\n * Downstream tools (e.g. pi-billion-memory) glob the sidecar directly instead\n * of running inside pi. To keep that stable across releases:\n *\n * - `schemaVersion` is written on every save. A MISSING version means v1\n * (pre-contract files). An unknown NEWER version means \"fields may have\n * changed\" — skip it, log once, never rewrite the file.\n * - `producer` identifies the writer (`billion-context-pi@x.y.z`).\n * - The file is replaced atomically (tmp + rename), so a reader either sees\n * the previous or the next complete file, never a torn write.\n * - Blocks are stored verbatim as the kernel's CompressionBlock; unknown\n * extra fields are additive and must be ignored by readers.\n */\nexport const SIDECAR_SCHEMA_VERSION = 1;\n\n/**\n * One compressed block, as persisted in the sidecar's `blocks[]`. Mirrors the\n * kernel's CompressionBlock (acp-kernel 0.0.81) — inlined rather than aliased\n * so this subpath carries no type dependency on acp-kernel (dev-only, bundled\n * at build time). Fields the kernel adds later are additive; tests assert the\n * kernel shape still covers this one.\n */\nexport interface BcpBlockV1 {\n blockId: string;\n runId: string;\n tier: 1 | 2 | 3;\n topic?: string;\n summary: string;\n directMessageIds: string[];\n effectiveMessageIds: string[];\n directBlockIds: string[];\n compressedTokens: number;\n createdAt: number;\n survivedCount: number;\n generation: \"young\" | \"old\";\n active: boolean;\n expanded?: boolean;\n durationMs?: number;\n compressCallId?: string;\n startRef?: string;\n endRef?: string;\n}\n\n/** Top-level shape of the sidecar (state fields beyond the contract allowed). */\nexport interface BcpSidecarV1 {\n schemaVersion: number;\n producer: string;\n blocks: BcpBlockV1[];\n [extra: string]: unknown;\n}\n\nexport function sidecarProducer(): string {\n return `billion-context-pi@${typeof CURRENT_VERSION !== \"undefined\" ? CURRENT_VERSION : \"dev\"}`;\n}\n\ndeclare const CURRENT_VERSION: string;\n"],"mappings":";;;;;;;AAeO,IAAM,yBAAyB;AAsC/B,SAAS,kBAA0B;AACxC,SAAO,sBAAsB,OAAyC,UAAkB,KAAK;AAC/F;","names":[]}
@@ -0,0 +1,61 @@
1
+ import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
+ import { type Component } from "@earendil-works/pi-tui";
3
+ import type { AdapterConfig } from "./config.js";
4
+ import { type IdleCompactHandle } from "./idle-compact.js";
5
+ import type { AcpRuntime } from "./runtime.js";
6
+ /** `/acp-config`: TUI settings panel over the GLOBAL ~/.pi/acp.json. Values
7
+ * shown are the effective ones (project acp.json included); changes are
8
+ * written to the global file and applied at once via reloadConfig. */
9
+ export interface PanelScope {
10
+ provider?: string;
11
+ modelId?: string;
12
+ }
13
+ type Raw = Record<string, unknown>;
14
+ export interface PanelItem {
15
+ id: string;
16
+ label: string;
17
+ description: string;
18
+ /** Model-scoped items need a current model. */
19
+ model?: boolean;
20
+ /** Upstream switch: while it reads off, this item shows off and is locked;
21
+ * its stored value is kept so turning the switch back on restores it. */
22
+ dependsOn?: string;
23
+ values?: (current: string) => string[];
24
+ read(adapter: AdapterConfig, scope: PanelScope): string;
25
+ write(raw: Raw, value: string, scope: PanelScope): void;
26
+ }
27
+ /** Order = importance: summary model and idle compact first, per-model
28
+ * compression next, tool guardrails and debug last. */
29
+ export declare const PANEL_ITEMS: PanelItem[];
30
+ export declare function panelItemsFor(scope: PanelScope): PanelItem[];
31
+ /** Apply one panel change to a parsed acp.json object (mutates). */
32
+ export declare function applyPanelValue(raw: Raw, id: string, value: string, scope: PanelScope): void;
33
+ export declare function readPanelValue(adapter: AdapterConfig, id: string, scope: PanelScope): string;
34
+ /** What the panel shows for an item: locked at off (no values to cycle) while its upstream is off. */
35
+ export declare function panelDisplay(item: PanelItem, adapter: AdapterConfig, scope: PanelScope): {
36
+ currentValue: string;
37
+ values?: string[];
38
+ locked: boolean;
39
+ };
40
+ export declare function makeConfigCommand(runtime: AcpRuntime, idle: IdleCompactHandle | undefined): {
41
+ name: string;
42
+ options: {
43
+ description: string;
44
+ handler: (_args: string, ctx: ExtensionCommandContext) => Promise<void>;
45
+ };
46
+ };
47
+ /** Model picker for the summary-model submenu: typing filters (fuzzy, like
48
+ * Pi's own pickers), arrows move, Enter picks, Esc goes back. */
49
+ export declare class SearchableList implements Component {
50
+ private readonly choices;
51
+ private readonly close;
52
+ private readonly dim;
53
+ private readonly input;
54
+ private list;
55
+ constructor(choices: string[], current: string, close: (value?: string) => void, dim: (text: string) => string);
56
+ private rebuild;
57
+ render(width: number): string[];
58
+ invalidate(): void;
59
+ handleInput(data: string): void;
60
+ }
61
+ export {};
package/dist/config.d.ts CHANGED
@@ -2,6 +2,7 @@ import { type Config, type Prompts } from "acp-kernel";
2
2
  import type { CompressReasoningConfig } from "./reasoning-drop.js";
3
3
  import type { DegenerationGuardConfig } from "./degeneration.js";
4
4
  import type { ThrottleRetryConfig } from "./throttle-retry.js";
5
+ import type { IdleCompactConfig } from "./idle-compact.js";
5
6
  import type { PiPromptSections } from "./system-prompt.js";
6
7
  import type { NudgeSectionsConfig, ToolPromptsConfig } from "./surface.js";
7
8
  /** Compression tuning fields, shared by all three levels (global, provider,
@@ -139,10 +140,6 @@ export interface AdapterConfig {
139
140
  * protect-everything instead). */
140
141
  preserveRecentTools?: string[];
141
142
  preserveRecentMessages?: number;
142
- /** Check npm for a newer billion-context-pi on startup and auto-install it. Default: true.
143
- * Disable via `autoUpdate: false` or env `ACP_AUTO_UPDATE=0` to avoid all
144
- * network calls on startup. */
145
- autoUpdate?: boolean;
146
143
  /** Enable debug-level events in the ACP log file (default ~/.pi/acp.log).
147
144
  * Always-on events (session/turn/compress lifecycle, all errors and
148
145
  * warnings) are written regardless; `debug` only adds verbose diagnostics.
@@ -171,6 +168,11 @@ export interface AdapterConfig {
171
168
  * disables) or a ThrottleRetryConfig object. Default: enabled, 10 retries,
172
169
  * 60s exponential base capped at 300s per kick. */
173
170
  throttleRetry?: boolean | ThrottleRetryConfig;
171
+ /** Lean: idle compaction check (src/idle-compact.ts). After `idleMinutes`
172
+ * (default 29) of idle time, one turn shows the main model the compress
173
+ * nudge so it can compress while the prefix is still cached.
174
+ * `true` or `{ enabled: true, idleMinutes: 29 }`. Default: off. */
175
+ idleCompact?: boolean | IdleCompactConfig;
174
176
  /** Cap on the output-headroom reservation as a fraction of the context
175
177
  * window: reserved = min(model.maxTokens, pct * window). Accepts a ratio
176
178
  * (0.25) or percent string ("25%"). Default: 0.25. Set 0 to disable the
package/dist/contract.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SIDECAR_SCHEMA_VERSION,
3
3
  sidecarProducer
4
- } from "./chunk-HTPJ5GG7.js";
4
+ } from "./chunk-PPYOZRUP.js";
5
5
  export {
6
6
  SIDECAR_SCHEMA_VERSION,
7
7
  sidecarProducer
@@ -0,0 +1,39 @@
1
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import type { NudgeDecision } from "acp-kernel";
3
+ import type { AcpRuntime } from "./runtime.js";
4
+ /**
5
+ * Idle compaction check (Lean). After the session has been idle for
6
+ * `idleMinutes` (default 29, just inside a 30-minute prompt cache), start one
7
+ * turn that shows the main model the regular compress nudge and lets it decide
8
+ * whether to compress. If the cache is still warm, that turn reads the long
9
+ * prefix from cache, and the request the user sends on return carries the
10
+ * shorter context instead of rewriting the long one uncached.
11
+ *
12
+ * Timing follows pi-keepwarm: the anchor is the start of the last provider
13
+ * request of a run. Any run counts (user input, sub-agent wake, throttle kick)
14
+ * except the idle check itself, so one idle period gets at most one check.
15
+ */
16
+ export declare const IDLE_CHECK_CUSTOM_TYPE = "acp-idle-check";
17
+ export declare const DEFAULT_IDLE_MINUTES = 29;
18
+ /** Timer woke this much later than planned (machine slept): the cache is likely cold, skip. */
19
+ export declare const IDLE_LATE_MS = 60000;
20
+ export interface IdleCompactConfig {
21
+ enabled?: boolean;
22
+ /** Minutes of idle time before the check. Default 29. */
23
+ idleMinutes?: number;
24
+ }
25
+ export interface ResolvedIdleCompact {
26
+ enabled: boolean;
27
+ idleMinutes: number;
28
+ }
29
+ export declare function resolveIdleCompact(cfg: boolean | IdleCompactConfig | undefined): ResolvedIdleCompact;
30
+ export declare function idleCheckText(awayMinutes: number): string;
31
+ export interface IdleCompactHandle {
32
+ /** Record the last context event's compressible mass (context hook, every event). */
33
+ noteNudge(sid: string, nudge: NudgeDecision | undefined): void;
34
+ /** True once per idle check: the context hook appends the nudge even below its usual thresholds. */
35
+ takeForcedNudge(sid: string): boolean;
36
+ /** Re-plan the pending timer after the config changed (settings panel). */
37
+ rearm(): void;
38
+ }
39
+ export declare function wireIdleCompact(pi: ExtensionAPI, runtime: AcpRuntime): IdleCompactHandle;