p9: queue steps via agent.Core.Queue; yield message on plan

- queuePlanBackend now holds agent.Core and calls Queue() directly
  instead of writing to a filesystem path (enqueue is a virtual file)
- fallback.core wired after NewAgentCore in createSession
- Returns yield message so agent stops after planning and lets the
  queue drive execution step by step

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Levi Neely 2026-04-11 17:24:47 +02:00
parent 8fa4a8e101
commit 8070238390
2 changed files with 16 additions and 12 deletions

View File

@ -3,30 +3,30 @@ package p9
import (
"context"
"fmt"
"os"
"strings"
"ollie/pkg/agent"
"ollie/pkg/tools"
)
// queuePlanBackend implements tools.PlanBackend by enqueuing each step as a
// prompt into the session's queue file. It is used as the reasoning_plan
// fallback when no task_create MCP tool is available.
// prompt into the session's queue via agent.Core.Queue. It is used as the
// reasoning_plan fallback when no task_create MCP tool is available.
//
// Steps are enqueued in topological order (blockers before dependents). The
// goal description is prepended to the first step for context. Placeholder IDs
// ("q1", "q2", …) are returned so the agent can refer to steps by name.
type queuePlanBackend struct {
enqueuePath string // absolute path to the session's enqueue file
core agent.Core
}
// CreatePlan enqueues each plan step as a prompt. Steps with After dependencies
// are sorted so blockers are enqueued before the steps that depend on them.
// The returned IDs are positional placeholders ("q1", "q2", …).
func (b *queuePlanBackend) CreatePlan(_ context.Context, goal string, steps []tools.PlanStep) ([]string, error) {
func (b *queuePlanBackend) CreatePlan(_ context.Context, goal string, steps []tools.PlanStep) ([]string, string, error) {
order, err := topoSort(steps)
if err != nil {
return nil, fmt.Errorf("queue plan: %w", err)
return nil, "", fmt.Errorf("queue plan: %w", err)
}
ids := make([]string, len(steps))
@ -61,11 +61,15 @@ func (b *queuePlanBackend) CreatePlan(_ context.Context, goal string, steps []to
sb.WriteString(")")
}
if err := os.WriteFile(b.enqueuePath, []byte(sb.String()+"\n"), 0644); err != nil {
return nil, fmt.Errorf("enqueue step %s: %w", ids[idx], err)
}
b.core.Queue(sb.String())
}
return ids, nil
msg := fmt.Sprintf(
"Plan queued (%d steps). Stop here — do not execute. "+
"The queue will re-enter you with each step in order.",
len(steps),
)
return ids, msg, nil
}
// topoSort returns the indices of steps in topological order (blockers first).

View File

@ -857,8 +857,7 @@ func (s *Server) createSession(args []string) error {
})
sessID := agent.NewSessionID()
enqueuePath := s.sessionsDir + "/" + sessID + "/enqueue"
fallback := &queuePlanBackend{enqueuePath: enqueuePath}
fallback := &queuePlanBackend{}
env := agent.BuildAgentEnv(cfg, newDisp(), workdir, agent.WithFallbackPlanBackend(fallback))
ctx, cancel := context.WithCancel(context.Background())
@ -872,6 +871,7 @@ func (s *Server) createSession(args []string) error {
Env: env,
NewDispatcher: newDisp,
})
fallback.core = core
sess := &session{
id: sessID,