Skip to content

fix: Ollama provider tool result handling and premature context condensing#848

Open
navedmerchant wants to merge 3 commits into
mainfrom
fix/ollama_ctx
Open

fix: Ollama provider tool result handling and premature context condensing#848
navedmerchant wants to merge 3 commits into
mainfrom
fix/ollama_ctx

Conversation

@navedmerchant

@navedmerchant navedmerchant commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Related GitHub Issue

Closes: #847
Also addresses: #851

Description

This PR fixes three issues in the native Ollama provider, plus a follow-up batch addressing review feedback on this PR and the related issue #851:

  1. Premature context condensingparseOllamaModel previously set maxTokens to the full contextWindow. Since getModelMaxOutputTokens reserves 20% of the window for output, this caused condensing to trigger far earlier than necessary. The fix inherits the sane default (4096) from ollamaDefaultModelInfo instead, so maxTokens correctly represents max output tokens rather than the full context window.

  2. Tool results sent as user messagesconvertToOllamaMessages always sent tool results with the "user" role, making it impossible for the model to distinguish tool results from actual user messages. The fix tracks tool_use IDs to tool names via a Map, and when a matching tool_use block is found, sends the result with Ollama's native "tool" role and tool_name field.

  3. additionalProperties in tool schema — The tool parameter schema included additionalProperties, which is not part of Ollama's tool schema definition and broke tool-calling templates on some models. The fix strips additionalProperties from the parameters before sending tools to Ollama.

