Files
goclaw/internal/tools/team_tool_manager.go
viettranx e9342533e0 refactor(tools): extract TeamToolBackend interface for team task testability
Extract TeamToolBackend interface from concrete *TeamToolManager to enable
unit testing of the 17 team task action handlers without DB or message bus.

- Add TeamToolBackend interface (19 methods) in team_tool_backend.go
- Add exported wrappers on TeamToolManager (cache, helpers, dispatch, manager)
- Migrate 133 call sites across 5 action handler files (pure casing rename)
- Change TeamTasksTool.manager field from *TeamToolManager to TeamToolBackend
- Add mock backend infrastructure (baseNoopTeamStore + mockTaskStore + mockBackend)
- Add 94 unit subtests across 6 test files covering all actions:
  lifecycle (claim/complete/cancel/review/approve/reject),
  create validation, blocker escalation, mutations (comment/progress/attach/update),
  followup (ask_user/clear_ask_user/retry), read actions (notification/policy/list/search/get)

WorkspaceInterceptor and PostTurnProcessor remain on concrete *TeamToolManager.
No behavioral changes — all existing logic preserved.
2026-03-27 22:26:36 +07:00

59 lines
2.2 KiB
Go

package tools
import (
"sync"
"time"
"github.com/nextlevelbuilder/goclaw/internal/bus"
"github.com/nextlevelbuilder/goclaw/internal/store"
)
const teamCacheTTL = 5 * time.Minute
// teamCacheEntry wraps cached team data + members with a timestamp for TTL expiration.
type teamCacheEntry struct {
team *store.TeamData
members []store.TeamMemberData // loaded together with team to avoid separate DB call
cachedAt time.Time
}
// agentCacheEntry wraps cached agent data with a timestamp for TTL expiration.
type agentCacheEntry struct {
agent *store.AgentData
cachedAt time.Time
}
// TeamToolManager is the shared backend for team_tasks tool and workspace interceptor.
// It resolves the calling agent's team from context and provides access to
// the team store, agent store, and message bus.
// Includes a TTL cache for team data to avoid DB queries on every tool call.
type TeamToolManager struct {
teamStore store.TeamStore
agentStore store.AgentStore
msgBus *bus.MessageBus
dataDir string // base data directory for workspace path resolution
teamCache sync.Map // agentID (uuid.UUID) → *teamCacheEntry
agentCache sync.Map // agentID (uuid.UUID) → *agentCacheEntry
agentKeyCache sync.Map // agentKey (string) → *agentCacheEntry
}
func NewTeamToolManager(teamStore store.TeamStore, agentStore store.AgentStore, msgBus *bus.MessageBus, dataDir string) *TeamToolManager {
return &TeamToolManager{teamStore: teamStore, agentStore: agentStore, msgBus: msgBus, dataDir: dataDir}
}
// ============================================================
// TeamToolBackend exported wrappers
// These thin wrappers satisfy the TeamToolBackend interface
// while keeping the unexported originals for internal use
// (WorkspaceInterceptor, PostTurnProcessor, etc.).
// ============================================================
func (m *TeamToolManager) Store() store.TeamStore { return m.teamStore }
func (m *TeamToolManager) DataDir() string { return m.dataDir }
func (m *TeamToolManager) TryPublishInbound(msg bus.InboundMessage) bool {
if m.msgBus == nil {
return false
}
return m.msgBus.TryPublishInbound(msg)
}