Class: Tools::SpawnSubagent

Inherits:
Base
  • Object
show all
Includes:
SubagentPrompts
Defined in:
lib/tools/spawn_subagent.rb

Overview

Spawns a generic child session that works on a task autonomously. The sub-agent starts clean — no parent conversation history — with only a system prompt, a Goal, and the task as its first user message. Runs via DrainJob and communicates with the parent through natural text messages routed by Events::Subscribers::SubagentMessageRouter.

Nickname assignment is handled by the Melete::Runner which runs synchronously at spawn time — the same muse that manages skills, goals, and workflows for the main session.

For named specialists with predefined prompts and tools, see SpawnSpecialist.

Constant Summary collapse

GENERIC_PROMPT =
"#{COMMUNICATION_INSTRUCTION}\n"

Constants included from SubagentPrompts

Tools::SubagentPrompts::COMMUNICATION_INSTRUCTION, Tools::SubagentPrompts::IDENTITY_TEMPLATE, Tools::SubagentPrompts::PROMPT_GUIDELINES

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

schema, truncation_threshold

Constructor Details

#initialize(session:, tool_use_id: nil) ⇒ SpawnSubagent

Returns a new instance of SpawnSubagent.

Parameters:

  • session (Session)

    the parent session spawning the sub-agent

  • tool_use_id (String, nil) (defaults to: nil)

    the invoking spawn_subagent tool_call’s pairing id, captured so the spawn pair can later be located by the HUD visibility sweep in Mneme::Runner



54
55
56
57
# File 'lib/tools/spawn_subagent.rb', line 54

def initialize(session:, tool_use_id: nil, **)
  @session = session
  @tool_use_id = tool_use_id
end

Class Method Details

.descriptionObject



22
23
24
25
26
27
# File 'lib/tools/spawn_subagent.rb', line 22

def self.description
  "Task feels like a sidequest or a context-switch? Hand it off. " \
    "Starts clean with just the task — include all relevant context in the task description. " \
    "Its messages appear as tool responses in your conversation. " \
    "Prefix its nickname with @ to send instructions."
end

.input_schemaObject



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/tools/spawn_subagent.rb', line 33

def self.input_schema
  {
    type: "object",
    properties: {
      task: {type: "string"},
      tools: {
        type: "array",
        items: {type: "string"},
        description: "Tool names to grant the sub-agent. " \
          "Omit for all standard tools. Empty array for pure reasoning. " \
          "Valid tools: #{Tools::Registry::STANDARD_TOOLS_BY_NAME.keys.join(", ")}"
      }
    },
    required: %w[task]
  }
end

.prompt_guidelinesObject



31
# File 'lib/tools/spawn_subagent.rb', line 31

def self.prompt_guidelines = SubagentPrompts::PROMPT_GUIDELINES

.prompt_snippetObject



29
# File 'lib/tools/spawn_subagent.rb', line 29

def self.prompt_snippet = "Hand off a sidequest to a sub-agent. Reachable later via @."

.tool_nameObject



20
# File 'lib/tools/spawn_subagent.rb', line 20

def self.tool_name = "spawn_subagent"

Instance Method Details

#execute(input) ⇒ String, Hash{Symbol => String}

Creates a child session with a clean context (no parent history), runs Melete to assign a nickname, pins the task as a Goal, and enqueues the task as the child’s first user_message PendingMessage —which kicks the standard inbound pipeline (Melete → (Mneme) →StartProcessing → DrainJob) so the sub-agent self-starts the same way a human-typed message would. Returns immediately after Melete completes (blocking for ~200ms).

Parameters:

  • input (Hash<String, Object>)

    with “task” and optional “tools”

Returns:

  • (String)

    confirmation with child session ID and @nickname

  • (Hash{Symbol => String})

    with :error key on validation failure



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/tools/spawn_subagent.rb', line 70

def execute(input)
  task = input["task"].to_s.strip

  return {error: "Task cannot be blank"} if task.empty?

  tools = normalize_tools(input["tools"])

  error = validate_tools(tools)
  return error if error

  child = spawn_child(task, tools)
  nickname = child.name
  "Sub-agent #{nickname} spawned (session #{child.id}). " \
    "Its messages will appear in your conversation. " \
    "To address it, prefix its name with @ in your message."
end