From 85f8536b67aa8d7972e6d525ce95508dd141ea20 Mon Sep 17 00:00:00 2001 From: teamchong <25894545+teamchong@users.noreply.github.com> Date: Mon, 22 Jun 2026 16:25:02 -0400 Subject: [PATCH] chore: release 0.6.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GPT autonomous agents (OpenCode/gpt-5.5) no longer lose the live request to history imaging — the most-recent user turn is pinned as legible text between before/after history images, with the guard echoing it. Fixes snap/confabulation /off-task drift; validated on gpt-5.5 (stays on task, no off-task edits). Patch, not minor: GPT is opt-in/WIP and hidden in the dashboard, and the visible Anthropic path is byte-identical (pin commit 08a2b0a touched only the GPT path). Also: clarifying comment on the minCollapseTokens gate (counts imageable work only; sub-floor histories stay fully text by design — request stays legible). 473 tests pass; tsc + build clean. --- CHANGELOG.md | 22 ++++++++++++++++++++++ package.json | 2 +- src/core/openai-history.ts | 5 +++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90da104..7b3ccf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,28 @@ All notable changes to pxpipe are documented here. This project adheres to [Semantic Versioning](https://semver.org/) (pre-1.0: minor = features / behavioral changes, patch = fixes). +## 0.6.3 — 2026-06-22 + +### Fixed +- **GPT autonomous agents no longer lose the live request to history imaging.** + Autonomous GPT agents (OpenCode/gpt-5.5) send one human request then a long run of + tool turns. The lone request is the oldest turn, so history collapse imaged it first + and the model lost it — confabulating the request and drifting off-task (observed: + editing a file instead of answering a compare question). Fix: the most-recent user + turn *overall* is kept as legible text, spliced between before-pin and after-pin + history images inside the synthetic user message; older user turns stay imaged (they + must not look live). The `developer` guard now echoes the request verbatim. History + stays imaged on both sides of the pin, so compression barely changes. Both Chat + Completions and Responses paths. GPT support remains opt-in/WIP (hidden in the + dashboard), so this does not affect the Anthropic path. (`openai-history.ts`, + `openai.ts`) + + Cache safety (adversarially reviewed): the pin fires only when the latest user turn + is *inside* the collapse range — otherwise it is already native text in the kept + tail — so the pin's position is fixed across a run and the before/after section grid + stays byte-stable. An undersized before-pin remainder merges into the previous + section rather than emitting a sub-threshold (net-negative) image. + ## 0.6.2 — 2026-06-22 ### Fixed diff --git a/package.json b/package.json index 72460d4..8491b5a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pxpipe-proxy", - "version": "0.6.2", + "version": "0.6.3", "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.", "type": "module", "bin": { diff --git a/src/core/openai-history.ts b/src/core/openai-history.ts index b076dad..ec3d560 100644 --- a/src/core/openai-history.ts +++ b/src/core/openai-history.ts @@ -281,6 +281,11 @@ export async function planGptCollapse( const text = joinTurns(turns, pp, rawEnd, pinIdx); // Floor gate in o200k TOKENS, not chars: imaging bills vision tokens and the // text baseline is o200k tokens, so the break-even is a token comparison. + // NOTE: this counts the IMAGEABLE work only (pin excluded), so a small history + // whose non-pin content is below the floor is left fully as text. That is correct, + // not a regression: the pinned request stays legible either way, and imaging a + // sub-floor amount of work would cost more vision tokens than it saves. Only long + // sessions (where the bug lived) clear the floor and collapse. if (!text || gptCountTokens(text) < o.minCollapseTokens) { return { ...base, reason: 'below_min_tokens', collapsedChars: text?.length ?? 0 }; }