Class: Silas::Tools::Delegate

Inherits:
Silas::Tool show all
Defined in:
lib/silas/tools/delegate.rb

Overview

Built-in. Added to the ROOT toolset only when subagents exist; NOT given to subagents (depth-1, no recursion). The whole delegation is ONE external effect: at_most_once! means a crash mid-run parks the parent invocation in-doubt (the exactly-once boundary), never silently re-runs.

Instance Attribute Summary

Attributes inherited from Silas::Tool

#session

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Silas::Tool

approval, #approval_policy, at_most_once!, effect_mode, #effect_mode, idempotent!, param, schema, transactional!, validate_signature!

Class Method Details

.descriptionObject

Dynamic description enumerates the roster, so the roster lands in the ROOT digest (schema -> Registry#definitions -> digest). Adding a subagent mid-turn => NondeterminismError, exactly like a skill change.



18
19
20
21
22
23
24
25
# File 'lib/silas/tools/delegate.rb', line 18

def self.description
  roster = Silas.subagent_index
  base = "Delegate a self-contained subtask to a specialized subagent that runs with its own " \
         "instructions, tools, and a fresh context, then returns its final answer."
  return base if roster.empty?

  base + "\n\nAvailable subagents:\n" + roster.map { |n, d| "- #{n}: #{d}" }.join("\n")
end

.tool_nameObject



13
# File 'lib/silas/tools/delegate.rb', line 13

def self.tool_name = "delegate"

Instance Method Details

#call(subagent:, input:) ⇒ Object

session is the PARENT session, set by the Ledger before #call.



28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/silas/tools/delegate.rb', line 28

def call(subagent:, input:)
  return { "error" => "unknown subagent #{subagent.inspect}" } unless Silas.subagent?(subagent)

  nested = Silas::Session.create!(agent_name: subagent, parent_session_id: session.id,
                                  metadata: { "delegated_from" => session.id })
  turn = Silas::NestedRunner.run(nested, input: input)
  if turn.completed?
    { "session_id" => nested.id, "answer" => turn.answer_text }
  else
    { "session_id" => nested.id, "error" => "subagent did not finish (#{turn.status}: #{turn.failure_reason})" }
  end
end