fix: allow manual chat compaction from the error state - #28022
Conversation
A chat that errors on context overflow is stuck: compaction is rejected outside the waiting state, and sending a new message re-runs the same oversized prompt. Allow RequestCompaction from E0/E1 and clear last_error on the request so /compact becomes the recovery path.
Docs previewCheck off each page once it's been reviewed. If a page changes in a later push, its checkbox clears automatically so it gets a fresh look. Pages not yet wired into the docs navigation aren't listed here. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0d340c6361
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0d340c6361
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
A chat that errored after exhausting retryable provider failures keeps generation_attempt at the cap; RequestCompaction inserts no history, so the history-change trigger never resets it and the recovery compaction would inherit the spent retry budget.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc7d9cb7ef
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Rewinding generation_attempt while sub-cap can reuse message part buffer episode keys (chat, history_version, attempt) still inside the 15s closed-episode retention window on the erroring replica. Sub-cap counters continue forward instead; at exhaustion the rewind is collision-free because backoff spacing expires the earliest episodes long before the budget runs out.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 705213cf25
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
RequestCompaction inserts no history, so the chat_messages triggers never granted the compaction turn a fresh retry budget. Conditionally resetting generation_attempt left a boundary at MaxAttempts-1 where the recovery turn inherited a spent budget, and rewinding the counter alone could collide with message part episode keys retained on the erroring replica. Advancing history_version to the transaction's new snapshot_version, exactly what a history change does, gives the turn a full budget and collision-free episode keys unconditionally.
|
@codex review |
|
Codex Review: Didn't find any major issues. Swish! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
…utionState A standalone AdvanceChatHistoryVersion query exposed a general store method that can move history_version without any history change. Make the epoch grant an option on the execution-state update instead, so it rides the same atomic UPDATE that clears last_error and sets the compaction marker, and only RequestCompaction can reach it.
At attempt 0 the sync_chat_retry_state trigger cannot clear a stale retry payload because generation_attempt does not change, so only the explicit clear in the epoch grant covers it.
|
@codex review |
|
Codex Review: Didn't find any major issues. Keep it up! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
A chat that fails generation with a context overflow (for example
Input length 262625 exceeds the maximum allowed input length of 262112 tokens) is stuck in a catch-22:POST /chats/{id}/compactreturns 409 because theRequestCompactiontransition is only allowed from the waiting state, and the only other way out of the error state is sending or editing a message, which re-runs generation with the same oversized prompt and fails again. Compaction is exactly the recovery a context-overflowed chat needs, and it is unreachable exactly when it is needed.Three semantic changes:
RequestCompactionfrom the error states:E0 -> R0andE1 -> R1(queued messages are preserved and processed after the compaction turn).last_errorinTx.RequestCompaction, matching the architecture rule that transitions leavingE0/E1clear the stored error. Without this a successful compaction would land in waiting with a stale persisted error.grant_history_epochflag onUpdateChatExecutionStatesetshistory_version = snapshot_version, resetsgeneration_attempt, and clearsretry_statein the same atomic update that clearslast_error(mirroring thechat_messagestrigger postcondition). The transition inserts no history, so without this the turn inherits the failed turn's spent retry budget, and resetting the counter alone could collide with message part episode keys still retained on the erroring replica.No frontend change is required: the chat input is already enabled in the error state and
/compactsubmission already handles both the success and 409 paths. Also updates ARCHITECTURE.md (transition matrix, endpoint, and manual compaction sections), the endpoint's swagger description, and SDK comments.