fix: support new MessageContent format in history replay

Added extractUserMessageText() helper to handle both new (MessageContent[])
and old ({ text: string }) user message formats. This fixes history replay
for resumed sessions after commit 913cccc changed the message storage format
without updating the extraction logic. Also updated integration test to use
the new MessageContent format.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Jiayuan
2026-01-15 23:41:35 +08:00
parent 0c37f8914f
commit ce068a8a55
2 changed files with 30 additions and 3 deletions

View File

@@ -3,10 +3,35 @@
* Formats conversation history for prepending to prompts when agent restarts
*/
import type { StoredSessionUpdate } from '../../shared/types'
import type { MessageContent } from '../../shared/types/message'
// Token estimation: ~4 bytes per token (same heuristic as Codex)
const APPROX_BYTES_PER_TOKEN = 4
/**
* Extract text from user message content
* Supports both new format (MessageContent[]) and old format ({ text: string })
*/
function extractUserMessageText(content: unknown): string {
if (!content) return ''
// New format: MessageContent[] (array of content items)
if (Array.isArray(content)) {
const textItem = (content as MessageContent).find((item) => item.type === 'text')
return textItem?.type === 'text' ? textItem.text : ''
}
// Old format: { type: 'text', text: string } or { text: string }
if (typeof content === 'object') {
const obj = content as { text?: string }
if (typeof obj.text === 'string') {
return obj.text
}
}
return ''
}
// Default max tokens for history (leaves room for user prompt and response)
const DEFAULT_MAX_HISTORY_TOKENS = 20000
@@ -58,7 +83,8 @@ function extractMessages(updates: StoredSessionUpdate[]): ExtractedMessage[] {
}
// Add user message (custom internal type)
const content = (inner as { content?: { text?: string } }).content?.text || ''
const rawContent = (inner as { content?: unknown }).content
const content = extractUserMessageText(rawContent)
if (content) {
messages.push({ role: 'user', content })
}
@@ -207,7 +233,8 @@ export function hasReplayableHistory(updates: StoredSessionUpdate[]): boolean {
const updateType = inner.sessionUpdate as string
if (updateType === 'user_message') {
const content = (inner as { content?: { text?: string } }).content?.text
const rawContent = (inner as { content?: unknown }).content
const content = extractUserMessageText(rawContent)
if (content) {
hasUser = true
}

View File

@@ -203,7 +203,7 @@ describe('Conductor', () => {
const session = await conductor.createSession('/test/project', mockAgentConfig)
// sendPrompt should trigger status changes
await conductor.sendPrompt(session.id, 'Hello')
await conductor.sendPrompt(session.id, [{ type: 'text', text: 'Hello' }])
// Should be called at least twice (start processing, end processing)
expect(onStatusChange).toHaveBeenCalled()