Class: Terret::LLM::Service
- Inherits:
-
Hames::Service
- Object
- Hames::Service
- Terret::LLM::Service
- Defined in:
- lib/terret/llm.rb
Overview
ctx.llm — the adapter seam. llm/stream is a waterfall wrapping every
request: middleware may rewrite the request or replace the stream.
Instance Method Summary collapse
-
#reconfigure(config) ⇒ Object
The role map is the whole of this service's config, and layering replaces a row's config wholesale — so does this.
- #register_adapter(name, adapter) ⇒ Object
- #resolve(role) ⇒ Object
-
#set_role(role, spec) ⇒ Object
§9.2 set_model lands here: repoint a role at a "provider/model" spec on the live service.
- #start(_ctx) ⇒ Object
-
#stream(ctx, role:, request:, &on_event) ⇒ Object
Streams the request through the
llm/streamwaterfall; the base of the waterfall invokes the resolved adapter.
Instance Method Details
#reconfigure(config) ⇒ Object
The role map is the whole of this service's config, and layering replaces a row's config wholesale — so does this. Registered adapters are runtime state, not config, and survive untouched.
100 101 102 |
# File 'lib/terret/llm.rb', line 100 def reconfigure(config) @roles = (config[:roles] || {}).dup end |
#register_adapter(name, adapter) ⇒ Object
104 105 106 107 |
# File 'lib/terret/llm.rb', line 104 def register_adapter(name, adapter) @adapters[name.to_s] = adapter -> { @adapters.delete(name.to_s) } end |
#resolve(role) ⇒ Object
109 110 111 112 113 |
# File 'lib/terret/llm.rb', line 109 def resolve(role) spec = @roles.fetch(role) { raise KeyError, "no model role #{role.inspect}" } provider, model = spec.split("/", 2) [@adapters.fetch(provider), model] end |
#set_role(role, spec) ⇒ Object
§9.2 set_model lands here: repoint a role at a "provider/model" spec on the live service. Takes effect at the next step's resolve.
117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/terret/llm.rb', line 117 def set_role(role, spec) raise ArgumentError, "role must be a name, got #{role.inspect}" unless role.respond_to?(:to_sym) provider, model = spec.to_s.split("/", 2) if provider.nil? || provider.empty? || model.nil? || model.empty? raise ArgumentError, "model spec must be provider/model, got #{spec.inspect}" end @adapters.fetch(provider) { raise ArgumentError, "unknown provider #{provider.inspect}" } @roles[role.to_sym] = spec.to_s end |
#start(_ctx) ⇒ Object
92 93 94 95 |
# File 'lib/terret/llm.rb', line 92 def start(_ctx) @adapters = {} @roles = (config[:roles] || {}).dup # :main => "fake/scripted" end |
#stream(ctx, role:, request:, &on_event) ⇒ Object
Streams the request through the llm/stream waterfall; the base of
the waterfall invokes the resolved adapter. Yields StreamEvents,
returns the final assistant Message.
132 133 134 135 136 137 138 |
# File 'lib/terret/llm.rb', line 132 def stream(ctx, role:, request:, &on_event) adapter, model = resolve(role) req = request.with(model: model) ctx.waterfall("llm/stream", req) do |final_req| adapter.stream(final_req, &on_event) end end |