mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-03 05:20:01 +00:00
* feat(collaboration): isolate delegated artifacts and child runs Isolate delegated inputs and outputs behind secure artifact exchange lifecycles. Scope Agent Link tasks by tenant and root agent, and enforce delegation spawn-tree boundaries. Add process-wide child-run admission and preserve logical media paths across native, MCP, and sandbox execution. * fix(collaboration): harden delegated task isolation Enforce tenant and root-agent task scope across migrations and stores. Add exactly-once async completion delivery, delegated sandbox boundaries, and confined artifact and media recovery across runtime surfaces. * fix(collaboration): recover interrupted async tasks * fix(collaboration): normalize persisted child-run status --------- Co-authored-by: ntduc <ntduc@cpp.ai.vn>
85 lines
4.2 KiB
Go
85 lines
4.2 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// Link direction constants.
|
|
const (
|
|
LinkDirectionOutbound = "outbound"
|
|
LinkDirectionInbound = "inbound"
|
|
LinkDirectionBidirectional = "bidirectional"
|
|
)
|
|
|
|
// Link status constants.
|
|
const (
|
|
LinkStatusActive = "active"
|
|
LinkStatusDisabled = "disabled"
|
|
)
|
|
|
|
// AgentLinkData represents a directional link between two agents for delegation.
|
|
type AgentLinkData struct {
|
|
BaseModel
|
|
SourceAgentID uuid.UUID `json:"source_agent_id" db:"source_agent_id"`
|
|
TargetAgentID uuid.UUID `json:"target_agent_id" db:"target_agent_id"`
|
|
Direction string `json:"direction" db:"direction"` // "outbound", "inbound", "bidirectional"
|
|
TeamID *uuid.UUID `json:"team_id,omitempty" db:"team_id"` // non-nil = auto-created by team
|
|
Description string `json:"description,omitempty" db:"description"`
|
|
MaxConcurrent int `json:"max_concurrent" db:"max_concurrent"`
|
|
Settings json.RawMessage `json:"settings,omitempty" db:"settings"`
|
|
Status string `json:"status" db:"status"` // "active", "disabled"
|
|
CreatedBy string `json:"created_by" db:"created_by"`
|
|
|
|
// Joined fields (populated by queries that JOIN agents table)
|
|
SourceAgentKey string `json:"source_agent_key,omitempty" db:"source_agent_key"`
|
|
SourceDisplayName string `json:"source_display_name,omitempty" db:"source_display_name"`
|
|
SourceEmoji string `json:"source_emoji,omitempty" db:"source_emoji"`
|
|
TargetAgentKey string `json:"target_agent_key,omitempty" db:"target_agent_key"`
|
|
TargetDisplayName string `json:"target_display_name,omitempty" db:"target_display_name"`
|
|
TargetEmoji string `json:"target_emoji,omitempty" db:"target_emoji"`
|
|
TargetDescription string `json:"target_description,omitempty" db:"target_description"`
|
|
TeamName string `json:"team_name,omitempty" db:"team_name"` // from LEFT JOIN agent_teams (link's own team)
|
|
TargetIsTeamLead bool `json:"target_is_team_lead,omitempty" db:"target_is_team_lead"` // true if target is lead of any active team
|
|
TargetTeamName string `json:"target_team_name,omitempty" db:"target_team_name"` // name of team the target leads
|
|
}
|
|
|
|
// AgentLinkStore manages inter-agent delegation links.
|
|
type AgentLinkStore interface {
|
|
CreateLink(ctx context.Context, link *AgentLinkData) error
|
|
DeleteLink(ctx context.Context, id uuid.UUID) error
|
|
UpdateLink(ctx context.Context, id uuid.UUID, updates map[string]any) error
|
|
GetLink(ctx context.Context, id uuid.UUID) (*AgentLinkData, error)
|
|
|
|
// ListLinksFrom returns all links where agentID is the source.
|
|
ListLinksFrom(ctx context.Context, agentID uuid.UUID) ([]AgentLinkData, error)
|
|
|
|
// ListLinksTo returns all links where agentID is the target.
|
|
ListLinksTo(ctx context.Context, agentID uuid.UUID) ([]AgentLinkData, error)
|
|
|
|
// CanDelegate checks if fromAgent can delegate to toAgent considering direction.
|
|
CanDelegate(ctx context.Context, fromAgentID, toAgentID uuid.UUID) (bool, error)
|
|
|
|
// GetLinkBetween returns the active directional link allowing fromAgent to
|
|
// delegate to toAgent. MaxConcurrent is retained for API compatibility but
|
|
// is reserved and has no runtime admission effect.
|
|
// Returns full link data including Settings for per-user permission checks.
|
|
// Returns nil, nil if no matching link exists.
|
|
GetLinkBetween(ctx context.Context, fromAgentID, toAgentID uuid.UUID) (*AgentLinkData, error)
|
|
|
|
// DelegateTargets returns all agents that fromAgent can delegate to,
|
|
// with joined agent_key and display_name for AGENTS.md generation.
|
|
DelegateTargets(ctx context.Context, fromAgentID uuid.UUID) ([]AgentLinkData, error)
|
|
|
|
// SearchDelegateTargets performs FTS search over delegation targets.
|
|
SearchDelegateTargets(ctx context.Context, fromAgentID uuid.UUID, query string, limit int) ([]AgentLinkData, error)
|
|
|
|
// SearchDelegateTargetsByEmbedding performs vector similarity search over delegation targets.
|
|
SearchDelegateTargetsByEmbedding(ctx context.Context, fromAgentID uuid.UUID, embedding []float32, limit int) ([]AgentLinkData, error)
|
|
|
|
// DeleteTeamLinksForAgent removes all team-specific links involving an agent.
|
|
DeleteTeamLinksForAgent(ctx context.Context, teamID, agentID uuid.UUID) error
|
|
}
|