@xynogen/pix-runtime 0.4.2 → 0.5.2
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 +14 -1
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/pix-command.ts +30 -2
- package/src/sections/compaction.ts +47 -0
- package/src/sections/index.ts +3 -0
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ See `DESIGN.md` for the full contract.
|
|
|
10
10
|
## What it does
|
|
11
11
|
|
|
12
12
|
- Versioned, sparse `pix.json` (`$version: 1`) — defaults resolve in code.
|
|
13
|
-
- Typed sections: `collapse`, `pretty`, `io`, `optimizer`, `gate`.
|
|
13
|
+
- Typed sections: `collapse`, `pretty`, `io`, `compaction`, `optimizer`, `gate`.
|
|
14
14
|
- Atomic writes behind a serialized in-process queue and a short-lived
|
|
15
15
|
cross-process lock. A failed write leaves the old file intact.
|
|
16
16
|
- Immutable, deeply frozen config snapshots with a monotonic revision.
|
|
@@ -49,6 +49,19 @@ with `/pix`. The default is 30 seconds. It applies to Pix network operations,
|
|
|
49
49
|
including remote skills, web fetch/search/transcription, MCP requests and
|
|
50
50
|
connection bootstrap, background model-data refreshes, and update downloads.
|
|
51
51
|
|
|
52
|
+
Set `compaction.triggerPercent` in `~/.pi/agent/pix.json`, or change **Compaction →
|
|
53
|
+
Trigger (% ctx)** with `/pix`. It is the context-window usage percent (0–100) used
|
|
54
|
+
to calculate the trigger; the default is `60` and `0` disables the self-trigger
|
|
55
|
+
(pi decides when to compact). The `/pix` picker offers 0, 5, 10, 15, 20, 25, 30,
|
|
56
|
+
40, 50, 60, 70, 80, 90.
|
|
57
|
+
|
|
58
|
+
`compaction.minimumTokens` is the absolute floor for that calculation. The
|
|
59
|
+
effective threshold is `max(contextWindow × triggerPercent, minimumTokens)`, so
|
|
60
|
+
a 300K-context model at 10% waits for 100K tokens instead of compacting at 30K.
|
|
61
|
+
The default floor is 100K and the hard minimum is 25K (values below clamp up);
|
|
62
|
+
`/pix` offers 25K, 50K, 100K, 150K, 200K, 300K, 400K, 600K, 800K, and 1M.
|
|
63
|
+
pix-core consumes both settings.
|
|
64
|
+
|
|
52
65
|
Collapse policy helpers:
|
|
53
66
|
|
|
54
67
|
```ts
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
package/src/pix-command.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
import type { PixRuntime } from "./runtime.ts";
|
|
19
19
|
import type { DeepPartial, SectionHandle } from "./schema.ts";
|
|
20
20
|
import { collapseSection } from "./sections/collapse.ts";
|
|
21
|
+
import { compactionSection } from "./sections/compaction.ts";
|
|
21
22
|
import { gateSection } from "./sections/gate.ts";
|
|
22
23
|
import { ioSection } from "./sections/io.ts";
|
|
23
24
|
import { prettySection } from "./sections/pretty.ts";
|
|
@@ -36,6 +37,17 @@ function row<T>(r: SettingRow<T>): SettingRow<unknown> {
|
|
|
36
37
|
return r as SettingRow<unknown>;
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
/** Render a token count as a compact label: 1_000_000 → "1M", 150_000 → "150k". */
|
|
41
|
+
function formatTokens(tokens: number): string {
|
|
42
|
+
return tokens % 1_000_000 === 0 ? `${tokens / 1_000_000}M` : `${tokens / 1000}k`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Parse a compact token label ("1M", "150k") back to an absolute count. */
|
|
46
|
+
function parseTokens(label: string): number {
|
|
47
|
+
const n = Number.parseFloat(label);
|
|
48
|
+
return /m$/i.test(label) ? n * 1_000_000 : n * 1000;
|
|
49
|
+
}
|
|
50
|
+
|
|
39
51
|
const SETTINGS: SettingRow<unknown>[] = [
|
|
40
52
|
row({
|
|
41
53
|
section: "Pretty",
|
|
@@ -77,6 +89,22 @@ const SETTINGS: SettingRow<unknown>[] = [
|
|
|
77
89
|
read: (v) => String(v.timeoutSec),
|
|
78
90
|
patch: (value) => ({ timeoutSec: Number(value) }),
|
|
79
91
|
}),
|
|
92
|
+
row({
|
|
93
|
+
section: "Compaction",
|
|
94
|
+
label: "Trigger (% ctx)",
|
|
95
|
+
handle: compactionSection,
|
|
96
|
+
values: ["0", "5", "10", "15", "20", "25", "30", "40", "50", "60", "70", "80", "90"],
|
|
97
|
+
read: (v) => String(v.triggerPercent),
|
|
98
|
+
patch: (value) => ({ triggerPercent: Number(value) }),
|
|
99
|
+
}),
|
|
100
|
+
row({
|
|
101
|
+
section: "Compaction",
|
|
102
|
+
label: "Minimum tokens",
|
|
103
|
+
handle: compactionSection,
|
|
104
|
+
values: ["25k", "50k", "100k", "150k", "200k", "300k", "400k", "600k", "800k", "1M"],
|
|
105
|
+
read: (v) => formatTokens(v.minimumTokens),
|
|
106
|
+
patch: (value) => ({ minimumTokens: parseTokens(value) }),
|
|
107
|
+
}),
|
|
80
108
|
row({
|
|
81
109
|
section: "Gate",
|
|
82
110
|
label: "Guardrails",
|
|
@@ -97,7 +125,7 @@ function buildSummary(runtime: PixRuntime): string {
|
|
|
97
125
|
lastSection = row.section;
|
|
98
126
|
}
|
|
99
127
|
const value = row.read(runtime.get(row.handle));
|
|
100
|
-
const isDefault = value === row.
|
|
128
|
+
const isDefault = value === row.read(row.handle.defaults);
|
|
101
129
|
lines.push(` ${row.label}: ${value}${isDefault ? "" : " *"}`);
|
|
102
130
|
}
|
|
103
131
|
return lines.join("\n");
|
|
@@ -169,7 +197,7 @@ export function registerPixCommand(pi: ExtensionAPI, runtime: PixRuntime): void
|
|
|
169
197
|
const cursor = sel ? theme.fg("accent", "→") : " ";
|
|
170
198
|
const label = theme.fg(sel ? "accent" : "text", row.label.padEnd(labelW));
|
|
171
199
|
const value = row.read(runtime.get(row.handle));
|
|
172
|
-
const isDefault = value === row.
|
|
200
|
+
const isDefault = value === row.read(row.handle.defaults);
|
|
173
201
|
settingBodyLines[i] = body.length;
|
|
174
202
|
body.push(`${cursor} ${label} ${theme.fg(isDefault ? "dim" : "success", value)}`);
|
|
175
203
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { defineSection, isObj } from "../schema.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Custom compaction config. pix-core always replaces pi's built-in compaction
|
|
5
|
+
* summary. When `triggerPercent > 0` it also drives its own trigger from live
|
|
6
|
+
* context usage. The effective threshold is the larger of that percentage of
|
|
7
|
+
* the active model's context window and `minimumTokens`. `0` disables the
|
|
8
|
+
* self-trigger (pi decides when to compact).
|
|
9
|
+
*/
|
|
10
|
+
export interface CompactionConfig {
|
|
11
|
+
/** Context-window usage percent that fires compaction; 0 = off. */
|
|
12
|
+
triggerPercent: number;
|
|
13
|
+
/** Absolute floor for a percentage-based trigger. */
|
|
14
|
+
minimumTokens: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const MINIMUM_TOKEN_FLOOR = 25_000;
|
|
18
|
+
const MINIMUM_TOKEN_DEFAULT = 100_000;
|
|
19
|
+
|
|
20
|
+
const DEFAULTS: Readonly<CompactionConfig> = {
|
|
21
|
+
triggerPercent: 60,
|
|
22
|
+
minimumTokens: MINIMUM_TOKEN_DEFAULT,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/** Clamp to [0, 100]; non-numbers fall back. */
|
|
26
|
+
function pctOr(v: unknown, fallback: number): number {
|
|
27
|
+
if (typeof v !== "number" || !Number.isFinite(v)) return fallback;
|
|
28
|
+
return Math.min(100, Math.max(0, v));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Require a finite token floor of at least 25k. */
|
|
32
|
+
function minimumTokensOr(v: unknown, fallback: number): number {
|
|
33
|
+
if (typeof v !== "number" || !Number.isFinite(v)) return fallback;
|
|
34
|
+
return Math.max(MINIMUM_TOKEN_FLOOR, Math.round(v));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const compactionSection = defineSection<"compaction", CompactionConfig>({
|
|
38
|
+
key: "compaction",
|
|
39
|
+
defaults: DEFAULTS,
|
|
40
|
+
parse(raw) {
|
|
41
|
+
if (!isObj(raw)) return { ...DEFAULTS };
|
|
42
|
+
return {
|
|
43
|
+
triggerPercent: pctOr(raw.triggerPercent, DEFAULTS.triggerPercent),
|
|
44
|
+
minimumTokens: minimumTokensOr(raw.minimumTokens, DEFAULTS.minimumTokens),
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
});
|
package/src/sections/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { type CollapseConfig, collapseSection } from "./collapse.ts";
|
|
2
|
+
export { type CompactionConfig, compactionSection } from "./compaction.ts";
|
|
2
3
|
export {
|
|
3
4
|
type GateConfig,
|
|
4
5
|
type GateRuleConfig,
|
|
@@ -22,6 +23,7 @@ export {
|
|
|
22
23
|
} from "./pretty.ts";
|
|
23
24
|
|
|
24
25
|
import { collapseSection } from "./collapse.ts";
|
|
26
|
+
import { compactionSection } from "./compaction.ts";
|
|
25
27
|
import { gateSection } from "./gate.ts";
|
|
26
28
|
import { ioSection } from "./io.ts";
|
|
27
29
|
import { optimizerSection } from "./optimizer.ts";
|
|
@@ -34,4 +36,5 @@ export const builtinSections = [
|
|
|
34
36
|
ioSection,
|
|
35
37
|
optimizerSection,
|
|
36
38
|
gateSection,
|
|
39
|
+
compactionSection,
|
|
37
40
|
] as const;
|