Repository navigation
Conversation
…ol stalls Self-hosted OpenAI-compatible backends (llama-server, Ollama, vLLM) often stop after tool results: the agent exits without follow-up tool calls, and users must run /continue. Local models may also echo "[Tool results received]" or emit tool calls as JSON text instead of structured API tool_calls. Add an explicit per-profile "Self-hosted compat" option (parseTextToolCalls). When enabled, behaviour is gated only by this option — not by host, port, or RFC1918/private-network detection. This works for any base URL (172.16.x.x, 192.168.x.x, hostname, public IP). Self-hosted compat enables: - parsing JSON tool calls from assistant text (streaming and non-streaming) - post-tool continuation prompts in the API request - automatic nudge when the model stalls after tool results (empty response, "[Tool results received]", or no tool calls) - withholding and stripping of semantic-placeholder assistant messages from history - fast path (skip cloud-oriented stableStringify, strict tool schemas, and tool-history compression) - toolless self-heal retry on tool_call_incompatible errors Mistral/Devstral-only: inject the synthetic "[Tool results received]" assistant boundary only for Mistral-class backends. Other providers no longer receive it. Provider UI: add Self-hosted compat step to openai-compatible profiles; Ollama preset defaults to enabled. Wire OPENAI_PARSE_TEXT_TOOL_CALLS through profile env. Tests: LAN/172.16 endpoints, post-tool stall helpers, continuation prompt after tool→user, placeholder stripping, fast-path option gating, toolless retry.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📜 Recent review details🧰 Additional context used📓 Path-based instructions (14)src/**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
{src/commands/**/*.ts,src/services/**/*.ts,src/entrypoints/**/*.ts}📄 CodeRabbit inference engine (AGENTS.md)
Files:
{src/services/**/*.ts,src/utils/**/*.ts}📄 CodeRabbit inference engine (AGENTS.md)
Files:
{src/integrations/**/*.ts,src/services/**/*.ts}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx,js,jsx,py,json,md}📄 CodeRabbit inference engine (CONTRIBUTING.md)
Files:
**/*.test.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (CONTRIBUTING.md)
Files:
src/**/*provider*.{ts,tsx,js}📄 CodeRabbit inference engine (CONTRIBUTING.md)
Files:
**/*.test.{ts,tsx,js}📄 CodeRabbit inference engine (CONTRIBUTING.md)
Files:
**/*.{ts,tsx,js,jsx,py}📄 CodeRabbit inference engine (CONTRIBUTING.md)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (CONTRIBUTING.md)
Files:
**/*⚙️ CodeRabbit configuration file
Files:
{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}⚙️ CodeRabbit configuration file
Files:
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}⚙️ CodeRabbit configuration file
Files:
**⚙️ CodeRabbit configuration file
Files:
🔇 Additional comments (1)
📝 WalkthroughWalkthroughAdds a ChangesSelf-hosted compat: text tool-call parsing and post-tool stall recovery
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 6 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (6 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/__tests__/bugfixes.test.ts`:
- Around line 181-197: The test fixture toolRound uses the double-cast pattern
`as unknown as` which bypasses TypeScript type checking and can hide issues with
malformed fixtures. Replace this cast pattern with a `satisfies Message[]` type
assertion on the toolRound array literal to ensure strict type safety at compile
time. Apply the same change to the other instances mentioned at lines 210-211
that use the same problematic casting pattern.
In `@src/services/api/openaiShim.ts`:
- Around line 3510-3513: The condition `!choice?.message?.tool_calls` in the
enableTextToolCallFallback variable only checks if tool_calls is falsy, but an
empty array is truthy, so fallback parsing is skipped when tool_calls exists as
an empty array. Modify the condition to enable text fallback when tool_calls is
either not present or is an empty array by checking both the existence and
length of the tool_calls array.
- Around line 595-606: The code currently collapses the content array (which may
contain text, images, and other content types) into plain text using
joinTextContentParts and then appends promptSuffix as a string, which drops
non-text blocks like images. Instead of converting the entire content array to a
string, preserve the array structure by appending the promptSuffix as a new text
content block to the array when last.content is an array, maintaining all
existing content blocks including non-text elements, rather than replacing the
entire content with a merged string.
In `@src/services/api/providerConfig.localFastPath.test.ts`:
- Around line 104-121: The tests in the "auto/empty string fall through to
profile option" and "garbage values fall through to profile option" test cases
are setting process.env[ENV_VAR] to specific values ('auto', '', 'maybe') but
then calling getLocalFastPathConfig with selfHostedEnv as the second parameter,
which omits OPENCLAUDE_LOCAL_FAST_PATH and prevents the set environment variable
values from being used. To properly exercise the override values being tested,
remove the selfHostedEnv parameter from the getLocalFastPathConfig calls in
these tests, or pass an environment object that includes the ENV_VAR so the
function actually evaluates the values being set.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 0a8835fe-8cfb-45bb-af58-e63e96c4e730
📒 Files selected for processing (18)
src/__tests__/bugfixes.test.tssrc/commands/ctx_viz/ctx_viz.test.tssrc/components/ProviderManager.test.tsxsrc/components/ProviderManager.tsxsrc/query.tssrc/services/api/openaiShim.compression.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/services/api/openaiShim.test.tssrc/services/api/openaiShim.tssrc/services/api/providerConfig.local.test.tssrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/utils/config.tssrc/utils/continuation.tssrc/utils/providerProfile.tssrc/utils/providerProfiles.test.tssrc/utils/providerProfiles.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (16)
src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript with strict mode and ESM imports
Files:
src/utils/config.tssrc/services/api/openaiShim.compression.test.tssrc/commands/ctx_viz/ctx_viz.test.tssrc/utils/providerProfiles.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/utils/continuation.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/components/ProviderManager.test.tsxsrc/__tests__/bugfixes.test.tssrc/query.tssrc/components/ProviderManager.tsxsrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/utils/providerProfile.tssrc/utils/providerProfiles.tssrc/services/api/openaiShim.ts
{src/services/**/*.ts,src/utils/**/*.ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use
execafor child processes
Files:
src/utils/config.tssrc/services/api/openaiShim.compression.test.tssrc/utils/providerProfiles.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/utils/continuation.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/utils/providerProfile.tssrc/utils/providerProfiles.tssrc/services/api/openaiShim.ts
**/*.{ts,tsx,js,jsx,py,json,md}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Follow the existing code style in the touched files
Files:
src/utils/config.tssrc/services/api/openaiShim.compression.test.tssrc/commands/ctx_viz/ctx_viz.test.tssrc/utils/providerProfiles.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/utils/continuation.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/components/ProviderManager.test.tsxsrc/__tests__/bugfixes.test.tssrc/query.tssrc/components/ProviderManager.tsxsrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/utils/providerProfile.tssrc/utils/providerProfiles.tssrc/services/api/openaiShim.ts
**/*.{ts,tsx,js,jsx,py}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Keep comments useful and concise
Files:
src/utils/config.tssrc/services/api/openaiShim.compression.test.tssrc/commands/ctx_viz/ctx_viz.test.tssrc/utils/providerProfiles.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/utils/continuation.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/components/ProviderManager.test.tsxsrc/__tests__/bugfixes.test.tssrc/query.tssrc/components/ProviderManager.tsxsrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/utils/providerProfile.tssrc/utils/providerProfiles.tssrc/services/api/openaiShim.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Follow TypeScript strict mode and type safety practices by running typecheck before submitting
Files:
src/utils/config.tssrc/services/api/openaiShim.compression.test.tssrc/commands/ctx_viz/ctx_viz.test.tssrc/utils/providerProfiles.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/utils/continuation.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/components/ProviderManager.test.tsxsrc/__tests__/bugfixes.test.tssrc/query.tssrc/components/ProviderManager.tsxsrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/utils/providerProfile.tssrc/utils/providerProfiles.tssrc/services/api/openaiShim.ts
**/*
⚙️ CodeRabbit configuration file
**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.
Files:
src/utils/config.tssrc/services/api/openaiShim.compression.test.tssrc/commands/ctx_viz/ctx_viz.test.tssrc/utils/providerProfiles.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/utils/continuation.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/components/ProviderManager.test.tsxsrc/__tests__/bugfixes.test.tssrc/query.tssrc/components/ProviderManager.tsxsrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/utils/providerProfile.tssrc/utils/providerProfiles.tssrc/services/api/openaiShim.ts
**
⚙️ CodeRabbit configuration file
**: # AGENTS.md - AI Agent Coding GuideThis guide is for AI coding agents working in the OpenClaude repository. Read it before changing code, and also follow CONTRIBUTING.md for contributor policy, PR expectations, review follow-up, and project scope.
Project Snapshot
OpenClaude is a coding-agent CLI for cloud and local model providers. It supports OpenAI-compatible APIs, Anthropic, Gemini, DeepSeek, Ollama, MCP, local backends, slash commands, tools, agents, and a React/Ink terminal UI.
The installed CLI runs on Node.js
>=22.0.0. Bun is used for source builds, scripts, dependency management, and tests.Work Style
- Keep changes focused on one problem.
- Prefer existing patterns in the file or nearby module.
- Avoid unrelated formatting, renames, dependency changes, or broad rewrites.
- Add or update tests when behavior changes.
- Update docs when setup, commands, provider behavior, or user-facing behavior changes.
- For new features, larger refactors, dependencies, or runtime changes, follow the issue-first guidance in CONTRIBUTING.md.
Stack And Conventions
- TypeScript with strict mode and ESM imports.
- React + Ink for terminal UI.
- Bun lockfile and Bun scripts for development workflows.
- Node runtime for the built CLI.
- Python exists for legacy/local-provider helper code. Do not add new Python code or expand Python-based features unless a maintainer explicitly approves that direction.
Common libraries and patterns:
chalkfor terminal color.commanderfor CLI argument parsing.execafor child processes.- Existing service, provider, settings, permission, and UI patterns over new abstractions.
Repository Map
src/commands/- slash and CLI command implementations.src/components/- React/Ink UI components.src/services/- API, MCP, OAuth, wiki, voice, and other service integrations.src/tools/- tool implementations.src/utils/- shared utilities.- `src/integration...
Files:
src/utils/config.tssrc/services/api/openaiShim.compression.test.tssrc/commands/ctx_viz/ctx_viz.test.tssrc/utils/providerProfiles.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/utils/continuation.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/components/ProviderManager.test.tsxsrc/__tests__/bugfixes.test.tssrc/query.tssrc/components/ProviderManager.tsxsrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/utils/providerProfile.tssrc/utils/providerProfiles.tssrc/services/api/openaiShim.ts
{src/commands/**/*.ts,src/services/**/*.ts,src/entrypoints/**/*.ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use
chalkfor terminal color in CLI code
Files:
src/services/api/openaiShim.compression.test.tssrc/commands/ctx_viz/ctx_viz.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/services/api/openaiShim.ts
{src/integrations/**/*.ts,src/services/**/*.ts}
📄 CodeRabbit inference engine (AGENTS.md)
Test the exact provider/model path you changed when possible for provider modifications
Files:
src/services/api/openaiShim.compression.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/services/api/openaiShim.ts
**/*.test.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Add or update tests when the change affects behavior
Files:
src/services/api/openaiShim.compression.test.tssrc/commands/ctx_viz/ctx_viz.test.tssrc/utils/providerProfiles.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/components/ProviderManager.test.tsxsrc/__tests__/bugfixes.test.tssrc/services/api/providerConfig.localFastPath.test.ts
**/*.test.{ts,tsx,js}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Test the exact provider/model path you changed when possible
Files:
src/services/api/openaiShim.compression.test.tssrc/commands/ctx_viz/ctx_viz.test.tssrc/utils/providerProfiles.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/components/ProviderManager.test.tsxsrc/__tests__/bugfixes.test.tssrc/services/api/providerConfig.localFastPath.test.ts
{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}
⚙️ CodeRabbit configuration file
{src/services/api/**,src/integrations/**,src/utils/model/**,src/utils/provider*.ts,src/commands/provider/**}: Review provider routing, model selection, env precedence, auth/token handling, OpenAI-compatible shims, retries, proxy behavior, and outbound HTTP behavior with high scrutiny. Block on silent default changes, hidden fallback expansion, credential reuse mistakes, hardcoded provider assumptions, or new network reach that is not intentional and documented.
Files:
src/services/api/openaiShim.compression.test.tssrc/utils/providerProfiles.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/utils/providerProfile.tssrc/utils/providerProfiles.tssrc/services/api/openaiShim.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}
⚙️ CodeRabbit configuration file
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.
Files:
src/services/api/openaiShim.compression.test.tssrc/commands/ctx_viz/ctx_viz.test.tssrc/utils/providerProfiles.test.tssrc/services/api/openaiShim.diagnostics.test.tssrc/services/api/openaiShim.ollamaTextToolCalls.test.tssrc/services/api/providerConfig.local.test.tssrc/services/api/openaiShim.test.tssrc/components/ProviderManager.test.tsxsrc/__tests__/bugfixes.test.tssrc/services/api/providerConfig.localFastPath.test.ts
{src/commands/**/*.ts,src/entrypoints/**/*.ts}
📄 CodeRabbit inference engine (AGENTS.md)
Use
commanderfor CLI argument parsing
Files:
src/commands/ctx_viz/ctx_viz.test.ts
src/**/*provider*.{ts,tsx,js}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Provider implementations must follow documented patterns in docs/integrations/
Files:
src/utils/providerProfiles.test.tssrc/services/api/providerConfig.local.test.tssrc/services/api/providerConfig.localFastPath.test.tssrc/services/api/providerConfig.tssrc/utils/providerProfile.tssrc/utils/providerProfiles.ts
src/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use React + Ink for terminal UI implementations
Files:
src/components/ProviderManager.test.tsxsrc/components/ProviderManager.tsx
🔇 Additional comments (17)
src/query.ts (3)
60-70: LGTM!
1074-1115: LGTM!
1779-1845: LGTM!src/utils/config.ts (1)
232-239: LGTM!src/services/api/providerConfig.ts (1)
411-414: LGTM!Also applies to: 430-433, 471-477, 517-575, 621-635
src/utils/providerProfile.ts (1)
78-78: LGTM!Also applies to: 186-187, 353-371, 683-684, 742-743
src/utils/providerProfiles.ts (1)
24-24: LGTM!Also applies to: 69-69, 260-262, 303-311, 385-385, 631-634, 823-823, 1057-1058, 1092-1092
src/utils/providerProfiles.test.ts (1)
69-69: LGTM!Also applies to: 1004-1028, 1594-1594
src/components/ProviderManager.tsx (1)
57-57: LGTM!Also applies to: 131-131, 180-187, 244-245, 280-281, 311-321, 808-810, 1433-1434, 1529-1533, 1966-1987
src/components/ProviderManager.test.tsx (1)
104-111: LGTM!Also applies to: 652-652, 1093-1099, 1169-1188, 2021-2069
src/utils/continuation.ts (1)
1-1: LGTM!Also applies to: 33-135
src/services/api/openaiShim.compression.test.ts (1)
18-18: LGTM!Also applies to: 137-137
src/commands/ctx_viz/ctx_viz.test.ts (1)
23-23: LGTM!Also applies to: 212-255
src/services/api/openaiShim.diagnostics.test.ts (1)
19-19: LGTM!Also applies to: 41-41, 217-219
src/services/api/openaiShim.ollamaTextToolCalls.test.ts (1)
216-223: LGTM!Also applies to: 272-279, 381-388, 440-447, 490-550, 576-583
src/services/api/openaiShim.test.ts (1)
48-48: LGTM!Also applies to: 187-187, 228-228, 5119-5119, 5416-5595, 5665-5665
src/services/api/providerConfig.local.test.ts (1)
6-12: LGTM!Also applies to: 25-25, 51-51, 225-317
| const toolRound = [ | ||
| { | ||
| type: 'assistant', | ||
| isApiErrorMessage: false, | ||
| message: { | ||
| role: 'assistant', | ||
| content: [{ type: 'tool_use', id: 'call_1', name: 'Read', input: {} }], | ||
| }, | ||
| }, | ||
| { | ||
| type: 'user', | ||
| message: { | ||
| role: 'user', | ||
| content: [{ type: 'tool_result', tool_use_id: 'call_1', content: 'ok' }], | ||
| }, | ||
| }, | ||
| ] as unknown as import('../types/message.js').Message[] |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial | ⚡ Quick win
Avoid as unknown as in strict-mode test fixtures.
These double-casts bypass message-shape checks and can hide malformed fixtures. Prefer typed literals (e.g., satisfies Message[]) so the regression test fails at compile time when the contract drifts.
As per coding guidelines, "Follow TypeScript strict mode and type safety practices by running typecheck before submitting."
Also applies to: 210-211
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/__tests__/bugfixes.test.ts` around lines 181 - 197, The test fixture
toolRound uses the double-cast pattern `as unknown as` which bypasses TypeScript
type checking and can hide issues with malformed fixtures. Replace this cast
pattern with a `satisfies Message[]` type assertion on the toolRound array
literal to ensure strict type safety at compile time. Apply the same change to
the other instances mentioned at lines 210-211 that use the same problematic
casting pattern.
Source: Coding guidelines
| const mergedText = joinTextContentParts( | ||
| typeof last.content === 'string' || !last.content | ||
| ? [] | ||
| : last.content, | ||
| ) | ||
| if (mergedText.includes(LOCAL_TOOL_CONTINUATION_PROMPT)) { | ||
| return openaiMessages | ||
| } | ||
| return [ | ||
| ...openaiMessages.slice(0, -1), | ||
| { ...last, content: mergedText + promptSuffix }, | ||
| ] |
There was a problem hiding this comment.
Preserve structured user content when appending continuation prompts.
When last.content is an array, this branch collapses it to text and rewrites it as a string. That drops non-text blocks (for example image parts) and changes the outbound request payload semantics.
Suggested fix
- const mergedText = joinTextContentParts(
- typeof last.content === 'string' || !last.content
- ? []
- : last.content,
- )
+ const existingParts = Array.isArray(last.content) ? last.content : []
+ const mergedText = joinTextContentParts(existingParts)
if (mergedText.includes(LOCAL_TOOL_CONTINUATION_PROMPT)) {
return openaiMessages
}
return [
...openaiMessages.slice(0, -1),
- { ...last, content: mergedText + promptSuffix },
+ {
+ ...last,
+ content: [
+ ...existingParts,
+ { type: 'text', text: LOCAL_TOOL_CONTINUATION_PROMPT },
+ ],
+ },
]🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/services/api/openaiShim.ts` around lines 595 - 606, The code currently
collapses the content array (which may contain text, images, and other content
types) into plain text using joinTextContentParts and then appends promptSuffix
as a string, which drops non-text blocks like images. Instead of converting the
entire content array to a string, preserve the array structure by appending the
promptSuffix as a new text content block to the array when last.content is an
array, maintaining all existing content blocks including non-text elements,
rather than replacing the entire content with a merged string.
| const enableTextToolCallFallback = | ||
| options?.enableTextToolCallFallback === true && | ||
| !choice?.message?.tool_calls | ||
|
|
There was a problem hiding this comment.
Enable text fallback when tool_calls is present but empty.
!choice?.message?.tool_calls treats tool_calls: [] as “present”, so fallback parsing is skipped even though no structured tool calls exist.
Suggested fix
- const enableTextToolCallFallback =
- options?.enableTextToolCallFallback === true &&
- !choice?.message?.tool_calls
+ const hasStructuredToolCalls =
+ Array.isArray(choice?.message?.tool_calls) &&
+ choice.message.tool_calls.length > 0
+ const enableTextToolCallFallback =
+ options?.enableTextToolCallFallback === true &&
+ !hasStructuredToolCalls📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const enableTextToolCallFallback = | |
| options?.enableTextToolCallFallback === true && | |
| !choice?.message?.tool_calls | |
| const hasStructuredToolCalls = | |
| Array.isArray(choice?.message?.tool_calls) && | |
| choice.message.tool_calls.length > 0 | |
| const enableTextToolCallFallback = | |
| options?.enableTextToolCallFallback === true && | |
| !hasStructuredToolCalls |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/services/api/openaiShim.ts` around lines 3510 - 3513, The condition
`!choice?.message?.tool_calls` in the enableTextToolCallFallback variable only
checks if tool_calls is falsy, but an empty array is truthy, so fallback parsing
is skipped when tool_calls exists as an empty array. Modify the condition to
enable text fallback when tool_calls is either not present or is an empty array
by checking both the existence and length of the tool_calls array.
…process.env The auto/empty/garbage override cases passed selfHostedEnv without ENV_VAR, so they never read the values set on process.env. Use process.env for LAN cases and an isolated env snapshot for the public-host negative assertion.
jatmn
left a comment
There was a problem hiding this comment.
I found one issue that needs to be addressed before this is ready.
Findings
- [P2] Enable self-hosted compat in the preferred Ollama setup path
src/commands/provider/provider.tsx:968
The PR makes self-hosted compat the sole gate for text tool-call parsing, post-tool continuation, and the local fast path, and the PR description says the Ollama preset defaults it on. However, the preferred/providerOllama flows still callbuildOllamaProfileEnv(...)withoutparseTextToolCalls: true, so saving the recommended Ollama profile or choosing an Ollama model through the preferred/providerpath persists onlyOPENAI_BASE_URLandOPENAI_MODEL. Users who configure Ollama through that preferred path will not getOPENAI_PARSE_TEXT_TOOL_CALLS=1, so this fix will not apply to the main built-in self-hosted provider setup. Please thread the new option through both Ollama/providersave paths and add coverage for the saved env. More generally, this should be a visible provider-profile setting wherever users configure providers: if/configexposes it, it should edit the active provider profile rather than setting a single global toggle, because enabling these local-model workarounds globally would also affect cloud/OpenAI-compatible providers after a provider switch.
|
Thanks for the contribution and for writing up the self-hosted provider failure mode. I’m going to close this PR rather than keep it open in its current form. The branch now has merge conflicts with current The remaining useful idea here is narrower: if self-hosted providers still need an explicit profile-level compatibility toggle or additional post-tool continuation handling after the current Closing this as stale/superseded by later work and no longer mergeable as-is. |
Self-hosted OpenAI-compatible backends (llama-server, Ollama, vLLM) often stop after tool results: the agent exits without follow-up tool calls, and users must run /continue. Local models may also echo "[Tool results received]" or emit tool calls as JSON text instead of structured API tool_calls.
Add an explicit per-profile "Self-hosted compat" option (parseTextToolCalls). When enabled, behaviour is gated only by this option — not by host, port, or RFC1918/private-network detection. This works for any base URL (172.16.x.x, 192.168.x.x, hostname, public IP).
Self-hosted compat enables:
Mistral/Devstral-only: inject the synthetic "[Tool results received]" assistant boundary only for Mistral-class backends. Other providers no longer receive it.
Provider UI: add Self-hosted compat step to openai-compatible profiles; Ollama preset defaults to enabled. Wire OPENAI_PARSE_TEXT_TOOL_CALLS through profile env.
Tests: LAN/172.16 endpoints, post-tool stall helpers, continuation prompt after tool→user, placeholder stripping, fast-path option gating, toolless retry.
Testing
bun run buildbun run smokebun run checkNotes
Summary by CodeRabbit
New Features
Bug Fixes