61 lines
1.6 KiB
Go
61 lines
1.6 KiB
Go
// Package plain ist der stdout-Renderer für den Print-Modus (5.8): Textdeltas
|
|
// nach stdout, Tool-Aktivität nach stderr. Reiner Consumer von tool.UIEvent.
|
|
package plain
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
|
|
"nub/internal/tool"
|
|
)
|
|
|
|
type Renderer struct {
|
|
Out io.Writer
|
|
Err io.Writer
|
|
}
|
|
|
|
// Render konsumiert den Event-Channel, bis er schließt, und liefert den
|
|
// zuletzt gesehenen Fehler zurück (für die Exit-Code-Entscheidung in main).
|
|
func (r *Renderer) Render(events <-chan tool.UIEvent) error {
|
|
var lastErr error
|
|
openText := false
|
|
|
|
for ev := range events {
|
|
switch e := ev.(type) {
|
|
case tool.TextDelta:
|
|
fmt.Fprint(r.Out, e.Text)
|
|
openText = true
|
|
case tool.ThinkingDelta:
|
|
// v1: kein separates Rendering für Thinking im Print-Modus.
|
|
case tool.ToolCallStart:
|
|
if openText {
|
|
fmt.Fprintln(r.Out)
|
|
openText = false
|
|
}
|
|
fmt.Fprintf(r.Err, "→ %s %s\n", e.Name, string(e.Input))
|
|
case tool.ToolStream:
|
|
fmt.Fprint(r.Err, e.Text)
|
|
case tool.ToolCallOutput:
|
|
status := "ok"
|
|
if e.Result.IsError {
|
|
status = "error"
|
|
}
|
|
fmt.Fprintf(r.Err, "← %s [%s]\n", e.Name, status)
|
|
case tool.TurnDone:
|
|
if openText {
|
|
fmt.Fprintln(r.Out)
|
|
openText = false
|
|
}
|
|
if e.Usage.InputTokens > 0 || e.Usage.OutputTokens > 0 {
|
|
fmt.Fprintf(r.Err, "usage: input=%d output=%d cache_read=%d\n",
|
|
e.Usage.InputTokens, e.Usage.OutputTokens, e.Usage.CacheReadTokens)
|
|
}
|
|
case tool.ErrorEvent:
|
|
fmt.Fprintf(r.Err, "error: %v\n", e.Err)
|
|
lastErr = e.Err
|
|
case tool.CompactionEvent:
|
|
fmt.Fprintf(r.Err, "compacted %d nodes into a %d-token summary\n", e.ReplacedNodes, e.SummaryTokens)
|
|
}
|
|
}
|
|
return lastErr
|
|
}
|