refactor: extract loop.go fork fields into loopExt embedded struct

Move fork-specific AgentLoop fields to loop_ext.go via embedded struct:
- stats, sessions, orchBroadcaster, orchReporter
- planStartPending, planClearHistory, sessionLocks, activeTasks
- done, saveConfig, onHeartbeatThreadUpdate
- SetConfigSaver, SetHeartbeatThreadUpdater methods

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
dj-oyu 2026-03-13 16:06:41 +09:00
parent 9cdd71420f
commit fb662b02d3
2 changed files with 56 additions and 42 deletions

View file

@ -39,6 +39,8 @@ import (
)
type AgentLoop struct {
loopExt // fork-specific fields (see loop_ext.go)
bus *bus.MessageBus
cfg *config.Config
@ -47,8 +49,6 @@ type AgentLoop struct {
state *state.Manager
stats *stats.Tracker // nil when --stats not passed
running atomic.Bool
summarizing sync.Map
@ -67,16 +67,6 @@ type AgentLoop struct {
providerCache map[string]providers.LLMProvider
planStartPending bool // set by /plan start to trigger LLM execution
planClearHistory bool // set by /plan start clear to wipe history on transition
sessionLocks sync.Map // sessionKey → *sessionSemaphore
activeTasks sync.Map // sessionKey → *activeTask
sessions *SessionTracker
lastSystemPrompt atomic.Value // string — last system prompt sent to LLM
promptDirty atomic.Bool // true = rebuild needed on next GetSystemPrompt read
@ -84,16 +74,6 @@ type AgentLoop struct {
OnStateChange func() // called on plan/session/skills mutations
OnUserMessage func() // called when a real user message is processed
saveConfig func(*config.Config) error
onHeartbeatThreadUpdate func(int)
orchBroadcaster *orch.Broadcaster // nil when --orchestration not set
orchReporter orch.AgentReporter // always non-nil (Noop when disabled)
done chan struct{} // closed by Close() to stop background goroutines
}
// processOptions configures how a message is processed
@ -186,6 +166,14 @@ func NewAgentLoop(
}
al := &AgentLoop{
loopExt: loopExt{
stats: statsTracker,
sessions: NewSessionTracker(),
orchBroadcaster: orchBroadcaster,
orchReporter: orchReporter,
done: make(chan struct{}),
},
bus: msgBus,
cfg: cfg,
@ -194,22 +182,12 @@ func NewAgentLoop(
state: stateManager,
stats: statsTracker,
summarizing: sync.Map{},
fallback: fallbackChain,
providerCache: providerCache,
sessions: NewSessionTracker(),
orchBroadcaster: orchBroadcaster,
orchReporter: orchReporter,
done: make(chan struct{}),
cmdRegistry: commands.NewRegistry(commands.BuiltinDefinitions()),
}
@ -222,16 +200,6 @@ func NewAgentLoop(
return al
}
func (al *AgentLoop) SetConfigSaver(fn func(*config.Config) error) {
al.saveConfig = fn
}
// SetHeartbeatThreadUpdater registers a callback to apply runtime heartbeat thread updates.
func (al *AgentLoop) SetHeartbeatThreadUpdater(fn func(int)) {
al.onHeartbeatThreadUpdate = fn
}
// registerSharedTools registers tools that are shared across all agents (web, message, spawn).
func registerSharedTools(
cfg *config.Config,

46
pkg/agent/loop_ext.go Normal file
View file

@ -0,0 +1,46 @@
package agent
import (
"sync"
"github.com/sipeed/picoclaw/pkg/config"
"github.com/sipeed/picoclaw/pkg/orch"
"github.com/sipeed/picoclaw/pkg/stats"
)
// loopExt holds fork-specific fields for AgentLoop.
// Embedded in AgentLoop so existing field access (al.stats, al.sessions, etc.) continues to work.
// Upstream additions to AgentLoop won't conflict with these fields.
type loopExt struct {
stats *stats.Tracker // nil when --stats not passed
sessions *SessionTracker
orchBroadcaster *orch.Broadcaster // nil when --orchestration not set
orchReporter orch.AgentReporter // always non-nil (Noop when disabled)
planStartPending bool // set by /plan start to trigger LLM execution
planClearHistory bool // set by /plan start clear to wipe history on transition
sessionLocks sync.Map // sessionKey → *sessionSemaphore
activeTasks sync.Map // sessionKey → *activeTask
done chan struct{} // closed by Close() to stop background goroutines
saveConfig func(*config.Config) error
onHeartbeatThreadUpdate func(int)
}
// SetConfigSaver registers a callback to persist config changes.
func (al *AgentLoop) SetConfigSaver(fn func(*config.Config) error) {
al.saveConfig = fn
}
// SetHeartbeatThreadUpdater registers a callback to apply runtime heartbeat thread updates.
func (al *AgentLoop) SetHeartbeatThreadUpdater(fn func(int)) {
al.onHeartbeatThreadUpdate = fn
}