Conversation
Both providers here are HTTP clients with a key, and the registry is closed, so a provider that runs a model in-process, or one that simply ships separately, cannot exist. This is the seam for both, modelled on what RubyLLM does with Provider.register and its provider gems. Providers.register(name, klass) adds a provider from anywhere, and build forwards extra keyword arguments so a provider can take its own options. Base gains requires_api_key? and transport, each defaulting to what the hosted providers already did, and env_var defaults to nil for a provider with no credential. Client honours both. Nothing about OpenRouter or Typesafe changes, and the gem still has no runtime dependencies: the new test fixture is a provider that answers from memory, which is the whole contract a gem outside this repository has to meet.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Both providers here are HTTP clients with a key, and
Providers::REGISTRYis frozen, so a provider cannot ship separately, and one that runs a model in this process cannot exist at all. This adds the seam for both, shaped after what RubyLLM does withProvider.registerand provider gems.Nothing about OpenRouter or Typesafe changes, and the gem still has no runtime dependencies.
What it adds
Providers.register(name, klass), so a provider defined anywhere can join the registry, plusregistered?.buildnow forwards extra keyword arguments, so a provider can take options of its own.Base#requires_api_key?(defaulttrue) andBase#transport(defaultnil, meaning "use Client's HTTP transport"). A provider that answers in-process returns a callable of the same shape Client already takes, so retries, error mapping and the typed answers are reused untouched.Base#env_vardefaults tonilinstead of raising, for a provider with no credential to read.ruby_decision_model-providers-<name>gem convention.The diff against existing files is 27 lines:
Tests
test/extension_test.rbis new, and its fixture is a provider that answers from memory: registration, a provider with no key, answering without HTTP, an injectedtransport:still winning, and the retry policy still applying to a local provider. That covers the contract without adding a dependency. Full suite passes, 109 runs.Why I wanted it
I wrote ruby-laya, which runs ONNX exports of the open-weights Laya checkpoints locally. With these hooks it becomes an ordinary provider in a separate gem, ruby_decision_model-providers-laya:
That gem is unpublished on purpose: it depends on this hook, so it waits on whatever shape you settle on here.
Happy to change the shape
If you would rather keep the registry closed and have providers vendored in, or split this into "registration" and "non-HTTP providers" as two PRs, or name the hooks differently, say the word. The local-provider half is the part I actually need; the registration half is what keeps it out of your tree.