Skip to content

Commit 435217e

Browse files
author
Test
committed
feat: add real-time progress reporting to Conductor
- Add ProgressCallback and reportProgress() for Live Dashboard updates - Report progress during planning, editing, and validation phases - Set LiveReportConfig to enable HTTP API reporting - Fix snapshot issue detection in formatValidationIssues
1 parent e88f497 commit 435217e

File tree

1 file changed

+45
-9
lines changed

1 file changed

+45
-9
lines changed

internal/maestro/conductor.go

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,26 @@ import (
1212
"gptcode/internal/agents"
1313
"gptcode/internal/config"
1414
"gptcode/internal/feedback"
15+
"gptcode/internal/live"
1516
"gptcode/internal/llm"
1617
"gptcode/internal/observability"
1718
)
1819

20+
// ProgressCallback is called during execution to report progress
21+
type ProgressCallback func(phase string, details string)
22+
1923
// Conductor is the central coordinator (Maestro) that orchestrates all agents
2024
type Conductor struct {
21-
selector *config.ModelSelector
22-
setup *config.Setup
23-
cwd string
24-
language string
25-
Recovery *RecoveryStrategy
26-
Tracer observability.Tracer
27-
Observer *observability.AgentObserver // For tracking and summary
28-
loopDetector *llm.LoopDetector // Centralized Claude Code-style loop detection
25+
selector *config.ModelSelector
26+
setup *config.Setup
27+
cwd string
28+
language string
29+
Recovery *RecoveryStrategy
30+
Tracer observability.Tracer
31+
Observer *observability.AgentObserver // For tracking and summary
32+
loopDetector *llm.LoopDetector // Centralized Claude Code-style loop detection
33+
liveReportConfig *live.ReportConfig // For Live Dashboard HTTP reporting
34+
progressCallback ProgressCallback // For real-time progress updates
2935
}
3036

3137
// NewConductor creates a new Maestro conductor
@@ -55,6 +61,26 @@ func NewConductor(
5561
}
5662
}
5763

64+
// SetLiveReportConfig sets the Live Dashboard HTTP reporting configuration
65+
func (c *Conductor) SetLiveReportConfig(reportConfig *live.ReportConfig) {
66+
c.liveReportConfig = reportConfig
67+
}
68+
69+
// SetProgressCallback sets the callback for real-time progress updates
70+
func (c *Conductor) SetProgressCallback(callback ProgressCallback) {
71+
c.progressCallback = callback
72+
}
73+
74+
// reportProgress sends progress to Live Dashboard and calls progress callback
75+
func (c *Conductor) reportProgress(phase string, details string) {
76+
if c.liveReportConfig != nil {
77+
c.liveReportConfig.Step(phase+": "+details, "step")
78+
}
79+
if c.progressCallback != nil {
80+
c.progressCallback(phase, details)
81+
}
82+
}
83+
5884
// ExecuteTask orchestrates the execution of a task
5985
func (c *Conductor) ExecuteTask(ctx context.Context, task string, complexity string) error {
6086
if os.Getenv("GPTCODE_DEBUG") == "1" {
@@ -95,9 +121,11 @@ func (c *Conductor) ExecuteTask(ctx context.Context, task string, complexity str
95121
planner := agents.NewPlanner(planProvider, planModel)
96122

97123
fmt.Println("Creating plan...")
124+
c.reportProgress("planning", "Creating plan")
98125
start := time.Now()
99126
plan, err := planner.CreatePlan(ctx, task, "", nil)
100127
elapsed := time.Since(start)
128+
c.reportProgress("planning", "Plan created")
101129
c.selector.RecordUsage(planBackend, planModel, err == nil, errorMsg(err))
102130
if err != nil {
103131
return fmt.Errorf("planning failed: %w", err)
@@ -142,6 +170,9 @@ func (c *Conductor) ExecuteTask(ctx context.Context, task string, complexity str
142170
attempt := c.loopDetector.Iteration
143171
if attempt > 1 {
144172
fmt.Printf("Retrying (attempt %d)...\n", attempt)
173+
c.reportProgress("retry", fmt.Sprintf("Attempt %d", attempt))
174+
} else {
175+
c.reportProgress("editing", "Starting code changes")
145176
}
146177

147178
// Select model for editing
@@ -166,9 +197,11 @@ func (c *Conductor) ExecuteTask(ctx context.Context, task string, complexity str
166197

167198
// Execute with editor
168199
fmt.Println("Executing changes...")
200+
c.reportProgress("editing", "Executing code changes")
169201
start = time.Now()
170202
result, modifiedFiles, err := editor.Execute(ctx, history, nil)
171203
elapsed = time.Since(start)
204+
c.reportProgress("editing", fmt.Sprintf("Completed - %d files changed", len(modifiedFiles)))
172205
c.selector.RecordUsage(editBackend, editModel, err == nil, errorMsg(err))
173206
if err != nil {
174207
// LoopDetector will handle max iterations check on next iteration
@@ -256,9 +289,11 @@ func (c *Conductor) ExecuteTask(ctx context.Context, task string, complexity str
256289

257290
// Validate
258291
fmt.Println("Validating...")
292+
c.reportProgress("validation", "Running tests and checks")
259293
start = time.Now()
260294
review, err := reviewer.Review(ctx, plan, modifiedFiles, nil)
261295
elapsed = time.Since(start)
296+
c.reportProgress("validation", "Validation complete")
262297
c.selector.RecordUsage(reviewBackend, reviewModel, err == nil, errorMsg(err))
263298
if err != nil {
264299
// LoopDetector will handle max iterations check on next iteration
@@ -469,10 +504,11 @@ func (c *Conductor) formatValidationIssues(issues []string) string {
469504
hasPackageError := false
470505
hasSnapshotFailure := false
471506
for _, issue := range issues {
507+
lowerIssue := strings.ToLower(issue)
472508
if strings.Contains(issue, "found packages") {
473509
hasPackageError = true
474510
}
475-
if strings.Contains(strings.ToLower(issue), "snapshot") {
511+
if strings.Contains(lowerIssue, "snapshot") {
476512
hasSnapshotFailure = true
477513
}
478514
}

0 commit comments

Comments
 (0)