Skip to content

Commit 9ed0d52

Browse files
author
Test
committed
feat: integrate WebSocket for real-time progress in Conductor
- Add SetLiveClient() to Conductor for WebSocket reporting - Add reportError() and reportComplete() helper methods - Update reportProgress() to send via both HTTP and WebSocket - Add NewAutonomousExecutorWithLive() for Live Dashboard integration - Update autonomous executor to support Live client - Update callers to use new function signature
1 parent 435217e commit 9ed0d52

File tree

4 files changed

+91
-20
lines changed

4 files changed

+91
-20
lines changed

cmd/gptcode/do.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ func runDoExecution(task string, verbose bool, supervised bool, setup *config.Se
349349
language = "go" // default
350350
}
351351
// Use queryProvider for analyzer/classifier with selected backend
352-
executor := modes.NewAutonomousExecutorWithBackend(queryProvider, cwd, queryModel, language, backendName)
352+
executor := modes.NewAutonomousExecutorWithLive(queryProvider, cwd, queryModel, language, nil, nil, backendName)
353353
return executor.Execute(context.Background(), task)
354354
}
355355

cmd/gptcode/issue.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ Examples:
205205
language = "go"
206206
}
207207
}
208-
exec := modes.NewAutonomousExecutorWithBackend(provider, workDir, queryModel, language, backendName)
208+
exec := modes.NewAutonomousExecutorWithLive(provider, workDir, queryModel, language, nil, nil, backendName)
209209
if err := exec.Execute(context.Background(), task); err != nil {
210210
return fmt.Errorf("autonomous implementation failed: %w", err)
211211
}
@@ -706,7 +706,7 @@ Comment: %s
706706
Please read the file, understand the context, and implement the requested change.`,
707707
comment.Path, comment.Line, comment.Body)
708708

709-
exec := modes.NewAutonomousExecutorWithBackend(provider, workDir, queryModel, language, backendName)
709+
exec := modes.NewAutonomousExecutorWithLive(provider, workDir, queryModel, language, nil, nil, backendName)
710710
if err := exec.Execute(context.Background(), task); err != nil {
711711
fmt.Printf("⚠️ Failed to address comment: %v\n", err)
712712
continue

internal/maestro/conductor.go

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type Conductor struct {
3131
Observer *observability.AgentObserver // For tracking and summary
3232
loopDetector *llm.LoopDetector // Centralized Claude Code-style loop detection
3333
liveReportConfig *live.ReportConfig // For Live Dashboard HTTP reporting
34+
liveClient *live.Client // For Live Dashboard WebSocket reporting
3435
progressCallback ProgressCallback // For real-time progress updates
3536
}
3637

@@ -66,21 +67,81 @@ func (c *Conductor) SetLiveReportConfig(reportConfig *live.ReportConfig) {
6667
c.liveReportConfig = reportConfig
6768
}
6869

70+
// SetLiveClient sets the Live Dashboard WebSocket client for real-time updates
71+
func (c *Conductor) SetLiveClient(client *live.Client) {
72+
c.liveClient = client
73+
}
74+
6975
// SetProgressCallback sets the callback for real-time progress updates
7076
func (c *Conductor) SetProgressCallback(callback ProgressCallback) {
7177
c.progressCallback = callback
7278
}
7379

74-
// reportProgress sends progress to Live Dashboard and calls progress callback
80+
// reportProgress sends progress to Live Dashboard via HTTP and WebSocket, and calls progress callback
7581
func (c *Conductor) reportProgress(phase string, details string) {
82+
msg := phase + ": " + details
83+
84+
// Send via HTTP API (backup/reliability)
7685
if c.liveReportConfig != nil {
77-
c.liveReportConfig.Step(phase+": "+details, "step")
86+
c.liveReportConfig.Step(msg, "step")
7887
}
88+
89+
// Send via WebSocket (real-time)
90+
if c.liveClient != nil {
91+
c.liveClient.SendExecutionStep(phase, details, map[string]interface{}{
92+
"phase": phase,
93+
"details": details,
94+
})
95+
}
96+
97+
// Call progress callback
7998
if c.progressCallback != nil {
8099
c.progressCallback(phase, details)
81100
}
82101
}
83102

103+
// reportError sends error to Live Dashboard
104+
func (c *Conductor) reportError(phase string, errMsg string) {
105+
// Send via HTTP API
106+
if c.liveReportConfig != nil {
107+
c.liveReportConfig.Step(phase+": ERROR - "+errMsg, "error")
108+
}
109+
110+
// Send via WebSocket
111+
if c.liveClient != nil {
112+
c.liveClient.SendExecutionStep("error", errMsg, map[string]interface{}{
113+
"phase": phase,
114+
"error": errMsg,
115+
})
116+
}
117+
}
118+
119+
// reportComplete sends completion to Live Dashboard
120+
func (c *Conductor) reportComplete(success bool, summary string) {
121+
stepType := "complete"
122+
if !success {
123+
stepType = "failed"
124+
}
125+
126+
// Send via HTTP API
127+
if c.liveReportConfig != nil {
128+
if success {
129+
c.liveReportConfig.Step("Completed: "+summary, "complete")
130+
} else {
131+
c.liveReportConfig.Step("Failed: "+summary, "error")
132+
}
133+
c.liveReportConfig.Disconnect()
134+
}
135+
136+
// Send via WebSocket
137+
if c.liveClient != nil {
138+
c.liveClient.SendExecutionStep(stepType, summary, map[string]interface{}{
139+
"success": success,
140+
"summary": summary,
141+
})
142+
}
143+
}
144+
84145
// ExecuteTask orchestrates the execution of a task
85146
func (c *Conductor) ExecuteTask(ctx context.Context, task string, complexity string) error {
86147
if os.Getenv("GPTCODE_DEBUG") == "1" {

internal/modes/autonomous.go

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,32 @@ import (
88
"gptcode/internal/autonomous"
99
"gptcode/internal/config"
1010
"gptcode/internal/events"
11+
"gptcode/internal/live"
1112
"gptcode/internal/llm"
1213
"gptcode/internal/maestro"
1314
)
1415

1516
// AutonomousExecutor wraps autonomous execution for use across modes
1617
type AutonomousExecutor struct {
17-
events *events.Emitter
18-
provider llm.Provider
19-
cwd string
20-
model string
21-
executor *autonomous.Executor
18+
events *events.Emitter
19+
provider llm.Provider
20+
cwd string
21+
model string
22+
executor *autonomous.Executor
23+
conductor *maestro.Conductor
2224
}
2325

24-
// NewAutonomousExecutor creates a new autonomous executor
26+
// NewAutonomousExecutor creates a new autonomous executor (no Live integration)
2527
func NewAutonomousExecutor(provider llm.Provider, cwd string, model string, language string) *AutonomousExecutor {
26-
return NewAutonomousExecutorWithBackend(provider, cwd, model, language, "")
28+
return NewAutonomousExecutorWithLive(provider, cwd, model, language, nil, nil, "")
2729
}
2830

29-
// NewAutonomousExecutorWithBackend creates executor with specific backend override
30-
func NewAutonomousExecutorWithBackend(provider llm.Provider, cwd string, model string, language string, backendName string) *AutonomousExecutor {
31+
// NewAutonomousExecutorWithLive creates executor with Live Dashboard integration
32+
func NewAutonomousExecutorWithLive(provider llm.Provider, cwd string, model string, language string, liveClient *live.Client, liveConfig *live.ReportConfig, backendName string) *AutonomousExecutor {
3133
// Load setup
3234
setup, err := config.LoadSetup()
3335
if err != nil {
3436
fmt.Printf("[WARN] Failed to load setup: %v, using defaults\n", err)
35-
// Create minimal setup
3637
setup = &config.Setup{
3738
Backend: make(map[string]config.BackendConfig),
3839
}
@@ -53,18 +54,27 @@ func NewAutonomousExecutorWithBackend(provider llm.Provider, cwd string, model s
5354
// Create Maestro
5455
conductor := maestro.NewConductor(selector, setup, cwd, language)
5556

57+
// Set up Live Dashboard integration
58+
if liveClient != nil {
59+
conductor.SetLiveClient(liveClient)
60+
}
61+
if liveConfig != nil {
62+
conductor.SetLiveReportConfig(liveConfig)
63+
}
64+
5665
// Create autonomous components
5766
classifier := agents.NewClassifier(provider, model)
5867
analyzer := autonomous.NewTaskAnalyzer(classifier, provider, cwd, model)
5968

6069
executor := autonomous.NewExecutor(analyzer, conductor, cwd)
6170

6271
return &AutonomousExecutor{
63-
events: events.NewEmitter(nil),
64-
provider: provider,
65-
cwd: cwd,
66-
model: model,
67-
executor: executor,
72+
events: events.NewEmitter(nil),
73+
provider: provider,
74+
cwd: cwd,
75+
model: model,
76+
executor: executor,
77+
conductor: conductor,
6878
}
6979
}
7080

0 commit comments

Comments
 (0)