@xamukavila/pxpipe 0.8.0 → 0.9.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 +33 -10
- package/dist/core/applicability.js +2 -2
- package/dist/core/export.js +2 -2
- package/dist/dashboard/fragments.js +1 -0
- package/dist/node.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ measured per-request against a free `count_tokens` counterfactual in
|
|
|
16
16
|
|
|
17
17
|
This is what the model sees instead of text:
|
|
18
18
|
|
|
19
|
-

|
|
20
20
|
|
|
21
21
|
*~48k chars of system prompt + tool docs: ≈25k tokens as text, ≈2.7k image
|
|
22
22
|
tokens as this page. Real pipeline output; the model reads renders like this
|
|
@@ -45,7 +45,7 @@ rate is why Opus is opt-in.
|
|
|
45
45
|
## Try it (30 seconds)
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
npx pxpipe
|
|
48
|
+
npx @xamukavila/pxpipe # proxy on 127.0.0.1:47821
|
|
49
49
|
ANTHROPIC_BASE_URL=http://127.0.0.1:47821 claude # point Claude Code at it
|
|
50
50
|
```
|
|
51
51
|
|
|
@@ -74,8 +74,8 @@ are imaged.
|
|
|
74
74
|
loses money on sparse prose (~3.5 chars/token); a profitability gate
|
|
75
75
|
(calibrated on N=391 production rows) images only where the math wins.
|
|
76
76
|
- **Model scope:** default `PXPIPE_MODELS=claude-fable-5,gpt-5.6`. Opus
|
|
77
|
-
4.7/4.8 misread ~7% of renders and GPT 5.5 degrades on imaged context, so
|
|
78
|
-
|
|
77
|
+
4.6/4.7/4.8 misread ~7% of renders and GPT 5.5 degrades on imaged context, so
|
|
78
|
+
all are opt-in via `PXPIPE_MODELS` or the dashboard chips.
|
|
79
79
|
`PXPIPE_MODELS=off` disables imaging. Everything else passes through
|
|
80
80
|
byte-identical. On the GPT path, tool definitions stay native JSON and no
|
|
81
81
|
Anthropic `cache_control` markers are used.
|
|
@@ -127,7 +127,7 @@ bench below shows it is cheaper and cache-stable, **not** that recall holds.
|
|
|
127
127
|
| Library | `transformAnthropicMessages({ …, caveman: true })` | boolean, default `false` |
|
|
128
128
|
|
|
129
129
|
```bash
|
|
130
|
-
PXPIPE_CAVEMAN=1 npx pxpipe
|
|
130
|
+
PXPIPE_CAVEMAN=1 npx @xamukavila/pxpipe # prose compression ON (experiment)
|
|
131
131
|
```
|
|
132
132
|
|
|
133
133
|
⚠️ Flipping the flag changes the rendered image bytes, which **busts warm image
|
|
@@ -172,6 +172,29 @@ PXPIPE_CAVEMAN=1 bash bench/run.sh --model 'claude-opus-4-6[1m]' --label caveman
|
|
|
172
172
|
node bench/score.mjs bench/runs/<off-dir> bench/runs/<caveman-dir>
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
+
### Does it hurt recall?
|
|
176
|
+
|
|
177
|
+
A recall A/B (`eval/caveman-slab/`, pre-registered) put seeded facts into an
|
|
178
|
+
imaged system-prompt slab and compared **plain image vs caveman image** at
|
|
179
|
+
production density, fable-5, N=50 answerable + 10 unanswerable per arm:
|
|
180
|
+
|
|
181
|
+
| arm | answerable correct | confabulated (never-stated facts) |
|
|
182
|
+
|---|---:|---:|
|
|
183
|
+
| plain image | 31/50 (62%) | 3/10 |
|
|
184
|
+
| caveman image | 32/50 (64%) | 0/10 |
|
|
185
|
+
|
|
186
|
+
Tied within noise across every fact type (decision, numeric, path, name,
|
|
187
|
+
negation); caveman confabulated *less*. **caveman does not measurably hurt
|
|
188
|
+
recall vs plain imaging** — and the caveman-rendered slabs cost **−6.9% image
|
|
189
|
+
tokens** (10,751 → 10,004 across the 10 slabs), so the saving is free of recall
|
|
190
|
+
cost. Two caveats keep this from being a default-on green light: both arms hit a
|
|
191
|
+
~63% **floor** (the single dense page is hard to read — plain fails the same
|
|
192
|
+
way, so the floor is the render, not caveman), and the eval deliberately omits
|
|
193
|
+
the production "fact sheet" that keeps exact identifiers as text
|
|
194
|
+
(`transform.ts:1627`), so the numeric/path misses it counts would not occur in
|
|
195
|
+
production. Full design, results, and follow-ups:
|
|
196
|
+
[`eval/caveman-slab/DESIGN.md`](eval/caveman-slab/DESIGN.md).
|
|
197
|
+
|
|
175
198
|
## How it works
|
|
176
199
|
|
|
177
200
|
```
|
|
@@ -188,7 +211,7 @@ sparse prose stays text. Events log to `~/.pxpipe/events.jsonl`.
|
|
|
188
211
|
## Library use (no proxy)
|
|
189
212
|
|
|
190
213
|
```ts
|
|
191
|
-
import { renderTextToImages, transformAnthropicMessages } from "pxpipe
|
|
214
|
+
import { renderTextToImages, transformAnthropicMessages } from "@xamukavila/pxpipe";
|
|
192
215
|
|
|
193
216
|
const { pages } = await renderTextToImages(toolResultText); // pages[i].png: Uint8Array
|
|
194
217
|
const { body, applied, info } = await transformAnthropicMessages({
|
|
@@ -245,10 +268,10 @@ Three kinds of *input* blocks, each behind a profitability gate:
|
|
|
245
268
|
Everything else passes through byte-identical: your messages, recent turns,
|
|
246
269
|
the model's output (it is the response, the proxy never touches it), sparse
|
|
247
270
|
prose, and anything too small to win. Models outside the allowlist pass
|
|
248
|
-
through entirely — the default scope is Fable 5 and GPT 5.6 only. Opus
|
|
249
|
-
and GPT 5.5 read imaged content measurably worse (FINDINGS.md
|
|
250
|
-
so they are deliberately opt-in via the dashboard or
|
|
251
|
-
silently imaged.
|
|
271
|
+
through entirely — the default scope is Fable 5 and GPT 5.6 only. Opus
|
|
272
|
+
4.6/4.7/4.8 and GPT 5.5 read imaged content measurably worse (FINDINGS.md
|
|
273
|
+
2026-06-16), so they are deliberately opt-in via the dashboard or
|
|
274
|
+
`PXPIPE_MODELS`, never silently imaged.
|
|
252
275
|
|
|
253
276
|
**Has it ever failed for real, outside the benchmarks?**
|
|
254
277
|
Yes, once in weeks of daily use: the model recalled a person's name from
|
|
@@ -7,11 +7,11 @@ function baseModelId(model) {
|
|
|
7
7
|
/** Dashboard runtime override; null = fall back to PXPIPE_MODELS env / built-in default. In-memory only. */
|
|
8
8
|
let runtimeModelBases = null;
|
|
9
9
|
/** Built-in default scope when PXPIPE_MODELS is unset: Fable 5 (Claude) plus
|
|
10
|
-
* GPT 5.6. GPT 5.5 and Opus 4.8 are intentionally off — same pipeline but
|
|
10
|
+
* GPT 5.6. GPT 5.5 and Opus 4.6/4.7/4.8 are intentionally off — same pipeline but
|
|
11
11
|
* measurably worse at reading imaged content (FINDINGS.md 2026-06-16: Opus 4.8
|
|
12
12
|
* ~2pp arithmetic, 6/15 dense-hex recall vs Fable's 100/100; GPT 5.5 likewise
|
|
13
13
|
* degrades on imaged history/context) — so silently imaging them is the wrong
|
|
14
|
-
* default.
|
|
14
|
+
* default. All stay opt-in via the dashboard chips or PXPIPE_MODELS. */
|
|
15
15
|
const DEFAULT_MODEL_BASES = ['claude-fable-5', 'gpt-5.6'];
|
|
16
16
|
function falsey(v) {
|
|
17
17
|
return /^(0|false|no|off|none)$/i.test(v.trim());
|
package/dist/core/export.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { DENSE_CONTENT_CHARS_PER_IMAGE, DENSE_CONTENT_COLS, MAX_HEIGHT_PX, PAD_X, CELL_W, } from './render.js';
|
|
10
10
|
// Dogfood the public SDK: render via the same `./transform` entry external
|
|
11
|
-
// consumers import (pxpipe
|
|
11
|
+
// consumers import (@xamukavila/pxpipe/transform → renderTextToImages), not the
|
|
12
12
|
// internal leaf renderer.
|
|
13
13
|
import { renderTextToImages } from './library.js';
|
|
14
14
|
import { estimateImageCount, ANTHROPIC_PIXELS_PER_TOKEN, IMAGE_COST_SAFETY_MARGIN, REPORT_CHARS_PER_TOKEN } from './transform.js';
|
|
@@ -324,7 +324,7 @@ export async function runExportCore(sourceText, opts) {
|
|
|
324
324
|
// Render to PNG pages via the public SDK primitive. shrink=true sizes the canvas
|
|
325
325
|
// to the widest line so short-line code isn't padded to full width; multiCol='auto'
|
|
326
326
|
// packs as many columns side-by-side as fit. Same render surface shipped to external
|
|
327
|
-
// SDK consumers (pxpipe
|
|
327
|
+
// SDK consumers (@xamukavila/pxpipe/transform).
|
|
328
328
|
const { pages: images } = await renderTextToImages(sourceText, {
|
|
329
329
|
cols: opts.cols,
|
|
330
330
|
shrink: true,
|
|
@@ -60,6 +60,7 @@ const MODEL_CATALOG = [
|
|
|
60
60
|
{ id: 'claude-fable-5', label: 'Fable 5' },
|
|
61
61
|
{ id: 'claude-opus-4-8', label: 'Opus 4.8' },
|
|
62
62
|
{ id: 'claude-opus-4-7', label: 'Opus 4.7' },
|
|
63
|
+
{ id: 'claude-opus-4-6', label: 'Opus 4.6' },
|
|
63
64
|
{ id: 'claude-sonnet-5', label: 'Sonnet 5' },
|
|
64
65
|
{ id: 'claude-sonnet-4-6', label: 'Sonnet 4.6' },
|
|
65
66
|
];
|
package/dist/node.js
CHANGED
|
@@ -6749,6 +6749,7 @@ var MODEL_CATALOG = [
|
|
|
6749
6749
|
{ id: "claude-fable-5", label: "Fable 5" },
|
|
6750
6750
|
{ id: "claude-opus-4-8", label: "Opus 4.8" },
|
|
6751
6751
|
{ id: "claude-opus-4-7", label: "Opus 4.7" },
|
|
6752
|
+
{ id: "claude-opus-4-6", label: "Opus 4.6" },
|
|
6752
6753
|
{ id: "claude-sonnet-5", label: "Sonnet 5" },
|
|
6753
6754
|
{ id: "claude-sonnet-4-6", label: "Sonnet 4.6" }
|
|
6754
6755
|
];
|
|
@@ -8349,7 +8350,7 @@ Use with OpenAI-compatible GPT clients:
|
|
|
8349
8350
|
`);
|
|
8350
8351
|
}
|
|
8351
8352
|
function printVersion() {
|
|
8352
|
-
const injected = true ? "0.
|
|
8353
|
+
const injected = true ? "0.9.0" : void 0;
|
|
8353
8354
|
console.log(injected ?? process.env.npm_package_version ?? "unknown");
|
|
8354
8355
|
}
|
|
8355
8356
|
function toWebRequest(req) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xamukavila/pxpipe",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Token-saving proxy for Claude Code: renders bulky context (system prompt, tool docs, old history) as dense PNGs to cut input tokens. Runs on Node and Cloudflare Workers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|