Skip to content

Commit 8f7cb32

Browse files
mini2ssebastiand-cerebrasroomote[bot]roomotedleffel
authored
Roo to main (#697)
* Update cerebras.ts (RooCodeInc#9024) * fix: update Opus 4.1 max tokens from 8K to 32K (RooCodeInc#9046) Aligns claude-opus-4-1-20250805 max token limit with claude-opus-4-20250514, both models now supporting 32K output tokens (overridable to 8K when enableReasoningEffort is false). Fixes RooCodeInc#9045 Co-authored-by: Roo Code <roomote@roocode.com> * Merge remote-tracking branch 'upstream/main' into roo-to-main * feat(api): add mode parameter to ZgsmAiHandler and add tooltips to ChatRow buttons * chore: simplify Google Analytics to standard implementation (RooCodeInc#9044) Co-authored-by: Roo Code <roomote@roocode.com> * feat: add conditional test running to pre-push hook (RooCodeInc#9055) * Fix dynamic provider model validation to prevent cross-contamination (RooCodeInc#9054) * Fix Bedrock user agent to report full SDK details (RooCodeInc#9043) * feat: add Qwen3 embedding models (0.6B and 4B) to OpenRouter support (RooCodeInc#9060) Co-authored-by: Roo Code <roomote@roocode.com> * web: Agent Landing Page A/B testing toolkit (RooCodeInc#9018) Co-authored-by: Roo Code <roomote@roocode.com> * feat: Global Inference for Bedrock models (RooCodeInc#8750) (RooCodeInc#8940) Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: Roo Code <roomote@roocode.com> * Release v3.30.2 (RooCodeInc#9065) chore: add changeset for v3.30.2 * Changeset version bump (RooCodeInc#9066) * changeset version bump * Revise CHANGELOG for version 3.30.2 Updated changelog for version 3.30.2 with new features and fixes. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * Merge branch 'main' of github.com:zgsm-ai/costrict into roo-to-main * feat(error-handling): add HTTP 413 payload too large error handling * fix(webview): correct default value for useZgsmCustomConfig and fix settings message order * feat: add kimi-k2-thinking model to moonshot provider (RooCodeInc#9079) * ux: Home screen visuals (RooCodeInc#9057) Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: Roo Code <roomote@roocode.com> * feat: add MiniMax-M2-Stable model and enable prompt caching (RooCodeInc#9072) Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: Daniel <57051444+daniel-lxs@users.noreply.github.com> * fix(task): auto-retry on empty assistant response (RooCodeInc#9076) (RooCodeInc#9083) * feat(chat): Improve diff appearance in main chat view (RooCodeInc#8932) Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com> * Clarify: setting 0 disables Error & Repetition Limit (RooCodeInc#8965) Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com> * fix: use system role for OpenAI Compatible provider when streaming is disabled (RooCodeInc#8216) Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com> * fix: prevent shell injection in pre-push hook environment loading (RooCodeInc#9059) * feat: auto-switch to imported mode with architect fallback (RooCodeInc#9003) Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> Co-authored-by: Seth Miller <sethmillerp@gmail.com> Co-authored-by: heyseth <sethmillerp@gmail.com> Co-authored-by: Roo Code <roomote@roocode.com> * fix: prevent notification sound on attempt_completion with queued messages (RooCodeInc#8540) Co-authored-by: Roo Code <roomote@roocode.com> * chore(deps): update dependency @changesets/cli to v2.29.7 (RooCodeInc#8490) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * chore: add changeset for v3.30.3 (RooCodeInc#9092) * Changeset version bump (RooCodeInc#9094) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * fix: respect custom OpenRouter URL for all API operations (RooCodeInc#8951) Co-authored-by: Roo Code <roomote@roocode.com> * feat: Add comprehensive error logging to Roo Cloud provider (RooCodeInc#9098) feat: add comprehensive error logging to Roo Cloud provider - Add detailed error logging in handleOpenAIError() to capture error details before transformation - Enhanced getRooModels() to log HTTP response details on failed requests - Added error context logging to RooHandler streaming and model loading - All existing tests passing (48 total) * ux: Less Caffeine (RooCodeInc#9104) Prevents stress on Roo's hip bones * fix: prevent crash when streaming chunks have null choices array (RooCodeInc#9105) * ux: Improvements to to-do lists and task headers (RooCodeInc#9096) Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * fix: prevent context condensing on settings save when provider/model unchanged (RooCodeInc#9108) Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * Release v3.31.0 (RooCodeInc#9111) * Changeset version bump (RooCodeInc#9112) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * fix: improve mobile responsiveness of hero section on /reviewer page (RooCodeInc#9138) Co-authored-by: Roo Code <roomote@roocode.com> * feat(integrations): update export markdown filename to include 'costrict' prefix * feat(core): enhance attempt_completion parsing with flexible result handling * test(core): update test configurations and CSP settings * feat: add Google Tag Manager to marketing website (RooCodeInc#9148) * feat: add Google Tag Manager to marketing website using Next.js Script component * refactor: remove Google Ads implementation in favor of Tag Manager * fix: wrap GTM script in consent-checking client component for GDPR compliance --------- Co-authored-by: Roo Code <roomote@roocode.com> * IPC command for sending messages to the current task (RooCodeInc#9149) * fix: prevent command_output ask from blocking in cloud/headless environments (RooCodeInc#9152) * chore: add changeset for v3.31.1 (RooCodeInc#9153) * Release: v1.85.0 (RooCodeInc#9155) * Gate XML out when native tool protocol is ON (RooCodeInc#9107) * Add native tool definitions (RooCodeInc#9156) * feat: sync reviewer landing page copy - variant B to variant A (RooCodeInc#9158) - Updated variant A content to match variant B messaging - Both variants now show the same improved copy focused on catching meaningful bugs - Emphasizes depth over token-saving and repository-aware analysis Co-authored-by: Roo Code <roomote@roocode.com> * feat: sync reviewer landing page copy - variant B to variant A (RooCodeInc#9158) - Updated variant A content to match variant B messaging - Both variants now show the same improved copy focused on catching meaningful bugs - Emphasizes depth over token-saving and repository-aware analysis Co-authored-by: Roo Code <roomote@roocode.com> * Move auto-approval from `ChatView` to `Task` (RooCodeInc#9157) * feat(i18n): add internationalization for unexpected API response error message * fix(task): use consistent error message for API response failures and ensure message queue is never undefined * test: update vscode mock and improve test coverage * fix: Model switch re-applies selected profile (sync task.apiConfiguration) (RooCodeInc#9179) (RooCodeInc#9181) * Add custom Button component with variant system (RooCodeInc#9150) Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> Co-authored-by: Roo Code <roomote@roocode.com> * Changeset version bump (RooCodeInc#9154) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * feat(core): detect API configuration changes for model switching * fix: include mcpServers in getState() for auto-approval (RooCodeInc#9199) * fix: replace rate-limited badges with badgen.net (RooCodeInc#9200) * Batch settings updates from the webview to the extension host (RooCodeInc#9165) Co-authored-by: Roo Code <roomote@roocode.com> * fix: Apply updated API profile settings when provider/model unchanged (RooCodeInc#9208) (RooCodeInc#9210) fix: apply updated API profile settings when provider/model unchanged (RooCodeInc#9208) * fix: migrate Issue Fixer to REST + ProjectsV2 (RooCodeInc#9207) * fix(issue-fixer): migrate to REST for issue/comments and add ProjectsV2; remove Projects Classic mentions * Update .roo/rules-issue-fixer/4_github_cli_usage.xml Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> * Update .roo/rules-issue-fixer/4_github_cli_usage.xml Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> --------- Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> * Migrate conversation continuity to plugin-side encrypted reasoning items (Responses API) (RooCodeInc#9203) * Migrate conversation continuity to plugin-side encrypted reasoning items (Responses API) Summary We moved continuity off OpenAI servers and now maintain conversation state locally by persisting and replaying encrypted reasoning items. Requests are stateless (store=false) while retaining the performance/caching benefits of the Responses API. Why This aligns with how Roo manages context and simplifies our Responses API implementation while keeping all the benefits of continuity, caching, and latency improvements. What changed - All OpenAI models now use the Responses API; system instructions are passed via the top-level instructions field; requests include store=false and include=["reasoning.encrypted_content"]. - We persist encrypted reasoning items (type: "reasoning", encrypted_content, optional id) into API history and replay them on subsequent turns. - Reasoning summaries default to summary: "auto" when supported; text.verbosity only when supported. - Atomic persistence via safeWriteJson. Removed - previous_response_id flows, suppressPreviousResponseId/skipPrevResponseIdOnce, persistGpt5Metadata(), and GPT‑5 response ID metadata in UI messages. Kept - taskId and mode metadata for cross-provider features. Result - ZDR-friendly, stateless continuity with equal or better performance and a simpler codepath. * fix(webview): remove unused metadata prop from ReasoningBlock render * Responses API: retain response id for troubleshooting (not continuity) Continuity is stateless via encrypted reasoning items that we persist and replay. We now capture the top-level response id in OpenAiNativeHandler and persist the assistant message id into api_conversation_history.json solely for debugging/correlation with provider logs; it is not used for continuity or control flow. Also: silence request-body debug logging to avoid leaking prompts. * remove DEPRECATED tests * chore: remove unused Task types file to satisfy knip CI * fix(task): properly type cleanConversationHistory and createMessage args in Task to address Dan's review * chore: add changeset for v3.31.2 (RooCodeInc#9216) * Changeset version bump (RooCodeInc#9217) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * rename: sliding-window -> context-management; truncateConversationIfNeeded -> manageContext (RooCodeInc#9206) * Fix: Roo Anthropic input token normalization (avoid double-count) (RooCodeInc#9224) * OpenAI Native: gate encrypted_content include; remove gpt-5-chat-latest verbosity flag (fixes RooCodeInc#9225) (RooCodeInc#9231) openai-native: include reasoning.encrypted_content only when reasoningEffort is set; prevent Responses API error on non-reasoning models. types: remove supportsVerbosity from gpt-5-chat-latest to avoid invalid verbosity error. Fixes RooCodeInc#9225 * docs: remove Contributors section from README files (RooCodeInc#9198) Co-authored-by: Roo Code <roomote@roocode.com> * Release v3.31.3 (RooCodeInc#9232) * Changeset version bump (RooCodeInc#9233) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * Add native tool call support (RooCodeInc#9159) Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> * Consistently use Package.name for better support of the nightly app (RooCodeInc#9240) * fix: resolve 400 error with native tools on OpenRouter (RooCodeInc#9238) * fix: change tool_choice from required to auto for native protocol (RooCodeInc#9242) * docs: include PR numbers in release guide (RooCodeInc#9236) * Add enum support to configuration schema (RooCodeInc#9247) * refactor(task): switch to <feedback> wrapper to prevent focus drift after context-management event (condense/truncate) (RooCodeInc#9237) * refactor(task): wrap initial user message in <feedback> instead of <task> to prevent focus drift after context-management Rationale: After a successful context-management event, framing the next user block as feedback reduces model focus drift. Mentions parsing already supports <feedback>, and tool flows (attemptCompletion, responses) are aligned. No change to loop/persistence. * refactor(mentions): drop <task> parsing; standardize on <feedback>; update tests * fix: Filter native tools by mode restrictions (RooCodeInc#9246) * fix: filter native tools by mode restrictions Native tools are now filtered based on mode restrictions before being sent to the API, matching the behavior of XML tools. Previously, all native tools were sent to the API regardless of mode, causing the model to attempt using disallowed tools. Changes: - Created filterNativeToolsForMode() and filterMcpToolsForMode() utility functions - Extracted filtering logic from Task.ts into dedicated module - Applied same filtering approach used for XML tools in system prompt - Added comprehensive test coverage (10 tests) Impact: - Model only sees tools allowed by current mode - No more failed tool attempts due to mode restrictions - Consistent behavior between XML and Native protocols - Better UX with appropriate tool suggestions per mode * refactor: eliminate repetitive tool checking using group-based approach - Add getAvailableToolsInGroup() helper to check tools by group instead of individually - Refactor filterNativeToolsForMode() to reuse getToolsForMode() instead of duplicating logic - Simplify capabilities.ts by using group-based checks (60% reduction) - Refactor rules.ts to use group helper (56% reduction) - Remove debug console.log statements - Update tests and snapshots Benefits: - Eliminates code duplication - Leverages existing TOOL_GROUPS structure - More maintainable - new tools in groups work automatically - All tests passing (26/26) * fix: add fallback to default mode when mode config not found Ensures the agent always has functional tools even if: - A custom mode is deleted while tasks still reference it - Mode configuration becomes corrupted - An invalid mode slug is provided Without this fallback, the agent would have zero tools (not even ask_followup_question or attempt_completion), completely breaking it. * Fix broken share button (RooCodeInc#9253) fix(webview-ui): make Share button popover work by forwarding ref in LucideIconButton - Convert LucideIconButton to forwardRef so Radix PopoverTrigger(asChild) receives a focusable element - Enables Share popover and shareCurrentTask flow - Verified with ShareButton/TaskActions Vitest suites * Add GPT-5.1 models and clean up reasoning effort logic (RooCodeInc#9252) * Reasoning effort: capability-driven; add disable/none/minimal; remove GPT-5 minimal special-casing; document UI semantics; remove temporary logs * Remove Unused supportsReasoningNone * Roo reasoning: omit field on 'disable'; UI: do not flip enableReasoningEffort when selecting 'disable' * Update packages/types/src/model.ts Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> * Update webview-ui/src/components/settings/SimpleThinkingBudget.tsx Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> --------- Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> * fix: make line_ranges optional in read_file tool schema (RooCodeInc#9254) The OpenAI tool schema required both 'path' and 'line_ranges' in FileEntry, but the TypeScript type definition marks lineRanges as optional. This caused the AI to fail when trying to read files without specifying line_ranges. Changes: - Updated read_file tool schema to only require 'path' parameter - line_ranges remains available but optional, matching TypeScript types - Aligns with implementation which treats lineRanges as optional throughout Fixes issue where read_file tool kept failing with missing parameters. * fix: prevent consecutive user messages on streaming retry (RooCodeInc#9249) * feat(openai): OpenAI Responses: model-driven prompt caching and generic reasoning options refactor (RooCodeInc#9259) * revert out of scope changes from RooCodeInc#9252 (RooCodeInc#9258) * Revert "refactor(task): switch to <feedback> wrapper to prevent focus drift after context-management event (condense/truncate)" (RooCodeInc#9261) * Release v3.32.0 (RooCodeInc#9264) * Changeset version bump (RooCodeInc#9265) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * [FIX] Fix OpenAI Native handling of encrypted reasoning blocks to prevent error when condensing (RooCodeInc#9263) * fix: prevent duplicate tool_result blocks in native protocol mode for read_file (RooCodeInc#9272) When read_file encountered errors (e.g., file not found), it would call handleError() which internally calls pushToolResult(), then continue to call pushToolResult() again with the final XML. In native protocol mode, this created two tool_result blocks with the same tool_call_id, causing 400 errors on subsequent API calls. This fix replaces handleError() with task.say() for error notifications. The agent still receives error details through the XML in the single final pushToolResult() call. This change works for both protocols: - Native: Only one tool_result per tool_call_id (fixes duplicate issue) - XML: Only one text block with complete XML (cleaner than before) Agent visibility preserved: Errors are included in the XML response sent to the agent via pushToolResult(). Tests: All 44 tests passing. Updated test to verify say() is called. * Fix duplicate tool blocks causing 'tool has already been used' error (RooCodeInc#9275) * feat(openai-native): add abort controller for request cancellation (RooCodeInc#9276) * Disable XML parser for native tool protocol (RooCodeInc#9277) * Release v3.32.1 (RooCodeInc#9278) * Changeset version bump (RooCodeInc#9280) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * refactor: centralize toolProtocol configuration checks (RooCodeInc#9279) * refactor: centralize toolProtocol configuration checks - Created src/utils/toolProtocol.ts with getToolProtocolFromSettings() utility - Replaced all direct vscode.workspace.getConfiguration() calls with centralized utility - Updated 6 files to use the new utility function - All tests pass and TypeScript compilation succeeds * refactor: use isNativeProtocol function from types package * fix: format tool responses for native protocol (RooCodeInc#9270) * fix: format tool responses for native protocol - Add toolResultFormatting utilities for protocol detection - ReadFileTool now builds both XML and native formats - Native format returns clean, readable text without XML tags - Legacy conversation history conversion is protocol-aware - All tests passing (55 total) * refactor: use isNativeProtocol from @roo-code/types Remove duplicate implementation and import from types package instead * fix: prevent duplicate tool_result blocks in native tool protocol (RooCodeInc#9248) * Merge remote-tracking branch 'upstream/main' into roo-to-main * Fix duplicate import (RooCodeInc#9281) * chore(core): remove unused TelemetryEventName import * feat: implement dynamic tool protocol resolution with proper precedence hierarchy (RooCodeInc#9286) Co-authored-by: Roo Code <roomote@roocode.com> * web: Roo Code Cloud Provider pricing page and changes elsewhere (RooCodeInc#9195) Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * feat(zgsm): add abort signal handling for streaming responses * Move the native tool call toggle to experimental settings (RooCodeInc#9297) Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com> * fix: Replace broken badgen.net badges with shields.io (RooCodeInc#9318) Co-authored-by: Roo Code <roomote@roocode.com> * fix: preserve tool blocks for native protocol in conversation history (RooCodeInc#9319) * feat: add git status to environment details (RooCodeInc#9310) * feat: Move Import/Export to Modes view toolbar (RooCodeInc#8686) Cleanup of Mode Edit view (RooCodeInc#9077) * Add max git status files to evals settings (RooCodeInc#9322) * Release: v1.86.0 (RooCodeInc#9323) * fix: prevent infinite loop when attempt_completion succeeds (RooCodeInc#9325) * feat: add tool protocol selector to advanced settings (RooCodeInc#9324) Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * Remove experimental setting for native tool calls (RooCodeInc#9333) * Fix the type of the list files recursive parameter (RooCodeInc#9337) * fix: use VSCode theme color for outline button borders (RooCodeInc#9336) Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: Bruno Bergher <bruno@roocode.com> * feat: update cloud agent CTA to point to setup page (RooCodeInc#9338) Co-authored-by: Roo Code <roomote@roocode.com> * Improve Google Gemini defaults, temperature, and cost reporting (RooCodeInc#9327) * fix: sync parser state with profile/model changes (RooCodeInc#9355) * feat: enable native tool calling for openai-native provider (RooCodeInc#9348) Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com> * Add Gemini 3 Pro Preview model (RooCodeInc#9357) * fix: pass tool protocol parameter to lineCountTruncationError (RooCodeInc#9358) * Remove the Roo model defaults (RooCodeInc#9340) * chore: add changeset and announcement for v3.33.0 (RooCodeInc#9360) * Changeset version bump (RooCodeInc#9362) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * fix: resolve native tool protocol race condition causing 400 errors (RooCodeInc#9363) * Retry eval tasks if API instability detected (RooCodeInc#9365) * fix: exclude XML tool examples from MODES section when native protocol enabled (RooCodeInc#9367) * Add native tool calling support to OpenAI-compatible (RooCodeInc#9369) * Add native tool calling support to OpenAI-compatible * Fix OpenAI strict mode schema validation by adding converter methods to BaseProvider - Add convertToolsForOpenAI() and convertToolSchemaForOpenAI() methods to BaseProvider - These methods ensure all properties are in required array and convert nullable types - Remove line_ranges from required array in read_file tool (converter handles it) - Update OpenAiHandler and BaseOpenAiCompatibleProvider to use helper methods - Eliminates code duplication across multiple tool usage sites - Fixes: OpenAI completion error: 400 Invalid schema for function 'read_file' --------- Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com> * fix: ensure no XML parsing when protocol is native (RooCodeInc#9371) * fix: ensure no XML parsing when protocol is native * refactor: remove redundant non-null assertions * fix: gemini maxOutputTokens and reasoning config (RooCodeInc#9375) * fix: gemini maxOutputTokens and reasoning config * test: tighten gemini reasoning typings * fix: Update tools to return structured JSON for native protocol (RooCodeInc#9373) * feat: add toolProtocol property to PostHog tool usage telemetry (RooCodeInc#9374) Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com> * fix: Include nativeArgs in tool repetition detection (RooCodeInc#9377) * fix: Include nativeArgs in tool repetition detection Fixes false positive 'stuck in a loop' error for native protocol tools like read_file that store parameters in nativeArgs instead of params. Previously, the ToolRepetitionDetector only compared the params object, which was empty for native protocol tools. This caused all read_file calls to appear identical, triggering false loop detection even when reading different files. Changes: - Updated serializeToolUse() to include nativeArgs in comparison - Added comprehensive tests for native protocol scenarios - Maintains backward compatibility with XML protocol tools Closes: Issue reported in Discord about read_file loop detection * Try to use safe-stable-stringify in the tool repetition detector --------- Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * Fix Gemini thought signature validation and token counting errors (RooCodeInc#9380) Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * Release v3.33.1 (RooCodeInc#9383) * Changeset version bump (RooCodeInc#9384) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * fix: preserve user images in native tool call results (RooCodeInc#9401) * feat: migrate PostHog client to ph.roocode.com (RooCodeInc#9402) Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * feat: enable native tool calling for gemini provider (RooCodeInc#9343) Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com> * Add a RCC credit balance display (RooCodeInc#9386) * Add a RCC credit balance display * Replace the provider docs with the balance when logged in * PR feedback --------- Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * perf: reduce excessive getModel() calls & implement disk cache fallback (RooCodeInc#9410) * Show zero price for free models (RooCodeInc#9419) * Release v3.33.2 (RooCodeInc#9420) * Changeset version bump (RooCodeInc#9421) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * Improve read_file tool description with examples (RooCodeInc#9422) * Improve read_file tool description with examples - Add explicit JSON structure documentation - Include three concrete examples (single file, with line ranges, multiple files) - Clarify that 'path' is required and 'line_ranges' is optional - Better explain line range format (1-based inclusive) This addresses agent confusion by providing clear examples similar to the XML tool definition. * Make read_file tool dynamic based on partialReadsEnabled setting - Convert read_file from static export to createReadFileTool() factory function - Add getNativeTools() function that accepts partialReadsEnabled parameter - Create buildNativeToolsArray() helper to encapsulate tool building logic - Update Task.ts to build native tools dynamically using maxReadFileLine setting - When partialReadsEnabled is false, line_ranges parameter is excluded from schema - Examples and descriptions adjust based on whether line ranges are supported This matches the behavior of the XML tool definition which dynamically adjusts its documentation based on settings, reducing confusion for agents. * Fix Marketplace crash by removing wildcard activation event (RooCodeInc#9423) * Revert "Fix Marketplace crash by removing wildcard activation event" (RooCodeInc#9432) * Fix OpenAI Native parallel tool calls for native protocol (RooCodeInc#9433) Fixes an issue where using the OpenAI Native provider together with Native Tool Calling could cause OpenAI’s Responses API to fail with errors like: * feat: add Google Gemini 3 Pro Image Preview to image generation models (RooCodeInc#9440) Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * fix: prevent duplicate environment_details when resuming cancelled tasks (RooCodeInc#9442) - Filter out complete environment_details blocks before appending fresh ones - Check for both opening and closing tags to ensure we're matching complete blocks - Prevents stale environment data from being kept during task resume - Add tests to verify deduplication logic and edge cases * Update glob to ^11.1.0 (RooCodeInc#9449) * chore: update tar-fs to 3.1.1 via pnpm override (RooCodeInc#9450) Co-authored-by: Roo Code <roomote@roocode.com> * Store reasoning in conversation history for all providers (RooCodeInc#9451) * Fix preserveReasoning flag to control API reasoning inclusion (RooCodeInc#9453) * feat: store reasoning in conversation history for all providers * refactor: address review feedback - Move comments inside else block - Combine reasoning checks into single if block - Make comments more concise * refactor: make comments more concise * Fix preserveReasoning flag to control API reasoning inclusion Changes: 1. Removed hardcoded <think> tag logic in streaming - Previously hardcoded reasoning into assistant message text - Now passes reasoning to addToApiConversationHistory as parameter 2. Updated buildCleanConversationHistory to respect preserveReasoning flag - When preserveReasoning: true → reasoning block included in API requests - When preserveReasoning: false/undefined → reasoning stripped from API - Reasoning stored in history for all cases 3. Added temporary debug logs to base-openai-compatible-provider.ts - Shows preserveReasoning flag value - Logs reasoning blocks in incoming messages - Logs <think> tags in converted messages sent to API * Fix: Use api.getModel() directly instead of cachedStreamingModel Addresses review comment: cachedStreamingModel is set during streaming but buildCleanConversationHistory is called before streaming starts. Using the cached value could cause stale model info when switching models between requests. Now directly uses this.api.getModel().info.preserveReasoning to ensure we always check the current model's flag, not a potentially stale cached value. * Clean up comments in Task.ts Removed outdated comment regarding model's preserveReasoning flag. * fix: remove unnecessary reasoningBlock variable in task reasoning logic * fix: send tool_result blocks for skipped tools in native protocol (RooCodeInc#9457) * fix: improve markdown formatting and add reasoning support (RooCodeInc#9458) * feat: implement Minimax as Anthropic-compatible provider (RooCodeInc#9455) * fix: improve search and replace symbol parsing (RooCodeInc#9456) * chore: add changeset for v3.33.3 (RooCodeInc#9459) * Changeset version bump (RooCodeInc#9460) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * feat(terminal): add inline shell integration with user input support * Release: v1.87.0 (RooCodeInc#9477) * refactor(terminal): remove inline shell integration callback and improve terminal process handling * fix: add fallback to yield tool calls regardless of finish_reason (RooCodeInc#9476) * Improvements to base openai compatible (RooCodeInc#9462) Co-authored-by: Roo Code <roomote@roocode.com> * Browser Use 2.0 (RooCodeInc#8941) Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com> * fix: resolve apply_diff performance regression from PR RooCodeInc#9456 (RooCodeInc#9474) * fix: implement model cache refresh to prevent stale disk cache (RooCodeInc#9478) * fix: Make cancel button immediately responsive during streaming (RooCodeInc#9448) * Test a provider-oriented welcome screen (RooCodeInc#9484) Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> * (feat): Add Baseten Provider (RooCodeInc#9461) Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> Co-authored-by: AlexKer <AlexKer@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * fix: copy model-level capabilities to OpenRouter endpoint models (RooCodeInc#9483) * Pin the Roo provider to the top of the list (RooCodeInc#9485) * Wait to experiment until state is hydrated (RooCodeInc#9488) * Change baseten default model to glm for now (RooCodeInc#9489) * Revert "Wait to experiment until state is hydrated" (RooCodeInc#9491) * Try to fix build (RooCodeInc#9490) * Update webview-ui Vite config (RooCodeInc#9493) * Enhance native tool descriptions with examples and clarifications (RooCodeInc#9486) * Revert "Revert "Wait to experiment until state is hydrated"" (RooCodeInc#9494) * chore: add changeset and announcement for v3.34.0 (RooCodeInc#9495) * Changeset version bump (RooCodeInc#9496) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * Enable the Roo Code Cloud provider in evals (RooCodeInc#9492) * Show the prompt for image gen (RooCodeInc#9505) * feat(chat): conditionally render UpdateTodoListToolBlock based on alwaysAllowUpdateTodoList flag * fix(web-evals): update checkbox handler in new-run component * Remove double todo list (RooCodeInc#9517) * Track cloud synced messages (RooCodeInc#9518) * 3.34.1 (RooCodeInc#9522) * Changeset version bump (RooCodeInc#9523) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> * fix: support reasoning_details format for Gemini 3 models (RooCodeInc#9506) * feat: update Cerebras models (RooCodeInc#9527) Co-authored-by: Roo Code <roomote@roocode.com> --------- Co-authored-by: Seb Duerr <sebastian.duerr@cerebras.net> Co-authored-by: roomote[bot] <219738659+roomote[bot]@users.noreply.github.com> Co-authored-by: Roo Code <roomote@roocode.com> Co-authored-by: dleffel <daniel.leffel@gmail.com> Co-authored-by: Daniel <57051444+daniel-lxs@users.noreply.github.com> Co-authored-by: AJ Juaire <46756248+ajjuaire@users.noreply.github.com> Co-authored-by: Bruno Bergher <me@brunobergher.com> Co-authored-by: Hannes Rudolph <hrudolph@gmail.com> Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> Co-authored-by: Matt Rubens <mrubens@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: daniel-lxs <ricciodaniel98@gmail.com> Co-authored-by: Seth Miller <sethmillerp@gmail.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Bruno Bergher <bruno@roocode.com> Co-authored-by: Chris Estreich <cestreich@gmail.com> Co-authored-by: John Richmond <5629+jr@users.noreply.github.com> Co-authored-by: Alex Ker <thealexker@gmail.com> Co-authored-by: AlexKer <AlexKer@users.noreply.github.com>
1 parent bba7a43 commit 8f7cb32

File tree

7 files changed

+186
-57
lines changed

7 files changed

+186
-57
lines changed

.changeset/v3.34.1.md

Lines changed: 0 additions & 8 deletions
This file was deleted.

packages/types/src/providers/cerebras.ts

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,6 @@ export const cerebrasModels = {
1515
outputPrice: 0,
1616
description: "Highly intelligent general purpose model with up to 1,000 tokens/s",
1717
},
18-
"qwen-3-coder-480b-free": {
19-
maxTokens: 40000,
20-
contextWindow: 64000,
21-
supportsImages: false,
22-
supportsPromptCache: false,
23-
inputPrice: 0,
24-
outputPrice: 0,
25-
description:
26-
"[SOON TO BE DEPRECATED] SOTA coding model with ~2000 tokens/s ($0 free tier)\n\n• Use this if you don't have a Cerebras subscription\n• 64K context window\n• Rate limits: 150K TPM, 1M TPH/TPD, 10 RPM, 100 RPH/RPD\n\nUpgrade for higher limits: [https://cloud.cerebras.ai/?utm=roocode](https://cloud.cerebras.ai/?utm=roocode)",
27-
},
28-
"qwen-3-coder-480b": {
29-
maxTokens: 40000,
30-
contextWindow: 128000,
31-
supportsImages: false,
32-
supportsPromptCache: false,
33-
inputPrice: 0,
34-
outputPrice: 0,
35-
description:
36-
"[SOON TO BE DEPRECATED] SOTA coding model with ~2000 tokens/s ($50/$250 paid tiers)\n\n• Use this if you have a Cerebras subscription\n• 131K context window with higher rate limits",
37-
},
3818
"qwen-3-235b-a22b-instruct-2507": {
3919
maxTokens: 64000,
4020
contextWindow: 64000,
@@ -62,16 +42,6 @@ export const cerebrasModels = {
6242
outputPrice: 0,
6343
description: "SOTA coding performance with ~2500 tokens/s",
6444
},
65-
"qwen-3-235b-a22b-thinking-2507": {
66-
maxTokens: 40000,
67-
contextWindow: 65000,
68-
supportsImages: false,
69-
supportsPromptCache: false,
70-
inputPrice: 0,
71-
outputPrice: 0,
72-
description: "SOTA performance with ~1500 tokens/s",
73-
supportsReasoningEffort: true,
74-
},
7545
"gpt-oss-120b": {
7646
maxTokens: 8000,
7747
contextWindow: 64000,

src/api/providers/cerebras.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,11 @@ export class CerebrasHandler extends BaseProvider implements SingleCompletionHan
9898
}
9999

100100
getModel(): { id: CerebrasModelId; info: (typeof cerebrasModels)[CerebrasModelId] } {
101-
const originalModelId = (this.options.apiModelId as CerebrasModelId) || this.defaultProviderModelId
102-
103-
// Route both qwen coder models to the same actual model ID for API calls
104-
// This allows them to have different rate limits/descriptions in the UI
105-
// while using the same underlying model
106-
let apiModelId = originalModelId
107-
if (originalModelId === "qwen-3-coder-480b-free") {
108-
apiModelId = "qwen-3-coder-480b"
109-
}
101+
const modelId = (this.options.apiModelId as CerebrasModelId) || this.defaultProviderModelId
110102

111103
return {
112-
id: apiModelId,
113-
info: this.providerModels[originalModelId], // Use original model info for rate limits/descriptions
104+
id: modelId,
105+
info: this.providerModels[modelId],
114106
}
115107
}
116108

src/api/providers/openrouter.ts

Lines changed: 137 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
import type { ApiHandlerOptions, ModelRecord } from "../../shared/api"
1313

1414
import { convertToOpenAiMessages } from "../transform/openai-format"
15+
import { resolveToolProtocol } from "../../utils/resolveToolProtocol"
16+
import { TOOL_PROTOCOL } from "@roo-code/types"
1517
import { ApiStreamChunk } from "../transform/stream"
1618
import { convertToR1Format } from "../transform/r1-format"
1719
import { addCacheBreakpoints as addAnthropicCacheBreakpoints } from "../transform/caching/anthropic"
@@ -88,6 +90,7 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
8890
protected models: ModelRecord = {}
8991
protected endpoints: ModelRecord = {}
9092
private readonly providerName = "OpenRouter"
93+
private currentReasoningDetails: any[] = []
9194

9295
constructor(options: ApiHandlerOptions) {
9396
super()
@@ -125,6 +128,10 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
125128
}
126129
}
127130

131+
getReasoningDetails(): any[] | undefined {
132+
return this.currentReasoningDetails.length > 0 ? this.currentReasoningDetails : undefined
133+
}
134+
128135
override async *createMessage(
129136
systemPrompt: string,
130137
messages: Anthropic.Messages.MessageParam[],
@@ -134,11 +141,14 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
134141

135142
let { id: modelId, maxTokens, temperature, topP, reasoning } = model
136143

137-
// OpenRouter sends reasoning tokens by default for Gemini 2.5 Pro
138-
// Preview even if you don't request them. This is not the default for
144+
// Reset reasoning_details accumulator for this request
145+
this.currentReasoningDetails = []
146+
147+
// OpenRouter sends reasoning tokens by default for Gemini 2.5 Pro models
148+
// even if you don't request them. This is not the default for
139149
// other providers (including Gemini), so we need to explicitly disable
140-
// i We should generalize this using the logic in `getModelParams`, but
141-
// this is easier for now.
150+
// them unless the user has explicitly configured reasoning.
151+
// Note: Gemini 3 models use reasoning_details format and should not be excluded.
142152
if (
143153
(modelId === "google/gemini-2.5-pro-preview" || modelId === "google/gemini-2.5-pro") &&
144154
typeof reasoning === "undefined"
@@ -157,6 +167,43 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
157167
openAiMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
158168
}
159169

170+
// Process reasoning_details when switching models to Gemini for native tool call compatibility
171+
const toolProtocol = resolveToolProtocol(this.options, model.info)
172+
const isNativeProtocol = toolProtocol === TOOL_PROTOCOL.NATIVE
173+
const isGemini = modelId.startsWith("google/gemini")
174+
175+
// For Gemini with native protocol: inject fake reasoning.encrypted blocks for tool calls
176+
// This is required when switching from other models to Gemini to satisfy API validation
177+
if (isNativeProtocol && isGemini) {
178+
openAiMessages = openAiMessages.map((msg) => {
179+
if (msg.role === "assistant") {
180+
const toolCalls = (msg as any).tool_calls as any[] | undefined
181+
const existingDetails = (msg as any).reasoning_details as any[] | undefined
182+
183+
// Only inject if there are tool calls and no existing encrypted reasoning
184+
if (toolCalls && toolCalls.length > 0) {
185+
const hasEncrypted = existingDetails?.some((d) => d.type === "reasoning.encrypted") ?? false
186+
187+
if (!hasEncrypted) {
188+
const fakeEncrypted = toolCalls.map((tc, idx) => ({
189+
id: tc.id,
190+
type: "reasoning.encrypted",
191+
data: "skip_thought_signature_validator",
192+
format: "google-gemini-v1",
193+
index: (existingDetails?.length ?? 0) + idx,
194+
}))
195+
196+
return {
197+
...msg,
198+
reasoning_details: [...(existingDetails ?? []), ...fakeEncrypted],
199+
}
200+
}
201+
}
202+
}
203+
return msg
204+
})
205+
}
206+
160207
// https://openrouter.ai/docs/features/prompt-caching
161208
// TODO: Add a `promptCacheStratey` field to `ModelInfo`.
162209
if (OPEN_ROUTER_PROMPT_CACHING_MODELS.has(modelId)) {
@@ -203,6 +250,20 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
203250

204251
let lastUsage: CompletionUsage | undefined = undefined
205252
const toolCallAccumulator = new Map<number, { id: string; name: string; arguments: string }>()
253+
// Accumulator for reasoning_details: accumulate text by type-index key
254+
const reasoningDetailsAccumulator = new Map<
255+
string,
256+
{
257+
type: string
258+
text?: string
259+
summary?: string
260+
data?: string
261+
id?: string | null
262+
format?: string
263+
signature?: string
264+
index: number
265+
}
266+
>()
206267

207268
for await (const chunk of stream) {
208269
// OpenRouter returns an error object instead of the OpenAI SDK throwing an error.
@@ -216,7 +277,73 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
216277
const finishReason = chunk.choices[0]?.finish_reason
217278

218279
if (delta) {
219-
if ("reasoning" in delta && delta.reasoning && typeof delta.reasoning === "string") {
280+
// Handle reasoning_details array format (used by Gemini 3, Claude, OpenAI o-series, etc.)
281+
// See: https://openrouter.ai/docs/use-cases/reasoning-tokens#preserving-reasoning-blocks
282+
// Priority: Check for reasoning_details first, as it's the newer format
283+
const deltaWithReasoning = delta as typeof delta & {
284+
reasoning_details?: Array<{
285+
type: string
286+
text?: string
287+
summary?: string
288+
data?: string
289+
id?: string | null
290+
format?: string
291+
signature?: string
292+
index?: number
293+
}>
294+
}
295+
296+
if (deltaWithReasoning.reasoning_details && Array.isArray(deltaWithReasoning.reasoning_details)) {
297+
for (const detail of deltaWithReasoning.reasoning_details) {
298+
const index = detail.index ?? 0
299+
const key = `${detail.type}-${index}`
300+
const existing = reasoningDetailsAccumulator.get(key)
301+
302+
if (existing) {
303+
// Accumulate text/summary/data for existing reasoning detail
304+
if (detail.text !== undefined) {
305+
existing.text = (existing.text || "") + detail.text
306+
}
307+
if (detail.summary !== undefined) {
308+
existing.summary = (existing.summary || "") + detail.summary
309+
}
310+
if (detail.data !== undefined) {
311+
existing.data = (existing.data || "") + detail.data
312+
}
313+
// Update other fields if provided
314+
if (detail.id !== undefined) existing.id = detail.id
315+
if (detail.format !== undefined) existing.format = detail.format
316+
if (detail.signature !== undefined) existing.signature = detail.signature
317+
} else {
318+
// Start new reasoning detail accumulation
319+
reasoningDetailsAccumulator.set(key, {
320+
type: detail.type,
321+
text: detail.text,
322+
summary: detail.summary,
323+
data: detail.data,
324+
id: detail.id,
325+
format: detail.format,
326+
signature: detail.signature,
327+
index,
328+
})
329+
}
330+
331+
// Yield text for display (still fragmented for live streaming)
332+
let reasoningText: string | undefined
333+
if (detail.type === "reasoning.text" && typeof detail.text === "string") {
334+
reasoningText = detail.text
335+
} else if (detail.type === "reasoning.summary" && typeof detail.summary === "string") {
336+
reasoningText = detail.summary
337+
}
338+
// Note: reasoning.encrypted types are intentionally skipped as they contain redacted content
339+
340+
if (reasoningText) {
341+
yield { type: "reasoning", text: reasoningText }
342+
}
343+
}
344+
} else if ("reasoning" in delta && delta.reasoning && typeof delta.reasoning === "string") {
345+
// Handle legacy reasoning format - only if reasoning_details is not present
346+
// See: https://openrouter.ai/docs/use-cases/reasoning-tokens
220347
yield { type: "reasoning", text: delta.reasoning }
221348
}
222349

@@ -280,6 +407,11 @@ export class OpenRouterHandler extends BaseProvider implements SingleCompletionH
280407
toolCallAccumulator.clear()
281408
}
282409

410+
// After streaming completes, store the accumulated reasoning_details
411+
if (reasoningDetailsAccumulator.size > 0) {
412+
this.currentReasoningDetails = Array.from(reasoningDetailsAccumulator.values())
413+
}
414+
283415
if (lastUsage) {
284416
yield {
285417
type: "usage",

src/api/transform/openai-format.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,21 @@ export function convertToOpenAiMessages(
132132
},
133133
}))
134134

135-
openAiMessages.push({
135+
// Check if the message has reasoning_details (used by Gemini 3, etc.)
136+
const messageWithDetails = anthropicMessage as any
137+
const baseMessage: OpenAI.Chat.ChatCompletionAssistantMessageParam = {
136138
role: "assistant",
137139
content,
138140
// Cannot be an empty array. API expects an array with minimum length 1, and will respond with an error if it's empty
139141
tool_calls: tool_calls.length > 0 ? tool_calls : undefined,
140-
})
142+
}
143+
144+
// Preserve reasoning_details if present (will be processed by provider if needed)
145+
if (messageWithDetails.reasoning_details && Array.isArray(messageWithDetails.reasoning_details)) {
146+
;(baseMessage as any).reasoning_details = messageWithDetails.reasoning_details
147+
}
148+
149+
openAiMessages.push(baseMessage)
141150
}
142151
}
143152
}

src/core/task-persistence/apiMessages.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export type ApiMessage = Anthropic.MessageParam & {
1818
summary?: any[]
1919
encrypted_content?: string
2020
text?: string
21+
// For OpenRouter reasoning_details array format (used by Gemini 3, etc.)
22+
reasoning_details?: any[]
2123
}
2224

2325
export async function readApiMessages({

src/core/task/Task.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -698,13 +698,15 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
698698
getEncryptedContent?: () => { encrypted_content: string; id?: string } | undefined
699699
getThoughtSignature?: () => string | undefined
700700
getSummary?: () => any[] | undefined
701+
getReasoningDetails?: () => any[] | undefined
701702
}
702703

703704
if (message.role === "assistant") {
704705
const responseId = handler.getResponseId?.()
705706
const reasoningData = handler.getEncryptedContent?.()
706707
const thoughtSignature = handler.getThoughtSignature?.()
707708
const reasoningSummary = handler.getSummary?.()
709+
const reasoningDetails = handler.getReasoningDetails?.()
708710

709711
// Start from the original assistant message
710712
const messageWithTs: any = {
@@ -713,8 +715,14 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
713715
ts: Date.now(),
714716
}
715717

718+
// Store reasoning_details array if present (for models like Gemini 3)
719+
if (reasoningDetails) {
720+
messageWithTs.reasoning_details = reasoningDetails
721+
}
722+
716723
// Store reasoning: plain text (most providers) or encrypted (OpenAI Native)
717-
if (reasoning) {
724+
// Skip if reasoning_details already contains the reasoning (to avoid duplication)
725+
if (reasoning && !reasoningDetails) {
718726
const reasoningBlock = {
719727
type: "reasoning",
720728
text: reasoning,
@@ -3686,6 +3694,30 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
36863694

36873695
const [first, ...rest] = contentArray
36883696

3697+
// Check if this message has reasoning_details (OpenRouter format for Gemini 3, etc.)
3698+
const msgWithDetails = msg
3699+
if (msgWithDetails.reasoning_details && Array.isArray(msgWithDetails.reasoning_details)) {
3700+
// Build the assistant message with reasoning_details
3701+
let assistantContent: Anthropic.Messages.MessageParam["content"]
3702+
3703+
if (contentArray.length === 0) {
3704+
assistantContent = ""
3705+
} else if (contentArray.length === 1 && contentArray[0].type === "text") {
3706+
assistantContent = (contentArray[0] as Anthropic.Messages.TextBlockParam).text
3707+
} else {
3708+
assistantContent = contentArray
3709+
}
3710+
3711+
// Create message with reasoning_details property
3712+
cleanConversationHistory.push({
3713+
role: "assistant",
3714+
content: assistantContent,
3715+
reasoning_details: msgWithDetails.reasoning_details,
3716+
} as any)
3717+
3718+
continue
3719+
}
3720+
36893721
// Embedded reasoning: encrypted (send) or plain text (skip)
36903722
const hasEncryptedReasoning =
36913723
first && (first as any).type === "reasoning" && typeof (first as any).encrypted_content === "string"

0 commit comments

Comments
 (0)