Skip to content

Conversation

@roomote
Copy link
Contributor

@roomote roomote bot commented Jan 10, 2026

Related GitHub Issue

Closes: #10540

Description

This PR attempts to address Issue #10540. Feedback and guidance are welcome.

This PR adds a new setting openAiStrictToolMessageOrdering for OpenAI Compatible providers that fixes the "Unexpected role 'user' after role 'tool'" error occurring with NVIDIA NIM, OpenRouter, and other strict OpenAI-compatible APIs.

Implementation approach (Option 1 from issue analysis):

  • Added a new boolean setting openAiStrictToolMessageOrdering to the provider settings schema
  • When enabled, passes mergeToolResultText: true to convertToOpenAiMessages(), which merges text content (like environment_details) into the last tool message instead of creating a separate user message
  • Added a UI checkbox in the OpenAI Compatible provider settings with a helpful description

Files modified:

  • packages/types/src/provider-settings.ts - Added the new setting to openAiSchema
  • src/api/providers/openai.ts - Use the setting when calling convertToOpenAiMessages()
  • webview-ui/src/components/settings/providers/OpenAICompatible.tsx - Added UI checkbox
  • webview-ui/src/i18n/locales/en/settings.json - Added translation keys

Test Procedure

  1. Configure OpenAI Compatible provider with NVIDIA NIM or similar strict API
  2. Enable the "Strict tool message ordering" checkbox in settings
  3. Verify that tool calls work without the "user after tool" error
  4. Tests: cd src && npx vitest run api/transform/__tests__/openai-format.spec.ts (all 24 tests pass)
  5. Type checks pass for both src and webview-ui packages

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and/or updated tests have been added to cover my changes (if applicable).
  • Documentation Impact: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Documentation Updates

  • No documentation updates are required.

Additional Notes

This implementation uses the same approach already proven by DeepSeek (for thinking models), Z.ai provider, and MiniMax. The codebase already had the mergeToolResultText option in convertToOpenAiMessages() - this PR simply exposes it as a user-facing setting for OpenAI Compatible providers.


Important

Adds openAiStrictToolMessageOrdering setting for strict message ordering in OpenAI Compatible providers, preventing specific errors and updating UI and tests.

  • Behavior:
    • Adds openAiStrictToolMessageOrdering setting to handle strict message ordering for OpenAI Compatible providers, preventing "Unexpected role 'user' after role 'tool'" errors.
    • When enabled, merges text content into the last tool message using mergeToolResultText in convertToOpenAiMessages().
  • UI:
    • Adds a checkbox for openAiStrictToolMessageOrdering in OpenAICompatible.tsx with description in settings.json.
  • Files Modified:
    • provider-settings.ts: Adds new setting to openAiSchema.
    • openai.ts: Implements setting in message conversion logic.
    • openai-format.spec.ts: Adds tests for mergeToolResultText behavior.
  • Tests:
    • Ensures tool calls work without "user after tool" error when setting is enabled.
    • Tests added for merging text into tool messages and handling images separately.

This description was created by Ellipsis for 3661e54. You can customize this summary. It will automatically update as commits are pushed.

…providers

Adds a new setting `openAiStrictToolMessageOrdering` to OpenAI Compatible
providers that enables merging text content after tool results into the
last tool message. This fixes "Unexpected role user after role tool"
errors with NVIDIA NIM, OpenRouter, and other strict OpenAI-compatible APIs.

When enabled, environment_details and other text content that follows
tool_result messages are merged into the last tool message instead of
being sent as a separate user message.

Fixes #10540
@roomote
Copy link
Contributor Author

roomote bot commented Jan 10, 2026

Rooviewer Clock   See task on Roo Cloud

All issues have been resolved. The latest commit adds comprehensive regression tests for multi-turn conversation support with the mergeToolResultText option.

  • settings.json: Duplicate translation keys - nested format entries added but old flat format entries at lines 539-541 were not removed, causing translation lookup to fail
Previous reviews

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

…providers

Adds a new setting `openAiStrictToolMessageOrdering` for OpenAI-compatible providers
that, when enabled, merges text content after tool results into the last tool message
instead of creating a separate user message.

