Skip to content

fix(ollama): num_ctx never set — small local models silently truncated to Ollama's default context window #210

Description

@bobbyj

Problem

Tinycode never sends num_ctx to Ollama at any point in the request path (grep -rln "num_ctx" packages/tinycode/src/ returns nothing). This means Ollama serves every local model at its own default runtime context window, completely independent of the model's actual trained capacity.

Reproduced with qwen3.5:9b, whose real trained context length is 262,144 tokens (confirmed via ollama show//api/tags — details.context_length: 262144). With num_ctx unset, the server truncated generation at a 4096-token total window (input+output combined) — roughly 1.5% of the model's real capacity.

Evidence

A large-enough first-turn prompt (~2050 input tokens) caused qwen3.5:9b to hit step_finish reason:"length" with tokens:{"total":4096,"input":2050,"output":2046} — input+output sums exactly to 4096, identically across 3 separate runs spanning 2 different tasks and a reworded retry (rules out prompt-content as the driver; confirms a fixed, deterministic ceiling).

Tinycode's own empty-response handling in packages/tinycode/src/session/prompt.ts:1200-1218,1235 compounds this: when a turn produces no tool call and no captured text (because generation was cut off mid-stream by the context overflow, not because the model was actually silent), it injects a synthetic nudge — literally "Please analyze and respond to the tool results above." — even though no tool call ever occurred. The model's next turn faithfully reacts to that misleading nudge, producing confused meta-commentary that looks like a prompt-engineering failure but is actually a downstream symptom of the context-window bug.

Root cause detail

packages/tinycode/src/provider/local-discovery.ts:181-183 already computes, per-model, from Ollama's own reported details.context_length:

const effectiveContext = contextLimit > 0 ? Math.floor(contextLimit * 0.8) : 0
const outputLimit = contextLimit > 0 ? Math.min(4096, Math.floor(contextLimit * 0.2)) : 0

But effectiveContext is used only for tinycode's own internal token-budget bookkeeping (limit: {context, output}) — it is never transmitted as an actual num_ctx request parameter to Ollama. So tinycode's own internal accounting believes ~209,715 tokens are available for qwen3.5:9b (80% of 262,144), while the server is actually enforcing ~4096 — a ~50x mismatch between what tinycode thinks it has and what it's actually being given.

Confirmed this isn't tinycode's own requested max_tokens (also coincidentally 4096, via maxOutputTokens() in packages/tinycode/src/provider/transform.ts:1277-1279) being the binding constraint: observed output (2046) stopped short of that 4096 client-side request. If the client-side cap were binding, output would have run the full 4096 regardless of input length. It didn't — it stopped exactly where input + output = 4096, which only happens when the server's context window (not the client's requested output ceiling) is the actual limit.

No user-facing workaround exists today either — the provider options config field (packages/tinycode/src/config/provider.ts:61,84) is forwarded into provider/client construction (baseURL, headers) per provider.ts:894-1121, not into per-request generation parameters.

Fix

  1. Immediate mitigation: gate the empty-response nudge (prompt.ts:1200-1218,1235) on whether a tool call occurred on a prior turn — stop injecting a "tool results above" message when no tool was ever called. This won't fix the underlying truncation but stops it from producing a confusing, misleading follow-up.
  2. Root fix: pass num_ctx explicitly when constructing Ollama requests, using the already-computed effectiveContext value (currently dead-ended at bookkeeping-only use).

Not specific to any one agent persona or prompt shape — any tinycode↔Ollama request with a first-turn prompt large enough to approach the default (not actual) context window is exposed.

Related research

Full investigation writeup with additional verification: ~/projects/ollama-lab/notes/tinycode-scaffolding-benchmark-2026.md (external repo, not in this codebase).

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions