Module: SolidAgent::Records::AgentTemplate
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/solid_agent/records/agent_template.rb
Overview
Behavior for the AgentTemplate record: a named, reusable agent
configuration that new agents are stamped out of.
A template holds the same configuration columns an agent holds — provider, model, instructions, tools, and so on — and knows how to copy them onto a fresh agent record for an owner. It is a prototype, not a parent: the agent gets a snapshot, and later edits to the template never reach agents already created from it.
What this concern deliberately leaves to the host:
- Catalog copy. Seeded template libraries pin provider model IDs ("gpt-4o", "claude-sonnet-4-20250514"). Shipping those from a gem would hand its release cadence to vendor deprecation schedules, so seeds stay in the application that curates them.
- Merchandising. Category, featured, popularity, public/free-tier — and
the usage counter that ranks them — describe how one product sells
templates. A persistence gem whose schema asserts a pricing model is
wrong. Every reference here to such a column is guarded with
has_attribute?so hosts that add them still work.
In place of a usage counter, #create_agent_for instruments USED_EVENT. Counting is a subscriber's job, which lets a dashboard increment a column, a metrics backend emit a gauge, and a plain host app do nothing at all — from the same code path.
Constant Summary collapse
- USED_EVENT =
Emitted after an agent is successfully created from a template. Payload:
:template,:agent,:owner, and:categorywhen the host has added that column. "template.used.solid_agent"- CONFIGURATION_ATTRIBUTES =
Columns copied verbatim onto the new agent. Identity (name, slug), ownership and lifecycle are handled separately — those are the agent's own, not the template's.
%w[ description provider model instructions preset_type appearance instruction_sets tools mcp_servers model_config ].freeze
Instance Method Summary collapse
-
#create_agent_for(owner, name: nil) ⇒ Object
Builds and saves an agent for
ownerfrom this template. -
#template_configuration ⇒ Hash{String => Object}
The configuration this template stamps onto an agent.
Instance Method Details
#create_agent_for(owner, name: nil) ⇒ Object
Builds and saves an agent for owner from this template.
Returns the agent whether or not it saved — unsaved with errors
populated, the way create does — because callers render those errors.
USED_EVENT fires only on a successful save.
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/solid_agent/records/agent_template.rb', line 98 def create_agent_for(owner, name: nil) model = SolidAgent.agent_model! # Intersect with the agent's columns rather than assuming the two # schemas match: template and agent drift independently once a host # starts editing generated migrations. attributes = template_configuration.slice(*model.column_names) attributes["name"] = name.presence || self.name attributes["status"] = :draft if draft_status?(model) agent = model.new(attributes) # Ownable maps `owner` onto whichever column the host actually has. # A single-tenant install may have none, and creating an unowned agent # is a legitimate outcome there, not an error worth raising. agent.owner = owner if agent.respond_to?(:owner=) if agent.save ActiveSupport::Notifications.instrument(USED_EVENT, used_event_payload(agent, owner)) end agent end |
#template_configuration ⇒ Hash{String => Object}
The configuration this template stamps onto an agent.
Only attributes the template actually has are included, so a host that trims columns it does not use — or adds them later — needs no change here.
79 80 81 82 83 |
# File 'lib/solid_agent/records/agent_template.rb', line 79 def template_configuration CONFIGURATION_ATTRIBUTES.each_with_object({}) do |attribute, config| config[attribute] = self[attribute] if has_attribute?(attribute) end end |