Skip to content

feat(compression): native OpenAI Responses server-side compaction for gpt-5.6 - #81747

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-5dacc5ff
Aug 8, 2026
Merged

teknium1 merged 1 commit into
mainfrom
hermes/hermes-5dacc5ff

Conversation

@teknium1

@teknium1 teknium1 commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

gpt-5.6 sessions on the direct OpenAI API or a ChatGPT Codex subscription can now opt in to OpenAI's server-side compaction (compression.codex_responses_native: true, default false) — the server prunes older context into an encrypted checkpoint that Hermes replays on later turns, and no other model, provider, or route is affected.

Root motivation: OpenAI's Responses API added context_management: [{type: "compaction", compact_threshold: N}] (July 2026). Draft PR #76950 by @laryhorb explored this; it was a 9.3k-line stale-base rewrite with a live hang bug on non-supporting models, so this is a minimal reimplementation on current main (direction credit to @laryhorb).

Changes

  • agent/native_compaction.py (new, ~170 LOC): the entire policy — model gate (gpt-5.6 family only), route gate (api.openai.com / Codex backend only), threshold clamp (native fires ~8K tokens below the local compression trigger so the server compacts first), and a narrow structured-rejection matcher.
  • agent/transports/codex.py + agent/chat_completion_helpers.py: thread the resolved context_management payload into Responses request kwargs (None ⇒ request byte-identical to before).
  • agent/codex_responses_adapter.py: capture compaction output items into the existing codex_reasoning_items sidecar (inherits persistence, session replay, cross-issuer stamping, and the encrypted-replay kill switch — zero new state); accept replayed compaction items in both preflights.
  • agent/conversation_loop.py + agent/turn_retry_state.py: one-shot recovery — a structured 400 naming context_management disables native compaction for the session and retries without the field. Generic 5xx/timeouts intentionally do NOT downgrade.
  • agent/agent_init.py, hermes_cli/config_defaults.py, cli-config.yaml.example: config plumbing (codex_responses_native, codex_responses_compact_threshold).
  • Docs: website/docs/developer-guide/context-compression-and-caching.md.
  • Tests: tests/run_agent/test_native_compaction.py (31 tests; sabotage-verified — removing the model gate or route gate each fails the suite).

Why gpt-5.6 only

Live testing (Aug 2026): gpt-5.6 compacts correctly; gpt-5.1/5.2 with the field fail server-side as HTTP 500 (blocking) or a permanent stream stall (90s watchdog × 3 retries = dead turn) with no structured rejection to downgrade on. An explicit model-family gate is the only safe shape.

Validation

Scenario Result
gpt-5.6 @ api.openai.com, threshold 4K, real AIAgent server compacted turn 1, checkpoints captured + replayed, secret-word + detail recall preserved across 3 turns
gpt-5.1 with flag enabled field never sent; turn clean in 2.3s
OpenRouter / xAI / GitHub / localhost routes field never sent
Default config flag off, requests unchanged
config.yaml → agent_init → wire full chain verified E2E
Tests 31/31 new + turn-retry-state contract updated; ruff clean

Infographic

Native Server-Side Compaction

… gpt-5.6

Opt-in via compression.codex_responses_native (default: false). When enabled,
gpt-5.6-family models on the direct OpenAI API (api.openai.com) or a ChatGPT
Codex subscription send context_management=[{type: compaction,
compact_threshold: N}] on Responses requests. OpenAI compacts server-side and
returns an encrypted compaction output item; Hermes captures it into the
existing codex_reasoning_items sidecar and replays it on later turns in place
of the pruned history — inheriting persistence, session replay, the
cross-issuer guard, and the encrypted-replay kill switch with zero new state.

Scope is deliberately hard-gated (agent/native_compaction.py, re-checked per
request): gpt-5.6 family only — gpt-5.1/5.2 fail server-side on the field
(HTTP 500 / stream stall, no structured rejection; live-verified) — and
direct OpenAI/Codex routes only; xAI, GitHub/Copilot, OpenRouter, relays,
and local servers never see the field.

