Files
jakeaturner a013eb6394 fix(chat): stop capping answers at 1024 tokens and surface truncation
planPrompt() returned the response reserve as num_predict, and the
reserve was clamped by MAX_RESPONSE_RESERVE = 1024. Chat answers
stopped at 1024 output tokens regardless of window size, often
mid-sentence, and the normalized stream chunks dropped Ollama's
done_reason, so neither the UI nor API clients could discern between
a cut-off answer and a finished one.

- Decouple the generation cap from the reserve. num_predict is now the
  space left in the window after the prompt, less a 5% (min 64 token)
  margin for estimator error, with the reserve as its floor. Raise
  MAX_RESPONSE_RESERVE to 8192 so it only bounds prompt hold-back.
- Carry done_reason through all four OllamaService chat paths. Native
  forwards Ollama's done_reason; compat maps OpenAI's finish_reason.
- Log length-limited stops in OllamaController with num_predict,
  num_ctx and tokens generated.
- Show a truncation notice on cut-off answers, with a Continue button
  on the latest one that sends a normal follow-up turn.

Generation evals before and after this change are not length
comparable.

Closes #1342
2026-09-29 15:54:41 -07:00

40 lines
900 B
TypeScript

/**
* A single provenance entry under an assistant answer: the document a chunk of
* injected context came from. `source` is the originating file/ZIM path and is
* what dedupes the list; `title` is what the user actually reads.
*/
export interface ChatSource {
title: string
date?: string
source?: string
}
export interface ChatMessage {
id: string
role: 'system' | 'user' | 'assistant'
content: string
images?: ChatImageAttachment[]
timestamp: Date
isStreaming?: boolean
thinking?: string
isThinking?: boolean
thinkingDuration?: number
sources?: ChatSource[]
// Generation stopped at the length limit, so the answer ends mid-thought.
truncated?: boolean
}
export interface ChatImageAttachment {
id: string
name: string
file: File
previewUrl: string
}
export interface ChatSession {
id: string
title: string
lastMessage?: string
timestamp: Date
}