Class: ActionAgent::Agent
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- ActionAgent::Agent
- Includes:
- Ownable
- Defined in:
- app/models/action_agent/agent.rb
Constant Summary collapse
- PRESET_TYPES =
Available presets matching AgentAvatar component
%w[ terminal webDeveloper documentAnalysis writing translation playwright research imageAnalysis computerUse productDesign ].freeze
- INSTRUCTION_SETS =
Available instruction sets
%w[ github ruby rails aws gcp python typescript docker kubernetes ].freeze
- AVAILABLE_TOOLS =
Available tools/MCPs
%w[ terminal playwright filesystem code database slack fetch search edit translate memory agents ].freeze
- PROVIDERS =
Available providers
%w[openai anthropic ollama openrouter].freeze
- DEFAULT_ACTION =
The default action every agent has; uses the base instructions alone.
"ask"
Constants included from Ownable
Class Method Summary collapse
-
.polymorphic_name ⇒ Object
Polymorphic rows (agent_memories, agent_contexts) store this string.
Instance Method Summary collapse
- #action_prompt_for(action_name) ⇒ Object
-
#available_actions ⇒ Object
All invokable action names: the default plus each named action prompt.
-
#composed_instructions_for(action_name) ⇒ Object
The system instructions an action executes under: named actions stack their prompt below the agent's base instructions; the default action uses the base instructions alone.
-
#configuration_snapshot ⇒ Object
Returns the configuration as a hash for versioning.
-
#execute(input_prompt, action: nil, **params) ⇒ Object
Execute a run with this agent.
-
#instructions_digest_versions ⇒ Object
Maps each historical instructions digest to the first version that introduced it ("v3"), so run cohorts can label instruction changes with real agent versions instead of raw hashes.
-
#latest_version ⇒ Object
Get the latest version.
-
#memory ⇒ Object
The agent's long-term memory (solid_agent HasMemory contract) — the summary list its runs read/write via the memory tools.
-
#restore_from_version!(version) ⇒ Object
Restore from a version.
-
#telemetry_agent_class ⇒ Object
The ActiveAgent class name this agent's runs are recorded under — the correlation key between platform Agent records and telemetry traces (TelemetryTrace#agent_class) and solid_agent contexts.
-
#test_execute(input_prompt, action: nil, **params) ⇒ Object
Quick test execution (synchronous).
-
#to_agent_class_code ⇒ Object
Generate Ruby agent class code.
-
#version_count ⇒ Object
Get version count.
Methods included from Ownable
Methods inherited from ApplicationRecord
Class Method Details
.polymorphic_name ⇒ Object
Polymorphic rows (agent_memories, agent_contexts) store this string. A host app that grew these tables under its own Agent constant keeps its existing rows readable by setting agent_polymorphic_name.
16 17 18 |
# File 'app/models/action_agent/agent.rb', line 16 def self.polymorphic_name ActionAgent.agent_polymorphic_name || super end |
Instance Method Details
#action_prompt_for(action_name) ⇒ Object
103 104 105 |
# File 'app/models/action_agent/agent.rb', line 103 def action_prompt_for(action_name) Array(action_prompts).find { |ap| ap["name"] == action_name.to_s } end |
#available_actions ⇒ Object
All invokable action names: the default plus each named action prompt.
99 100 101 |
# File 'app/models/action_agent/agent.rb', line 99 def available_actions [ DEFAULT_ACTION ] + Array(action_prompts).filter_map { |ap| ap["name"].presence } end |
#composed_instructions_for(action_name) ⇒ Object
The system instructions an action executes under: named actions stack their prompt below the agent's base instructions; the default action uses the base instructions alone.
110 111 112 113 |
# File 'app/models/action_agent/agent.rb', line 110 def composed_instructions_for(action_name) action = action_prompt_for(action_name) [ instructions, action&.dig("prompt") ].map(&:presence).compact.join("\n\n").presence end |
#configuration_snapshot ⇒ Object
Returns the configuration as a hash for versioning
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'app/models/action_agent/agent.rb', line 116 def configuration_snapshot { name: name, description: description, provider: provider, model: model, instructions: instructions, action_prompts: action_prompts, preset_type: preset_type, appearance: appearance, instruction_sets: instruction_sets, tools: tools, mcp_servers: mcp_servers, model_config: model_config, response_format: response_format } end |
#execute(input_prompt, action: nil, **params) ⇒ Object
Execute a run with this agent
198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'app/models/action_agent/agent.rb', line 198 def execute(input_prompt, action: nil, **params) run = agent_runs.create!( input_prompt: input_prompt, action_name: normalized_action(action), input_params: params, status: :pending, trace_id: SecureRandom.uuid ) # Queue the execution job AgentExecutionJob.perform_later(run.id) run end |
#instructions_digest_versions ⇒ Object
Maps each historical instructions digest to the first version that introduced it ("v3"), so run cohorts can label instruction changes with real agent versions instead of raw hashes.
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'app/models/action_agent/agent.rb', line 158 def instructions_digest_versions agent_versions.order(:version_number).each_with_object({}) do |version, map| snapshot = version.configuration_snapshot base = snapshot["instructions"] label = "v#{version.version_number}" if base.present? map[Digest::SHA256.hexdigest(base).first(8)] ||= label end # Named actions run under composed instructions (base + action # prompt), so their runs carry a different digest per action. Array(snapshot["action_prompts"]).each do |action| composed = [ base, action["prompt"] ].map(&:presence).compact.join("\n\n") next if composed.blank? map[Digest::SHA256.hexdigest(composed).first(8)] ||= label end end end |
#latest_version ⇒ Object
Get the latest version
151 152 153 |
# File 'app/models/action_agent/agent.rb', line 151 def latest_version agent_versions.order(version_number: :desc).first end |
#memory ⇒ Object
The agent's long-term memory (solid_agent HasMemory contract) — the summary list its runs read/write via the memory tools.
91 92 93 |
# File 'app/models/action_agent/agent.rb', line 91 def memory AgentMemory.for(self) end |
#restore_from_version!(version) ⇒ Object
Restore from a version
135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'app/models/action_agent/agent.rb', line 135 def restore_from_version!(version) config = version.configuration_snapshot update!( instructions: config["instructions"], action_prompts: config["action_prompts"] || [], preset_type: config["preset_type"], appearance: config["appearance"], instruction_sets: config["instruction_sets"], tools: config["tools"], mcp_servers: config["mcp_servers"], model_config: config["model_config"], response_format: config["response_format"] ) end |
#telemetry_agent_class ⇒ Object
The ActiveAgent class name this agent's runs are recorded under — the correlation key between platform Agent records and telemetry traces (TelemetryTrace#agent_class) and solid_agent contexts.
84 85 86 87 |
# File 'app/models/action_agent/agent.rb', line 84 def telemetry_agent_class base = agent_class_name.presence || name.parameterize(separator: "_").camelize base.end_with?("Agent") ? base : "#{base}Agent" end |
#test_execute(input_prompt, action: nil, **params) ⇒ Object
Quick test execution (synchronous)
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'app/models/action_agent/agent.rb', line 214 def test_execute(input_prompt, action: nil, **params) run = agent_runs.create!( input_prompt: input_prompt, action_name: normalized_action(action), input_params: params, status: :running, trace_id: SecureRandom.uuid, started_at: Time.current ) begin # Build and execute the agent result = AgentExecutionService.call(self, run) run.update!( output: result[:output], output_metadata: result[:metadata], status: :complete, completed_at: Time.current, duration_ms: ((Time.current - run.started_at) * 1000).to_i, input_tokens: result.dig(:usage, :input_tokens), output_tokens: result.dig(:usage, :output_tokens), total_tokens: result.dig(:usage, :total_tokens) ) rescue => e run.update!( status: :failed, completed_at: Time.current, error_message: e., error_backtrace: e.backtrace&.first(10)&.join("\n") ) end run end |
#to_agent_class_code ⇒ Object
Generate Ruby agent class code
185 186 187 188 189 190 191 192 193 194 195 |
# File 'app/models/action_agent/agent.rb', line 185 def to_agent_class_code <<~RUBY class #{agent_class_name || name.camelize}Agent < ApplicationAgent generate_with :#{provider}, model: "#{model}"#{model_config_code} def perform prompt#{instructions_code} end end RUBY end |
#version_count ⇒ Object
Get version count
180 181 182 |
# File 'app/models/action_agent/agent.rb', line 180 def version_count agent_versions.count end |