peaks-loop 4.0.24 → 4.0.26
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 +29 -0
- package/dist/cli/commands/codegraph-commands.d.ts +10 -0
- package/dist/cli/commands/codegraph-commands.js +18 -4
- package/dist/cli/commands/core/memory-command.js +1 -3
- package/dist/cli/commands/dispatch-commands.js +11 -67
- package/dist/cli/commands/memory-commands.d.ts +0 -2
- package/dist/cli/commands/memory-commands.js +4 -7
- package/dist/cli/commands/preferences-commands.js +0 -1
- package/dist/cli/commands/qa-commands.js +5 -5
- package/dist/cli/commands/sub-agent-shared.d.ts +0 -4
- package/dist/cli/commands/sub-agent-shared.js +0 -14
- package/dist/cli/commands/workflow-commands.js +5 -5
- package/dist/services/context/build-dispatch-system-prompt.d.ts +4 -4
- package/dist/services/context/build-dispatch-system-prompt.js +6 -6
- package/dist/services/context/context-guard.d.ts +2 -4
- package/dist/services/context/context-guard.js +4 -6
- package/dist/services/context/{headroom-fetcher.d.ts → doc-cache-fetcher.d.ts} +2 -2
- package/dist/services/context/{headroom-fetcher.js → doc-cache-fetcher.js} +4 -3
- package/dist/services/context/memory-preflight-service.js +6 -17
- package/dist/services/context/threshold.d.ts +0 -3
- package/dist/services/context/threshold.js +0 -3
- package/dist/services/dispatch/batch-counter.js +1 -1
- package/dist/services/dispatch/leak-detector.js +1 -1
- package/dist/services/fuzzy-matching/fzf-pick-service.d.ts +1 -1
- package/dist/services/fuzzy-matching/fzf-pick-service.js +1 -1
- package/dist/services/memory/llm-reranker.d.ts +4 -5
- package/dist/services/memory/llm-reranker.js +6 -8
- package/dist/services/memory/memory-search-service.d.ts +0 -32
- package/dist/services/memory/memory-search-service.js +0 -37
- package/dist/services/preferences/preferences-service.d.ts +5 -8
- package/dist/services/preferences/preferences-service.js +0 -30
- package/dist/services/preferences/preferences-types.d.ts +0 -22
- package/dist/services/preferences/preferences-types.js +0 -12
- package/dist/services/retrospective/retrospective-search-service.d.ts +0 -18
- package/dist/services/retrospective/retrospective-search-service.js +0 -32
- package/dist/services/slice/slice-benchmark-service.d.ts +1 -1
- package/dist/services/slice/slice-benchmark-service.js +1 -1
- package/dist/services/slice/slice-pick-service.d.ts +1 -1
- package/dist/services/slice/slice-pick-service.js +1 -1
- package/package.json +5 -6
- package/skills/bee/peaks-qa/references/qa-context-governance.md +1 -1
- package/skills/bee/peaks-rd/SKILL.md +9 -2
- package/skills/bee/peaks-rd/references/frontend-acl-mapper.md +29 -0
- package/skills/bee/peaks-rd/references/rd-context-governance.md +2 -2
- package/skills/bee/peaks-txt/SKILL.md +1 -1
- package/skills/bee/peaks-ui/SKILL.md +1 -1
- package/skills/peaks-code/SKILL.md +1 -1
- package/skills/peaks-code/references/codegraph-orchestration.md +7 -1
- package/skills/peaks-code/references/context-governance.md +7 -34
- package/skills/peaks-code/references/envelope-contract.md +2 -7
- package/skills/peaks-code/references/sub-agent-dispatch.md +2 -4
- package/dist/services/context/headroom-client.d.ts +0 -34
- package/dist/services/context/headroom-client.js +0 -117
- package/dist/services/context/headroom-prefs.d.ts +0 -46
- package/dist/services/context/headroom-prefs.js +0 -34
- package/skills/peaks-code/references/headroom-integration.md +0 -107
|
@@ -33,19 +33,14 @@ Top-level fields (post-2.1.0):
|
|
|
33
33
|
- `envelopeVersion: '2.1.0'`
|
|
34
34
|
- `role: string` — sub-agent role string
|
|
35
35
|
- `ide: string` — detected IDE label (`claude-code` etc.)
|
|
36
|
-
- `originalPromptSize: number` — bytes of the
|
|
37
|
-
- `promptSize: number` — bytes
|
|
38
|
-
equal to `originalPromptSize` when `--use-headroom` is off or
|
|
39
|
-
unavailable)
|
|
36
|
+
- `originalPromptSize: number` — bytes of the caller-supplied prompt
|
|
37
|
+
- `promptSize: number` — bytes of the composed dispatch prompt
|
|
40
38
|
- `toolCall: { name: string; args: Record<string, unknown> }` —
|
|
41
39
|
the per-IDE tool-call descriptor the LLM must execute
|
|
42
40
|
- `dispatchRecordPath: string` — absolute path to the dispatch
|
|
43
41
|
record on disk
|
|
44
42
|
- `batchId: string` — uuid-like opaque token grouping one batch
|
|
45
43
|
- `dispatchedInBatch: number` — current count after this dispatch
|
|
46
|
-
- `headroomCompressed: boolean` — true if headroom-ai actually
|
|
47
|
-
reduced the prompt
|
|
48
|
-
- `headroomResult: { mode, compressed, compressionRatio, tokensSaved, warning } | null`
|
|
49
44
|
- `forcedAt: string | null` — ISO8601 when `--force` overrode
|
|
50
45
|
the G9 hard-reject tier
|
|
51
46
|
- `contextImpact: { promptBytes, artifactBytes, totalBytes }`
|
|
@@ -51,8 +51,8 @@ peaks sub-agent dispatch <role> --prompt <text> [--request-id <rid>] [--session-
|
|
|
51
51
|
> scrollback. The dispatch record on disk (gitignored under
|
|
52
52
|
> `.peaks/_sub_agents/`) keeps the prompt for the sub-agent to read;
|
|
53
53
|
> CLI stdout stays metadata-only. Surface `originalPromptSize` +
|
|
54
|
-
> `promptSize` so the LLM-side runner can still reason about
|
|
55
|
-
> without seeing the content. The prompt content the LLM should pass
|
|
54
|
+
> `promptSize` so the LLM-side runner can still reason about the size
|
|
55
|
+
> delta without seeing the content. The prompt content the LLM should pass
|
|
56
56
|
> through lives in `data.toolCall.args.prompt` (the IDE-arg the
|
|
57
57
|
> consumer passes to the tool), NOT in the outer envelope.
|
|
58
58
|
|
|
@@ -77,8 +77,6 @@ peaks sub-agent dispatch <role> --prompt <text> [--request-id <rid>] [--session-
|
|
|
77
77
|
"dispatchRecordPath": ".peaks/_sub_agents/2026-06-06-session-5b1095/dispatch-002-2026-06-07-...-...json",
|
|
78
78
|
"batchId": "<uuid>",
|
|
79
79
|
"dispatchedInBatch": 3,
|
|
80
|
-
"headroomCompressed": false,
|
|
81
|
-
"headroomResult": null,
|
|
82
80
|
"forcedAt": null,
|
|
83
81
|
"contextImpact": {
|
|
84
82
|
"promptBytes": 4321,
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export type HeadroomMode = 'balanced' | 'aggressive' | 'conservative';
|
|
2
|
-
export interface HeadroomResult {
|
|
3
|
-
readonly compressed: boolean;
|
|
4
|
-
readonly originalSize: number;
|
|
5
|
-
readonly compressedSize: number;
|
|
6
|
-
readonly compressionRatio: number;
|
|
7
|
-
readonly mode: HeadroomMode;
|
|
8
|
-
/** `'HEADROOM_UNAVAILABLE'` on fallback; `null` on success. */
|
|
9
|
-
readonly warning: string | null;
|
|
10
|
-
/** Compressed prompt body. `null` if no compression happened. */
|
|
11
|
-
readonly compressedPrompt: string | null;
|
|
12
|
-
/** Tokens saved (from the SDK). 0 on fallback. */
|
|
13
|
-
readonly tokensSaved: number;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Compress a prompt via headroom-ai. The `fallback: true` option is
|
|
17
|
-
* non-negotiable: if the proxy daemon is unavailable, the SDK returns
|
|
18
|
-
* `result.compressed = false` and the original messages; we surface
|
|
19
|
-
* that as `HEADROOM_UNAVAILABLE` warning + G7 metadata-only fallback.
|
|
20
|
-
*/
|
|
21
|
-
export declare function compressPrompt(prompt: string, mode?: HeadroomMode): Promise<HeadroomResult>;
|
|
22
|
-
/**
|
|
23
|
-
* Bridge interface: when `--use-headroom` is set, share entries written
|
|
24
|
-
* via `peaks sub-agent share` MAY also flow through headroom's
|
|
25
|
-
* `SharedContext`. Slice #010 implements a peak-internal shared channel
|
|
26
|
-
* (see `shared-channel.ts`); the headroom-side `SharedContext` is a
|
|
27
|
-
* separate concept that future slices can layer on. For now this
|
|
28
|
-
* function is a stub that returns the peak-internal channel ID, which
|
|
29
|
-
* is enough to demonstrate the bridge contract.
|
|
30
|
-
*/
|
|
31
|
-
export declare function buildSharedContextBridge(batchId: string): {
|
|
32
|
-
peakChannelId: string;
|
|
33
|
-
headroomContextId: string;
|
|
34
|
-
};
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
2
|
-
const DEFAULT_MODEL = 'claude-sonnet-4-5-20250929';
|
|
3
|
-
// Approximate 1 token = 4 bytes for English text. This is a rough
|
|
4
|
-
// heuristic; the SDK does its own tokenization internally.
|
|
5
|
-
const BYTES_PER_TOKEN = 4;
|
|
6
|
-
/**
|
|
7
|
-
* Compress a prompt via headroom-ai. The `fallback: true` option is
|
|
8
|
-
* non-negotiable: if the proxy daemon is unavailable, the SDK returns
|
|
9
|
-
* `result.compressed = false` and the original messages; we surface
|
|
10
|
-
* that as `HEADROOM_UNAVAILABLE` warning + G7 metadata-only fallback.
|
|
11
|
-
*/
|
|
12
|
-
export async function compressPrompt(prompt, mode = 'balanced') {
|
|
13
|
-
const originalSize = Buffer.byteLength(prompt, 'utf8');
|
|
14
|
-
let compressFn = null;
|
|
15
|
-
try {
|
|
16
|
-
const mod = await import('headroom-ai');
|
|
17
|
-
if (typeof mod.compress === 'function') {
|
|
18
|
-
compressFn = mod.compress;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
return fallback(originalSize, mode);
|
|
23
|
-
}
|
|
24
|
-
if (compressFn === null) {
|
|
25
|
-
return fallback(originalSize, mode);
|
|
26
|
-
}
|
|
27
|
-
const messages = [
|
|
28
|
-
{ role: 'user', content: prompt }
|
|
29
|
-
];
|
|
30
|
-
const opts = {
|
|
31
|
-
model: DEFAULT_MODEL,
|
|
32
|
-
timeout: DEFAULT_TIMEOUT_MS,
|
|
33
|
-
fallback: true, // CRITICAL: return original messages if proxy is down
|
|
34
|
-
retries: 1
|
|
35
|
-
};
|
|
36
|
-
if (mode === 'aggressive') {
|
|
37
|
-
opts.tokenBudget = Math.max(1, Math.floor(originalSize * 0.20 / BYTES_PER_TOKEN));
|
|
38
|
-
}
|
|
39
|
-
else if (mode === 'conservative') {
|
|
40
|
-
opts.tokenBudget = Math.max(1, Math.floor(originalSize * 0.70 / BYTES_PER_TOKEN));
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
// balanced: target ~60% reduction
|
|
44
|
-
opts.tokenBudget = Math.max(1, Math.floor(originalSize * 0.40 / BYTES_PER_TOKEN));
|
|
45
|
-
}
|
|
46
|
-
let result;
|
|
47
|
-
try {
|
|
48
|
-
result = await compressFn(messages, opts);
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
return fallback(originalSize, mode);
|
|
52
|
-
}
|
|
53
|
-
if (result.compressed === false) {
|
|
54
|
-
return {
|
|
55
|
-
compressed: false,
|
|
56
|
-
originalSize,
|
|
57
|
-
compressedSize: originalSize,
|
|
58
|
-
compressionRatio: 1.0,
|
|
59
|
-
mode,
|
|
60
|
-
warning: 'HEADROOM_UNAVAILABLE',
|
|
61
|
-
compressedPrompt: null,
|
|
62
|
-
tokensSaved: 0
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
const compressedContent = extractContent(result.messages);
|
|
66
|
-
if (compressedContent === null) {
|
|
67
|
-
return fallback(originalSize, mode);
|
|
68
|
-
}
|
|
69
|
-
const compressedSize = Buffer.byteLength(compressedContent, 'utf8');
|
|
70
|
-
return {
|
|
71
|
-
compressed: true,
|
|
72
|
-
originalSize,
|
|
73
|
-
compressedSize,
|
|
74
|
-
compressionRatio: compressedSize / originalSize,
|
|
75
|
-
mode,
|
|
76
|
-
warning: null,
|
|
77
|
-
compressedPrompt: compressedContent,
|
|
78
|
-
tokensSaved: result.tokensSaved ?? 0
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
function fallback(originalSize, mode) {
|
|
82
|
-
return {
|
|
83
|
-
compressed: false,
|
|
84
|
-
originalSize,
|
|
85
|
-
compressedSize: originalSize,
|
|
86
|
-
compressionRatio: 1.0,
|
|
87
|
-
mode,
|
|
88
|
-
warning: 'HEADROOM_UNAVAILABLE',
|
|
89
|
-
compressedPrompt: null,
|
|
90
|
-
tokensSaved: 0
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
function extractContent(messages) {
|
|
94
|
-
if (!Array.isArray(messages) || messages.length === 0) {
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
const last = messages[messages.length - 1];
|
|
98
|
-
if (typeof last.content === 'string') {
|
|
99
|
-
return last.content;
|
|
100
|
-
}
|
|
101
|
-
return null;
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Bridge interface: when `--use-headroom` is set, share entries written
|
|
105
|
-
* via `peaks sub-agent share` MAY also flow through headroom's
|
|
106
|
-
* `SharedContext`. Slice #010 implements a peak-internal shared channel
|
|
107
|
-
* (see `shared-channel.ts`); the headroom-side `SharedContext` is a
|
|
108
|
-
* separate concept that future slices can layer on. For now this
|
|
109
|
-
* function is a stub that returns the peak-internal channel ID, which
|
|
110
|
-
* is enough to demonstrate the bridge contract.
|
|
111
|
-
*/
|
|
112
|
-
export function buildSharedContextBridge(batchId) {
|
|
113
|
-
return {
|
|
114
|
-
peakChannelId: batchId,
|
|
115
|
-
headroomContextId: `headroom-ctx-${batchId}`
|
|
116
|
-
};
|
|
117
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Headroom preferences resolver (slice 2026-06-14-fzf-headroom-rollout).
|
|
3
|
-
*
|
|
4
|
-
* Pure functions that turn `ProjectPreferences.headroom.*` + CLI
|
|
5
|
-
* overrides into a single decision the dispatch path can act on.
|
|
6
|
-
* No IO. No side effects. Easy to test in isolation.
|
|
7
|
-
*
|
|
8
|
-
* Two distinct decisions:
|
|
9
|
-
* 1. `resolveHeadroomOptions` — should we compress the dispatch prompt?
|
|
10
|
-
* Used by `peaks sub-agent dispatch`. Returns one of:
|
|
11
|
-
* - `{ mode: <m>, blocked: null }` → compress with mode <m>
|
|
12
|
-
* - `{ mode: null, blocked: null }` → skip compression (no --use-headroom)
|
|
13
|
-
* - `{ mode: null, blocked: 'HEADROOM_DISABLED_BY_PREFERENCE' }` → hard fail
|
|
14
|
-
* 2. `shouldCompressResults` — should we compress search-result text?
|
|
15
|
-
* Used by `peaks memory search` / `peaks retrospective search`.
|
|
16
|
-
* Non-blocking: returns a `reason` instead of a `blocked` code.
|
|
17
|
-
*
|
|
18
|
-
* Precedence (dispatch):
|
|
19
|
-
* 1. `headroom.enabled = false` → hard block (regardless of --use-headroom)
|
|
20
|
-
* 2. `headroom.enabled = true` + `--headroom-mode <m>` → use <m>
|
|
21
|
-
* 3. `headroom.enabled = true` + `--use-headroom` (no --headroom-mode) →
|
|
22
|
-
* use `perTouchpoint.subAgentDispatch` (preferred) else `defaultMode`
|
|
23
|
-
* 4. no `--use-headroom` → mode = null (compression skipped)
|
|
24
|
-
*/
|
|
25
|
-
import type { HeadroomMode, ProjectPreferences } from '../preferences/preferences-types.js';
|
|
26
|
-
export type HeadroomTouchpoint = keyof ProjectPreferences['headroom']['perTouchpoint'];
|
|
27
|
-
export type HeadroomBlockCode = 'HEADROOM_DISABLED_BY_PREFERENCE';
|
|
28
|
-
export interface ResolvedHeadroomOptions {
|
|
29
|
-
/** The mode to use for compression, or null if not compressing. */
|
|
30
|
-
readonly mode: HeadroomMode | null;
|
|
31
|
-
/** Hard-block reason; null when compression is allowed (or simply not requested). */
|
|
32
|
-
readonly blocked: HeadroomBlockCode | null;
|
|
33
|
-
}
|
|
34
|
-
export interface ResolveCliOverrides {
|
|
35
|
-
readonly useHeadroom: boolean;
|
|
36
|
-
readonly headroomMode?: string;
|
|
37
|
-
}
|
|
38
|
-
export declare function isHeadroomMode(value: string | undefined): value is HeadroomMode;
|
|
39
|
-
export declare function resolveHeadroomOptions(prefs: ProjectPreferences['headroom'], cliOverrides: ResolveCliOverrides): ResolvedHeadroomOptions;
|
|
40
|
-
export interface ShouldCompressDecision {
|
|
41
|
-
readonly compress: boolean;
|
|
42
|
-
readonly mode: HeadroomMode;
|
|
43
|
-
/** Non-null reason if not compressing. */
|
|
44
|
-
readonly reason: 'DISABLED' | 'BELOW_THRESHOLD' | null;
|
|
45
|
-
}
|
|
46
|
-
export declare function shouldCompressResults(prefs: ProjectPreferences['headroom'], joinedBytes: number, touchpoint: HeadroomTouchpoint): ShouldCompressDecision;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
const VALID_MODES = new Set([
|
|
2
|
-
'balanced',
|
|
3
|
-
'aggressive',
|
|
4
|
-
'conservative'
|
|
5
|
-
]);
|
|
6
|
-
export function isHeadroomMode(value) {
|
|
7
|
-
return typeof value === 'string' && VALID_MODES.has(value);
|
|
8
|
-
}
|
|
9
|
-
export function resolveHeadroomOptions(prefs, cliOverrides) {
|
|
10
|
-
// (1) Hard block when preference disables headroom entirely.
|
|
11
|
-
if (cliOverrides.useHeadroom === true && prefs.enabled === false) {
|
|
12
|
-
return { mode: null, blocked: 'HEADROOM_DISABLED_BY_PREFERENCE' };
|
|
13
|
-
}
|
|
14
|
-
// (4) No --use-headroom → no compression.
|
|
15
|
-
if (cliOverrides.useHeadroom !== true) {
|
|
16
|
-
return { mode: null, blocked: null };
|
|
17
|
-
}
|
|
18
|
-
// (2) CLI --headroom-mode wins (even if preference is set, CLI overrides).
|
|
19
|
-
if (isHeadroomMode(cliOverrides.headroomMode)) {
|
|
20
|
-
return { mode: cliOverrides.headroomMode, blocked: null };
|
|
21
|
-
}
|
|
22
|
-
// (3) Preference path: perTouchpoint > defaultMode > 'balanced'.
|
|
23
|
-
const touchpointMode = prefs.perTouchpoint.subAgentDispatch;
|
|
24
|
-
return { mode: touchpointMode ?? prefs.defaultMode, blocked: null };
|
|
25
|
-
}
|
|
26
|
-
export function shouldCompressResults(prefs, joinedBytes, touchpoint) {
|
|
27
|
-
if (prefs.enabled === false) {
|
|
28
|
-
return { compress: false, mode: prefs.defaultMode, reason: 'DISABLED' };
|
|
29
|
-
}
|
|
30
|
-
if (joinedBytes < prefs.compressMinBytes) {
|
|
31
|
-
return { compress: false, mode: prefs.perTouchpoint[touchpoint], reason: 'BELOW_THRESHOLD' };
|
|
32
|
-
}
|
|
33
|
-
return { compress: true, mode: prefs.perTouchpoint[touchpoint], reason: null };
|
|
34
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
# Headroom Integration — G7.7 opt-in compression channel
|
|
2
|
-
|
|
3
|
-
> Slice #010 (G7.7 headroom-ai integration route).
|
|
4
|
-
> Source: https://github.com/chopratejas/headroom
|
|
5
|
-
> Package: `headroom-ai@0.22.4` (Apache-2.0, MIT-compatible).
|
|
6
|
-
> See: `THIRD_PARTY_LICENSES.md` for the license record.
|
|
7
|
-
|
|
8
|
-
## Why headroom-ai is justified (R-14)
|
|
9
|
-
|
|
10
|
-
The dev-preference red line "非必要不添加新的 dep" is preserved:
|
|
11
|
-
headroom-ai is the only opt-in mechanism for G7.7 + G9 to compress
|
|
12
|
-
sub-agent prompts that exceed the 75% / 80% threshold. Without
|
|
13
|
-
headroom-ai, `--use-headroom` is a no-op and the only fallback is
|
|
14
|
-
`--force` override at CLI.
|
|
15
|
-
|
|
16
|
-
The user's explicit reference (https://github.com/chopratejas/headroom)
|
|
17
|
-
is the basis for the dev-preference override.
|
|
18
|
-
|
|
19
|
-
## API shape (real SDK, not the PRD's spec)
|
|
20
|
-
|
|
21
|
-
```ts
|
|
22
|
-
import { compress } from 'headroom-ai';
|
|
23
|
-
|
|
24
|
-
const result = await compress(messages, {
|
|
25
|
-
model: 'claude-sonnet-4-5-20250929',
|
|
26
|
-
baseUrl: 'http://localhost:8787', // local proxy; not used in slice #010
|
|
27
|
-
apiKey: 'hr_...', // Headroom Cloud; not used in slice #010
|
|
28
|
-
timeout: 30_000,
|
|
29
|
-
fallback: true, // CRITICAL: return original messages if proxy is dead
|
|
30
|
-
retries: 1,
|
|
31
|
-
tokenBudget: 4000, // compress to fit this limit
|
|
32
|
-
hooks: new MyHooks(), // pre/post compression hooks
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
result.messages // compressed messages
|
|
36
|
-
result.tokensBefore // original token count
|
|
37
|
-
result.tokensAfter // compressed token count
|
|
38
|
-
result.tokensSaved // tokens removed
|
|
39
|
-
result.compressionRatio // tokensAfter / tokensBefore
|
|
40
|
-
result.transformsApplied // e.g. ['router:smart_crusher:0.35']
|
|
41
|
-
result.compressed // false if fallback kicked in
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
`fallback: true` is the key option: if the proxy is unavailable, the SDK
|
|
45
|
-
returns the original messages + `result.compressed: false` instead of
|
|
46
|
-
throwing. This makes the failure mode non-blocking (RL-22d / RL-32).
|
|
47
|
-
|
|
48
|
-
## Mode table (peaks wrapper)
|
|
49
|
-
|
|
50
|
-
The peaks wrapper maps the user-facing `HeadroomMode` to the SDK's
|
|
51
|
-
`tokenBudget` option. Slice #010 does not consume the SDK's internal
|
|
52
|
-
"audit" / "optimize" / "simulate" modes (those are SDK-internal);
|
|
53
|
-
|
|
54
|
-
| Mode | tokenBudget | Use case |
|
|
55
|
-
|---|---|---|
|
|
56
|
-
| `balanced` (default) | promptSize * 0.40 / 4 | General sub-agent dispatch |
|
|
57
|
-
| `aggressive` | promptSize * 0.20 / 4 | Last-resort large prompt |
|
|
58
|
-
| `conservative` | promptSize * 0.70 / 4 | Sensitive code analysis, accuracy-critical |
|
|
59
|
-
|
|
60
|
-
The `0.40 / 4` factor approximates 60% byte reduction (1 token ≈ 4 bytes
|
|
61
|
-
for English text). The SDK does its own tokenization internally; the
|
|
62
|
-
`tokenBudget` is a hint, not a hard cap.
|
|
63
|
-
|
|
64
|
-
## Failure semantics (RL-22d / RL-32)
|
|
65
|
-
|
|
66
|
-
- `result.compressed === false` → `code: "HEADROOM_UNAVAILABLE"` warning
|
|
67
|
-
- `compress()` throws (network error, JSON parse error) → caught and treated as `HEADROOM_UNAVAILABLE`
|
|
68
|
-
- Import failure (headroom-ai not installed) → caught and treated as `HEADROOM_UNAVAILABLE`
|
|
69
|
-
- **NOT blocking** — peak falls back to G7 metadata-only and continues dispatch
|
|
70
|
-
|
|
71
|
-
## CCR reversible hydration (slice #011+ TODO)
|
|
72
|
-
|
|
73
|
-
The PRD mentions "CCR (Cross-Context Reversible)" as a benefit of
|
|
74
|
-
headroom. In the SDK, this is implemented via the `hooks` option on
|
|
75
|
-
`compress()`. A pre/post hook can persist the `ccrHashes` to disk,
|
|
76
|
-
and a later `rehydrate()` call can re-hydrate the compressed prompt
|
|
77
|
-
to the original. Slice #010 does NOT consume CCR — it only uses
|
|
78
|
-
compression. R-17 (CCR for aggressive / conservative modes) is
|
|
79
|
-
deferred to slice #011+.
|
|
80
|
-
|
|
81
|
-
## Cross-platform behavior (R-19)
|
|
82
|
-
|
|
83
|
-
- In-process compression (the SDK's library mode) is platform-agnostic.
|
|
84
|
-
- The long-running `headroom proxy` daemon is platform-specific
|
|
85
|
-
(Unix socket on Linux/macOS, named pipe on Windows). Slice #010
|
|
86
|
-
does NOT consume the proxy daemon.
|
|
87
|
-
- All headroom-ai calls in slice #010 go through the in-process SDK
|
|
88
|
-
with `fallback: true`. The peak wrapper at
|
|
89
|
-
`src/services/context/headroom-client.ts` catches all errors and
|
|
90
|
-
treats them as fallback.
|
|
91
|
-
|
|
92
|
-
## What slice #010 does NOT do
|
|
93
|
-
|
|
94
|
-
- Does NOT install the `headroom proxy` daemon (N-7).
|
|
95
|
-
- Does NOT consume headroom's `SharedContext` directly (G7.7.3 in the
|
|
96
|
-
PRD); the peak-internal `SharedChannel` (G8) is the cross-sub-agent
|
|
97
|
-
state store. `buildSharedContextBridge()` is a stub that returns
|
|
98
|
-
the peak-internal channel ID + a placeholder headroom context ID.
|
|
99
|
-
- Does NOT use the SDK's `audit` / `optimize` / `simulate` modes
|
|
100
|
-
(those are SDK-internal; the peak wrapper exposes
|
|
101
|
-
`balanced` / `aggressive` / `conservative` to the user).
|
|
102
|
-
|
|
103
|
-
## Security + license
|
|
104
|
-
|
|
105
|
-
- License: Apache-2.0 (MIT-compatible) — see `THIRD_PARTY_LICENSES.md`.
|
|
106
|
-
- Pinned version: exact `0.22.4` (no `^` / `~` range) per dev-preference.
|
|
107
|
-
- `pnpm audit` ran on install; no new high-severity vulnerabilities.
|