This fixes the "Unexpected role user after role tool" error that occurs with
providers like NVIDIA NIM and Devstral that enforce strict message ordering rules.

Fixes #10540
@hannesrudolph hannesrudolph added the Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. label Jan 10, 2026
Comment on lines +501 to +504
"openAiStrictToolMessageOrdering": {
"label": "Strict tool message ordering",
"description": "Enable for providers like NVIDIA NIM and Devstral that require strict message ordering. When enabled, text content after tool results is merged into the last tool message instead of creating a separate user message."
},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This addition creates duplicate keys in the JSON file. There are older flat format entries at lines 539-541 ("openAiStrictToolMessageOrdering": "Strict tool message ordering" and "openAiStrictToolMessageOrderingDescription": "...") that were not removed. Since JSON parsers typically use the last value for duplicate keys, the flat format at line 539 will take precedence, causing t("settings:providers.openAiStrictToolMessageOrdering.label") to return undefined. Remove the old flat format entries at lines 539-541.

Fix it with Roo Code or mention @roomote and request a fix.

@bngfavored
Copy link

@roomote I found after running the branch locally that if "Enable R1 model parameters" is enabled at the same time it will still produce the 400 error. Why would that happen?

@roomote
Copy link
Contributor Author

roomote bot commented Jan 10, 2026

Fixaroo Clock   See task on Roo Cloud

Fixed the issue where "Strict tool message ordering" was not applied when "Enable R1 model parameters" was also enabled. The mergeToolResultText option is now passed to convertToR1Format() in both streaming and non-streaming code paths.

View commit | Revert commit

…e is enabled

When both "Enable R1 model parameters" and "Strict tool message ordering" are
enabled, the mergeToolResultText option was not being passed to convertToR1Format,
causing the 400 error to still occur.

This fix ensures the strictToolMessageOrdering setting is respected in both
the streaming and non-streaming code paths when using R1 format.
@roomote
Copy link
Contributor Author

roomote bot commented Jan 10, 2026

Fixaroo Clock   See task on Roo Cloud

Removed duplicate translation keys in settings.json. All local checks passed.

View commit | Revert commit

@bngfavored
Copy link

@roomote After more testing, if I have the option checked and an image is added to the chat it does not merge the text. So when handling images it needs to take that into account to merge the text.

@roomote
Copy link
Contributor Author

roomote bot commented Jan 10, 2026

Fixaroo Clock   See task on Roo Cloud

Fixed the reported issue. Text content is now merged into the last tool message even when images are present. All local checks passed.

View commit | Revert commit

When mergeToolResultText is enabled and both text and images are present
after tool results, the text content is now merged into the last tool
message while images are sent as a separate user message.

This fixes the issue where strict tool message ordering would not work
when images were added to the chat, causing "Unexpected role user after
role tool" errors on providers like NVIDIA NIM.
@bngfavored
Copy link

@roomote The fix works for the first message but after the first response the text content is NOT merged into the last tool message.

@roomote
Copy link
Contributor Author

roomote bot commented Jan 10, 2026

Fixaroo Clock   See task on Roo Cloud

I investigated the reported issue and added multi-turn conversation tests to verify the mergeToolResultText behavior.

Findings: All 27 tests pass, including new tests that specifically verify text is merged into tool messages for ALL tool_result messages in a conversation (not just the first one). The convertToOpenAiMessages function works correctly for multi-turn scenarios.

If the issue persists, please verify:

  1. You're using the "OpenAI Compatible" provider (not OpenRouter or other providers)
  2. The "Strict tool message ordering" checkbox is enabled in settings
  3. The provider type is set to "openai" (the setting is only available for this provider type)

View commit | Revert commit

Add regression tests to verify that the mergeToolResultText option works
correctly for ALL tool_result messages in a conversation, not just the first one.

Tests added:
- Multi-turn conversation with multiple tool calls
- Verification that no user messages appear after tool messages when mergeToolResultText is enabled

All 27 tests pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels.

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

[BUG] Code mode does not work with devstral2 123b 2512 (NVIDIA NIM provider)

4 participants