-
Notifications
You must be signed in to change notification settings - Fork 2.9k
feat: wire RooMessage storage into Task.ts and all providers #11386
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: wire RooMessage storage into Task.ts and all providers #11386
Conversation
Re-reviewed after fef98f6. The
Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
|
Generated with ❤️ by ellipsis.dev |
PR #11386 Review: Wire RooMessage Storage into Task.ts and All ProvidersReviewed: 104 files, +4200/-2167, 4 commits (including fix commit What's Done Well
Issues FoundMEDIUM1.
|
|
Generated with ❤️ by ellipsis.dev |
…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>
fc24684 to
fef98f6
Compare
| const isError = getToolResultIsError(block) | ||
| const errorSuffix = isError ? " (Error)" : "" | ||
| // AI SDK uses `output`, legacy uses `content` | ||
| const rawContent = getToolResultContent(block) |
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.
getToolResultContent now returns block.output for AI SDK tool results, which is { type: "text", value: "..." }. toolResultToText checks for string and Array but not for this object shape, so the content falls through to the bare [Tool Result] return on line 85 -- losing all tool result text. This affects condensation summaries for new-format conversations since every tool result renders without its content. openai-format.ts (lines 377, 426) already handles this with a "value" in rawContent branch; the same check is needed here.
Fix it with Roo Code or mention @roomote and request a fix.
- 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>
|
|
||
| // Convert messages to AI SDK format | ||
| const aiSdkMessages = convertToAiSdkMessages(messages) | ||
| const aiSdkMessages = messages as ModelMessage[] |
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.
RooReasoningMessage items (which have type: "reasoning" and no role) are cast directly to ModelMessage[] without filtering. Bedrock and Gemini both filter these out before the cast (e.g. messages.filter(msg => msg.type !== "reasoning")), but Anthropic and Anthropic-Vertex do not. If a user switches providers mid-conversation from OpenAI Native (which produces standalone encrypted reasoning items) to Anthropic, these role-less objects will be sent to streamText, likely causing an API error. The same filter pattern from bedrock.ts lines 204-210 is needed here.
| const aiSdkMessages = messages as ModelMessage[] | |
| // Filter out standalone reasoning meta-items (e.g. encrypted reasoning from OpenAI Native) | |
| // that lack a `role` property and would break the AI SDK. | |
| const aiSdkMessages = messages.filter( | |
| (msg) => !((msg as { type?: string }).type === "reasoning"), | |
| ) as ModelMessage[] |
Fix it with Roo Code or mention @roomote and request a fix.
|
|
||
| // Convert messages to AI SDK format | ||
| const aiSdkMessages = convertToAiSdkMessages(messages) | ||
| const aiSdkMessages = messages as ModelMessage[] |
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.
Same issue as in anthropic.ts: RooReasoningMessage items (no role, just type: "reasoning") are not filtered before the cast. Bedrock and Gemini both filter these out. If the conversation history contains standalone encrypted reasoning items from a previous OpenAI Native session, they will be sent as role-less objects to streamText.
| const aiSdkMessages = messages as ModelMessage[] | |
| // Filter out standalone reasoning meta-items (e.g. encrypted reasoning from OpenAI Native) | |
| // that lack a `role` property and would break the AI SDK. | |
| const aiSdkMessages = messages.filter( | |
| (msg) => !((msg as { type?: string }).type === "reasoning"), | |
| ) as ModelMessage[] |
Fix it with Roo Code or mention @roomote and request a fix.
Create src/api/transform/cache-breakpoints.ts with applyCacheBreakpoints() that replaces duplicated targeting+apply logic in: - anthropic.ts (applyCacheControlToAiSdkMessages removed) - anthropic-vertex.ts (applyCacheControlToAiSdkMessages removed) - minimax.ts (applyCacheControlToAiSdkMessages removed) - bedrock.ts (applyCachePointsToAiSdkMessages removed) Key improvement: targets non-assistant batches (user + tool messages) instead of only role=user. After PR #11386, tool results are separate role=tool messages that now correctly receive cache breakpoints. The shared utility supports per-provider configuration: - Anthropic/Vertex/Minimax: 2 breakpoints (last 2 non-assistant batches) - Bedrock: 3 breakpoints + anchor at ~1/3 for 20-block lookback coverage 8 new tests in cache-breakpoints.spec.ts, 0 regressions in provider tests.
Summary
Wires the RooMessage foundation (PR #11380, now merged) into the entire codebase. Messages are now stored as
ModelMessage + metadataand passed directly to providers with zero conversion.Built on: PR #11380 (
feature/ext-646-design-modelmessage-schema-migration-strategy, merged)Changes (~80 files)
Storage Layer
apiConversationHistorytype:ApiMessage[]→RooMessage[]readApiMessages→readRooMessages(auto-converts old Anthropic format)saveApiMessages→saveRooMessages(versioned v2 format)Message Construction (Task.ts)
userMessageContent:Anthropic.TextBlockParam[]→Array<TextPart | ImagePart>pendingToolResults: Array<ToolResultPart>— tool results separated from user contentaddToApiConversationHistoryacceptsRooMessagedirectlypushToolResultToUserContentacceptsToolResultPart(AI SDK format)buildCleanConversationHistory: ~140 lines → ~20 lines (messages pass through)Provider Interface
ApiHandler.createMessage():Anthropic.Messages.MessageParam[]→RooMessage[]RooMessage[]convertToAiSdkMessages()from 22 AI SDK providers — messages go directly tostreamText()Supporting Systems
Test Results
Resolves EXT-647
Important
Wired the RooMessage foundation into the entire codebase, migrating from Anthropic SDK message types to a new internal RooMessage format based on AI SDK types across all 40+ API providers, message handling utilities, and task persistence logic.
Summary
Wires the RooMessage foundation (PR #11380, now merged) into the entire codebase. Messages are now stored as
ModelMessage + metadataand passed directly to providers with zero conversion.Built on: PR #11380 (
feature/ext-646-design-modelmessage-schema-migration-strategy, merged)Changes (~80 files)
Storage Layer
apiConversationHistorytype:ApiMessage[]�RooMessage[]readApiMessages�readRooMessages(auto-converts old Anthropic format)saveApiMessages�saveRooMessages(versioned v2 format)Message Construction (Task.ts)
userMessageContent:Anthropic.TextBlockParam[]�Array<TextPart | ImagePart>pendingToolResults: Array<ToolResultPart>� tool results separated from user contentaddToApiConversationHistoryacceptsRooMessagedirectlypushToolResultToUserContentacceptsToolResultPart(AI SDK format)buildCleanConversationHistory: ~140 lines � ~20 lines (messages pass through)Provider Interface
ApiHandler.createMessage():Anthropic.Messages.MessageParam[]�RooMessage[]RooMessage[]convertToAiSdkMessages()from 22 AI SDK providers � messages go directly tostreamText()Supporting Systems
Test Results
Resolves EXT-647
Detailed Changes
Message Type Migration
rooMessage.tsdefiningRooMessageunion type with variants for user, assistant, tool, and reasoning messages, all extending AI SDK types with Roo-specific metadata (timestamps, condense/truncation tracking).readRooMessages()andsaveRooMessages()functions inapiMessages.tsto handle v2 versioned format with automatic fallback to legacyclaude_messages.jsonand conversion from old Anthropic format.convertAnthropicToRooMessages()converter in newanthropicToRoo.tsmodule to transform legacyApiMessagearrays toRooMessageformat, handling all message types, reasoning formats, and metadata preservation.API Provider Updates
createMessage()method signatures to acceptRooMessage[]instead ofAnthropic.Messages.MessageParam[]across all providers (OpenAI, Anthropic, Azure, Gemini, Bedrock, etc.).convertToAiSdkMessages()calls with direct type casts toModelMessage[]in providers that use AI SDK (Anthropic, Azure, Baseten, Bedrock, DeepSeek, Fireworks, Gemini, LM Studio, Minimax, Mistral, OpenAI, OpenRouter, Requesty, Sambanova, Vercel AI Gateway, Vertex, ZAI).roleproperty existence before accessing it.RooMessage[]in helper functions.Task and Message Management
Task.tsto useRooMessage[]forapiConversationHistory, separated user message content and tool results intouserMessageContentandpendingToolResultsproperties.tool_use_id,content,is_error) to internal format (toolCallId,toolName,outputwith nestedtypeandvalue).flattenModelMessagesToStringContent()utility to convert message content arrays to strings where applicable, with options to control flattening behavior.getMessagesSinceLastSummary()andgetEffectiveApiHistory()incondense/index.tsto useRooMessage[]with type guards (isRooUserMessage,isRooAssistantMessage,isRooToolMessage).mergeConsecutiveApiMessages()to work withRooMessagetype and pass throughRooReasoningMessageitems unmerged.Assistant Message Handling
presentAssistantMessage.tsto transform tool results to internal format withtoolCallId,toolName, andoutputstructure, prepending[ERROR]prefix for errors instead of usingis_errorflag.ImagePartformat withimageandmediaTypefields.pendingToolResultsinstead ofuserMessageContentand verify new tool result structure.Test Coverage
rooMessage.ts,rooMessages.ts,messageUtils.ts, andanthropicToRoo.tscovering type guards, message detection, persistence, and conversion logic.RooMessage[]type and new message structure.as anytype assertions throughout tests to handle type compatibility during migration.This description was created by
for de6982e. You can customize this summary. It will automatically update as commits are pushed.