🤖 refactor: envelope pattern for compaction follow-up types#2308
🤖 refactor: envelope pattern for compaction follow-up types#2308ammar-agent wants to merge 1 commit intomainfrom
Conversation
Separate message content from send policy in CompactionFollowUpRequest. Add ChatInputMessageDraft as canonical shared type between chat-input and compaction. Add normalizeCompactionFollowUpRequest for legacy persistence compat. Update all callers and tests.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e8c967e6e5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (!followUpContent) return null; | ||
| if (isDefaultSourceContent(followUpContent)) return null; | ||
| const text = followUpContent.text; | ||
| if (isDefaultSourceContent(followUpContent.message)) return null; | ||
| const text = followUpContent.message.content; | ||
| if (typeof text !== "string" || text.trim().length === 0) { |
There was a problem hiding this comment.
Guard legacy follow-up shape before reading message.content
This now assumes followUpContent.message always exists, but getCompactionFollowUpContent() still returns legacy continueMessage data from persisted history (flat text/fileParts with no message field). In that case followUpContent.message is undefined and followUpContent.message.content throws, which can break compaction retry/command formatting when loading older chat history. Consider normalizing the legacy shape before calling this, or add a defensive fallback here (e.g., if message is missing, derive content from legacy text).
Useful? React with 👍 / 👎.
Summary
Refactors compaction follow-up typing to match the chat-input message shape, separating message content from execution policy (model, agentId, thinking level, etc.) into a clean envelope pattern.
Background
The compaction follow-up system had a structural mismatch: chat input uses
content-based drafts (PendingUserMessage), while compaction follow-ups used a flattened shape withtextand inline send-policy fields (model,agentId,thinkingLevel, etc.). This forced translation glue at every boundary and contributed to drift between the two code paths.Implementation
New types in
src/common/types/message.tsChatInputMessageDraft— canonical message shape shared between chat input and compaction follow-up. Usescontent(matching chat-input convention) instead oftext.CompactionFollowUpSendOptions— isolated execution policy (model, agentId, preserved send options).CompactionFollowUpInputrefactored to{ message: ChatInputMessageDraft, muxMetadata? }(nested, not extending).CompactionFollowUpRequestrefactored toextends CompactionFollowUpInput { sendOptions: CompactionFollowUpSendOptions }.normalizeCompactionFollowUpRequest()— centralizes legacy migration (flattext/model/agentId/imageParts/mode→ envelope shape). Used by backend dispatch.Updated callers (13 files)
chatCommands.tsprepareCompactionMessagebuildssendOptionsenvelope instead of spreading flat fieldschatCommands.tshandleCompactCommandconstructs{ message: { content, fileParts, reviews } }useCompactAndRetry.tsbuildFollowUpFromSourceuses nestedmessageobjectChatInput/index.tsxprepareUserMessageForSend({ content: ... })ChatPane.tsx{ message: { content: "Continue" } }chatEditing.tsbuildEditingStateFromCompactionreadsfollowUp.message.fileParts/reviewsagentSession.tsdispatchPendingFollowUpusesnormalizeCompactionFollowUpRequest— all legacy handling centralizedcompaction/format.tsgetFollowUpContentTextreadsfollowUpContent.message.contentmockAiRouter.tsfollowUpContent.message.contentmessage.tsisDefaultSourceContentacceptsChatInputMessageDraft,prepareUserMessageForSendacceptsChatInputMessageDraftTest coverage
normalizeCompactionFollowUpRequest(legacy flat, modern envelope, mode migration, imageParts migration, defaults, muxMetadata preservation, missing sendOptions)Risks
chat.jsonlentries with flat follow-up fields are handled bynormalizeCompactionFollowUpRequest. The normalizer detects legacy shape by checking for themessagefield and migrates accordingly. The existing agentSession legacy test (continueMessageAgentId.test.ts) validates this path.Generated with
mux• Model:anthropic:claude-opus-4-6• Thinking:xhigh• Cost:$5.96