feat(compaction): capability-gated OpenAI remote compaction with faithful history degradation#294
Merged
code-yeongyu merged 3 commits intoJul 22, 2026
Conversation
…mote-convert module Pure move: wire item types, details schema guard, and branch-to-input conversion now live in openai-remote-convert.ts. No behavior change; openai-remote.ts re-exports the moved public symbols. Existing suite: 22 files / 170 tests green, tsgo + biome clean.
The remote-compaction route no longer requires the entire session branch to be OpenAI Responses-native. Matching codex's supports_remote_compaction(), the gate is now provider capability only (current model is openai + openai-responses), and branch conversion is total: entries flow through the same sessionEntryToContextMessages + convertToLlm pipeline the normal context path uses, so foreign-provider assistant messages, bash executions, branch summaries, custom messages, and prior local compaction entries degrade to their canonical text form instead of forcing a local-summary fallback. Image-bearing tool results mirror the Responses payload builder (structured parts for image-capable models, placeholder otherwise). The payload rewrite no longer silently skips when post-compaction history is not OpenAI-native. Evidence: test/compaction 23 files green; senpi-qa compaction-remote-qa 5/5 on the real CLI (mixed anthropic->openai session compacts via /v1/responses/compact, replay verified), artifacts under local-ignore/qa-evidence/20260722-openai-remote-capability-gate/.
…eplay The before_provider_request replay after a remote compaction rebuilt the payload from the persisted branch only. The in-flight user prompt is not yet persisted at that point, so the replayed payload silently dropped it - the model never saw the first message after a remote compaction. Pre-existing on main; surfaced by the mixed-history e2e QA scenario. The context handler now stashes the not-yet-persisted tail messages and rewriteOpenAiPayloadWithRemoteCompaction appends their conversion after the branch-derived items. Evidence: test/compaction 22 files / 177 tests green; senpi-qa compaction-remote-qa 6/6 incl. prompt-presence assertion on the real CLI; npm run check green.
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 34049272 | Triggered | Generic High Entropy Secret | fe6a8bc | .agents/skills/senpi-qa/scripts/compaction-remote-qa.mjs | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
This was referenced Jul 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Senpi's OpenAI remote compaction (
/responses/compactand the Responses WebSocketcontext_compactionroute) previously only ran when the entire session branch was OpenAI Responses-native — any foreign-provider assistant message,!bash execution, branch summary, custom message, image tool result, or a prior local compaction silently forced the route back to local text summarization for the rest of the session. This PR changes the gate to a provider-capability check only (current model isopenai+openai-responses, matching codex'ssupports_remote_compaction()), and makes branch-to-input conversion total by degrading non-native entries to their canonical text form via the samesessionEntryToContextMessages+convertToLlmpipeline the normal context path uses.It also fixes a pre-existing replay bug surfaced by the new end-to-end QA: after a remote compaction, the next provider request's payload was rebuilt from the persisted branch only, and the user's in-flight prompt (not yet persisted) was silently dropped — the model never saw the first message after a remote compaction.
Changes
compaction/openai-remote-convert.ts(extracted fromopenai-remote.tsin a prep refactor): branch conversion is now total. Foreign assistant messages keep text/tool calls and skip unrepresentable thinking/provider-native blocks; bash executions, branch summaries, custom messages, and prior local compaction entries convert to their canonical user-text forms; image-bearing tool results mirror the Responses payload builder (structuredinput_text/input_imageparts for image-capable models,(see attached image)otherwise). Prior remote-compaction checkpoints still splice nativereplacementInputin order.compaction/openai-remote.ts: route gate = capability only; thesession-not-openai-nativefallback reason is gone (onlyempty-compaction-inputremains); payload rewrite always applies and now appends the in-flight pending messages after the branch-derived items.compaction/index.ts: thecontexthandler stashes the not-yet-persisted tail messages (pendingProviderMessages) so the rewrite can include them; computed defensively frombuildContextEntries(branch)for partial-session-manager contexts.test/compaction/openai-remote-compaction.test.ts— pure-OpenAI characterization (unchanged expectations), degradation cases (mixed providers, bash executions, local compaction entries, branch/custom entries, image tool results), a mixed-history remote run throughrunOpenAiRemoteCompaction, rewrite with a non-native tail, and pending-prompt preservation..agents/skills/senpi-qa/scripts/compaction-remote-qa.mjs— drives the real CLI (--mode rpc) against a local mock serving Anthropic Messages, OpenAI Responses, and/v1/responses/compact.compaction/changes.md: fork-tracker entries for both changes.QA & Evidence
npx vitest run test/compaction/(22 files, 177 tests) covering every degradation path and both rewrites; static —npm run check(biome, tsgo, pinned deps, shrinkwrap, neo) green.node .agents/skills/senpi-qa/scripts/compaction-remote-qa.mjs --self-test— real CLI over RPC: anthropic mock turn → openai mock turn →compact→ follow-up turn./v1/responses/compactcalled despite the anthropic turn in history; the anthropic turn reaches OpenAI as a degradedoutput_textitem; the RPCcompactresponse carriessenpi.compaction.openai-remote.v1details; the post-compaction/v1/responsespayload replays the native compaction item and still contains the user's new prompt (this last assertion fails without the replay fix); real~/.senpiauth untouched.local-ignore/qa-evidence/20260722-openai-remote-capability-gate/compaction-remote-qa.json(full request/response capture).openai-responsesself-test (4/4) confirms no QA-channel regression.Risks & Residuals
buildContextEntries(branch)alignment with the context messages; earliercontext-chain extensions that inject messages could shift the count. Mitigation: miscounts bias toward dropping the pending tail (today's behavior), never toward corrupting history; covered by unit + e2e tests. Accepted, noted inchanges.md.Related Issues
Discord report: senpi fell back to local compaction for GPT sessions whenever history wasn't fully OpenAI-native (mixed-model sessions,
!commands, prior local compactions).Summary by cubic
Enables OpenAI remote compaction whenever the current model supports it, even with mixed-provider history, by converting non-native entries into faithful text so
/v1/responses/compactsees the full context. Also fixes a replay bug that dropped the user's first post-compaction message.New Features
openai+openai-responses), not history provenance.sessionEntryToContextMessages+convertToLlm; degrade foreign assistant turns,!bash, local compactions, branch summaries, and custom messages to canonical text.input_text/input_imageparts for image-capable models, or a text placeholder otherwise.Bug Fixes
Written for commit 339389a. Summary will update on new commits.