Skip to content

Commit 7dbb275

Browse files
committed
logging and metrics
1 parent d457092 commit 7dbb275

12 files changed

+704
-572
lines changed

internal/core/runtime/command_executor_failure_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func TestCommandFailureLogging(t *testing.T) {
4242
},
4343
}
4444

45-
exec := NewCommandExecutor()
45+
exec := NewCommandExecutor(nil, nil)
4646

4747
// Execute and expect an error.
4848
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)

internal/core/runtime/command_executor_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func TestEnforceObservationLimit(t *testing.T) {
104104
func TestCommandExecutorExecuteInternal(t *testing.T) {
105105
t.Parallel()
106106

107-
executor := NewCommandExecutor()
107+
executor := NewCommandExecutor(nil, nil)
108108
if err := executor.RegisterInternalCommand("beep", func(_ context.Context, req InternalCommandRequest) (PlanObservationPayload, error) {
109109
if req.Name != "beep" {
110110
return PlanObservationPayload{}, fmt.Errorf("unexpected name %q", req.Name)
@@ -148,7 +148,7 @@ func TestCommandExecutorExecuteBuiltinApplyPatch(t *testing.T) {
148148
t.Fatalf("failed to seed file: %v", err)
149149
}
150150

151-
executor := NewCommandExecutor()
151+
executor := NewCommandExecutor(nil, nil)
152152
if err := registerBuiltinInternalCommands(nil, executor); err != nil {
153153
t.Fatalf("failed to register builtins: %v", err)
154154
}
@@ -184,7 +184,7 @@ func TestCommandExecutorExecuteBuiltinApplyPatch(t *testing.T) {
184184
func TestCommandExecutorExecuteInternalUnknown(t *testing.T) {
185185
t.Parallel()
186186

187-
executor := NewCommandExecutor()
187+
executor := NewCommandExecutor(nil, nil)
188188
step := PlanStep{ID: "step-1", Command: CommandDraft{Shell: agentShell, Run: "noop"}}
189189
_, err := executor.Execute(context.Background(), step)
190190
if err == nil || !strings.Contains(err.Error(), "unknown internal command") {

internal/core/runtime/loop.go

Lines changed: 1 addition & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -168,110 +168,7 @@ func (r *Runtime) handlePrompt(ctx context.Context, evt InputEvent) error {
168168
return nil
169169
}
170170

171-
func (r *Runtime) planExecutionLoop(ctx context.Context) {
172-
for {
173-
if ctx.Err() != nil {
174-
return
175-
}
176-
177-
pass := r.incrementPassCount()
178-
r.options.Metrics.RecordPass(pass)
179-
r.options.Logger.Info(ctx, "Starting plan execution pass",
180-
Field("pass", pass),
181-
)
182-
183-
if r.options.MaxPasses > 0 && pass > r.options.MaxPasses {
184-
message := fmt.Sprintf("Maximum pass limit (%d) reached. Stopping execution.", r.options.MaxPasses)
185-
r.emit(RuntimeEvent{
186-
Type: EventTypeError,
187-
Message: message,
188-
Level: StatusLevelError,
189-
Metadata: map[string]any{"max_passes": r.options.MaxPasses, "pass": pass},
190-
})
191-
r.emitRequestInput("Pass limit reached. Provide additional guidance to continue.")
192-
if r.options.HandsFree {
193-
r.close()
194-
}
195-
return
196-
}
197-
198-
r.emit(RuntimeEvent{
199-
Type: EventTypeStatus,
200-
Message: fmt.Sprintf("Starting plan execution pass #%d.", pass),
201-
Level: StatusLevelInfo,
202-
})
203-
204-
plan, toolCall, err := r.requestPlan(ctx)
205-
if err != nil {
206-
r.options.Logger.Error(ctx, "Failed to request plan from OpenAI", err,
207-
Field("pass", pass),
208-
)
209-
r.emit(RuntimeEvent{
210-
Type: EventTypeError,
211-
Message: fmt.Sprintf("Failed to contact OpenAI: %v", err),
212-
Level: StatusLevelError,
213-
})
214-
r.emitRequestInput("You can provide another prompt.")
215-
return
216-
}
217-
218-
if plan == nil {
219-
r.options.Logger.Error(ctx, "Received nil plan response", nil,
220-
Field("pass", pass),
221-
)
222-
r.emit(RuntimeEvent{
223-
Type: EventTypeError,
224-
Message: "Received nil plan response.",
225-
Level: StatusLevelError,
226-
})
227-
r.emitRequestInput("Unable to continue plan execution. Provide the next instruction.")
228-
return
229-
}
230-
231-
execCount := r.recordPlanResponse(plan, toolCall)
232-
233-
if plan.RequireHumanInput {
234-
// The assistant explicitly requested help from the human, so surface the
235-
// request and pause automated execution until the user responds.
236-
r.appendToolObservation(toolCall, PlanObservationPayload{
237-
Summary: "Assistant requested additional input before continuing the plan.",
238-
})
239-
r.emitRequestInput("Assistant requested additional input before continuing.")
240-
return
241-
}
242-
243-
if execCount == 0 {
244-
r.appendToolObservation(toolCall, PlanObservationPayload{
245-
Summary: "Assistant returned a plan without executable steps.",
246-
})
247-
r.emit(RuntimeEvent{
248-
Type: EventTypeStatus,
249-
Message: "Plan has no executable steps.",
250-
Level: StatusLevelInfo,
251-
})
252-
if r.options.HandsFree {
253-
summary := fmt.Sprintf("Hands-free session complete after %d pass(es); assistant reported no further work.", pass)
254-
if trimmed := strings.TrimSpace(plan.Message); trimmed != "" {
255-
summary = fmt.Sprintf("%s Summary: %s", summary, trimmed)
256-
}
257-
r.emit(RuntimeEvent{
258-
Type: EventTypeStatus,
259-
Message: summary,
260-
Level: StatusLevelInfo,
261-
})
262-
r.close()
263-
return
264-
}
265-
r.emitRequestInput("Plan has no executable steps. Provide the next instruction.")
266-
return
267-
}
268-
269-
r.executePendingCommands(ctx, toolCall)
270-
if ctx.Err() != nil {
271-
return
272-
}
273-
}
274-
}
171+
// planExecutionLoop is now implemented in plan_execution.go
275172

276173
// requestPlan centralizes the logic for requesting a new plan from the assistant.
277174
// It snapshots the history to guarantee a consistent view, forwards the request

internal/core/runtime/loop_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func TestPlanExecutionLoopPausesForHumanInput(t *testing.T) {
140140
"data: [DONE]\n\n"
141141
transport := &stubTransport{body: []byte(sse), statusCode: http.StatusOK}
142142

143-
client, err := NewOpenAIClient("test-key", "gpt-4o", "", "")
143+
client, err := NewOpenAIClient("test-key", "gpt-4o", "", "", nil, nil)
144144
if err != nil {
145145
t.Fatalf("failed to create client: %v", err)
146146
}
@@ -158,7 +158,7 @@ func TestPlanExecutionLoopPausesForHumanInput(t *testing.T) {
158158
closed: make(chan struct{}),
159159
plan: NewPlanManager(),
160160
client: client,
161-
executor: NewCommandExecutor(),
161+
executor: NewCommandExecutor(nil, nil),
162162
history: []ChatMessage{{Role: RoleSystem, Content: "system"}},
163163
agentName: "main",
164164
}
@@ -226,7 +226,7 @@ func TestPlanExecutionLoopHandsFreeCompletes(t *testing.T) {
226226
"data: [DONE]\n\n"
227227
transport := &stubTransport{body: []byte(sse), statusCode: http.StatusOK}
228228

229-
client, err := NewOpenAIClient("test-key", "gpt-4o", "", "")
229+
client, err := NewOpenAIClient("test-key", "gpt-4o", "", "", nil, nil)
230230
if err != nil {
231231
t.Fatalf("failed to create client: %v", err)
232232
}
@@ -245,7 +245,7 @@ func TestPlanExecutionLoopHandsFreeCompletes(t *testing.T) {
245245
closed: make(chan struct{}),
246246
plan: NewPlanManager(),
247247
client: client,
248-
executor: NewCommandExecutor(),
248+
executor: NewCommandExecutor(nil, nil),
249249
history: []ChatMessage{{Role: RoleSystem, Content: "system"}},
250250
agentName: "main",
251251
}
@@ -323,13 +323,13 @@ func TestPlanExecutionLoopHandsFreeStopsAtPassLimit(t *testing.T) {
323323
"data: [DONE]\n\n"
324324
transport := &stubTransport{body: []byte(sse), statusCode: http.StatusOK}
325325

326-
client, err := NewOpenAIClient("test-key", "gpt-4o", "", "")
326+
client, err := NewOpenAIClient("test-key", "gpt-4o", "", "", nil, nil)
327327
if err != nil {
328328
t.Fatalf("failed to create client: %v", err)
329329
}
330330
client.httpClient = &http.Client{Transport: transport}
331331

332-
executor := NewCommandExecutor()
332+
executor := NewCommandExecutor(nil, nil)
333333
if err := executor.RegisterInternalCommand("noop", func(_ context.Context, _ InternalCommandRequest) (PlanObservationPayload, error) {
334334
return PlanObservationPayload{Summary: "noop", ExitCode: &zero}, nil
335335
}); err != nil {

0 commit comments

Comments
 (0)