Hermes' local compression stays armed as the fallback owner: the native
threshold is clamped ~8K tokens below the local trigger so the server
compacts first, and a structured provider rejection of context_management
disables native compaction for the session and retries without it
(one-shot guard in TurnRetryState).

Live-verified E2E on api.openai.com/gpt-5.6: server compaction fired at a
4K threshold, checkpoints captured and replayed, recall preserved across
3 turns; gpt-5.1 with the flag enabled stays clean (field never sent).

Direction credit: PR #76950 by @laryhorb explored native Responses
compaction; this is a minimal reimplementation on current main.
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 690b953

⚠️ Warnings

OSV vulnerability scan · View job

56 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.


debug info

CI timings

CI timings · View report · View job

Wall time 4m11s vs 7m15s (-42.3%). 10 job(s) slower, 12 faster, 2 unchanged.

  • Python tests / Run tests slice 5/12: -22.0s
  • Python tests / Run tests slice 1/12: +16.0s
  • Python tests / Run tests slice 12/12: +13.0s
  • Python tests / Run tests slice 4/12: +11.0s
  • Python tests / Run tests slice 11/12: +8.0s

@alt-glitch alt-glitch added type/feature New feature or request comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint provider/openai OpenAI / Codex Responses API area/compression Context compression and continuation sessions P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 8, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Supersedes the stale draft direction in #76950 with a focused current-main implementation; #76950 is retained here for design lineage.

@teknium1
teknium1 merged commit 5e1b501 into main Aug 8, 2026
46 checks passed
@teknium1
teknium1 deleted the hermes/hermes-5dacc5ff branch August 8, 2026 18:24
teknium1 added a commit that referenced this pull request Aug 8, 2026
…heckpoints

Two corrections on top of the #71077 base (the whole bug class):

