| 1 | package boot |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "errors" |
| 6 | |
| 7 | "reasonix/internal/agent" |
| 8 | "reasonix/internal/event" |
| 9 | "reasonix/internal/provider" |
| 10 | "reasonix/internal/tool" |
| 11 | ) |
| 12 | |
| 13 | func preserveSubagentFailure(run *agent.SubagentRun, store *agent.SubagentStore, cause error) (string, error) { |
| 14 | subErr := agent.NewSubagentRunError(run, cause) |
| 15 | var saveErr error |
| 16 | if store != nil { |
| 17 | saveErr = store.SaveOutcome(run, subErr.Outcome) |
| 18 | } |
| 19 | return subErr.SubagentOutput(), errors.Join(subErr, saveErr) |
| 20 | } |
| 21 | |
| 22 | func runReadOnlySkillSession(ctx context.Context, prov provider.Provider, reg *tool.Registry, prompt string, opts agent.Options, sink event.Sink, systemPrompt string, |
| 23 | runner func(context.Context, provider.Provider, *tool.Registry, *agent.Session, string, agent.Options, event.Sink) (string, error), |
| 24 | ) (string, error) { |
| 25 | run := agent.EphemeralSubagentRun(systemPrompt) |
| 26 | answer, err := runner(ctx, prov, reg, run.Session, prompt, opts, sink) |
| 27 | if err != nil { |
| 28 | return preserveSubagentFailure(run, nil, err) |
| 29 | } |
| 30 | return answer, nil |
| 31 | } |
| 32 | |
| 33 | func saveSubagentCompleted(store *agent.SubagentStore, run *agent.SubagentRun) error { |
| 34 | if store == nil { |
| 35 | return nil |
| 36 | } |
| 37 | return store.SaveCompleted(run) |
| 38 | } |
| 39 | |
| 40 | func announceSkillSubagentStart(sink event.Sink, parentID, skillName, model, effort string, run *agent.SubagentRun, continued bool) { |
| 41 | phase := "child_created" |
| 42 | if continued { |
| 43 | phase = "child_resume" |
| 44 | } |
| 45 | agent.EmitSubagentLifecycle(sink, phase, parentID, skillName, model, effort, run, nil) |
| 46 | } |
| 47 | |
| 48 | func finishSkillSubagentFailure(ctx context.Context, taskTool *agent.TaskTool, store *agent.SubagentStore, sink event.Sink, parentID, skillName, model, effort, taskText string, run *agent.SubagentRun, cause error) (string, error) { |
| 49 | result, runErr := preserveSubagentFailure(run, store, cause) |
| 50 | if taskTool != nil { |
| 51 | result, runErr = taskTool.ResolveAmbiguousSubagentFailure(ctx, run, taskText, model, sink, cause) |
| 52 | } |
| 53 | phase, outcome := agent.TerminalSubagentLifecycle(runErr) |
| 54 | agent.EmitSubagentLifecycle(sink, phase, parentID, skillName, model, effort, run, outcome) |
| 55 | return result, runErr |
| 56 | } |
| 57 |