@oh-my-pi-zen/snapcompact 17.2.13-zen.2 → 17.2.15-zen.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/CHANGELOG.md +6 -0
- package/package.json +6 -5
- package/src/prompts/snapcompact-summary.md +15 -15
- package/src/snapcompact.ts +26 -11
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [17.2.15] - 2026-08-12
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed Anthropic model ID parsing to be case-insensitive and extended the high-resolution 1932px frame tier to Claude Opus 5 and later, preventing sessions from falling back to lower-resolution 1568px frames and preserving full history per compaction.
|
|
10
|
+
|
|
5
11
|
## [17.1.5] - 2026-07-27
|
|
6
12
|
|
|
7
13
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi-zen/snapcompact",
|
|
4
|
-
"version": "17.2.
|
|
4
|
+
"version": "17.2.15-zen.2",
|
|
5
5
|
"description": "Bitmap-frame context compression for vision-capable LLMs",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -31,10 +31,11 @@
|
|
|
31
31
|
"fmt": "biome format --write ."
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@oh-my-pi-zen/pi-ai": "17.2.
|
|
35
|
-
"@oh-my-pi-zen/pi-
|
|
36
|
-
"@oh-my-pi-zen/pi-
|
|
37
|
-
"@oh-my-pi-zen/pi-
|
|
34
|
+
"@oh-my-pi-zen/pi-ai": "17.2.15-zen.2",
|
|
35
|
+
"@oh-my-pi-zen/pi-catalog": "17.2.15-zen.2",
|
|
36
|
+
"@oh-my-pi-zen/pi-natives": "17.2.15-zen.2",
|
|
37
|
+
"@oh-my-pi-zen/pi-utils": "17.2.15-zen.2",
|
|
38
|
+
"@oh-my-pi-zen/pi-wire": "17.2.15-zen.2"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@types/bun": "^1.3.14"
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
Resume prior conversation. Earlier turns archived under HISTORY below, oldest→newest. Read HISTORY fully; continue the live conversation following it.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
- `¶user:`, `¶think:`, `¶ai:`,
|
|
5
|
-
-
|
|
6
|
-
-
|
|
3
|
+
Archived transcript scopes:
|
|
4
|
+
- `¶user:`, `¶think:`, `¶ai:`, `¶call:`: user, assistant reasoning, assistant reply, tool call.
|
|
5
|
+
- Unprefixed following lines: current scope. Consecutive same-kind blocks omit repeated prefix.
|
|
6
|
+
- Tool call: `¶call:name(args)//intent`; trailing `//intent` optional. `<out>…</out>`: tool output.
|
|
7
7
|
|
|
8
8
|
Reading HISTORY:
|
|
9
|
-
- Plain
|
|
10
|
-
{{#if frameCount}}- Some middle sections
|
|
11
|
-
{{#if docColumns}} -
|
|
12
|
-
{{else}} -
|
|
13
|
-
{{/if}}{{#if sentenceInk}} - Ink
|
|
14
|
-
{{/if}}{{#if stopwordDimmed}} - Function words
|
|
15
|
-
{{/if}}{{#if lineRepeated}} - Each line
|
|
16
|
-
{{/if}}{{/if}}{{#if includedPreviousSummary}}- HISTORY opens with a condensed digest of still-older context
|
|
17
|
-
{{/if}}{{#if truncatedChars}}- About {{truncatedChars}} characters of older middle history
|
|
9
|
+
- Plain text: verbatim transcript; rely on it exactly.
|
|
10
|
+
{{#if frameCount}}- Some middle sections: images, not text. Each image: one page of that transcript, in reading order between marked delimiters. Solid black cell: newline; runs of spaces collapse to one.
|
|
11
|
+
{{#if docColumns}} - Frame: two side-by-side columns, each {{cols}} characters wide, up to {{rows}} rows tall; read left top→bottom, then right.
|
|
12
|
+
{{else}} - Frame: one grid {{cols}} characters wide, up to {{rows}} rows tall; read left→right, top→bottom. No word wrap; words may break across rows.
|
|
13
|
+
{{/if}}{{#if sentenceInk}} - Ink: six colors, one per sentence.
|
|
14
|
+
{{/if}}{{#if stopwordDimmed}} - Function words: dim gray; content words: full ink.
|
|
15
|
+
{{/if}}{{#if lineRepeated}} - Each line printed twice (white, then pale-yellow band); copies identical.
|
|
16
|
+
{{/if}}{{/if}}{{#if includedPreviousSummary}}- HISTORY opens with a condensed digest of still-older context predating archived turns.
|
|
17
|
+
{{/if}}{{#if truncatedChars}}- About {{truncatedChars}} characters of older middle history dropped to fit archive budget.
|
|
18
18
|
{{/if}}{{#if exactStrings}}- Image text may contain exact-string anchors like `[E001]`. Resolve them from EXACT STRING ANCHORS below; use the side-channel value for paths, commands, hashes, architecture tokens, URI refs, and other byte-sensitive facts.
|
|
19
|
-
{{/if}}-
|
|
19
|
+
{{/if}}- If an exact earlier detail matters and a section is unclear, re-derive from workspace (re-read files, re-run commands), rather than guess.
|
|
20
20
|
|
|
21
21
|
{{#if files}}FILES
|
|
22
22
|
===================
|
package/src/snapcompact.ts
CHANGED
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
48
|
import type { Api, ImageContent, Message, TextContent } from "@oh-my-pi-zen/pi-ai";
|
|
49
|
+
import { isFableOrMythos, parseAnthropicModel, semverGte } from "@oh-my-pi-zen/pi-catalog/identity";
|
|
49
50
|
import { renderSnapcompactPng, snapcompactAdvanceFrameCounts, snapcompactSupportedChars } from "@oh-my-pi-zen/pi-natives";
|
|
50
51
|
import { formatGroupedPaths, prompt } from "@oh-my-pi-zen/pi-utils";
|
|
51
52
|
import { INTENT_FIELD } from "@oh-my-pi-zen/pi-wire";
|
|
@@ -396,17 +397,17 @@ export interface IdealShape {
|
|
|
396
397
|
frameSize?: number;
|
|
397
398
|
}
|
|
398
399
|
|
|
399
|
-
/** Eval-winning format per model line
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
* family's winner at the standard 1568px frame.
|
|
400
|
+
/** Eval-winning format per model line. The wire API only identifies the
|
|
401
|
+
* gateway — a Claude served through Vertex or OpenRouter still reads best
|
|
402
|
+
* with its own shape. Classified Anthropic models use the shared catalog
|
|
403
|
+
* identity parser; remaining model lines use first-match regex rules and fall
|
|
404
|
+
* back to the API family's winner at the standard 1568px frame. */
|
|
405
|
+
const HIGH_RES_ANTHROPIC_VARIANT = { variant: "11on16-bw", frameSize: 1932 } as const satisfies IdealShape;
|
|
404
406
|
const MODEL_VARIANTS: readonly (readonly [RegExp, IdealShape])[] = [
|
|
405
|
-
//
|
|
406
|
-
//
|
|
407
|
-
//
|
|
408
|
-
[/claude.*(fable|mythos)/i,
|
|
409
|
-
[/claude-?opus-?4[.-][7-9]/i, { variant: "11on16-bw", frameSize: 1932 }],
|
|
407
|
+
// Versionless Fable/Mythos aliases (e.g. `claude-fable-latest`) never parse
|
|
408
|
+
// a numeric version, so keep them on the high-res tier by name — every
|
|
409
|
+
// Fable/Mythos line reads it natively.
|
|
410
|
+
[/claude.*(fable|mythos)/i, HIGH_RES_ANTHROPIC_VARIANT],
|
|
410
411
|
// Older Claude lines downscale past 1568px — keep the safe size.
|
|
411
412
|
[/claude/i, { variant: "11on16-bw" }],
|
|
412
413
|
// Gemini 3.x bills a fixed 1,120-token budget per image regardless of
|
|
@@ -423,6 +424,20 @@ const MODEL_VARIANTS: readonly (readonly [RegExp, IdealShape])[] = [
|
|
|
423
424
|
|
|
424
425
|
/** Eval-ideal format for a model id, or undefined when unmeasured. */
|
|
425
426
|
export function idealShapeVariant(modelId: string): IdealShape | undefined {
|
|
427
|
+
// The catalog parser is case-sensitive; the regex rules below are not.
|
|
428
|
+
// Normalize so mixed-case gateway ids keep matching the Anthropic tier.
|
|
429
|
+
const anthropic = parseAnthropicModel(modelId.toLowerCase());
|
|
430
|
+
if (
|
|
431
|
+
anthropic &&
|
|
432
|
+
(isFableOrMythos(anthropic.kind) || (anthropic.kind === "opus" && semverGte(anthropic.version, "4.7")))
|
|
433
|
+
) {
|
|
434
|
+
// Opus 4.7+ and Fable/Mythos read high-res natively: same recall and
|
|
435
|
+
// cost as 1568, a third fewer frames. 1932 is the largest *square* not
|
|
436
|
+
// downscaled under Anthropic's 4,784 visual-token cap ((1932/28)² =
|
|
437
|
+
// 69² = 4,761 ≤ 4,784 28px patches), and staying below 2000px clears
|
|
438
|
+
// the stricter ≤2000px limit for requests with more than 20 images.
|
|
439
|
+
return HIGH_RES_ANTHROPIC_VARIANT;
|
|
440
|
+
}
|
|
426
441
|
return MODEL_VARIANTS.find(([pattern]) => pattern.test(modelId))?.[1];
|
|
427
442
|
}
|
|
428
443
|
|
|
@@ -993,7 +1008,7 @@ function textBlocks(content: Message["content"]): string[] {
|
|
|
993
1008
|
if (typeof content === "string") return [content];
|
|
994
1009
|
const texts: string[] = [];
|
|
995
1010
|
for (const block of content) {
|
|
996
|
-
if (block.type === "text") texts.push(block.text);
|
|
1011
|
+
if (block.type === "text" && "text" in block) texts.push(block.text);
|
|
997
1012
|
}
|
|
998
1013
|
return texts;
|
|
999
1014
|
}
|