@oh-my-pi/snapcompact 17.0.9 → 17.1.1
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/dist/types/snapcompact.d.ts +6 -0
- package/package.json +5 -5
- package/src/snapcompact.ts +39 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [17.1.0] - 2026-07-24
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added an `includeThinking` serialization option (defaulting to `true`) to allow excluding assistant reasoning (`¶think:` sections) from archived transcripts.
|
|
10
|
+
|
|
5
11
|
## [16.5.0] - 2026-07-13
|
|
6
12
|
|
|
7
13
|
### Changed
|
|
@@ -479,6 +479,12 @@ export interface SerializeOptions {
|
|
|
479
479
|
/** Print tool-result text in dim gray ink so archived conversation reads
|
|
480
480
|
* louder than archived tool noise. Defaults to `true`. */
|
|
481
481
|
dimToolResults?: boolean;
|
|
482
|
+
/** Serialize assistant reasoning as `¶think:` sections. Defaults to `true`.
|
|
483
|
+
* Callers archiving for a Claude/Anthropic-dialect model set this `false`:
|
|
484
|
+
* the archive frames are replayed as text into every later request, and
|
|
485
|
+
* reasoning rendered back to Claude trips its `reasoning_extraction`
|
|
486
|
+
* classifier (issue #6093). */
|
|
487
|
+
includeThinking?: boolean;
|
|
482
488
|
}
|
|
483
489
|
export declare function serializeConversation(messages: Message[], options?: SerializeOptions): string;
|
|
484
490
|
/** Printed in place of newline runs: the native renderer fills this cell
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/snapcompact",
|
|
4
|
-
"version": "17.
|
|
4
|
+
"version": "17.1.1",
|
|
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,10 @@
|
|
|
31
31
|
"fmt": "biome format --write ."
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@oh-my-pi/pi-ai": "17.
|
|
35
|
-
"@oh-my-pi/pi-natives": "17.
|
|
36
|
-
"@oh-my-pi/pi-utils": "17.
|
|
37
|
-
"@oh-my-pi/pi-wire": "17.
|
|
34
|
+
"@oh-my-pi/pi-ai": "17.1.1",
|
|
35
|
+
"@oh-my-pi/pi-natives": "17.1.1",
|
|
36
|
+
"@oh-my-pi/pi-utils": "17.1.1",
|
|
37
|
+
"@oh-my-pi/pi-wire": "17.1.1"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/bun": "^1.3.14"
|
package/src/snapcompact.ts
CHANGED
|
@@ -735,6 +735,12 @@ export interface SerializeOptions {
|
|
|
735
735
|
/** Print tool-result text in dim gray ink so archived conversation reads
|
|
736
736
|
* louder than archived tool noise. Defaults to `true`. */
|
|
737
737
|
dimToolResults?: boolean;
|
|
738
|
+
/** Serialize assistant reasoning as `¶think:` sections. Defaults to `true`.
|
|
739
|
+
* Callers archiving for a Claude/Anthropic-dialect model set this `false`:
|
|
740
|
+
* the archive frames are replayed as text into every later request, and
|
|
741
|
+
* reasoning rendered back to Claude trips its `reasoning_extraction`
|
|
742
|
+
* classifier (issue #6093). */
|
|
743
|
+
includeThinking?: boolean;
|
|
738
744
|
}
|
|
739
745
|
|
|
740
746
|
/** Keep the head and tail of `text`, eliding the middle beyond `maxChars`. */
|
|
@@ -773,6 +779,7 @@ export function serializeConversation(messages: Message[], options?: SerializeOp
|
|
|
773
779
|
const toolCallMaxChars = options?.toolCallMaxChars ?? TOOL_CALL_MAX_CHARS;
|
|
774
780
|
const headRatio = options?.truncateHeadRatio ?? TRUNCATE_HEAD_RATIO;
|
|
775
781
|
const dimToolResults = options?.dimToolResults !== false;
|
|
782
|
+
const includeThinking = options?.includeThinking !== false;
|
|
776
783
|
const parts: string[] = [];
|
|
777
784
|
let lastPrefix: string | null = null;
|
|
778
785
|
|
|
@@ -845,6 +852,7 @@ export function serializeConversation(messages: Message[], options?: SerializeOp
|
|
|
845
852
|
const text = stripDimMarkers(block.text);
|
|
846
853
|
if (text.trim()) pendingText.push(text);
|
|
847
854
|
} else if (block.type === "thinking") {
|
|
855
|
+
if (!includeThinking) continue;
|
|
848
856
|
const thinking = stripDimMarkers(block.thinking);
|
|
849
857
|
if (thinking.trim()) pendingThinking.push(thinking);
|
|
850
858
|
} else if (block.type === "toolCall") {
|
|
@@ -1833,6 +1841,29 @@ function planArchive(text: string, high: Shape, low: Shape, maxFrames: number):
|
|
|
1833
1841
|
};
|
|
1834
1842
|
}
|
|
1835
1843
|
|
|
1844
|
+
/**
|
|
1845
|
+
* Drop `¶think:` sections from serialized archive source text.
|
|
1846
|
+
*
|
|
1847
|
+
* Archives written before {@link SerializeOptions.includeThinking} existed bake
|
|
1848
|
+
* reasoning into their kept source; replaying it to Claude trips the
|
|
1849
|
+
* `reasoning_extraction` classifier (issue #6093). Re-compaction re-renders the
|
|
1850
|
+
* whole unfolded source, so scrubbing the prior text heals a poisoned session
|
|
1851
|
+
* at its next compaction. Conservative by construction: only sections that
|
|
1852
|
+
* start with `¶think:` at a section boundary are dropped.
|
|
1853
|
+
*/
|
|
1854
|
+
function stripThinkingSections(text: string): string {
|
|
1855
|
+
return text
|
|
1856
|
+
.split(NEWLINE_GLYPH)
|
|
1857
|
+
.map(segment =>
|
|
1858
|
+
segment
|
|
1859
|
+
.split(/\n\n(?=¶(?:user|think|ai|call):)/)
|
|
1860
|
+
.filter(section => !section.startsWith("¶think:"))
|
|
1861
|
+
.join("\n\n"),
|
|
1862
|
+
)
|
|
1863
|
+
.filter(segment => segment.length > 0)
|
|
1864
|
+
.join(NEWLINE_GLYPH);
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1836
1867
|
/**
|
|
1837
1868
|
* Run a snapcompact compaction over prepared messages. Fully local: serializes
|
|
1838
1869
|
* the discarded history, appends it to the accumulated archive source text, and
|
|
@@ -1858,11 +1889,18 @@ export async function compact<TMessage = Message>(
|
|
|
1858
1889
|
const llmMessages = (options?.convertToLlm ?? defaultConvertToLlm)(messages);
|
|
1859
1890
|
const serialized = serializeConversation(llmMessages, options);
|
|
1860
1891
|
const previousArchive = getPreservedArchive(previousPreserveData);
|
|
1861
|
-
const
|
|
1892
|
+
const previousTextRaw =
|
|
1862
1893
|
previousArchive?.text ??
|
|
1863
1894
|
[previousArchive?.textHead, previousArchive?.textTail]
|
|
1864
1895
|
.filter((part): part is string => typeof part === "string" && part.length > 0)
|
|
1865
1896
|
.join(NEWLINE_GLYPH);
|
|
1897
|
+
// Legacy archives may carry `¶think:` sections from before includeThinking
|
|
1898
|
+
// existed; scrub them when this compaction excludes thinking so the
|
|
1899
|
+
// re-rendered archive stops replaying reasoning (issue #6093).
|
|
1900
|
+
const previousText =
|
|
1901
|
+
options?.includeThinking === false && previousTextRaw.length > 0
|
|
1902
|
+
? stripThinkingSections(previousTextRaw)
|
|
1903
|
+
: previousTextRaw;
|
|
1866
1904
|
const hasPreviousText = previousText.length > 0;
|
|
1867
1905
|
const includedPreviousSummary = !hasPreviousText && !!previousSummary;
|
|
1868
1906
|
const shapeProbeText = renderabilityProbeText(serialized, previousPreserveData, previousSummary);
|