Skip to content

Commit 99b1769

Browse files
committed
release: v0.31.3
1 parent 3f57ace commit 99b1769

File tree

3 files changed

+34
-10
lines changed

3 files changed

+34
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2222
- SQLite: auto-detect schema changes from external tools (#704)
2323
- UI layout stability when toggling menus, panels, and inspectors (#702)
2424
- Misc bug fixes: save tabs before DB switch, log rollback failures, standardize colors, fix localization, button safety, filter validation (#707)
25+
- Fix Ollama AI chat streaming — responses were silently discarded due to wrong stream format parsing
2526

2627
### Changed
2728

TablePro/Core/AI/OpenAICompatibleProvider.swift

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,38 @@ final class OpenAICompatibleProvider: AIProvider {
6363
for try await line in bytes.lines {
6464
if Task.isCancelled { break }
6565

66-
guard line.hasPrefix("data: ") else { continue }
67-
let jsonString = String(line.dropFirst(6))
68-
guard jsonString != "[DONE]" else { break }
69-
70-
if let text = parseChatCompletionDelta(jsonString) {
71-
continuation.yield(.text(text))
72-
}
73-
if let usage = parseUsageFromChunk(jsonString) {
74-
inputTokens = usage.inputTokens
75-
outputTokens = usage.outputTokens
66+
if self.providerType == .ollama {
67+
// Ollama: raw newline-delimited JSON (no SSE "data: " prefix)
68+
guard !line.isEmpty else { continue }
69+
Self.logger.debug("Ollama stream line: \(line.prefix(200), privacy: .public)")
70+
71+
if let text = self.parseChatCompletionDelta(line) {
72+
continuation.yield(.text(text))
73+
}
74+
if let usage = self.parseUsageFromChunk(line) {
75+
inputTokens = usage.inputTokens
76+
outputTokens = usage.outputTokens
77+
}
78+
// Ollama signals completion with "done":true
79+
if let data = line.data(using: .utf8),
80+
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
81+
json["done"] as? Bool == true
82+
{
83+
break
84+
}
85+
} else {
86+
// OpenAI/OpenRouter/Custom: SSE with "data: " prefix
87+
guard line.hasPrefix("data: ") else { continue }
88+
let jsonString = String(line.dropFirst(6))
89+
guard jsonString != "[DONE]" else { break }
90+
91+
if let text = self.parseChatCompletionDelta(jsonString) {
92+
continuation.yield(.text(text))
93+
}
94+
if let usage = self.parseUsageFromChunk(jsonString) {
95+
inputTokens = usage.inputTokens
96+
outputTokens = usage.outputTokens
97+
}
7698
}
7799
}
78100

docs/changelog.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ rss: true
2626
- Fixed UI layout breaks when toggling menus, panels, and inspectors (#702)
2727
- Fixed `⌘W` accidentally closing connection window instead of tab
2828
- Fixed tabs not saved before database switch, rollback failures now logged, filter validation improved (#707)
29+
- Fixed Ollama AI chat streaming — responses were silently discarded
2930
</Update>
3031

3132
<Update label="April 13, 2026" description="v0.31.2">

0 commit comments

Comments
 (0)