Skip to content

feat(web): add an Ask chat panel backed by Ollama - #36

Merged
meddlin merged 1 commit into
mainfrom
claude/ollama-chat-integration-f7dda8
Nov 2, 2026
Merged

meddlin merged 1 commit into
mainfrom
claude/ollama-chat-integration-f7dda8

Conversation

@meddlin

@meddlin meddlin commented Nov 2, 2026

Copy link
Copy Markdown
Owner

Summary

Adds an Ask button to the top bar that slides out a chat panel on the right. It answers questions about your repositories with a model on an Ollama server, which can be another machine on the network. Ollama is optional: without it the panel says it cannot reach the server and nothing else changes.

The goal is to run local models against the data gitlib already holds, with a single 12 GB GPU in mind. The research behind the design is included in this PR (docs/ollama-integration.md), along with a second note on a scheduled Dependabot watch that is not built here.

What changed

Core (packages/core/src/ai)

  • ChatBackend interface and an OllamaBackend over plain fetch: NDJSON streaming, abort, a stall timeout, and readable errors. It is injected into GitLibApp like SearchBackend, so tests use a fake.
  • [ollama] config table with GITLIB_OLLAMA_HOST, GITLIB_OLLAMA_MODEL and GITLIB_OLLAMA_NUM_CTX overrides, mirroring [search].
  • A token budget that cuts history to fit the context window (Ollama truncates silently and has no tokenizer endpoint), and a system prompt built from a capped repository list plus the current repository's notes and README.
  • isGitLibError, a brand check for errors that cross a module-copy boundary (see reviewer notes).

Web

  • POST /api/chat streams NDJSON events. server.mjs now aborts the request when the browser disconnects, so closing the panel or pressing Stop stops the model.
  • A non-modal Sheet panel in the root layout (conversation survives navigation), with a model picker, Stop, a scope chip, and states for turned off, unreachable and no models installed.
  • MarkdownBody gets an untrusted mode used for model output: no images, and link targets are shown. An image URL in text shaped by a hostile README could otherwise carry data out.
  • The top bar's link list scrolls sideways so Ask stays visible on a phone.

Docs and config: README "Chat" section, runbook troubleshooting rows, .env.example files and docker-compose.yml.

For reviewers

  • Not run against a real model. Everything was exercised against a stand-in Ollama (streaming, Stop, mid-stream errors, unreachable server, phone width, and the production server). Model quality, tool use and VRAM fit are untested.
  • @ts-expect-error in routes/api.chat.ts. @tanstack/react-router pins router-core 1.171.38 while Start pins 1.171.39, so Start's type for a route's server option lands on a different copy and is not applied. The build finds server by its shape in the object literal, so it has to stay written out there. When npm ls @tanstack/router-core shows one copy the directive becomes an error, which is the cue to delete it. Realigning those versions is worth a separate change.
  • isGitLibError. In the dev server instanceof against core's error classes failed (an expected error came back as a 500). There is a regression test.
  • Top bar. It already overflowed at 375px before this change; the new button made it worse, so the nav now has min-w-0 and a scrolling link list.
  • apps/web/src/routeTree.gen.ts is regenerated for the new route.
  • The branch is 5 commits behind main; a dry-run merge is clean.

Not in this PR

Tool calling and retrieval beyond the capped prompt, a shared work queue for the GPU, and the Dependabot watch (research only, in docs/dependabot-watch.md).

Test plan

  • npm run typecheck
  • npm test: 278 passing, 126 of them new (config, token budget, prompt building, Ollama client over a real local HTTP server, route handler, protocol parsing)
  • npm run build, and no server code in the browser bundle
  • Manual, against a fake Ollama: streaming, Stop reaching Ollama (dev and production servers), repo scope, mid-stream error, unreachable then recovered, 375px width
  • Against a real Ollama: run the "Verify against your server" commands in docs/ollama-integration.md, ask a question, and confirm ollama ps shows the model fully on the GPU

🤖 Generated with Claude Code

Adds an "Ask" button to the top bar that slides out a chat panel on the
right. It answers questions about the user's repositories with a model on an
Ollama server, which can be another machine on the network. Ollama is
optional: without it the panel says it cannot reach the server and nothing
else changes.

Core (packages/core/src/ai):
- ChatBackend interface and an OllamaBackend over plain fetch (NDJSON
  streaming, abort, stall timeout, readable errors), injected like
  SearchBackend so tests use a fake.
- [ollama] config table with GITLIB_OLLAMA_HOST, _MODEL and _NUM_CTX
  overrides.
- A token budget that cuts history to fit the context window, because Ollama
  truncates silently, and a system prompt built from the repository list plus
  the current repository's notes and README, each with a fixed cap.
- isGitLibError, a brand check for errors that cross a module-copy boundary:
  the dev server can load core twice, which made instanceof fail and turned an
  expected error into a 500.

Web:
- POST /api/chat streams NDJSON events. server.mjs now aborts the request when
  the browser disconnects, so closing the panel stops the model.
- A non-modal Sheet panel mounted in the root layout, with a model picker,
  Stop, and states for turned off, unreachable and no models. Model output is
  rendered without images, which closes an exfiltration path through image
  URLs in text shaped by a hostile README.
- The top bar's link list scrolls sideways so Ask stays visible on a phone; it
  already overflowed at 375px before this change.

Docs: README Chat section, runbook troubleshooting rows, env and compose
settings, and the research behind the design (docs/ollama-integration.md and
docs/dependabot-watch.md, the latter not implemented here).

Tested against a fake Ollama only (streaming, Stop, mid-stream errors,
unreachable server, phone width, production server); not yet run with a real
model.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@meddlin
meddlin merged commit 4d50515 into main Nov 2, 2026
1 check passed
@meddlin
meddlin deleted the claude/ollama-chat-integration-f7dda8 branch November 2, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant