mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-14 02:15:57 +00:00
Makes the Stop button on the traces page actually stop running traces. Seven-phase implementation across provider HTTP, agent router, trace persistence, WS events, tool exec, i18n, and integration tests. - Provider HTTP+SSE ctx-aware: close socket on cancel via CtxBody wrapper - Router 2-phase abort: CAS state machine, 3s grace, force-mark fallback - Trace retry: 3 inline retries + 10-max retry queue, stale recovery 10min - trace.status WS event: real-time UI updates (invalidates query on receive) - Tool exec: process-group kill (SIGTERM→3s→SIGKILL), Rod page ctx watch - i18n: 6 abort toast variants in en/vi/zh - Integration: 9 scenarios, -race clean Fixes tenant-ctx loss in forceMarkTraceAborted and retry worker broadcast (caught by code-reviewer: C1/C2). Stale threshold intentionally 10min because start_time-based; last_span_at migration is a follow-up.
65 lines
1.9 KiB
Go
65 lines
1.9 KiB
Go
package orchestration
|
|
|
|
import (
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/agent"
|
|
"github.com/nextlevelbuilder/goclaw/internal/bus"
|
|
plpkg "github.com/nextlevelbuilder/goclaw/internal/pipeline"
|
|
)
|
|
|
|
// ChildResult is a unified struct capturing the outcome of a child agent run,
|
|
// regardless of whether it came from v2 RunResult or v3 PipelineResult.
|
|
type ChildResult struct {
|
|
Content string
|
|
Media []bus.MediaFile
|
|
InputTokens int64
|
|
OutputTokens int64
|
|
Runtime time.Duration
|
|
Iterations int
|
|
Status string // "completed", "failed", "cancelled"
|
|
}
|
|
|
|
// CaptureFromRunResult converts an agent.RunResult (v2) to ChildResult.
|
|
func CaptureFromRunResult(r *agent.RunResult, runtime time.Duration) ChildResult {
|
|
if r == nil {
|
|
return ChildResult{Status: "failed", Runtime: runtime}
|
|
}
|
|
var inTok, outTok int64
|
|
if r.Usage != nil {
|
|
inTok = int64(r.Usage.PromptTokens)
|
|
outTok = int64(r.Usage.CompletionTokens)
|
|
}
|
|
return ChildResult{
|
|
Content: r.Content,
|
|
Media: MediaResultToBusFiles(r.Media),
|
|
InputTokens: inTok,
|
|
OutputTokens: outTok,
|
|
Runtime: runtime,
|
|
Iterations: r.Iterations,
|
|
Status: "completed",
|
|
}
|
|
}
|
|
|
|
// CaptureFromPipelineResult converts a pipeline.RunResult (v3) to ChildResult.
|
|
func CaptureFromPipelineResult(r *plpkg.RunResult, runtime time.Duration) ChildResult {
|
|
if r == nil {
|
|
return ChildResult{Status: "failed", Runtime: runtime}
|
|
}
|
|
media := make([]bus.MediaFile, 0, len(r.MediaResults))
|
|
for _, m := range r.MediaResults {
|
|
// Basename preserves any sanitized stem from the producing agent's persistMedia.
|
|
media = append(media, bus.MediaFile{Path: m.Path, MimeType: m.ContentType, Filename: filepath.Base(m.Path)})
|
|
}
|
|
return ChildResult{
|
|
Content: r.Content,
|
|
Media: media,
|
|
InputTokens: int64(r.TotalUsage.PromptTokens),
|
|
OutputTokens: int64(r.TotalUsage.CompletionTokens),
|
|
Runtime: runtime,
|
|
Iterations: r.Iterations,
|
|
Status: "completed",
|
|
}
|
|
}
|