pi-reasoning-zip 0.2.5 → 0.2.6

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/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.6] - 2026-07-03
11
+
12
+ ### Changed
13
+
14
+ - Replaced `thresholds.targetRatio` with `compressionRole` presets for compactor prompt style.
15
+
10
16
  ## [0.2.5] - 2026-07-03
11
17
 
12
18
  ### Fixed
@@ -78,7 +84,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
78
84
  - Added package motto to README.
79
85
  - Added npm release metadata: description, keywords, repository links, exports, and Node engine.
80
86
 
81
- [Unreleased]: https://github.com/Ryu-CZ/pi-reasoning-zip/compare/v0.2.5...HEAD
87
+ [Unreleased]: https://github.com/Ryu-CZ/pi-reasoning-zip/compare/v0.2.6...HEAD
88
+ [0.2.6]: https://github.com/Ryu-CZ/pi-reasoning-zip/compare/v0.2.5...v0.2.6
82
89
  [0.2.5]: https://github.com/Ryu-CZ/pi-reasoning-zip/compare/v0.2.4...v0.2.5
83
90
  [0.2.4]: https://github.com/Ryu-CZ/pi-reasoning-zip/compare/v0.2.3...v0.2.4
84
91
  [0.2.3]: https://github.com/Ryu-CZ/pi-reasoning-zip/compare/v0.2.2...v0.2.3
package/README.md CHANGED
@@ -27,7 +27,7 @@ Compress reasoning blocks to keep the context short.
27
27
  verbose thinking block -> facts / decisions / constraints / failed / next
28
28
  ```
29
29
 
30
- Use this when local models expose long reasoning and you want future Pi turns to replay compact traces instead of raw reasoning haystacks.
30
+ Use this when local models expose long reasoning and you want future Pi turns to replay compact traces instead of raw reasoning as verbose prose.
31
31
 
32
32
  ## Install
33
33
 
@@ -83,6 +83,7 @@ Settings live in project `.pi/settings.json` or global `~/.pi/agent/settings.jso
83
83
  "enabled": true,
84
84
  "mode": "llama-only",
85
85
  "storageMode": "compact-new",
86
+ "compressionRole": "grug",
86
87
  "injectPrompt": true,
