Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
6fe1aea83a
2 changed files with 43 additions and 4 deletions
|
|
@ -39,9 +39,10 @@ type AgentLoop struct {
|
||||||
stats *stats.Tracker // nil when --stats not passed
|
stats *stats.Tracker // nil when --stats not passed
|
||||||
running atomic.Bool
|
running atomic.Bool
|
||||||
summarizing sync.Map
|
summarizing sync.Map
|
||||||
fallback *providers.FallbackChain
|
fallback *providers.FallbackChain
|
||||||
channelManager *channels.Manager
|
channelManager *channels.Manager
|
||||||
providerCache map[string]providers.LLMProvider
|
providerCache map[string]providers.LLMProvider
|
||||||
|
planStartPending bool // set by /plan start to trigger LLM execution
|
||||||
}
|
}
|
||||||
|
|
||||||
// processOptions configures how a message is processed
|
// processOptions configures how a message is processed
|
||||||
|
|
@ -204,6 +205,23 @@ func (al *AgentLoop) Run(ctx context.Context) error {
|
||||||
SkipPlaceholder: true,
|
SkipPlaceholder: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// /plan start sets the flag — enqueue a synthetic message so
|
||||||
|
// the LLM worker actually begins executing the plan.
|
||||||
|
if al.planStartPending {
|
||||||
|
al.planStartPending = false
|
||||||
|
select {
|
||||||
|
case llmQueue <- bus.InboundMessage{
|
||||||
|
Channel: msg.Channel,
|
||||||
|
ChatID: msg.ChatID,
|
||||||
|
SenderID: msg.SenderID,
|
||||||
|
SessionKey: msg.SessionKey,
|
||||||
|
Content: "The plan has been approved. Begin executing.",
|
||||||
|
Metadata: msg.Metadata,
|
||||||
|
}:
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1644,6 +1662,7 @@ func (al *AgentLoop) handlePlanCommand(args []string) (string, bool) {
|
||||||
if err := agent.ContextBuilder.SetPlanStatus("executing"); err != nil {
|
if err := agent.ContextBuilder.SetPlanStatus("executing"); err != nil {
|
||||||
return fmt.Sprintf("Error: %v", err), true
|
return fmt.Sprintf("Error: %v", err), true
|
||||||
}
|
}
|
||||||
|
al.planStartPending = true
|
||||||
return "Plan approved. Executing.", true
|
return "Plan approved. Executing.", true
|
||||||
|
|
||||||
case "next":
|
case "next":
|
||||||
|
|
|
||||||
|
|
@ -1044,6 +1044,11 @@ func TestPlanCommand_Start(t *testing.T) {
|
||||||
if status := agent.ContextBuilder.GetPlanStatus(); status != "executing" {
|
if status := agent.ContextBuilder.GetPlanStatus(); status != "executing" {
|
||||||
t.Errorf("expected 'executing', got %q", status)
|
t.Errorf("expected 'executing', got %q", status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// planStartPending must be set so Run() enqueues an LLM trigger
|
||||||
|
if !al.planStartPending {
|
||||||
|
t.Error("expected planStartPending to be true after /plan start")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPlanCommand_StartFromReview(t *testing.T) {
|
func TestPlanCommand_StartFromReview(t *testing.T) {
|
||||||
|
|
@ -1065,6 +1070,10 @@ func TestPlanCommand_StartFromReview(t *testing.T) {
|
||||||
if status := agent.ContextBuilder.GetPlanStatus(); status != "executing" {
|
if status := agent.ContextBuilder.GetPlanStatus(); status != "executing" {
|
||||||
t.Errorf("expected 'executing', got %q", status)
|
t.Errorf("expected 'executing', got %q", status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !al.planStartPending {
|
||||||
|
t.Error("expected planStartPending to be true after /plan start from review")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPlanCommand_StartNoPhases(t *testing.T) {
|
func TestPlanCommand_StartNoPhases(t *testing.T) {
|
||||||
|
|
@ -1084,6 +1093,10 @@ func TestPlanCommand_StartNoPhases(t *testing.T) {
|
||||||
if status := agent.ContextBuilder.GetPlanStatus(); status != "interviewing" {
|
if status := agent.ContextBuilder.GetPlanStatus(); status != "interviewing" {
|
||||||
t.Errorf("expected status to remain 'interviewing', got %q", status)
|
t.Errorf("expected status to remain 'interviewing', got %q", status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if al.planStartPending {
|
||||||
|
t.Error("planStartPending must not be set when start is rejected (no phases)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPlanCommand_StartAlreadyExecuting(t *testing.T) {
|
func TestPlanCommand_StartAlreadyExecuting(t *testing.T) {
|
||||||
|
|
@ -1097,11 +1110,18 @@ func TestPlanCommand_StartAlreadyExecuting(t *testing.T) {
|
||||||
_ = agent.ContextBuilder.WriteMemory(plan)
|
_ = agent.ContextBuilder.WriteMemory(plan)
|
||||||
al.handleCommand(context.Background(), bus.InboundMessage{Content: "/plan start"})
|
al.handleCommand(context.Background(), bus.InboundMessage{Content: "/plan start"})
|
||||||
|
|
||||||
// Try start again
|
// Clear the flag from the first call (simulating Run() consuming it)
|
||||||
|
al.planStartPending = false
|
||||||
|
|
||||||
|
// Try start again — should be rejected
|
||||||
response, _ := al.handleCommand(context.Background(), bus.InboundMessage{Content: "/plan start"})
|
response, _ := al.handleCommand(context.Background(), bus.InboundMessage{Content: "/plan start"})
|
||||||
if !strings.Contains(response, "already executing") {
|
if !strings.Contains(response, "already executing") {
|
||||||
t.Errorf("expected 'already executing', got %q", response)
|
t.Errorf("expected 'already executing', got %q", response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if al.planStartPending {
|
||||||
|
t.Error("planStartPending must not be set when plan is already executing")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPlanCommand_Done(t *testing.T) {
|
func TestPlanCommand_Done(t *testing.T) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue