-
Notifications
You must be signed in to change notification settings - Fork 2.9k
feat: implement ModelMessage storage layer with AI SDK response messages #11409
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: implement ModelMessage storage layer with AI SDK response messages #11409
Conversation
…igration Add foundation infrastructure for migrating message storage from Anthropic format to AI SDK ModelMessage format (EXT-646). - RooMessage type = AI SDK ModelMessage + Roo metadata (ts, condense, truncation) - Anthropic-to-RooMessage converter for migrating old conversations on read - Versioned storage (readRooMessages/saveRooMessages) with auto-detection - flattenModelMessagesToStringContent utility for providers needing string content No behavior change - purely additive. Existing code paths untouched. EXT-647 will wire Task.ts to use these new functions.
…s/index.ts and unnecessary re-exports
- Narrow summary from any[] to Array<{ type: string; text: string }> matching EncryptedReasoningItem
- Delete unused converters/index.ts barrel (knip: unused file)
- Remove UserContent, AssistantContent, ToolContent re-exports (importable from 'ai' directly)
- Remove FlattenMessagesOptions re-export from index.ts
Complete migration from Anthropic.MessageParam to RooMessage (ModelMessage + metadata) for internal message storage and the entire provider pipeline. Key changes: - Task.ts: apiConversationHistory is now RooMessage[], stored via readRooMessages/saveRooMessages - Message construction: userMessageContent uses TextPart/ImagePart, pendingToolResults uses ToolResultPart - ApiHandler.createMessage() accepts RooMessage[] instead of Anthropic.Messages.MessageParam[] - All 30 providers updated: messages passed directly to streamText()/generateText() - Removed convertToAiSdkMessages() calls from all AI SDK providers - buildCleanConversationHistory simplified from ~140 lines to ~20 lines - Resume logic rewritten for RooMessage format - Supporting systems updated: condense, messageManager, ClineProvider Old Anthropic-format conversations auto-convert on first open via readRooMessages(). New conversations stored in versioned v2 format. 5536 tests pass, 0 failures. EXT-647
Replace `as any` / `as unknown as` casts with proper RooMessage types across the storage and API pipeline: - Add UserContentPart alias and content-part type guards to rooMessage.ts - Migrate maybeRemoveImageBlocks, formatResponse, processUserContentMentions, validateAndFixToolResultIds, condense system, and convertToOpenAiMessages from Anthropic SDK types to AI SDK RooMessage types - Change initiateTaskLoop/recursivelyMakeClineRequests signatures from Anthropic.Messages.ContentBlockParam[] to UserContentPart[] - Type the assistant message builder in Task.ts, remove double-casts in the API pipeline - Remove unused Anthropic imports from 7 source files - Update ToolResponse type and presentAssistantMessage to use ImagePart - All functions accept both AI SDK (tool-call/tool-result) and legacy Anthropic (tool_use/tool_result) formats for backward compatibility Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add RooRoleMessage type, dual-format legacy block interfaces (LegacyToolUseBlock, LegacyToolResultBlock), union types (AnyToolCallBlock, AnyToolResultBlock), type guards, and accessor helpers to rooMessage.ts. Replace scattered `as any` casts across condense, context-management, Task.ts, validateToolResultIds.ts, and openai-format.ts with these shared typed utilities. Remove leaked Anthropic SDK import from context-management in favor of a provider-agnostic ContentBlockParam type. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- toolResultToText: handle { type, value } object shape returned by
getToolResultContent for AI SDK ToolResultPart.output, preventing
tool result content from being lost during condensation summaries
- export-markdown: add tool-call/tool-result (AI SDK format) handling
alongside legacy tool_use/tool_result, preventing post-migration
conversations from rendering as [Unexpected content type: tool-call]
Addresses review feedback from PR #11386.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of manually reconstructing assistant messages from stream events and injecting custom blocks (thinking, redacted_thinking, thoughtSignature) via side-channel handler methods, grab the fully-formed AssistantModelMessage from the AI SDK's result.response.messages and store it directly. This eliminates validation errors on subsequent turns caused by custom blocks that don't match the AI SDK's ModelMessage schema. - Add ApiStreamResponseMessageChunk type to stream chunk union - Add yieldResponseMessage helper and wire it into consumeAiSdkStream - All 24 AI SDK providers now yield response_message after streaming - Task.ts captures and stores native-format messages directly - addToApiConversationHistory detects native format (providerOptions on content parts) and skips legacy block injection - buildCleanConversationHistory passes native-format messages through - Remove dead side-channel methods: getThoughtSignature, getRedactedThinkingBlocks, getReasoningDetails, getSummary and their backing fields from all providers - Add redacted_thinking conversion in anthropicToRoo.ts for backward compat Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Re-reviewed after 984857e. Both commits address all previously flagged issues:
Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
- Remove redundant double cast in bedrock.ts (as ModelMessage[] as ModelMessage[]) - Use isAnyToolCallBlock/getToolCallId in condense orphan filter to handle both AI SDK tool-call and legacy tool_use formats - Fix misleading comment and remove dead conditional in processUserContentMentions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…dling in Task class
…ve saveApiConversationHistory error handling
hannesrudolph
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
weeeeee
Move cache breakpoint logic from individual providers to a shared utility called from Task.ts before createMessage(). Messages arrive at providers pre-annotated with providerOptions, and the AI SDK routes the correct options to the active provider automatically. New files: - src/api/transform/prompt-cache.ts: resolveCacheProviderOptions() + applyCacheBreakpoints() with provider adapter mapping - src/api/transform/__tests__/prompt-cache.spec.ts: 14 test cases Changes per provider: - anthropic.ts: removed targeting block + applyCacheControlToAiSdkMessages() - anthropic-vertex.ts: same - minimax.ts: same - bedrock.ts: removed targeting block + applyCachePointsToAiSdkMessages() Key improvements: - Targets non-assistant batches (user + tool) instead of only role=user. After PR #11409, tool results are separate role=tool messages that now correctly receive cache breakpoints. - Single source of truth: cache strategy defined once in prompt-cache.ts - Provider-specific config preserved: Bedrock gets 3 breakpoints + anchor, Anthropic family gets 2 breakpoints Preserved (untouched): - systemProviderOptions in all providers' streamText() calls - OpenAI Native promptCacheRetention (provider-level, not per-message) - Bedrock usePromptCache opt-in + supportsAwsPromptCache() 5,491 tests pass, 0 regressions.
Summary
RooMessagetype system that wraps AI SDKModelMessagewith metadata (timestamps, condense/truncation IDs), replacing the legacy Anthropic-formatApiMessageresult.response.messagesfrom the AI SDK for assistant message storage instead of manually reconstructing messages from stream events and injecting custom blocks (thinking,redacted_thinking,thoughtSignature)ModelMessageschemagetThoughtSignature,getRedactedThinkingBlocks,getReasoningDetails,getSummary) and their backing fields from all providersanthropicToRoo.ts) for loading old Anthropic-format conversation historiesTest plan
tsc --noEmit)🤖 Generated with Claude Code