mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-25 03:55:27 +02:00
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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user