feat: наблюдение за живой opencode-сессией (/status N показывает что делает агент)
LiveRegistry собирает live-шаги из stdout процесса opencode по taskID (через контекст, без изменения интерфейса Runner). /status N для running-задачи прикладывает живое состояние: активный субагент, давность последнего шага, последние text-шаги агента. Ничего не перезапускается и не убивается — только наблюдение по запросу.
This commit is contained in:
46
internal/app/live.go
Normal file
46
internal/app/live.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kamelion/ratatoskr-go/internal/opencode"
|
||||
)
|
||||
|
||||
// liveProbe адаптирует *opencode.LiveRegistry под интерфейс core.LiveProber.
|
||||
// Формирует короткое человекочитаемое описание живой сессии задачи.
|
||||
type liveProbe struct {
|
||||
reg *opencode.LiveRegistry
|
||||
}
|
||||
|
||||
func (p *liveProbe) Probe(taskID int64) (string, bool) {
|
||||
if p == nil || p.reg == nil {
|
||||
return "", false
|
||||
}
|
||||
snap, ok := p.reg.Snap(taskID)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
var b strings.Builder
|
||||
b.WriteString(fmt.Sprintf("Агент **%s** активен", snap.Agent))
|
||||
if idl := time.Since(snap.Last).Round(time.Second); idl > 0 {
|
||||
b.WriteString(fmt.Sprintf(" (последний шаг %s назад)", idl))
|
||||
}
|
||||
// последние text-шаги — что агент делает прямо сейчас
|
||||
n := 0
|
||||
for i := len(snap.Steps) - 1; i >= 0 && n < 3; i-- {
|
||||
st := snap.Steps[i]
|
||||
if st.Type != "text" || strings.TrimSpace(st.Text) == "" {
|
||||
continue
|
||||
}
|
||||
text := strings.TrimSpace(st.Text)
|
||||
if len(text) > 140 {
|
||||
text = text[:140] + "…"
|
||||
}
|
||||
text = strings.ReplaceAll(text, "\n", " ")
|
||||
b.WriteString("\n▸ " + text)
|
||||
n++
|
||||
}
|
||||
return b.String(), true
|
||||
}
|
||||
Reference in New Issue
Block a user