feat: Phase 2 — chat templates, reasoning parser, collapsible TUI, mouse support

- internal/llama/template.go: ChatML/Llama3 template engine with stop tokens
- internal/agent/reasoning.go: parse <think>/<reasoning> tags from LLM output
- companion/promptbuilder.go: output structured BuildResult, add date/time context
- agent/agent.go: wire templates + reasoning split into message loop
- storage: add reasoning TEXT column to messages table + migration
- channel/tui.go: collapsible reasoning (tab toggle), mouse scroll, polished dimmed style
- config: CHAT_TEMPLATE env var (chatml|llama3|none)
- plan.md: mark Phase 2 complete, add themes TODO
This commit is contained in:
2026-06-10 09:42:45 +03:30
parent f57b42fd6e
commit 3895ca68c0
14 changed files with 327 additions and 144 deletions

View File

@@ -0,0 +1,41 @@
package agent
import (
"strings"
)
type ParsedResponse struct {
Reasoning string
Content string
}
func ParseResponse(raw string) ParsedResponse {
tags := []struct {
open string
close string
}{
{"<reasoning>", "</reasoning>"},
{"<reason>", "</reason>"},
{"<thinking>", "</thinking>"},
{"<think>", "</think>"},
{"", ""},
}
for _, t := range tags {
if t.open == "" {
break
}
idxOpen := strings.Index(raw, t.open)
idxClose := strings.LastIndex(raw, t.close)
if idxOpen != -1 && idxClose != -1 && idxClose > idxOpen {
reasoning := raw[idxOpen+len(t.open) : idxClose]
content := raw[:idxOpen] + raw[idxClose+len(t.close):]
return ParsedResponse{
Reasoning: strings.TrimSpace(reasoning),
Content: strings.TrimSpace(content),
}
}
}
return ParsedResponse{Content: strings.TrimSpace(raw)}
}