87
88
  "compactor": {
88
89
  "baseUrl": "http://127.0.0.1:7484/v1",
@@ -94,7 +95,6 @@ Settings live in project `.pi/settings.json` or global `~/.pi/agent/settings.jso
94
95
  },
95
96
  "thresholds": {
96
97
  "minChars": 1000,
97
- "targetRatio": 0.15,
98
98
  "maxTraceChars": 2000
99
99
  }
100
100
  }
@@ -117,6 +117,14 @@ Settings live in project `.pi/settings.json` or global `~/.pi/agent/settings.jso
117
117
  | `compact-new` | Compact new assistant thinking before storage |
118
118
  | `off` | Do not alter assistant messages |
119
119
 
120
+ ### Compression roles
121
+
122
+ | Role | Behavior |
123
+ |---|---|
124
+ | `balanced` | concise bullets while preserving extra context |
125
+ | `grug` | terse, keyword-heavy default |
126
+ | `ultra-grug` | most aggressive fragment-style trace |
127
+
120
128
  ## Compactor endpoint
121
129
 
122
130
  The compactor must expose an OpenAI-compatible chat completions endpoint:
@@ -142,7 +150,7 @@ next:
142
150
  - ...
143
151
  ```
144
152
 
145
- If the compactor returns `none`, empty output, output above `thresholds.targetRatio` of the original length, output longer than the original, or output over `thresholds.maxTraceChars`, the original block is preserved.
153
+ The configured `compressionRole` guides the compactor's terse style. If the compactor returns `none`, empty output, output longer than the original, or output over `thresholds.maxTraceChars`, the original block is preserved.
146
154
 
147
155
  ## Safety model
148
156
 
@@ -1 +1,2 @@
1
- export declare function buildCompactionPrompt(thinking: string): string;
1
+ import type { ReasoningZipCompressionRole } from "./types.js";
2
+ export declare function buildCompactionPrompt(thinking: string, compressionRole?: ReasoningZipCompressionRole): string;
@@ -1,10 +1,15 @@
1
- export function buildCompactionPrompt(thinking) {
1
+ const ROLE_INSTRUCTIONS = {
2
+ balanced: "Compression role: balanced. Use concise bullets, but keep enough context that another coding agent can continue without guessing.",
3
+ grug: "Compression role: grug. Few words. Keyword-heavy. No prose. Keep only useful state for the next coding turn.",
4
+ "ultra-grug": "Compression role: ultra-grug. Compress hard. Fragment bullets only. Symbols and exact names over sentences. Keep only critical state.",
5
+ };
6
+ export function buildCompactionPrompt(thinking, compressionRole = "grug") {
2
7
  return `Compress this model reasoning into a compact decision trace for future coding-agent context.
3
8
 
4
9
  Keep exact paths, commands, symbols, errors, decisions, constraints, failed attempts, and next actions.
5
10
  Drop self-talk, repeated planning, obvious reasoning, filler, and prose.
6
11
  Use terse bullets under: facts, decisions, constraints, failed, next.
7
- Target 10-20% of original length.
12
+ ${ROLE_INSTRUCTIONS[compressionRole]}
8
13
  If no useful content remains, output exactly: none
9
14
 
10
15
  Reasoning:
@@ -4,7 +4,7 @@ function buildPayload(thinking, settings, disableThinking) {
4
4
  model: settings.compactor.model,
5
5
  messages: [
6
6
  { role: "system", content: "You compress reasoning traces. Output only compact trace." },
7
- { role: "user", content: buildCompactionPrompt(thinking) },
7
+ { role: "user", content: buildCompactionPrompt(thinking, settings.compressionRole) },
8
8
  ],
9
9
  max_tokens: settings.compactor.maxTokens,
10
10
  temperature: settings.compactor.temperature,
@@ -16,8 +16,6 @@ function acceptableCompaction(original, compacted, settings) {
16
16
  return undefined;
17
17
  if (text.length >= original.length)
18
18
  return undefined;
19
- if (text.length / original.length > settings.thresholds.targetRatio)
20
- return undefined;
21
19
  if (text.length > settings.thresholds.maxTraceChars)
22
20
  return undefined;
23
21
  return text;
package/dist/settings.js CHANGED
@@ -2,6 +2,7 @@ export const DEFAULT_SETTINGS = {
2
2
  enabled: true,
3
3
  mode: "llama-only",
4
4
  storageMode: "compact-new",
5
+ compressionRole: "grug",
5
6
  injectPrompt: true,
6
7
  compactor: {
7
8
  baseUrl: "http://127.0.0.1:7484/v1",
@@ -13,12 +14,12 @@ export const DEFAULT_SETTINGS = {
13
14
  },
14
15
  thresholds: {
15
16
  minChars: 1000,
16
- targetRatio: 0.15,
17
17
  maxTraceChars: 2000,
18
18
  },
19
19
  };
20
20
  const modes = new Set(["llama-only", "local-only", "all", "disabled"]);
21
21
  const storageModes = new Set(["compact-new", "off"]);
22
+ const compressionRoles = new Set(["balanced", "grug", "ultra-grug"]);
22
23
  function asObject(value) {
23
24
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
24
25
  }
@@ -39,10 +40,14 @@ export function resolveReasoningZipSettings(input) {
39
40
  const storageMode = storageModes.has(root.storageMode)
40
41
  ? root.storageMode
41
42
  : DEFAULT_SETTINGS.storageMode;
43
+ const compressionRole = compressionRoles.has(root.compressionRole)
44
+ ? root.compressionRole
45
+ : DEFAULT_SETTINGS.compressionRole;
42
46
  return {
43
47
  enabled: booleanValue(root.enabled, DEFAULT_SETTINGS.enabled),
44
48
  mode,
45
49
  storageMode,
50
+ compressionRole,
46
51
  injectPrompt: booleanValue(root.injectPrompt, DEFAULT_SETTINGS.injectPrompt),
47
52
  compactor: {
48
53
  baseUrl: stringValue(compactor.baseUrl, DEFAULT_SETTINGS.compactor.baseUrl).replace(/\/$/, ""),
@@ -54,7 +59,6 @@ export function resolveReasoningZipSettings(input) {
54
59
  },
55
60
  thresholds: {
56
61
  minChars: numberValue(thresholds.minChars, DEFAULT_SETTINGS.thresholds.minChars, 0),
57
- targetRatio: numberValue(thresholds.targetRatio, DEFAULT_SETTINGS.thresholds.targetRatio, 0),
58
62
  maxTraceChars: numberValue(thresholds.maxTraceChars, DEFAULT_SETTINGS.thresholds.maxTraceChars, 1),
59
63
  },
60
64
  };
package/dist/types.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  export type ReasoningZipMode = "llama-only" | "local-only" | "all" | "disabled";
2
2
  export type ReasoningZipStorageMode = "compact-new" | "off";
3
+ export type ReasoningZipCompressionRole = "balanced" | "grug" | "ultra-grug";
3
4
  export interface ReasoningZipSettings {
4
5
  enabled: boolean;
5
6
  mode: ReasoningZipMode;
6
7
  storageMode: ReasoningZipStorageMode;
8
+ compressionRole: ReasoningZipCompressionRole;
7
9
  injectPrompt: boolean;
8
10
  compactor: {
9
11
  baseUrl: string;
@@ -15,7 +17,6 @@ export interface ReasoningZipSettings {
15
17
  };
16
18
  thresholds: {
17
19
  minChars: number;
18
- targetRatio: number;
19
20
  maxTraceChars: number;
20
21
  };
21
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-reasoning-zip",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "private": false,
5
5
  "description": "Compact reasoning blocks to keep the context short.",
6
6
  "license": "MIT",
@@ -15,7 +15,7 @@ try {
15
15
  JSON.stringify({
16
16
  reasoningZip: {
17
17
  mode: "llama-only",
18
- thresholds: { minChars: 5, targetRatio: 1, maxTraceChars: 100 },
18
+ thresholds: { minChars: 5, maxTraceChars: 100 },
19
19
  compactor: { baseUrl: "http://mock.local/v1", model: "mock", timeoutMs: 1000 },
20
20
  },
21
21
  }),
@@ -1,10 +1,18 @@
1
- export function buildCompactionPrompt(thinking: string): string {
1
+ import type { ReasoningZipCompressionRole } from "./types.js";
2
+
3
+ const ROLE_INSTRUCTIONS: Record<ReasoningZipCompressionRole, string> = {
4
+ balanced: "Compression role: balanced. Use concise bullets, but keep enough context that another coding agent can continue without guessing.",
5
+ grug: "Compression role: grug. Few words. Keyword-heavy. No prose. Keep only useful state for the next coding turn.",
6
+ "ultra-grug": "Compression role: ultra-grug. Compress hard. Fragment bullets only. Symbols and exact names over sentences. Keep only critical state.",
7
+ };
8
+
9
+ export function buildCompactionPrompt(thinking: string, compressionRole: ReasoningZipCompressionRole = "grug"): string {
2
10
  return `Compress this model reasoning into a compact decision trace for future coding-agent context.
3
11
 
4
12
  Keep exact paths, commands, symbols, errors, decisions, constraints, failed attempts, and next actions.
5
13
  Drop self-talk, repeated planning, obvious reasoning, filler, and prose.
6
14
  Use terse bullets under: facts, decisions, constraints, failed, next.
7
- Target 10-20% of original length.
15
+ ${ROLE_INSTRUCTIONS[compressionRole]}
8
16
  If no useful content remains, output exactly: none
9
17
 
10
18
  Reasoning:
@@ -6,7 +6,7 @@ function buildPayload(thinking: string, settings: ReasoningZipSettings, disableT
6
6
  model: settings.compactor.model,
7
7
  messages: [
8
8
  { role: "system", content: "You compress reasoning traces. Output only compact trace." },
9
- { role: "user", content: buildCompactionPrompt(thinking) },
9
+ { role: "user", content: buildCompactionPrompt(thinking, settings.compressionRole) },
10
10
  ],
11
11
  max_tokens: settings.compactor.maxTokens,
12
12
  temperature: settings.compactor.temperature,
@@ -22,7 +22,6 @@ function acceptableCompaction(original: string, compacted: string, settings: Rea
22
22
  const text = compacted.trim();
23
23
  if (!text || text === "none") return undefined;
24
24
  if (text.length >= original.length) return undefined;
25
- if (text.length / original.length > settings.thresholds.targetRatio) return undefined;
26
25
  if (text.length > settings.thresholds.maxTraceChars) return undefined;
27
26
  return text;
28
27
  }
package/src/settings.ts CHANGED
@@ -1,9 +1,10 @@
1
- import type { ReasoningZipMode, ReasoningZipSettings, ReasoningZipStorageMode } from "./types.js";
1
+ import type { ReasoningZipCompressionRole, ReasoningZipMode, ReasoningZipSettings, ReasoningZipStorageMode } from "./types.js";
2
2
 
3
3
  export const DEFAULT_SETTINGS: ReasoningZipSettings = {
4
4
  enabled: true,
5
5
  mode: "llama-only",
6
6
  storageMode: "compact-new",
7
+ compressionRole: "grug",
7
8
  injectPrompt: true,
8
9
  compactor: {
9
10
  baseUrl: "http://127.0.0.1:7484/v1",
@@ -15,13 +16,13 @@ export const DEFAULT_SETTINGS: ReasoningZipSettings = {
15
16
  },
16
17
  thresholds: {
17
18
  minChars: 1000,
18
- targetRatio: 0.15,
19
19
  maxTraceChars: 2000,
20
20
  },
21
21
  };
22
22
 
23
23
  const modes = new Set<ReasoningZipMode>(["llama-only", "local-only", "all", "disabled"]);
24
24
  const storageModes = new Set<ReasoningZipStorageMode>(["compact-new", "off"]);
25
+ const compressionRoles = new Set<ReasoningZipCompressionRole>(["balanced", "grug", "ultra-grug"]);
25
26
 
26
27
  function asObject(value: unknown): Record<string, unknown> {
27
28
  return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : {};
@@ -48,11 +49,15 @@ export function resolveReasoningZipSettings(input: unknown): ReasoningZipSetting
48
49
  const storageMode = storageModes.has(root.storageMode as ReasoningZipStorageMode)
49
50
  ? (root.storageMode as ReasoningZipStorageMode)
50
51
  : DEFAULT_SETTINGS.storageMode;
52
+ const compressionRole = compressionRoles.has(root.compressionRole as ReasoningZipCompressionRole)
53
+ ? (root.compressionRole as ReasoningZipCompressionRole)
54
+ : DEFAULT_SETTINGS.compressionRole;
51
55
 
52
56
  return {
53
57
  enabled: booleanValue(root.enabled, DEFAULT_SETTINGS.enabled),
54
58
  mode,
55
59
  storageMode,
60
+ compressionRole,
56
61
  injectPrompt: booleanValue(root.injectPrompt, DEFAULT_SETTINGS.injectPrompt),
57
62
  compactor: {
58
63
  baseUrl: stringValue(compactor.baseUrl, DEFAULT_SETTINGS.compactor.baseUrl).replace(/\/$/, ""),
@@ -64,7 +69,6 @@ export function resolveReasoningZipSettings(input: unknown): ReasoningZipSetting
64
69
  },
65
70
  thresholds: {
66
71
  minChars: numberValue(thresholds.minChars, DEFAULT_SETTINGS.thresholds.minChars, 0),
67
- targetRatio: numberValue(thresholds.targetRatio, DEFAULT_SETTINGS.thresholds.targetRatio, 0),
68
72
  maxTraceChars: numberValue(thresholds.maxTraceChars, DEFAULT_SETTINGS.thresholds.maxTraceChars, 1),
69
73
  },
70
74
  };
package/src/types.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  export type ReasoningZipMode = "llama-only" | "local-only" | "all" | "disabled";
2
2
  export type ReasoningZipStorageMode = "compact-new" | "off";
3
+ export type ReasoningZipCompressionRole = "balanced" | "grug" | "ultra-grug";
3
4
 
4
5
  export interface ReasoningZipSettings {
5
6
  enabled: boolean;
6
7
  mode: ReasoningZipMode;
7
8
  storageMode: ReasoningZipStorageMode;
9
+ compressionRole: ReasoningZipCompressionRole;
8
10
  injectPrompt: boolean;
9
11
  compactor: {
10
12
  baseUrl: string;
@@ -16,7 +18,6 @@ export interface ReasoningZipSettings {
16
18
  };
17
19
  thresholds: {
18
20
  minChars: number;
19
- targetRatio: number;
20
21
  maxTraceChars: number;
21
22
  };
22
23
  }