Repository navigation
Chat with local models through Ollama and LM Studio, and Markdown in answers - #156
Merged
Merged
Conversation
- Add ollama/lmstudio cases to ChatProvider with isLocal, pillID, init?(pillID:) - Add LocalChat helpers: normaliseURL, parseSSEDelta, filterThinkingBlocks - Stream local responses token-by-token via URLSession.bytes - Add ai_ollama (#FACC15) and ai_lmstudio (#A3E635) pills to PillCatalog - Add server URL settings in Settings → Chat (Local models GroupBox) - NSAllowsLocalNetworking in both Info.plist targets Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add ChatMarkdown block parser (Foundation only) and ChatMarkdownView renderer - ChatBubble uses ChatMarkdownView for assistant messages - Update system prompt to allow markdown formatting - Add ChatMarkdown/LocalChat test suite with compile-and-run script - Add test-chat-parsing step to CI build workflow Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… e2e tests - Add LocalChatError typed enum (serverUnreachable, modelNotFound, serverError) - Add LocalChat.fetchModels with embedding model filter (nomic-embed, bge, etc.) - Add LocalChat.streamChat: full SSE streaming with typed error handling - Add LocalChat.progressiveFilter for partial think-block suppression - ClaudeService delegates local streaming entirely to LocalChat.streamChat - Add tests/fake_local_llm.py: stdlib Python server with think blocks, null-content deltas, model filter, unknown model 404, and Markdown streaming - ChatParsingTests: unit tests + 4 end-to-end tests against fake server - test-chat-parsing.sh starts/stops fake server with port-file handoff Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lish Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
3 of 4 tasks
JhoanG956
pushed a commit
to JhoanG956/coucou
that referenced
this pull request
Oct 7, 2026
… server As the Mac does since 0.1.3 (Louis-CFM#156, LocalChat.swift), plus a server of the user's own that speaks the OpenAI API (vLLM, llama.cpp…), with an optional key kept in the credential store (openai-compatible-key). - local_connect checks that a server answers and lists its chat models (embedding and rerank models are left out). An empty address means the usual one on this computer; Ollama's OLLAMA_HOST is honoured. - Addresses are validated and cleaned: http or https only, no user:password@, trailing /v1 and /api dropped, and the loopback names pinned to 127.0.0.1 (on Windows "localhost" can resolve to ::1 first while Ollama listens on IPv4 only). Requests to this computer skip any proxy. - The answer streams: each step goes to the island as a chat-delta event with the text visible so far, at most 15 times a second. <think> blocks stay hidden while open and are dropped from the finished answer; reasoning-only deltas are ignored and an error event ends the turn. - Every read is bounded: model lists and error bodies, one event line (1 MB) and the whole streamed answer (4 MB). - A dropped text file goes along inline, 24 000 characters at most, read without loading more of the file than that; images and PDFs by name only. - Settings: ollamaUrl, lmstudioUrl, customUrl (empty: not connected). Based on Louis-CFM#173 by Justin Minkmar (local_chat.rs), re-applied on main without the branches it was stacked on; ideas from Louis-CFM#262 by bagpotato94 (loopback pinning, no proxy for loopback, OLLAMA_HOST). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
JhoanG956
pushed a commit
to JhoanG956/coucou
that referenced
this pull request
Oct 7, 2026
As on the Mac since Louis-CFM#156 (ChatMarkdown.swift, ChatMarkdownView.swift): headings, paragraphs, bullet and numbered lists, quotes, rules, and fenced code blocks with a copy button; bold, italic, inline code and links inside the text. Every provider's answer goes through it. - Built as DOM nodes from text only, never as HTML: nothing a model writes can inject markup. The tests run the renderer on a fake DOM whose innerHTML throws. - A link opens only when it is http or https, and through Rust's open_url, which checks the scheme again; any other target stays plain text. - Inline syntax is parsed into a tree first (parseInline), so it can be tested without a webview. No lookbehind in the regex: older WebKitGTK builds reject it, and one bad literal would take the whole island down. snake_case words are not italics. Based on Louis-CFM#173 by Justin Minkmar (markdown.ts and its styles). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Tests