omnibot-ruby 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a9e962ec1fc30233e103cc753f9db7db243db279f3bb51f6fa8a7bf5abdd940
4
- data.tar.gz: 73f4531396f0d8a73a7e6302195a6ff42a9d70ab9b3436a0c9c877a5f234af85
3
+ metadata.gz: 3e09a524c80d29220a03ae50ab6a48a60646fa9ba5ab9b19f574bf75454a423c
4
+ data.tar.gz: 1b143d6d5928d2e987b450b5d4c314e3b01b4d2dad6f310fd9129a7d23ab02d3
5
5
  SHA512:
6
- metadata.gz: d9373a4af7299c9a2ef450b93242c387cefd23ec8efd21b9eeec30dc51e1f7c003848b861e1ae3e52d6698800725e419ad1b09db0256f7bb57a5445ee7e25bdf
7
- data.tar.gz: 9b24f2b865bee9764f474e7613e91d14d09c9afc9144175caf48d2a996294588ca501c47bfb5e48ed554a42189f5cfff7fcba76497e963c6b8fd6f6dde69c776
6
+ metadata.gz: 64417bee74cbe85d183c62f1c7f8cae0f9e4e4ee2c1c266f46560985af130fbb0057cf120c1cdc36785fbe008c996365a22bdc74b089687df6506948088b5df9
7
+ data.tar.gz: db6b5bfb1f62029572f1aad07f32057c9b7a96760eebeacc3ac76159479c71fba6339161db775b8e95bfc9ace70b850cf419cf1c76f06cbab9c70f5bc8275958
data/README.md CHANGED
@@ -58,6 +58,7 @@ Semantics worth knowing:
58
58
  - `instructions` support `{{var}}` interpolation from `context`; a missing variable raises `KeyError`.
59
59
  - `history` is a plain array of `{ role:, content: }` hashes (or anything that responds to `#role`/`#content`) — the gem never persists conversations itself.
60
60
  - A custom `Omnibot.chat_factory` lambda must accept extra kwargs (e.g. `->(model:, **) { ... }`) — Agent always calls it with `agent_class:` in addition to `model:`.
61
+ - Per-agent factories (v0.2.1): declare `chat_factory ->(model:, **) { RubyLLM.chat(model: model).with_temperature(0.9) }` inside an agent class to customize chat construction for that agent only (inherited by subclasses; overridable). Precedence: `Omnibot::Testing.fake!` > class-level `chat_factory` > global `Omnibot.chat_factory` — so specs stay offline even for agents with custom factories.
61
62
  - Block-tool params are always JSON type `"string"` — models send `"123"`, not `123`. Declare param types via class-form tools (`param :n, type: "integer"`) when types matter.
62
63
  - Class-form tools must declare `param` explicitly — the wrapper that adds error capture shadows `#execute`'s signature, so ruby_llm's automatic param inference doesn't see your keyword args:
63
64
 
data/lib/omnibot/agent.rb CHANGED
@@ -28,6 +28,18 @@ module Omnibot
28
28
  def fast_paths = @fast_paths ||= []
29
29
  def fast_path(&block) = fast_paths << block
30
30
 
31
+ # Per-agent chat factory (e.g. to set temperature/params for THIS agent
32
+ # only). Precedence: Omnibot::Testing.fake! override > class factory >
33
+ # Omnibot.chat_factory. Accepts a callable or a block.
34
+ def chat_factory(callable = nil, &block)
35
+ factory = callable || block
36
+ factory ? @chat_factory = factory : @chat_factory
37
+ end
38
+
39
+ def resolved_chat_factory
40
+ Omnibot.chat_factory_override || chat_factory || Omnibot.chat_factory
41
+ end
42
+
31
43
  def inherited(subclass)
32
44
  super
33
45
  subclass.instance_variable_set(:@model, @model)
@@ -35,6 +47,7 @@ module Omnibot
35
47
  subclass.instance_variable_set(:@max_turns, @max_turns)
36
48
  subclass.instance_variable_set(:@tools, tools.dup)
37
49
  subclass.instance_variable_set(:@fast_paths, fast_paths.dup)
50
+ subclass.instance_variable_set(:@chat_factory, @chat_factory)
38
51
  end
39
52
 
40
53
  def run(message, history: [], context: {}, stream: nil)
@@ -69,7 +82,7 @@ module Omnibot
69
82
  def reply(text) = throw(FAST_REPLY, text)
70
83
 
71
84
  def extract(input, schema:)
72
- chat = Omnibot.chat_factory.call(model: self.class.model, agent_class: self.class)
85
+ chat = self.class.resolved_chat_factory.call(model: self.class.model, agent_class: self.class)
73
86
  chat.with_instructions(interpolated_instructions) if self.class.instructions
74
87
  chat.with_schema(schema)
75
88
 
@@ -137,7 +150,7 @@ module Omnibot
137
150
  end
138
151
 
139
152
  def build_chat
140
- chat = Omnibot.chat_factory.call(model: self.class.model, agent_class: self.class)
153
+ chat = self.class.resolved_chat_factory.call(model: self.class.model, agent_class: self.class)
141
154
  chat.with_instructions(interpolated_instructions) if self.class.instructions
142
155
  attach_history(chat)
143
156
  tools = tools_for(context).map { |t| t.is_a?(Class) ? t.new(context) : t }
@@ -17,5 +17,9 @@ module Omnibot
17
17
  @chat_factory ||= ->(model:, **) { RubyLLM.chat(model: model) }
18
18
  end
19
19
  attr_writer :chat_factory
20
+
21
+ # Set by Omnibot::Testing.fake! — beats per-agent factories so specs
22
+ # stay offline even for agents that declare their own chat_factory.
23
+ attr_accessor :chat_factory_override
20
24
  end
21
25
  end
@@ -7,14 +7,19 @@ module Omnibot
7
7
  class << self
8
8
  def fake!
9
9
  @original_factory ||= Omnibot.chat_factory
10
- Omnibot.chat_factory = ->(model:, agent_class: nil, **) {
10
+ fake = ->(model:, agent_class: nil, **) {
11
11
  FakeChat.new(agent_class: agent_class)
12
12
  }
13
+ Omnibot.chat_factory = fake
14
+ # Override beats per-agent chat_factory declarations, so specs stay
15
+ # offline even for agents that configure their own factory.
16
+ Omnibot.chat_factory_override = fake
13
17
  end
14
18
 
15
19
  def reset!
16
20
  Omnibot.chat_factory = @original_factory if @original_factory
17
21
  @original_factory = nil
22
+ Omnibot.chat_factory_override = nil
18
23
  scripts.clear
19
24
  end
20
25
 
@@ -1,3 +1,3 @@
1
1
  module Omnibot
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omnibot-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johannes Dwicahyo