Class: Omakase::Agent
- Inherits:
-
Object
- Object
- Omakase::Agent
- Defined in:
- lib/omakase/agent.rb
Overview
Fields are state, methods are what the model can call, generates declares
the methods the model implements.
Class Method Summary collapse
- .chat_options ⇒ Object
-
.describe(text) ⇒ Object
Documents the method defined next — the docstring Ruby does not have.
- .descriptions ⇒ Object
-
.generates(name, prompt = nil, returns: nil, strategy: nil, &schema) ⇒ Object
Without a prompt, the method name is the prompt.
- .generations ⇒ Object
- .instructions(text = nil) ⇒ Object
-
.mcp(name, **options) ⇒ Object
An MCP server's tools, as methods on the agent.
-
.memory ⇒ Object
Two more methods: one to save something, one to search it by meaning.
-
.model(id = nil, **options) ⇒ Object
The model and any RubyLLM chat option.
-
.skill(path) ⇒ Object
A skill directory — a SKILL.md with YAML front matter.
- .strategy(name = nil) ⇒ Object
Instance Method Summary collapse
-
#chat ⇒ Object
A fresh conversation per call — two threads calling one agent must not share a mutable chat.
-
#context ⇒ Object
That state, as the model should read it: rebuilt on every call, and added to the class's instructions.
-
#doc(object) ⇒ Object
For generated code meeting an object whose type it does not know.
-
#finish(value) ⇒ Object
How generated code answers: with the value itself.
-
#initialize(chat: nil) ⇒ Agent
constructor
chat:injects a prepared RubyLLM::Chat — the seam for tests. -
#marshal_dump ⇒ Object
Resuming a run is loading the object back, so an agent marshals like any other Ruby object — minus the live chat, which is rebuilt on demand.
- #marshal_load(state) ⇒ Object
- #p(*args) ⇒ Object (also: #pp)
- #print(*args) ⇒ Object
-
#puts(*args) ⇒ Object
Printing from generated code goes to the observation, not to the process's stdout — and the buffer is per thread, so concurrent agents stay separate.
Constructor Details
#initialize(chat: nil) ⇒ Agent
chat: injects a prepared RubyLLM::Chat — the seam for tests.
96 97 98 |
# File 'lib/omakase/agent.rb', line 96 def initialize(chat: nil) @chat = chat end |
Class Method Details
.chat_options ⇒ Object
70 |
# File 'lib/omakase/agent.rb', line 70 def = @chat_options ||= {} |
.describe(text) ⇒ Object
Documents the method defined next — the docstring Ruby does not have.
50 51 52 |
# File 'lib/omakase/agent.rb', line 50 def describe(text) @pending_description = text end |
.descriptions ⇒ Object
68 |
# File 'lib/omakase/agent.rb', line 68 def descriptions = @descriptions ||= {} |
.generates(name, prompt = nil, returns: nil, strategy: nil, &schema) ⇒ Object
Without a prompt, the method name is the prompt.
55 56 57 58 59 60 61 62 63 64 |
# File 'lib/omakase/agent.rb', line 55 def generates(name, prompt = nil, returns: nil, strategy: nil, &schema) generations[name] = Generation.new( name:, prompt: prompt || humanize(name), schema: Schema.define(returns:, &schema), strategy: Strategies.fetch(strategy || self.strategy) ) define_method(name) { |**inputs| generate(name, inputs) } define_singleton_method(name) { |**inputs| new.public_send(name, **inputs) } end |
.generations ⇒ Object
66 |
# File 'lib/omakase/agent.rb', line 66 def generations = @generations ||= {} |
.instructions(text = nil) ⇒ Object
18 19 20 21 22 |
# File 'lib/omakase/agent.rb', line 18 def instructions(text = nil) return @instructions.to_s if text.nil? @instructions = text end |
.mcp(name, **options) ⇒ Object
An MCP server's tools, as methods on the agent. Options are passed to
ruby_llm-mcp verbatim: mcp :files, transport_type: :stdio, config: {command: "npx", …}.
32 33 34 35 |
# File 'lib/omakase/agent.rb', line 32 def mcp(name, **) require "ruby_llm/mcp" MCP.attach(self, RubyLLM::MCP.add_client(name: name.to_s, **)) end |
.memory ⇒ Object
Two more methods: one to save something, one to search it by meaning. The store is a field, so it marshals with the agent and outlives the run.
43 44 45 46 47 48 |
# File 'lib/omakase/agent.rb', line 43 def memory describe "Save something worth remembering after this run" define_method(:remember) { |text| (@memory ||= Memory.new).remember(text) } describe "Search what you remember, by meaning; the closest few come back" define_method(:recall) { |query, limit: 5| (@memory ||= Memory.new).recall(query, limit:) } end |
.model(id = nil, **options) ⇒ Object
The model and any RubyLLM chat option. Naming a provider takes the model id on trust, since providers like OpenRouter or Ollama serve ids that are not in RubyLLM's registry.
11 12 13 14 15 16 |
# File 'lib/omakase/agent.rb', line 11 def model(id = nil, **) return if id.nil? && .empty? = {assume_model_exists: true, **} if [:provider] @chat_options = {model: id, **}.compact end |
.skill(path) ⇒ Object
A skill directory — a SKILL.md with YAML front matter. Its description joins the agent's capabilities; its body arrives when the model asks.
39 |
# File 'lib/omakase/agent.rb', line 39 def skill(path) = Skills.attach(self, path) |
.strategy(name = nil) ⇒ Object
24 25 26 27 28 |
# File 'lib/omakase/agent.rb', line 24 def strategy(name = nil) return @strategy || :code_act if name.nil? @strategy = name end |
Instance Method Details
#chat ⇒ Object
A fresh conversation per call — two threads calling one agent must not share a mutable chat. What carries between calls is the object's own state.
102 |
# File 'lib/omakase/agent.rb', line 102 def chat = @chat || RubyLLM.chat(**self.class.) |
#context ⇒ Object
That state, as the model should read it: rebuilt on every call, and added to the class's instructions. Override it to remember anything.
106 |
# File 'lib/omakase/agent.rb', line 106 def context = nil |
#doc(object) ⇒ Object
For generated code meeting an object whose type it does not know.
115 |
# File 'lib/omakase/agent.rb', line 115 def doc(object) = puts(Doc.of(object)) |
#finish(value) ⇒ Object
How generated code answers: with the value itself.
118 |
# File 'lib/omakase/agent.rb', line 118 def finish(value) = throw(Executor::RESULT, value) |
#marshal_dump ⇒ Object
Resuming a run is loading the object back, so an agent marshals like any other Ruby object — minus the live chat, which is rebuilt on demand.
110 |
# File 'lib/omakase/agent.rb', line 110 def marshal_dump = (instance_variables - [:@chat]).to_h { |name| [name, instance_variable_get(name)] } |
#marshal_load(state) ⇒ Object
112 |
# File 'lib/omakase/agent.rb', line 112 def marshal_load(state) = state.each { |name, value| instance_variable_set(name, value) } |
#p(*args) ⇒ Object Also known as: pp
126 127 128 129 |
# File 'lib/omakase/agent.rb', line 126 def p(*args) args.each { |arg| omakase_output.puts(arg.inspect) } args.size <= 1 ? args.first : args end |
#print(*args) ⇒ Object
124 |
# File 'lib/omakase/agent.rb', line 124 def print(*args) = omakase_output.print(*args) |
#puts(*args) ⇒ Object
Printing from generated code goes to the observation, not to the process's stdout — and the buffer is per thread, so concurrent agents stay separate.
122 |
# File 'lib/omakase/agent.rb', line 122 def puts(*args) = omakase_output.puts(*args) |