mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-11 12:18:59 +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>
106 lines
3.6 KiB
Go
106 lines
3.6 KiB
Go
// Package edition defines feature tiers for GoClaw.
|
|
// Set once at startup via SetCurrent(), read everywhere via Current().
|
|
// Adding a new edition = add one preset struct. No code changes elsewhere.
|
|
package edition
|
|
|
|
import "sync/atomic"
|
|
|
|
// Edition defines the feature limits for a GoClaw instance.
|
|
type Edition struct {
|
|
Name string `json:"name"` // "standard" or "lite"
|
|
MaxAgents int `json:"max_agents"` // 0 = unlimited
|
|
MaxTeams int `json:"max_teams"` // 0 = unlimited
|
|
MaxTeamMembers int `json:"max_team_members"` // 0 = unlimited
|
|
MaxChannels map[string]int `json:"max_channels"` // per channel type, nil = unlimited
|
|
MaxSubagentConcurrent int `json:"max_subagent_concurrent"` // 0 = unlimited
|
|
MaxSubagentDepth int `json:"max_subagent_depth"` // 0 = use config default
|
|
KGEnabled bool `json:"kg_enabled"`
|
|
RBACEnabled bool `json:"rbac_enabled"`
|
|
TeamFullMode bool `json:"team_full_mode"` // false = lite task actions only
|
|
VectorSearch bool `json:"vector_search"` // false = FTS5 only
|
|
SupportsPipNpm bool `json:"supports_pip_npm"` // false for Lite desktop
|
|
SupportsApk bool `json:"supports_apk"` // false for Lite desktop (no apk on macOS/Windows)
|
|
}
|
|
|
|
// --- Presets ---
|
|
|
|
// Standard is the default edition: all features enabled, no limits.
|
|
var Standard = Edition{
|
|
Name: "standard",
|
|
KGEnabled: true,
|
|
RBACEnabled: true,
|
|
TeamFullMode: true,
|
|
VectorSearch: true,
|
|
SupportsPipNpm: true,
|
|
SupportsApk: true,
|
|
}
|
|
|
|
// Lite is the desktop/self-hosted edition with sensible limits.
|
|
var Lite = Edition{
|
|
Name: "lite",
|
|
MaxAgents: 5,
|
|
MaxTeams: 1,
|
|
MaxTeamMembers: 5,
|
|
MaxChannels: map[string]int{"telegram": 1, "discord": 1},
|
|
MaxSubagentConcurrent: 2,
|
|
MaxSubagentDepth: 1,
|
|
KGEnabled: false,
|
|
RBACEnabled: false,
|
|
TeamFullMode: false,
|
|
VectorSearch: false,
|
|
SupportsPipNpm: false,
|
|
SupportsApk: false,
|
|
}
|
|
|
|
// --- Global state ---
|
|
|
|
// current holds the active edition. Atomic pointer for safe concurrent reads.
|
|
var current atomic.Pointer[Edition]
|
|
|
|
func init() {
|
|
std := Standard
|
|
current.Store(&std)
|
|
}
|
|
|
|
// Current returns the active edition. Safe for concurrent use.
|
|
func Current() Edition {
|
|
return *current.Load()
|
|
}
|
|
|
|
// SetCurrent sets the active edition. Call once at startup.
|
|
func SetCurrent(e Edition) {
|
|
current.Store(&e)
|
|
}
|
|
|
|
// --- Helpers ---
|
|
|
|
// IsLimited returns true if the edition enforces resource limits.
|
|
func (e Edition) IsLimited() bool {
|
|
return e.MaxAgents > 0 || e.MaxTeams > 0
|
|
}
|
|
|
|
// ChannelLimit returns the max instances for a channel type.
|
|
// Returns 0 (unlimited) if the channel type is not in MaxChannels.
|
|
func (e Edition) ChannelLimit(channelType string) int {
|
|
if e.MaxChannels == nil {
|
|
return 0
|
|
}
|
|
return e.MaxChannels[channelType]
|
|
}
|
|
|
|
// AllowsChannels reports whether this edition permits channel-based webhook routes
|
|
// (kind="message"). Standard edition allows channels; Lite does not.
|
|
func (e Edition) AllowsChannels() bool {
|
|
return e.Name == "standard"
|
|
}
|
|
|
|
// ChildRunLimit returns the process-wide cap for executing self-spawn and
|
|
// Agent Link child callbacks. It is separate from the per-agent
|
|
// maxConcurrent setting and is intentionally not serialized.
|
|
func (e Edition) ChildRunLimit() int {
|
|
if e.Name == Lite.Name {
|
|
return 2
|
|
}
|
|
return 32
|
|
}
|