summaryrefslogtreecommitdiff
path: root/internal/executor/channel.go
diff options
context:
space:
mode:
authorClaude Sonnet 5 <noreply@anthropic.com>2026-07-03 08:49:43 +0000
committerClaude Sonnet 5 <noreply@anthropic.com>2026-07-03 08:49:43 +0000
commit67e0081c6d573b701ed931f96e14dbe5b4258a17 (patch)
treebc7f8ce0d57876dd85720924d0275dc39c05e5b4 /internal/executor/channel.go
parent3d286974cdc28c68c5ee536ce9303899dae9540e (diff)
refactor(executor): extract provider-neutral tool-use loop (Phase 1)
Splits LocalRunner's OpenAI-specific agentic loop into reusable, provider- agnostic pieces so later phases can add native Anthropic/OpenAI/Google/Groq/ OpenRouter adapters without duplicating the control flow: - internal/provider: neutral Provider/ChatRequest/ChatResponse types, plus an openaicompat adapter wrapping the existing internal/llm.Client unchanged - internal/sandbox: Sandbox interface + HostSandbox (git clone/push/cleanup, read_file/write_file/run_bash/glob), lifted verbatim from local.go/localtools.go - internal/agentloop: the extracted tool-use loop (request/response/tool- dispatch/loop, ask_user blocking, stream-json envelope, summary fallback) - internal/agentchannel: AgentChannel/SubtaskSpec/BlockedError/ErrAgentBlocked moved out of internal/executor so agentloop can use them without an import cycle; internal/executor re-exports via type aliases, so no call site changes - internal/executor/nativerunner.go: NativeRunner replaces LocalRunner, wiring agentloop.Loop + openaicompat + HostSandbox together - config.Providers map[string]ProviderConfig added (unused until Phase 2+) Zero intended behavior change: go test -race ./... passes across all packages, and end-to-end stream-json/summary/changestats output was verified byte-compatible against a fake OpenAI-compatible server. Adds test coverage for sandbox tool-dispatch (git clone/push, read/write/bash/glob) that LocalRunner never had. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V1moSNCJRcP6kykA4tyUSs
Diffstat (limited to 'internal/executor/channel.go')
-rw-r--r--internal/executor/channel.go51
1 files changed, 19 insertions, 32 deletions
diff --git a/internal/executor/channel.go b/internal/executor/channel.go
index 8605ffa..debe21d 100644
--- a/internal/executor/channel.go
+++ b/internal/executor/channel.go
@@ -3,46 +3,33 @@ package executor
import (
"context"
"encoding/json"
- "errors"
"sync"
"time"
+ "github.com/thepeterstone/claudomator/internal/agentchannel"
"github.com/thepeterstone/claudomator/internal/event"
"github.com/thepeterstone/claudomator/internal/task"
"github.com/google/uuid"
)
-// ErrAgentBlocked is returned by AgentChannel.AskUser when the transport cannot
-// deliver an answer within the current run — e.g. the file transport, which can
-// only write-and-exit. Runners translate it into a *BlockedError so the task
-// blocks and resumes later. Transports that can suspend the agent in-session
-// (MCP, Phase 2) instead block and return the answer.
-var ErrAgentBlocked = errors.New("agent blocked awaiting user input")
-
-// SubtaskSpec describes a child task an agent wants to spawn.
-type SubtaskSpec struct {
- Name string
- Instructions string
- Model string
- MaxBudgetUSD float64
-}
-
-// AgentChannel is how a Runner reports agent-originated signals to the rest of
-// the system. Implementations translate these into stored artifacts and events.
-// The transport by which a Runner detects these signals — post-exit files
-// today, MCP/tool-use in Phase 2 — is the Runner's private concern.
-type AgentChannel interface {
- // AskUser records that the agent needs human input. Transports that can
- // suspend the agent in-session return the answer; those that cannot return
- // ErrAgentBlocked.
- AskUser(ctx context.Context, questionJSON string) (answer string, err error)
- // ReportSummary records the agent's final summary text.
- ReportSummary(ctx context.Context, summary string) error
- // SpawnSubtask creates a child task and returns its ID.
- SpawnSubtask(ctx context.Context, spec SubtaskSpec) (taskID string, err error)
- // RecordProgress records a free-form progress note from the agent.
- RecordProgress(ctx context.Context, message string) error
-}
+// AgentChannel, SubtaskSpec, BlockedError, and ErrAgentBlocked used to be
+// defined directly in this package. Phase 1 of the multi-provider refactor
+// moved them to internal/agentchannel (a small leaf package with no
+// executor dependency) so that internal/agentloop — the new provider-neutral
+// tool-use loop — can construct/inspect them without importing
+// internal/executor. That matters because internal/executor now imports
+// internal/agentloop (via nativerunner.go, which wires an agentloop.Loop up
+// to a Runner); if agentloop imported executor too, that would be a direct
+// import cycle. Re-exporting via type aliases (and a var assignment for the
+// sentinel error) here means every existing reference to
+// executor.AgentChannel / executor.SubtaskSpec / executor.BlockedError /
+// executor.ErrAgentBlocked keeps compiling and behaving identically — an
+// alias is the same type, not a copy.
+type AgentChannel = agentchannel.AgentChannel
+type SubtaskSpec = agentchannel.SubtaskSpec
+type BlockedError = agentchannel.BlockedError
+
+var ErrAgentBlocked = agentchannel.ErrAgentBlocked
// channelStore is the subset of storage the default channel needs.
type channelStore interface {