1. Turn boundary = last USER message, not last assistant message. A Codex
   turn spans several assistant messages (assistant+tool_calls -> tool ->
   ... -> final assistant) whose reasoning items must replay together; the
   last-assistant boundary would strip reasoning mid-chain from the active
   turn (the gap flagged in PR #71077 review).

2. type="compaction" checkpoints (native server-side compaction, PR #81747)
   are exempt: they carry already-pruned history, not per-turn reasoning.
   Pruning filters items instead of popping the sidecar key.

Sibling site fixed in the same class: the Codex incomplete-continuation
dedup path blind-overwrote codex_reasoning_items on visually-duplicate
interim messages, which would drop the only copy of a checkpoint captured
on the earlier response. Extracted merge_interim_reasoning_items() into
agent/native_compaction.py; newer reasoning wins, prior checkpoints are
preserved unless the newer payload carries its own.
teknium1 added a commit that referenced this pull request Aug 8, 2026
…heckpoints

Two corrections on top of the #71077 base (the whole bug class):

1. Turn boundary = last USER message, not last assistant message. A Codex
   turn spans several assistant messages (assistant+tool_calls -> tool ->
   ... -> final assistant) whose reasoning items must replay together; the
   last-assistant boundary would strip reasoning mid-chain from the active
   turn (the gap flagged in PR #71077 review).

2. type="compaction" checkpoints (native server-side compaction, PR #81747)
   are exempt: they carry already-pruned history, not per-turn reasoning.
   Pruning filters items instead of popping the sidecar key.

Sibling site fixed in the same class: the Codex incomplete-continuation
dedup path blind-overwrote codex_reasoning_items on visually-duplicate
interim messages, which would drop the only copy of a checkpoint captured
on the earlier response. Extracted merge_interim_reasoning_items() into
agent/native_compaction.py; newer reasoning wins, prior checkpoints are
preserved unless the newer payload carries its own.
teknium1 added a commit that referenced this pull request Aug 9, 2026
…e newest assistant turn (#73624)

Generic thinking fields (reasoning / reasoning_content + the
reasoning_details text charge) are replayed for at most the NEWEST
assistant turn on every transport: Anthropic strips all-but-newest at
convert time, Bedrock Converse never replays thinking, and strict
chat-completions providers reject or one-space-pad the field. The tail
budget walks charged them on every message anyway, spending 19-24% of
the budget (per the issue's 1,025-message measurement) on bytes that
provably never reach the wire — so the tail cut landed early and each
compaction discarded more real transcript than configured.

_estimate_msg_budget_tokens now partitions the replay keys:

* _ALWAYS_REPLAYED_BUDGET_KEYS (codex_reasoning_items,
  codex_message_items) — charged unconditionally. These ride the wire
  on every retained turn (#55572), and codex_reasoning_items now also
  carries native server-side compaction checkpoints (#81747).
* _NEWEST_TURN_ONLY_BUDGET_KEYS (reasoning, reasoning_content) + the
  reasoning_details text charge — charged only for the newest assistant
  turn via charge_stale_thinking, resolved by the three budget walks
  (tail cut, raw-budget re-walk, proactive-prune boundary).

Default stays the conservative full charge for callers without
turn-position context. A partition invariant test pins that any future
_REPLAY_BUDGET_KEYS entry must be classified into exactly one class.

Direction credit: #73669 (@x7peeps) and #73730 (@webtecnica) both
attacked this; the keep_open reviews asked for provider/API-mode-aware
accounting that keeps Codex carriers charged — this implements that
shape.
teknium1 added a commit that referenced this pull request Aug 9, 2026
…e newest assistant turn (#73624)

Generic thinking fields (reasoning / reasoning_content + the
reasoning_details text charge) are replayed for at most the NEWEST
assistant turn on every transport: Anthropic strips all-but-newest at
convert time, Bedrock Converse never replays thinking, and strict
chat-completions providers reject or one-space-pad the field. The tail
budget walks charged them on every message anyway, spending 19-24% of
the budget (per the issue's 1,025-message measurement) on bytes that
provably never reach the wire — so the tail cut landed early and each
compaction discarded more real transcript than configured.

_estimate_msg_budget_tokens now partitions the replay keys:

* _ALWAYS_REPLAYED_BUDGET_KEYS (codex_reasoning_items,
  codex_message_items) — charged unconditionally. These ride the wire
  on every retained turn (#55572), and codex_reasoning_items now also
  carries native server-side compaction checkpoints (#81747).
* _NEWEST_TURN_ONLY_BUDGET_KEYS (reasoning, reasoning_content) + the
  reasoning_details text charge — charged only for the newest assistant
  turn via charge_stale_thinking, resolved by the three budget walks
  (tail cut, raw-budget re-walk, proactive-prune boundary).

Default stays the conservative full charge for callers without
turn-position context. A partition invariant test pins that any future
_REPLAY_BUDGET_KEYS entry must be classified into exactly one class.

Direction credit: #73669 (@x7peeps) and #73730 (@webtecnica) both
attacked this; the keep_open reviews asked for provider/API-mode-aware
accounting that keeps Codex carriers charged — this implements that
shape.
ma1138569845 pushed a commit to ma1138569845/dechnicAuditor-agent that referenced this pull request Aug 10, 2026
…heckpoints

Two corrections on top of the NousResearch#71077 base (the whole bug class):

1. Turn boundary = last USER message, not last assistant message. A Codex
   turn spans several assistant messages (assistant+tool_calls -> tool ->
   ... -> final assistant) whose reasoning items must replay together; the
   last-assistant boundary would strip reasoning mid-chain from the active
   turn (the gap flagged in PR NousResearch#71077 review).

2. type="compaction" checkpoints (native server-side compaction, PR NousResearch#81747)
   are exempt: they carry already-pruned history, not per-turn reasoning.
   Pruning filters items instead of popping the sidecar key.

Sibling site fixed in the same class: the Codex incomplete-continuation
dedup path blind-overwrote codex_reasoning_items on visually-duplicate
interim messages, which would drop the only copy of a checkpoint captured
on the earlier response. Extracted merge_interim_reasoning_items() into
agent/native_compaction.py; newer reasoning wins, prior checkpoints are
preserved unless the newer payload carries its own.
ma1138569845 pushed a commit to ma1138569845/dechnicAuditor-agent that referenced this pull request Aug 10, 2026
…e newest assistant turn (NousResearch#73624)

Generic thinking fields (reasoning / reasoning_content + the
reasoning_details text charge) are replayed for at most the NEWEST
assistant turn on every transport: Anthropic strips all-but-newest at
convert time, Bedrock Converse never replays thinking, and strict
chat-completions providers reject or one-space-pad the field. The tail
budget walks charged them on every message anyway, spending 19-24% of
the budget (per the issue's 1,025-message measurement) on bytes that
provably never reach the wire — so the tail cut landed early and each
compaction discarded more real transcript than configured.

_estimate_msg_budget_tokens now partitions the replay keys:

* _ALWAYS_REPLAYED_BUDGET_KEYS (codex_reasoning_items,
  codex_message_items) — charged unconditionally. These ride the wire
  on every retained turn (NousResearch#55572), and codex_reasoning_items now also
  carries native server-side compaction checkpoints (NousResearch#81747).
* _NEWEST_TURN_ONLY_BUDGET_KEYS (reasoning, reasoning_content) + the
  reasoning_details text charge — charged only for the newest assistant
  turn via charge_stale_thinking, resolved by the three budget walks
  (tail cut, raw-budget re-walk, proactive-prune boundary).

Default stays the conservative full charge for callers without
turn-position context. A partition invariant test pins that any future
_REPLAY_BUDGET_KEYS entry must be classified into exactly one class.

Direction credit: NousResearch#73669 (@x7peeps) and NousResearch#73730 (@webtecnica) both
attacked this; the keep_open reviews asked for provider/API-mode-aware
accounting that keeps Codex carriers charged — this implements that
shape.
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
…heckpoints

Two corrections on top of the NousResearch#71077 base (the whole bug class):

1. Turn boundary = last USER message, not last assistant message. A Codex
   turn spans several assistant messages (assistant+tool_calls -> tool ->
   ... -> final assistant) whose reasoning items must replay together; the
   last-assistant boundary would strip reasoning mid-chain from the active
   turn (the gap flagged in PR NousResearch#71077 review).

2. type="compaction" checkpoints (native server-side compaction, PR NousResearch#81747)
   are exempt: they carry already-pruned history, not per-turn reasoning.
   Pruning filters items instead of popping the sidecar key.

Sibling site fixed in the same class: the Codex incomplete-continuation
dedup path blind-overwrote codex_reasoning_items on visually-duplicate
interim messages, which would drop the only copy of a checkpoint captured
on the earlier response. Extracted merge_interim_reasoning_items() into
agent/native_compaction.py; newer reasoning wins, prior checkpoints are
preserved unless the newer payload carries its own.
randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
…e newest assistant turn (NousResearch#73624)

Generic thinking fields (reasoning / reasoning_content + the
reasoning_details text charge) are replayed for at most the NEWEST
assistant turn on every transport: Anthropic strips all-but-newest at
convert time, Bedrock Converse never replays thinking, and strict
chat-completions providers reject or one-space-pad the field. The tail
budget walks charged them on every message anyway, spending 19-24% of
the budget (per the issue's 1,025-message measurement) on bytes that
provably never reach the wire — so the tail cut landed early and each
compaction discarded more real transcript than configured.

_estimate_msg_budget_tokens now partitions the replay keys:

* _ALWAYS_REPLAYED_BUDGET_KEYS (codex_reasoning_items,
  codex_message_items) — charged unconditionally. These ride the wire
  on every retained turn (NousResearch#55572), and codex_reasoning_items now also
  carries native server-side compaction checkpoints (NousResearch#81747).
* _NEWEST_TURN_ONLY_BUDGET_KEYS (reasoning, reasoning_content) + the
  reasoning_details text charge — charged only for the newest assistant
  turn via charge_stale_thinking, resolved by the three budget walks
  (tail cut, raw-budget re-walk, proactive-prune boundary).

Default stays the conservative full charge for callers without
turn-position context. A partition invariant test pins that any future
_REPLAY_BUDGET_KEYS entry must be classified into exactly one class.

Direction credit: NousResearch#73669 (@x7peeps) and NousResearch#73730 (@webtecnica) both
attacked this; the keep_open reviews asked for provider/API-mode-aware
accounting that keeps Codex carriers charged — this implements that
shape.
blut-agent pushed a commit to blut-agent/hermes-agent-fork that referenced this pull request Aug 11, 2026
…heckpoints

Two corrections on top of the NousResearch#71077 base (the whole bug class):

1. Turn boundary = last USER message, not last assistant message. A Codex
   turn spans several assistant messages (assistant+tool_calls -> tool ->
   ... -> final assistant) whose reasoning items must replay together; the
   last-assistant boundary would strip reasoning mid-chain from the active
   turn (the gap flagged in PR NousResearch#71077 review).

2. type="compaction" checkpoints (native server-side compaction, PR NousResearch#81747)
   are exempt: they carry already-pruned history, not per-turn reasoning.
   Pruning filters items instead of popping the sidecar key.

Sibling site fixed in the same class: the Codex incomplete-continuation
dedup path blind-overwrote codex_reasoning_items on visually-duplicate
interim messages, which would drop the only copy of a checkpoint captured
on the earlier response. Extracted merge_interim_reasoning_items() into
agent/native_compaction.py; newer reasoning wins, prior checkpoints are
preserved unless the newer payload carries its own.
blut-agent pushed a commit to blut-agent/hermes-agent-fork that referenced this pull request Aug 11, 2026
…e newest assistant turn (NousResearch#73624)

Generic thinking fields (reasoning / reasoning_content + the
reasoning_details text charge) are replayed for at most the NEWEST
assistant turn on every transport: Anthropic strips all-but-newest at
convert time, Bedrock Converse never replays thinking, and strict
chat-completions providers reject or one-space-pad the field. The tail
budget walks charged them on every message anyway, spending 19-24% of
the budget (per the issue's 1,025-message measurement) on bytes that
provably never reach the wire — so the tail cut landed early and each
compaction discarded more real transcript than configured.

_estimate_msg_budget_tokens now partitions the replay keys:

* _ALWAYS_REPLAYED_BUDGET_KEYS (codex_reasoning_items,
  codex_message_items) — charged unconditionally. These ride the wire
  on every retained turn (NousResearch#55572), and codex_reasoning_items now also
  carries native server-side compaction checkpoints (NousResearch#81747).
* _NEWEST_TURN_ONLY_BUDGET_KEYS (reasoning, reasoning_content) + the
  reasoning_details text charge — charged only for the newest assistant
  turn via charge_stale_thinking, resolved by the three budget walks
  (tail cut, raw-budget re-walk, proactive-prune boundary).

Default stays the conservative full charge for callers without
turn-position context. A partition invariant test pins that any future
_REPLAY_BUDGET_KEYS entry must be classified into exactly one class.

Direction credit: NousResearch#73669 (@x7peeps) and NousResearch#73730 (@webtecnica) both
attacked this; the keep_open reviews asked for provider/API-mode-aware
accounting that keeps Codex carriers charged — this implements that
shape.
33hodl pushed a commit to 33hodl/hermes-agent that referenced this pull request Aug 12, 2026
…heckpoints

Two corrections on top of the NousResearch#71077 base (the whole bug class):

1. Turn boundary = last USER message, not last assistant message. A Codex
   turn spans several assistant messages (assistant+tool_calls -> tool ->
   ... -> final assistant) whose reasoning items must replay together; the
   last-assistant boundary would strip reasoning mid-chain from the active
   turn (the gap flagged in PR NousResearch#71077 review).

2. type="compaction" checkpoints (native server-side compaction, PR NousResearch#81747)
   are exempt: they carry already-pruned history, not per-turn reasoning.
   Pruning filters items instead of popping the sidecar key.

Sibling site fixed in the same class: the Codex incomplete-continuation
dedup path blind-overwrote codex_reasoning_items on visually-duplicate
interim messages, which would drop the only copy of a checkpoint captured
on the earlier response. Extracted merge_interim_reasoning_items() into
agent/native_compaction.py; newer reasoning wins, prior checkpoints are
preserved unless the newer payload carries its own.
33hodl pushed a commit to 33hodl/hermes-agent that referenced this pull request Aug 12, 2026
…e newest assistant turn (NousResearch#73624)

Generic thinking fields (reasoning / reasoning_content + the
reasoning_details text charge) are replayed for at most the NEWEST
assistant turn on every transport: Anthropic strips all-but-newest at
convert time, Bedrock Converse never replays thinking, and strict
chat-completions providers reject or one-space-pad the field. The tail
budget walks charged them on every message anyway, spending 19-24% of
the budget (per the issue's 1,025-message measurement) on bytes that
provably never reach the wire — so the tail cut landed early and each
compaction discarded more real transcript than configured.

_estimate_msg_budget_tokens now partitions the replay keys:

* _ALWAYS_REPLAYED_BUDGET_KEYS (codex_reasoning_items,
  codex_message_items) — charged unconditionally. These ride the wire
  on every retained turn (NousResearch#55572), and codex_reasoning_items now also
  carries native server-side compaction checkpoints (NousResearch#81747).
* _NEWEST_TURN_ONLY_BUDGET_KEYS (reasoning, reasoning_content) + the
  reasoning_details text charge — charged only for the newest assistant
  turn via charge_stale_thinking, resolved by the three budget walks
  (tail cut, raw-budget re-walk, proactive-prune boundary).

Default stays the conservative full charge for callers without
turn-position context. A partition invariant test pins that any future
_REPLAY_BUDGET_KEYS entry must be classified into exactly one class.

Direction credit: NousResearch#73669 (@x7peeps) and NousResearch#73730 (@webtecnica) both
attacked this; the keep_open reviews asked for provider/API-mode-aware
accounting that keeps Codex carriers charged — this implements that
shape.
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
…heckpoints

Two corrections on top of the NousResearch#71077 base (the whole bug class):

1. Turn boundary = last USER message, not last assistant message. A Codex
   turn spans several assistant messages (assistant+tool_calls -> tool ->
   ... -> final assistant) whose reasoning items must replay together; the
   last-assistant boundary would strip reasoning mid-chain from the active
   turn (the gap flagged in PR NousResearch#71077 review).

2. type="compaction" checkpoints (native server-side compaction, PR NousResearch#81747)
   are exempt: they carry already-pruned history, not per-turn reasoning.
   Pruning filters items instead of popping the sidecar key.

Sibling site fixed in the same class: the Codex incomplete-continuation
dedup path blind-overwrote codex_reasoning_items on visually-duplicate
interim messages, which would drop the only copy of a checkpoint captured
on the earlier response. Extracted merge_interim_reasoning_items() into
agent/native_compaction.py; newer reasoning wins, prior checkpoints are
preserved unless the newer payload carries its own.
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
…e newest assistant turn (NousResearch#73624)

Generic thinking fields (reasoning / reasoning_content + the
reasoning_details text charge) are replayed for at most the NEWEST
assistant turn on every transport: Anthropic strips all-but-newest at
convert time, Bedrock Converse never replays thinking, and strict
chat-completions providers reject or one-space-pad the field. The tail
budget walks charged them on every message anyway, spending 19-24% of
the budget (per the issue's 1,025-message measurement) on bytes that
provably never reach the wire — so the tail cut landed early and each
compaction discarded more real transcript than configured.

_estimate_msg_budget_tokens now partitions the replay keys:

* _ALWAYS_REPLAYED_BUDGET_KEYS (codex_reasoning_items,
  codex_message_items) — charged unconditionally. These ride the wire
  on every retained turn (NousResearch#55572), and codex_reasoning_items now also
  carries native server-side compaction checkpoints (NousResearch#81747).
* _NEWEST_TURN_ONLY_BUDGET_KEYS (reasoning, reasoning_content) + the
  reasoning_details text charge — charged only for the newest assistant
  turn via charge_stale_thinking, resolved by the three budget walks
  (tail cut, raw-budget re-walk, proactive-prune boundary).

Default stays the conservative full charge for callers without
turn-position context. A partition invariant test pins that any future
_REPLAY_BUDGET_KEYS entry must be classified into exactly one class.

Direction credit: NousResearch#73669 (@x7peeps) and NousResearch#73730 (@webtecnica) both
attacked this; the keep_open reviews asked for provider/API-mode-aware
accounting that keeps Codex carriers charged — this implements that
shape.
smfworks pushed a commit to smfworks/hermes-agent that referenced this pull request Sep 7, 2026
…heckpoints

Two corrections on top of the NousResearch#71077 base (the whole bug class):

1. Turn boundary = last USER message, not last assistant message. A Codex
   turn spans several assistant messages (assistant+tool_calls -> tool ->
   ... -> final assistant) whose reasoning items must replay together; the
   last-assistant boundary would strip reasoning mid-chain from the active
   turn (the gap flagged in PR NousResearch#71077 review).

2. type="compaction" checkpoints (native server-side compaction, PR NousResearch#81747)
   are exempt: they carry already-pruned history, not per-turn reasoning.
   Pruning filters items instead of popping the sidecar key.

Sibling site fixed in the same class: the Codex incomplete-continuation
dedup path blind-overwrote codex_reasoning_items on visually-duplicate
interim messages, which would drop the only copy of a checkpoint captured
on the earlier response. Extracted merge_interim_reasoning_items() into
agent/native_compaction.py; newer reasoning wins, prior checkpoints are
preserved unless the newer payload carries its own.
smfworks pushed a commit to smfworks/hermes-agent that referenced this pull request Sep 7, 2026
…e newest assistant turn (NousResearch#73624)

Generic thinking fields (reasoning / reasoning_content + the
reasoning_details text charge) are replayed for at most the NEWEST
assistant turn on every transport: Anthropic strips all-but-newest at
convert time, Bedrock Converse never replays thinking, and strict
chat-completions providers reject or one-space-pad the field. The tail
budget walks charged them on every message anyway, spending 19-24% of
the budget (per the issue's 1,025-message measurement) on bytes that
provably never reach the wire — so the tail cut landed early and each
compaction discarded more real transcript than configured.

_estimate_msg_budget_tokens now partitions the replay keys:

* _ALWAYS_REPLAYED_BUDGET_KEYS (codex_reasoning_items,
  codex_message_items) — charged unconditionally. These ride the wire
  on every retained turn (NousResearch#55572), and codex_reasoning_items now also
  carries native server-side compaction checkpoints (NousResearch#81747).
* _NEWEST_TURN_ONLY_BUDGET_KEYS (reasoning, reasoning_content) + the
  reasoning_details text charge — charged only for the newest assistant
  turn via charge_stale_thinking, resolved by the three budget walks
  (tail cut, raw-budget re-walk, proactive-prune boundary).

Default stays the conservative full charge for callers without
turn-position context. A partition invariant test pins that any future
_REPLAY_BUDGET_KEYS entry must be classified into exactly one class.

Direction credit: NousResearch#73669 (@x7peeps) and NousResearch#73730 (@webtecnica) both
attacked this; the keep_open reviews asked for provider/API-mode-aware
accounting that keeps Codex carriers charged — this implements that
shape.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/compression Context compression and continuation sessions comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have provider/openai OpenAI / Codex Responses API sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants