| 1 | package boot |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "os" |
| 6 | |
| 7 | "reasonix/internal/ablation" |
| 8 | "reasonix/internal/agent" |
| 9 | "reasonix/internal/config" |
| 10 | "reasonix/internal/control" |
| 11 | "reasonix/internal/event" |
| 12 | "reasonix/internal/provider" |
| 13 | "reasonix/internal/sandbox" |
| 14 | "reasonix/internal/skill" |
| 15 | "reasonix/internal/tool" |
| 16 | "reasonix/internal/workspacelease" |
| 17 | ) |
| 18 | |
| 19 | func newSubagentSkillOptionsFactory( |
| 20 | cfg config.AgentConfig, |
| 21 | quoteCtx *event.QuoteContext, |
| 22 | gate agent.Gate, |
| 23 | keepPolicy agent.KeepPolicy, |
| 24 | maxDepth int, |
| 25 | ablationSet ablation.Set, |
| 26 | lease *workspacelease.Owner, |
| 27 | writeRoots *sandbox.WritableRootSet, |
| 28 | imageRoutes ...childImageRouting, |
| 29 | ) func(context.Context, int, *provider.Pricing, int, int) agent.Options { |
| 30 | home, stateRoot := userHomeDir(), config.MemoryUserDir() |
| 31 | return func(ctx context.Context, steps int, price *provider.Pricing, ctxWin, childDepth int) agent.Options { |
| 32 | opts := agent.Options{ |
| 33 | MaxSteps: steps, Temperature: cfg.Temperature, Pricing: price, QuoteContext: quoteCtx, UsageSource: event.UsageSourceSubagent, |
| 34 | Gate: gate, ContextWindow: ctxWin, RecentKeep: cfg.RecentKeep, |
| 35 | SoftCompactRatio: cfg.SoftCompactRatio, ToolResultSnipRatio: cfg.ToolResultSnipRatio, |
| 36 | CompactRatio: cfg.CompactRatio, CompactForceRatio: cfg.CompactForceRatio, ContextEditing: cfg.ContextEditing, |
| 37 | ArchiveDir: config.ArchiveDir(), KeepPolicy: keepPolicy, |
| 38 | ResponseLanguage: agent.ResponseLanguageFromContext(ctx), ReasoningLanguage: agent.ReasoningLanguageFromContext(ctx), |
| 39 | SubagentDepth: childDepth, MaxSubagentDepth: maxDepth, |
| 40 | Ablation: ablationSet, WorkspaceLease: lease, WriteRoots: writeRoots, |
| 41 | DisableWriteAccessExpand: true, HomeDir: home, StateRoot: stateRoot, |
| 42 | } |
| 43 | if len(imageRoutes) > 0 { |
| 44 | opts.ImageRequestResolver = imageRoutes[0].controller() |
| 45 | opts.ImageInput = imageRoutes[0].config |
| 46 | } |
| 47 | return opts |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | func reviewSubagentSkillOptions( |
| 52 | ctx context.Context, |
| 53 | profile, task string, |
| 54 | steps int, |
| 55 | price *provider.Pricing, |
| 56 | ctxWin, childDepth int, |
| 57 | factory func(context.Context, int, *provider.Pricing, int, int) agent.Options, |
| 58 | ) (string, agent.Options) { |
| 59 | reviewTokens := 0 |
| 60 | if reviewTask, reviewSteps, tokens, ok := agent.PrepareReviewSubagentContext(ctx, profile, task); ok { |
| 61 | task, steps, reviewTokens = reviewTask, reviewSteps, tokens |
| 62 | } |
| 63 | opts := factory(ctx, steps, price, ctxWin, childDepth) |
| 64 | if reviewTokens > 0 { |
| 65 | opts.MaxOutputTokens = reviewTokens |
| 66 | } |
| 67 | return task, opts |
| 68 | } |
| 69 | |
| 70 | func skillSubagentRegistry( |
| 71 | sk skill.Skill, |
| 72 | parent *tool.Registry, |
| 73 | childDepth, maxDepth int, |
| 74 | runtime *agent.MCPCapabilityRuntime, |
| 75 | writeRoots *sandbox.WritableRootSet, |
| 76 | ) (*tool.Registry, *sandbox.WritableRootSet) { |
| 77 | if sk.ReadOnly { |
| 78 | return agent.ReadOnlySubagentToolRegistryForDepthWithRuntime(parent, sk.AllowedTools, childDepth, maxDepth, runtime), nil |
| 79 | } |
| 80 | reg := agent.SubagentToolRegistryForDepthWithRuntime(parent, sk.AllowedTools, childDepth, maxDepth, runtime) |
| 81 | return agent.BindChildWriteRoots(reg, writeRoots, agent.WritePathSet{}) |
| 82 | } |
| 83 | |
| 84 | func projectWriteAccessPersister(root string) control.PersistWriteAccessFunc { |
| 85 | return func(dirs []string, permRule string) error { |
| 86 | return config.PersistProjectWriteAccess(rememberPermissionConfigPath(root), dirs, permRule) |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | func userHomeDir() string { |
| 91 | home, _ := os.UserHomeDir() |
| 92 | return home |
| 93 | } |
| 94 |