nub/internal/ui/tui/question.go
Tom a97013d876 initial commit
- v 0.1.0 siehe CHANGELOG.md
2026-07-25 11:08:01 +02:00

77 lines
2.3 KiB
Go

package tui
import (
"context"
"strings"
tea "github.com/charmbracelet/bubbletea"
)
// askRequest kommt vom question-Tool über Model.askCh. Anders als eine
// Permission-Rückfrage (bool, Tastendruck) ist die Antwort hier Freitext —
// die Antwort läuft deshalb über das normale Eingabefeld: submit() prüft
// zuerst, ob eine Frage offen ist, und behandelt den getippten Text als
// Antwort statt als neue Chat-Nachricht/Slash-Command (siehe submit in
// model.go).
type askRequest struct {
question string
options []string
resp chan string
}
type askRequestMsg struct{ req askRequest }
func listenAskRequests(ch <-chan askRequest) tea.Cmd {
return func() tea.Msg {
req, ok := <-ch
if !ok {
return nil
}
return askRequestMsg{req: req}
}
}
// askUser ist der Hook, den loop.AskUser aufruft (siehe New()). Läuft auf
// dem Goroutine des Backend-Loops, nicht dem der TUI.
func (m *Model) askUser(ctx context.Context, question string, options []string) (string, error) {
resp := make(chan string, 1)
req := askRequest{question: question, options: options, resp: resp}
select {
case m.askCh <- req:
case <-ctx.Done():
return "", ctx.Err()
}
select {
case answer := <-resp:
return answer, nil
case <-ctx.Done():
return "", ctx.Err()
}
}
// answerQuestion schließt die offene Frage ab und schickt answer an den
// wartenden Loop-Goroutine zurück. resp ist mit Cap 1 gepuffert, der Send
// blockiert also nie. Die Bestätigung im Transkript kommt bewusst nicht von
// hier, sondern aus dem regulären ToolCallOutput-Event (renderToolResult,
// builtin.QuestionResult) — sonst erschiene die Antwort doppelt.
func (m *Model) answerQuestion(answer string) {
req := m.askReq
m.askReq = nil
m.textarea.Placeholder = defaultInputPlaceholder
req.resp <- answer
}
// renderAskRequest baut den Transkript-Block für eine offene Frage — wie
// bei Permissions kein Vollbild-Overlay, sondern ein Eintrag im normalen
// Nachrichtenfluss (siehe renderPermissionRequest).
func renderAskRequest(question string, options []string) string {
var b strings.Builder
b.WriteString("❓ Rückfrage: " + question)
if len(options) > 0 {
b.WriteString("\nVorschläge: " + strings.Join(options, " · "))
}
b.WriteString("\n\nAntwort eingeben und Enter drücken.")
return styleAskBox.Render(b.String())
}