@raquezha/noheadroom 0.2.2 → 0.2.4
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/dist/client.d.ts +1 -0
- package/dist/client.js +14 -0
- package/dist/index.js +15 -6
- package/extensions/client.ts +14 -0
- package/extensions/index.ts +12 -6
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare class HeadroomHttpClient {
|
|
|
8
8
|
private readonly timeoutMs;
|
|
9
9
|
constructor(options: HeadroomClientOptions);
|
|
10
10
|
health(signal?: AbortSignal): Promise<boolean>;
|
|
11
|
+
probe(signal?: AbortSignal): Promise<boolean>;
|
|
11
12
|
stats(signal?: AbortSignal): Promise<unknown>;
|
|
12
13
|
compress(messages: OpenAIMessage[], model: string | undefined, signal?: AbortSignal): Promise<CompressResult>;
|
|
13
14
|
}
|
package/dist/client.js
CHANGED
|
@@ -21,6 +21,20 @@ export class HeadroomHttpClient {
|
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
+
async probe(signal) {
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetch(`${this.baseUrl}/v1/compress`, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: { "Content-Type": "application/json" },
|
|
29
|
+
body: JSON.stringify({ messages: [{ role: "user", content: "ping" }], model: "gpt-4o" }),
|
|
30
|
+
signal: buildSignal(5_000, signal),
|
|
31
|
+
});
|
|
32
|
+
return response.ok;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
24
38
|
async stats(signal) {
|
|
25
39
|
const response = await fetch(`${this.baseUrl}/stats`, {
|
|
26
40
|
signal: buildSignal(this.timeoutMs, signal),
|
package/dist/index.js
CHANGED
|
@@ -82,7 +82,12 @@ function createRuntime(pi) {
|
|
|
82
82
|
async function updateHealthState(runtime, signal) {
|
|
83
83
|
if (isRemoteBlocked(runtime.config))
|
|
84
84
|
return false;
|
|
85
|
-
|
|
85
|
+
if (await runtime.client.health(signal)) {
|
|
86
|
+
runtime.state.proxyOnline = true;
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
runtime.state.proxyOnline = await runtime.client.probe(signal);
|
|
90
|
+
}
|
|
86
91
|
return runtime.state.proxyOnline;
|
|
87
92
|
}
|
|
88
93
|
async function ensureProxy(runtime, ctx) {
|
|
@@ -293,8 +298,8 @@ function generateFingerprint(messages) {
|
|
|
293
298
|
return messages
|
|
294
299
|
.map((m) => {
|
|
295
300
|
const converted = convertMessage(m);
|
|
296
|
-
const
|
|
297
|
-
return `${m.role}:${
|
|
301
|
+
const text = converted ? extractOpenAIText(converted) : "";
|
|
302
|
+
return `${m.role}:${text.length}:${stableHash(text)}`;
|
|
298
303
|
})
|
|
299
304
|
.join(",");
|
|
300
305
|
}
|
|
@@ -382,12 +387,16 @@ function announceAppliedCompression(pi, ctx, result, appliedMessages) {
|
|
|
382
387
|
// Note: we no longer use pi.appendEntry or pi.sendMessage here because
|
|
383
388
|
// modifying the session history inside the context event triggers an infinite loop.
|
|
384
389
|
// Non-interactive `pi -p` does not always show footer/status UI, so print an explicit proof line.
|
|
385
|
-
|
|
390
|
+
// In interactive Pi TUI, writing to stderr during the context hook can leave a stale "Working..." row.
|
|
391
|
+
if (!ctx.hasUI)
|
|
392
|
+
process.stderr.write(`🗜 ${line}\n`);
|
|
386
393
|
}
|
|
387
394
|
function announceGuardSkip(ctx, reason, result) {
|
|
388
395
|
const line = `noheadroom: compression skipped by guard (${reason}); Headroom reported ${result.tokensSaved.toLocaleString()} tokens saved but Pi context was left unchanged`;
|
|
389
396
|
ctx.ui.notify(line, "warning");
|
|
390
|
-
|
|
397
|
+
// In interactive Pi TUI, writing to stderr during the context hook can leave a stale "Working..." row.
|
|
398
|
+
if (!ctx.hasUI)
|
|
399
|
+
process.stderr.write(`⚠ ${line}\n`);
|
|
391
400
|
}
|
|
392
401
|
function recordCompressionError(runtime, ctx, error) {
|
|
393
402
|
runtime.state.stats.lastError = getErrorMessage(error);
|
|
@@ -479,7 +488,7 @@ function renderFooterStatus(ctx, config, state) {
|
|
|
479
488
|
if (!state.stats.last)
|
|
480
489
|
return paint("success", "✓") + paint("dim", " Headroom");
|
|
481
490
|
const pct = Math.round((1 - state.stats.last.compressionRatio) * 100);
|
|
482
|
-
return (paint("success", "✓") + paint("dim", ` Headroom -${pct}% (${state.stats.last.tokensSaved.toLocaleString()}
|
|
491
|
+
return (paint("success", "✓") + paint("dim", ` Headroom -${pct}% (${state.stats.last.tokensSaved.toLocaleString()} sve)`));
|
|
483
492
|
}
|
|
484
493
|
async function showProxyStats(ctx, client, config) {
|
|
485
494
|
if (isRemoteBlocked(config)) {
|
package/extensions/client.ts
CHANGED
|
@@ -38,6 +38,20 @@ export class HeadroomHttpClient {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
async probe(signal?: AbortSignal): Promise<boolean> {
|
|
42
|
+
try {
|
|
43
|
+
const response = await fetch(`${this.baseUrl}/v1/compress`, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: { "Content-Type": "application/json" },
|
|
46
|
+
body: JSON.stringify({ messages: [{ role: "user", content: "ping" }], model: "gpt-4o" }),
|
|
47
|
+
signal: buildSignal(5_000, signal),
|
|
48
|
+
});
|
|
49
|
+
return response.ok;
|
|
50
|
+
} catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
41
55
|
async stats(signal?: AbortSignal): Promise<unknown> {
|
|
42
56
|
const response = await fetch(`${this.baseUrl}/stats`, {
|
|
43
57
|
signal: buildSignal(this.timeoutMs, signal),
|
package/extensions/index.ts
CHANGED
|
@@ -137,7 +137,11 @@ function createRuntime(pi: ExtensionAPI): HeadroomRuntime {
|
|
|
137
137
|
|
|
138
138
|
async function updateHealthState(runtime: HeadroomRuntime, signal?: AbortSignal): Promise<boolean> {
|
|
139
139
|
if (isRemoteBlocked(runtime.config)) return false;
|
|
140
|
-
|
|
140
|
+
if (await runtime.client.health(signal)) {
|
|
141
|
+
runtime.state.proxyOnline = true;
|
|
142
|
+
} else {
|
|
143
|
+
runtime.state.proxyOnline = await runtime.client.probe(signal);
|
|
144
|
+
}
|
|
141
145
|
return runtime.state.proxyOnline;
|
|
142
146
|
}
|
|
143
147
|
|
|
@@ -368,8 +372,8 @@ function generateFingerprint(messages: AgentMessage[]): string {
|
|
|
368
372
|
return messages
|
|
369
373
|
.map((m) => {
|
|
370
374
|
const converted = convertMessage(m);
|
|
371
|
-
const
|
|
372
|
-
return `${m.role}:${
|
|
375
|
+
const text = converted ? extractOpenAIText(converted) : "";
|
|
376
|
+
return `${m.role}:${text.length}:${stableHash(text)}`;
|
|
373
377
|
})
|
|
374
378
|
.join(",");
|
|
375
379
|
}
|
|
@@ -460,13 +464,15 @@ function announceAppliedCompression(
|
|
|
460
464
|
// Note: we no longer use pi.appendEntry or pi.sendMessage here because
|
|
461
465
|
// modifying the session history inside the context event triggers an infinite loop.
|
|
462
466
|
// Non-interactive `pi -p` does not always show footer/status UI, so print an explicit proof line.
|
|
463
|
-
|
|
467
|
+
// In interactive Pi TUI, writing to stderr during the context hook can leave a stale "Working..." row.
|
|
468
|
+
if (!ctx.hasUI) process.stderr.write(`🗜 ${line}\n`);
|
|
464
469
|
}
|
|
465
470
|
|
|
466
471
|
function announceGuardSkip(ctx: ExtensionContext, reason: string, result: CompressResult): void {
|
|
467
472
|
const line = `noheadroom: compression skipped by guard (${reason}); Headroom reported ${result.tokensSaved.toLocaleString()} tokens saved but Pi context was left unchanged`;
|
|
468
473
|
ctx.ui.notify(line, "warning");
|
|
469
|
-
|
|
474
|
+
// In interactive Pi TUI, writing to stderr during the context hook can leave a stale "Working..." row.
|
|
475
|
+
if (!ctx.hasUI) process.stderr.write(`⚠ ${line}\n`);
|
|
470
476
|
}
|
|
471
477
|
|
|
472
478
|
function recordCompressionError(runtime: HeadroomRuntime, ctx: ExtensionContext, error: unknown): void {
|
|
@@ -576,7 +582,7 @@ function renderFooterStatus(ctx: ExtensionContext, config: HeadroomConfig, state
|
|
|
576
582
|
|
|
577
583
|
const pct = Math.round((1 - state.stats.last.compressionRatio) * 100);
|
|
578
584
|
return (
|
|
579
|
-
paint("success", "✓") + paint("dim", ` Headroom -${pct}% (${state.stats.last.tokensSaved.toLocaleString()}
|
|
585
|
+
paint("success", "✓") + paint("dim", ` Headroom -${pct}% (${state.stats.last.tokensSaved.toLocaleString()} sve)`)
|
|
580
586
|
);
|
|
581
587
|
}
|
|
582
588
|
|
package/package.json
CHANGED