Skip to content

Releases: obie/ruby_decision_model

Release list

v0.3.0

Choose a tag to compare

@obie obie released this 12 Oct 16:55
ca7f3d2

Cloudflare's clef-omni reads audio and video, and Client#ask can now send both.

gem "ruby_decision_model", "~> 0.3"

Tested on 2026-10-12

  • Text questions answered live through OpenRouter on Jev and Clef.
  • Audio and video for clef-omni have unit test coverage only. No audio or video request has been sent to Cloudflare yet; the audio and videos field names come from Cloudflare's model page. To check it with your own account: rake smoke TARGETS=cloudflare:clef-omni SMOKE_AUDIO=clip.mp3 SMOKE_VIDEO=clip.mp4.

Changes

  • Client#ask takes audio: and videos:, arrays of base64 data URLs, for
    clef-omni. Cloudflare reads WAV or MP3 audio and MP4 or WebM video. Added
    RubyDecisionModel::Media.data_url and .from_file, which build data URLs
    for images, audio, and video.
  • When the provider or model doesn't read audio or video, including clef
    and clef-flash, the client raises RequestError before sending.
  • cloudflare/clef-omni and @cf/cloudflare/clef-omni resolve to
    clef-omni on the Cloudflare provider. In 0.2.0 they raised
    ConfigurationError. The bare clef-omni already worked.
  • New provider hooks supports_audio?(model) and supports_videos?(model),
    both false by default. Base#request_body accepts audio: and videos:.
  • rake smoke takes SMOKE_AUDIO and SMOKE_VIDEO.
  • Hosted clef-flash now has a 24,576-token context window. Cloudflare cuts
    a text state that runs past the window to fit instead of rejecting it. The
    gem is unchanged.

v0.2.0

Choose a tag to compare

@obie obie released this 07 Oct 17:38
5154d43

Five more decision-model providers behind the same Client: OpenAI's Decisions API (gpt-6-luna), Cloudflare Workers AI (Clef and Clef-flash), Perplexity (pplx-decider), Databricks ai_decide, and any server that speaks Typesafe's System One API.

gem "ruby_decision_model", "~> 0.2"

Tested live on 2026-10-07

  • OpenAI, Perplexity, and Cloudflare (Clef and Clef-flash) on their own APIs, with text and with images.
  • Jev, Luna, Clef, Clef-flash, and pplx-decider through OpenRouter.
  • Databricks and System One servers have unit test coverage only.

Changes

  • Added providers :openai (OpenAI Decisions API, gpt-6-luna),
    :cloudflare (Clef and Clef-flash on Workers AI), :perplexity
    (pplx-decider-v1.1-27b and pplx-decider-v1-27b), :databricks
    (ai_decide over REST), and :system_one (any server speaking
    /v1/systemone: Ollama, the autojev server, strands-decider, and others).
  • The OpenAI provider translates both ways between System One and OpenAI's
    wire format. Questions, answers, and Answers::* types are unchanged for
    callers. A noul with true/false criteria goes out as a boolean choice and
    comes back as a noul.
  • Client#ask takes images:, an array of base64 data URLs. Each provider
    places them where its API expects. Providers that don't read images raise
    RequestError before sending. Added RubyDecisionModel::Images.data_url
    and .from_file.
  • Refused questions (OpenAI) raise MissingAnswers as before, with the new
    #refused listing the ids the provider declined.
  • Noul probabilities are always {"true" => p, "false" => 1 - p}. Jev,
    Clef, pplx-decider, and most System One servers send only the probability,
    so the client fills in the split. A noul with junk probabilities now gets
    the split instead of {}, and a noul outside 0..1 raises
    InvalidResponse.
  • State or questions that cannot be encoded as JSON (invalid UTF-8, NaN,
    nesting deeper than 100 levels) raise RequestError, with the original
    error on #cause.
  • RUBY_DECISION_MODEL_PROVIDER names a provider from the environment ahead
    of key detection (any case; - reads as _), and
    Client.new(api_key: ...) sends that key to the named provider rather
    than OpenRouter. SYSTEM_ONE_BASE_URL joins detection after
    TYPESAFE_API_KEY and OPENROUTER_API_KEY. Keys like OPENAI_API_KEY do
    not select a provider by themselves.
  • New aliases. On OpenRouter: luna and gpt-6-luna resolve to
    openai/gpt-6-luna-decisions, clef and clef-flash to the
    cloudflare/ slugs, and pplx-decider to
    perplexity/pplx-decider-v1-27b. Native providers accept the OpenRouter
    slugs for their own models. Typesafe accepts ~typesafe/jev-latest.
  • Each provider names its own request id header: x-request-id on OpenAI
    and Perplexity, cf-ray on Cloudflare, and x-typesafe-request-id
    everywhere else, as in 0.1.0.
  • timeout: now defaults to nil, meaning the provider's read timeout: 5
    seconds for Typesafe, OpenRouter, and Cloudflare, 30 for OpenAI,
    Perplexity, Databricks, and System One servers, with a 5 second open
    timeout. Passing a number sets both, as before. The write timeout, which
    bounds image uploads, follows the read timeout, and a write timeout is
    retried and raised as TimeoutError like the other two. In 0.1.0 an
    explicit timeout: nil meant no limit at all; it now means these
    defaults. Added Client#open_timeout.
  • ApiError messages end with the vendor's reason when the error body has
    one, for example api error (status 400): Invalid model 'x'. The client
    reads OpenAI, Perplexity, and OpenRouter error.message, Cloudflare
    errors[].message, FastAPI detail[].msg (Typesafe), and Databricks
    message. The API key is masked if a vendor echoes it, and the text is
    capped at 500 characters. #body is unchanged.
  • API keys are stripped before they go into the Authorization header, so
    a key read from a file with its trailing newline works.
  • Added rake smoke, an opt-in live check against every provider whose keys
    are set. CI never runs it.
  • Provider hooks for authors: normalize_response, supports_images?,
    request_id_header, requires_api_key?, default_timeout,
    error_message, validate!, configured?, and url(model). Base sends
    Authorization only when a key is present. Providers written against
    0.1.0 keep working: a url override without the model argument is still
    called without it.