Class: Rubino::Agent::Definition

Inherits:
Object
  • Object
show all
Defined in:
lib/rubino/agent/definition.rb

Overview

Defines an agent type with its own model, system prompt, permissions, and tools. Agents can be primary (user-facing) or subagents (invokable by other agents).

Constant Summary collapse

TYPES =

Types: :primary (user-switchable), :subagent (invokable), :utility (hidden)

%i[primary subagent utility].freeze
DELEGATION_TOOLS =

Returns tool list based on the agent’s tool configuration.

Scoped nesting (S1): a subagent now KEEPS the delegation tools (‘task` and its companions `task_result`/`task_stop`) so it can spawn its own subagents. Runaway recursion / fan-out is no longer prevented by hiding the tool here — it is bounded in ONE place, Tools::BackgroundTasks#reserve, by the depth / per-owner / global caps. (DELEGATION_TOOLS is kept as a named set for any reader that still wants to reason about the group.)

%w[task task_result task_stop].freeze
SUBAGENT_ONLY_TOOLS =

Tools that ONLY make sense for a subagent and must be hidden from a primary/top-level agent. ask_parent escalates a question to the PARENT — a top-level agent has no parent, so exposing it there would be a dead tool. Subagents keep it; everyone else drops it. This is the single enforcement point and is UNCHANGED by S1 (re-enabling nesting does not expose ask_parent to top-level agents).

%w[ask_parent].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attrs = {}) ⇒ Definition

Returns a new instance of Definition.



14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/rubino/agent/definition.rb', line 14

def initialize(attrs = {})
  @name = attrs[:name]
  @type = attrs[:type] || :primary
  @model = attrs[:model]
  @system_prompt = attrs[:system_prompt]
  @description = attrs[:description] || ""
  @permissions = attrs[:permissions] || {}
  @mcp_servers = attrs[:mcp_servers] # :all or array of server names
  @tools = attrs[:tools] || :all # :all, :read_only, or array of tool names
  @hidden = attrs[:hidden] || false
  @max_turns = attrs[:max_turns]
end

Instance Attribute Details

#descriptionObject (readonly)

Returns the value of attribute description.



8
9
10
# File 'lib/rubino/agent/definition.rb', line 8

def description
  @description
end

#hiddenObject (readonly)

Returns the value of attribute hidden.



8
9
10
# File 'lib/rubino/agent/definition.rb', line 8

def hidden
  @hidden
end

#modelObject (readonly)

Returns the value of attribute model.



8
9
10
# File 'lib/rubino/agent/definition.rb', line 8

def model
  @model
end

#nameObject (readonly)

Returns the value of attribute name.



8
9
10
# File 'lib/rubino/agent/definition.rb', line 8

def name
  @name
end

#permissionsObject (readonly)

Returns the value of attribute permissions.



8
9
10
# File 'lib/rubino/agent/definition.rb', line 8

def permissions
  @permissions
end

#system_promptObject (readonly)

Returns the value of attribute system_prompt.



8
9
10
# File 'lib/rubino/agent/definition.rb', line 8

def system_prompt
  @system_prompt
end

#toolsObject (readonly)

Returns the value of attribute tools.



8
9
10
# File 'lib/rubino/agent/definition.rb', line 8

def tools
  @tools
end

#typeObject (readonly)

Returns the value of attribute type.



8
9
10
# File 'lib/rubino/agent/definition.rb', line 8

def type
  @type
end

Instance Method Details

#hidden?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'lib/rubino/agent/definition.rb', line 39

def hidden?
  @hidden
end

#max_turnsObject

Returns the max turns for this agent (falls back to global config)



60
61
62
# File 'lib/rubino/agent/definition.rb', line 60

def max_turns
  @max_turns || Rubino.configuration.agent_max_turns
end

#mcp_serversObject

Which MCP servers this agent may use: :all, or an array of server names. An explicit value passed in code wins; otherwise the ‘agents.<name>.mcp_servers` block in config.yml applies (#92), and absent both the agent sees every server. YAML has no symbols, so the literal string “all” from config normalizes to :all — the value #resolved_tools compares against.



49
50
51
52
53
54
55
56
57
# File 'lib/rubino/agent/definition.rb', line 49

def mcp_servers
  return @mcp_servers if @mcp_servers

  configured = Rubino.configuration.dig("agents", name.to_s, "mcp_servers")
  case configured
  when Array then configured.map(&:to_s)
  else :all
  end
end

#primary?Boolean

Returns:

  • (Boolean)


27
28
29
# File 'lib/rubino/agent/definition.rb', line 27

def primary?
  @type == :primary
end

#resolved_modelObject

Returns the resolved model (falls back to global default)



65
66
67
# File 'lib/rubino/agent/definition.rb', line 65

def resolved_model
  @model || Rubino.configuration.model_default
end

#resolved_toolsObject



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/rubino/agent/definition.rb', line 87

def resolved_tools
  tools =
    case @tools
    when :all
      Tools::Registry.enabled_tools
    when :read_only
      Tools::Registry.enabled_tools.select { |t| t.risk_level == :low }
    when Array
      @tools.filter_map { |name| Tools::Registry.find(name) }
    else
      Tools::Registry.enabled_tools
    end

  # Per-agent MCP scoping (#92/#173): every consumer of this agent's tool
  # set (Lifecycle#load_tools, prompt assembler) goes through here, so
  # filtering MCP wrappers HERE is what actually keeps an out-of-scope
  # server's tools away from the model.
  tools = reject_unscoped_mcp_tools(tools)

  # ask_parent is subagent-only; a primary/top-level agent has no parent.
  # Nesting is otherwise allowed for everyone — the delegation tools stay.
  if subagent?
    tools
  else
    tools.reject { |t| SUBAGENT_ONLY_TOOLS.include?(t.name) }
  end
end

#subagent?Boolean

Returns:

  • (Boolean)


31
32
33
# File 'lib/rubino/agent/definition.rb', line 31

def subagent?
  @type == :subagent
end

#utility?Boolean

Returns:

  • (Boolean)


35
36
37
# File 'lib/rubino/agent/definition.rb', line 35

def utility?
  @type == :utility
end