feat: наблюдение за живой opencode-сессией (/status N показывает что делает агент)
All checks were successful
CI / test (push) Successful in 54s
CI / build-and-package (amd64, linux) (push) Successful in 35s
CI / build-and-package (amd64, windows) (push) Successful in 43s

LiveRegistry собирает live-шаги из stdout процесса opencode по taskID
(через контекст, без изменения интерфейса Runner). /status N для running-задачи
прикладывает живое состояние: активный субагент, давность последнего шага,
последние text-шаги агента. Ничего не перезапускается и не убивается —
только наблюдение по запросу.
This commit is contained in:
Hermes
2026-08-17 08:05:15 +05:00
parent 2255917949
commit da775ac227
9 changed files with 329 additions and 26 deletions

View File

@@ -68,7 +68,7 @@ func (w *Worker) runReviewer(ctx context.Context, taskID int64, cwd, prompt stri
return nil, "", 0, fmt.Errorf("%w: %v", ErrReviewTrace, err)
}
res, resErr := w.Runner.Run(ctx, prompt, cwd, "reviewer", "")
res, resErr := w.Runner.Run(w.runCtx(ctx, taskID), prompt, cwd, "reviewer", "")
if resErr != nil {
w.finalizeTrace(ctx, traceID, storage.TraceFailed, resErr.Error())
return nil, "", traceID, fmt.Errorf("%w: %v", ErrReviewSpawn, resErr)
@@ -114,4 +114,4 @@ func parseReviewVerdict(out string) (*reviewVerdict, error) {
return nil, err
}
return &v, nil
}
}

View File

@@ -35,6 +35,10 @@ type Worker struct {
GitBaseURL string
GitToken string
// Live — опциональный журнал живых сессий (наблюдение /status N).
// Через него Runner пишет live-шаги задачи; nil — наблюдение выключено.
Live *opencode.LiveRegistry
sem chan struct{} // семафор
cancel context.CancelFunc
@@ -42,6 +46,15 @@ type Worker struct {
pollFn PollTaskFunc
}
// runCtx оборачивает контекст запуска субагента, привязывая живое наблюдение
// сессии задачи (если Live-журнал включён). Возвращает ctx без изменений при nil Live.
func (w *Worker) runCtx(ctx context.Context, taskID int64) context.Context {
if w.Live == nil {
return ctx
}
return opencode.WithLive(ctx, w.Live, taskID)
}
// Start запускает цикл опроса в фоновой горутине.
func (w *Worker) Start(ctx context.Context) {
if w.Agent == "" {
@@ -195,8 +208,8 @@ func (w *Worker) runTask(ctx context.Context, task *storage.Task) (err error) {
return fmt.Errorf("%w: create: %v", ErrTrace, tErr)
}
// 5. запускаем dev-агент (fresh сессия в текущей ветке)
res, resErr := w.Runner.Run(ctx, prompt, cwd, w.Agent, "")
// 5. запускаем dev-агента (fresh сессия в текущей ветке)
res, resErr := w.Runner.Run(w.runCtx(ctx, task.ID), prompt, cwd, w.Agent, "")
if resErr != nil {
// O1 ErrSpawn — не смог запустить бинарь
w.failTask(ctx, task)
@@ -416,4 +429,4 @@ func validateRepoName(repo string) error {
}
}
return nil
}
}