Review feedback (#848) and issue #851 follow-ups

  1. Concurrent model fetch single-point-of-failure ([BUG] Ollama model details concurrent fetch is a single-point-of-failure (Promise.all error) #851)getOllamaModels retrieved model details concurrently with Promise.all over individual /api/show POST requests. A single failing request (corrupt model manifest, timeout, or server overload) rejected the whole Promise.all, wiping out all otherwise healthy models. Each per-model promise now has a .catch() that logs the individual failure and resolves cleanly, so Promise.all completes and the remaining healthy models still load.

  2. Tool results must be text-only — Tool results were attaching images to native tool-role messages, which Ollama's tool role does not support and can invalidate the request. The toolResultImages accumulator was also reused across iterations, so one image could leak into later tool results. Tool results are now text-only (content + tool_name); images extracted from tool results are moved onto the adjacent user message (the only role that supports images), and the per-result image accumulator is reset for each tool result to prevent leakage.

  3. Recursive additionalProperties strippingdelete parameters.additionalProperties only stripped the field at the top level, leaving nested properties/items schemas leaking additionalProperties into Ollama payloads. A recursive stripAdditionalProperties helper now sanitizes the schema at every nesting level while preserving the rest of the schema shape.

Test Procedure

  • Unit tests added/updated in src/api/providers/__tests__/native-ollama.spec.ts covering:
    • Tool results using the "tool" role with tool_name when the tool_use ID is known
    • Tool results falling back to the "user" role when the tool_use ID is unknown
    • additionalProperties being stripped from tool parameter schemas (top-level and nested)
    • maxTokens inheriting the default rather than the full context window
    • Tool results staying text-only with images moved onto the adjacent user message
    • No image leakage between sibling tool results
  • Unit tests added/updated in src/api/providers/fetchers/__tests__/ollama.test.ts covering:
  • Run tests with:
    • cd src && npx vitest run api/providers/__tests__/native-ollama.spec.ts
    • cd src && npx vitest run api/providers/fetchers/__tests__/ollama.test.ts

Pre-Submission Checklist

Screenshots / Videos

N/A — no UI changes.

Documentation Updates

  • No documentation updates are required.

Additional Notes

Also resolves the CodeRabbit review comments on this PR (maxTokens test expectations, text-only tool results / image relocation, and recursive additionalProperties stripping).

Get in Touch

@navedmerchant

Summary by CodeRabbit

  • Bug Fixes
    • Fixed tool-result handling to use the correct tool role and tool name when a matching tool call exists; unmatched tool results now follow a safe fallback.
    • Prevented image leakage across multiple tool results; images now route to the appropriate adjacent messages.
    • Removed unsupported fields from tool schemas before sending, including nested schema structures.
    • Improved model metadata so token limits behave correctly, and improved model loading so one failed model fetch won’t block others.
  • Tests
    • Expanded coverage for tool calling, schema sanitization, and partial model-fetch failures.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 756475f2-56e0-4319-81ee-f7b50c1bff89

📥 Commits

Reviewing files that changed from the base of the PR and between 5ec15c7 and c620a25.

📒 Files selected for processing (2)
  • src/api/providers/__tests__/native-ollama.spec.ts
  • src/api/providers/native-ollama.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/api/providers/tests/native-ollama.spec.ts
  • src/api/providers/native-ollama.ts

📝 Walkthrough

Walkthrough

This PR updates Ollama model parsing and loading, tool-result conversion, and tool schema handling. It also adds tests covering maxTokens behavior, partial model fetch failures, tool-result role mapping, image placement, and recursive schema sanitization.

Changes

Ollama provider fixes

Layer / File(s) Summary
maxTokens default restoration
src/api/providers/fetchers/ollama.ts, src/api/providers/fetchers/__tests__/ollama.test.ts
Stops deriving maxTokens from contextWindow, keeps the default model info value, and updates tests to expect the default maxTokens. Adds per-model /api/show failure handling and a test for partial-success loading.
Tool-use tracking and tool_result mapping
src/api/providers/native-ollama.ts, src/api/providers/__tests__/native-ollama.spec.ts
Tracks tool_use IDs to tool names, emits matching tool_result blocks as Ollama tool messages, keeps tool-result images off tool messages, and adds test coverage for matched, unmatched, and multi-result cases.
Tool schema cleanup
src/api/providers/native-ollama.ts, src/api/providers/__tests__/native-ollama.spec.ts
Recursively strips additionalProperties from tool parameter schemas before sending them to Ollama, with tests covering flat and nested schemas.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • Zoo-Code-Org/Zoo-Code#600: Also changes convertToOllamaMessages in the Ollama provider, specifically its tool_result handling.

Suggested labels: awaiting-review

Suggested reviewers: hannesrudolph, JamesRobert20

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR also adds follow-up fetcher resilience for #851, which is outside the linked issue #847 scope. Move the #851 model-fetch resilience into a separate PR or link that issue explicitly, and keep this PR limited to #847.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main Ollama provider fixes for tool-result handling and context condensing.
Description check ✅ Passed The PR description follows the template with linked issues, summary, test steps, checklist, screenshots, docs, notes, and contact.
Linked Issues check ✅ Passed The code addresses #847's three requirements: output-token maxTokens, native tool-role mapping, and stripping additionalProperties.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ollama_ctx

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/api/providers/__tests__/native-ollama.spec.ts (1)

788-864: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a nested-schema case.

This test only covers top-level additionalProperties stripping. As noted in native-ollama.ts (convertToolsToOllama), the current implementation only strips the top-level key, so a schema with additionalProperties nested inside a properties sub-object wouldn't be covered here or fixed in the implementation. Adding a nested-schema fixture would catch a regression once/if the stripping logic is made recursive. As per coding guidelines, **/*.{test,spec}.{ts,tsx,js} should cover "validation, serialization, request construction" for pure logic — this is exactly that kind of case.

🤖 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/api/providers/__tests__/native-ollama.spec.ts` around lines 788 - 864,
The current test only verifies top-level removal of additionalProperties in
NativeOllamaHandler’s tool conversion, so it misses nested schema cases. Extend
the native-ollama.spec.ts coverage around createMessage and convertToolsToOllama
by adding a fixture with additionalProperties inside a nested properties object,
then assert the outgoing mockChat tools payload strips that nested key as well.
This should exercise the same tool schema path used by apply_diff and confirm
the implementation handles recursive schema sanitization, not just the top-level
parameters object.

Source: Coding guidelines

src/api/providers/native-ollama.ts (1)

208-225: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Strip additionalProperties recursively

Native tools already nest additionalProperties under items and nested objects, e.g. src/core/prompts/tools/native-tools/ask_followup_question.ts and src/core/prompts/tools/native-tools/read_file.ts, so the current top-level delete leaves those fields in Ollama payloads.

🤖 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/api/providers/native-ollama.ts` around lines 208 - 225, The tool schema
sanitization in native-ollama only removes additionalProperties at the top
level, so nested occurrences still leak into Ollama payloads. Update the mapping
logic in the tool conversion path to recursively strip additionalProperties from
tool.function.parameters, including nested objects and items, while preserving
the rest of the schema shape.
🤖 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/api/providers/fetchers/ollama.ts`:
- Around line 56-59: The Ollama fetcher tests still assert the old maxTokens
value, so update the expectations in ollama.test.ts to match the new default
inherited by parseOllamaModel. Adjust both failing assertions to use maxTokens
4096 instead of 40960, keeping the test cases aligned with
ollamaDefaultModelInfo and the behavior of parseOllamaModel.

In `@src/api/providers/native-ollama.ts`:
- Around line 73-82: The Ollama tool-result path in native-ollama.ts is
attaching images to native tool messages and reusing the same image accumulator
across iterations. Update the logic around the ollamaMessages push so tool
results stay text-only with only content and tool_name, move any images onto the
adjacent user message instead, and reset toolResultImages for each tool result
to prevent leakage between results.

---

Nitpick comments:
In `@src/api/providers/__tests__/native-ollama.spec.ts`:
- Around line 788-864: The current test only verifies top-level removal of
additionalProperties in NativeOllamaHandler’s tool conversion, so it misses
nested schema cases. Extend the native-ollama.spec.ts coverage around
createMessage and convertToolsToOllama by adding a fixture with
additionalProperties inside a nested properties object, then assert the outgoing
mockChat tools payload strips that nested key as well. This should exercise the
same tool schema path used by apply_diff and confirm the implementation handles
recursive schema sanitization, not just the top-level parameters object.

In `@src/api/providers/native-ollama.ts`:
- Around line 208-225: The tool schema sanitization in native-ollama only
removes additionalProperties at the top level, so nested occurrences still leak
into Ollama payloads. Update the mapping logic in the tool conversion path to
recursively strip additionalProperties from tool.function.parameters, including
nested objects and items, while preserving the rest of the schema shape.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c5ab80b3-81ab-49dc-b494-b55d67f5de07

📥 Commits

Reviewing files that changed from the base of the PR and between 15d4d8c and ad9c1cc.

📒 Files selected for processing (3)
  • src/api/providers/__tests__/native-ollama.spec.ts
  • src/api/providers/fetchers/ollama.ts
  • src/api/providers/native-ollama.ts

Comment thread src/api/providers/fetchers/ollama.ts
Comment thread src/api/providers/native-ollama.ts

@edelauna edelauna left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also noticed this pre-existing issue: #851 - could maybe include a fix in this PR since it's small enough.

// Strip additionalProperties from the parameters schema.
// This field is not part of Ollama's tool schema definition and can
// cause issues with some models' tool-calling templates.
const rawParams = tool.function.parameters as Record<string, unknown> | undefined

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The delete parameters.additionalProperties only strips the property at the top level of the parameters object. If your tools define nested properties (for example, object properties or items of type object), those nested schemas will still leak additionalProperties: false.

Since Ollama model templates are highly sensitive to these fields, consider recursing through the schema to sanitize it completely. You can introduce a recursive helper like:

function stripAdditionalProperties(schema: unknown): unknown {
	if (!schema || typeof schema !== "object") return schema;
	if (Array.isArray(schema)) return schema.map(stripAdditionalProperties);
	const result: Record<string, unknown> = {};
	for (const [key, value] of Object.entries(schema)) {
		if (key === "additionalProperties") continue;
		result[key] = stripAdditionalProperties(value);
	}
	return result;
}

- getOllamaModels: append per-request .catch() so a single failing
  /api/show no longer rejects the whole Promise.all and wipes out all
  healthy models (issue #851)
- native-ollama: keep tool results text-only; move images extracted from
  tool results onto the adjacent user message and reset the per-result
  image accumulator to prevent leakage between tool results
- native-ollama: recursively strip additionalProperties from tool schemas
  (top-level and nested properties/items) instead of only the top level
- tests: update ollama fetcher maxTokens expectations to the inherited
  default (4096), add regression test for individual model fetch failure,
  and add coverage for text-only tool results, image relocation, image
  leakage prevention, and nested additionalProperties stripping

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/api/providers/__tests__/native-ollama.spec.ts (1)

900-944: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover items schemas in the recursive sanitizer test.

The helper explicitly recurses arrays/items, but this test only exercises nested object properties. Add an array-of-objects parameter with items.additionalProperties to guard the common schema shape that previously leaked unsupported fields.

Suggested test expansion
 							properties: {
 								path: { type: "string", description: "File path" },
+								files: {
+									type: "array",
+									items: {
+										type: "object",
+										properties: {
+											path: { type: "string" },
+										},
+										additionalProperties: false,
+									},
+								},
 								options: {
 									type: "object",
 									properties: {
 										dry_run: { type: "boolean" },
@@
 			// Nested additionalProperties also stripped
 			expect(params.properties.options).not.toHaveProperty("additionalProperties")
 			expect(params.properties.options.properties.dry_run).toEqual({ type: "boolean" })
+			expect(params.properties.files.items).not.toHaveProperty("additionalProperties")
+			expect(params.properties.files.items.properties.path).toEqual({ type: "string" })

As per coding guidelines, **/*.{test,spec}.{ts,tsx,js} files should use package-local unit tests for serialization and request construction logic.

🤖 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/api/providers/__tests__/native-ollama.spec.ts` around lines 900 - 944,
The recursive sanitizer test in native-ollama.spec.ts only covers nested object
properties, so it misses the array/items schema path that the sanitizer also
handles. Expand the existing createMessage/mockChat assertion test to include a
tool parameter with an array of objects and an items schema containing
additionalProperties, then verify the serialized
callArgs.tools[0].function.parameters has stripped additionalProperties from
both the top level and the nested items/object schemas. Use the existing
createMessage, handler, mockChat, and params assertions as the location to
extend the coverage.

Source: Coding guidelines

🤖 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.

Nitpick comments:
In `@src/api/providers/__tests__/native-ollama.spec.ts`:
- Around line 900-944: The recursive sanitizer test in native-ollama.spec.ts
only covers nested object properties, so it misses the array/items schema path
that the sanitizer also handles. Expand the existing createMessage/mockChat
assertion test to include a tool parameter with an array of objects and an items
schema containing additionalProperties, then verify the serialized
callArgs.tools[0].function.parameters has stripped additionalProperties from
both the top level and the nested items/object schemas. Use the existing
createMessage, handler, mockChat, and params assertions as the location to
extend the coverage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b591716b-d1b2-4528-afad-bf69d4483915

📥 Commits

Reviewing files that changed from the base of the PR and between ad9c1cc and 5ec15c7.

📒 Files selected for processing (4)
  • src/api/providers/__tests__/native-ollama.spec.ts
  • src/api/providers/fetchers/__tests__/ollama.test.ts
  • src/api/providers/fetchers/ollama.ts
  • src/api/providers/native-ollama.ts

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.00000% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/api/providers/native-ollama.ts 95.83% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@github-actions github-actions Bot added the awaiting-review PR changes are ready and waiting for maintainer re-review label Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting-review PR changes are ready and waiting for maintainer re-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Ollama provider: premature context condensing and incorrect tool result handling

2 participants