0.0
There's a lot of open issues
Use Jev, TypeSafe's System One model, from Ruby or Rails.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 13.0
~> 3.13
~> 3.0
 Project Readme

typesafe-jev

CI Gem Version Ruby License: MIT

Ruby client for Jev, TypeSafe's System One model. Ask natural-language questions about your application state and get typed, probabilistic answers you can program against.

Zero runtime dependencies: pure Ruby stdlib (Net::HTTP, JSON), so it works in plain Ruby and Rails alike.

Installation

gem install typesafe-jev

or in your Gemfile:

gem "typesafe-jev"

Quickstart

require "typesafe"

response = Typesafe::Jev.evaluate(
  state: { ticket: { text: "My payouts failed twice this week." } },
  questions: {
    refund_requested: Typesafe::Noul.new("Does the customer request a refund?"),
    category: Typesafe::Choice.new("Which category does this ticket belong to?", criteria: {
      billing:   "Payment, invoices, refunds",
      technical: "Bugs and outages",
      sales:     "Pre-sales questions"
    }),
    severity: Typesafe::Score.new("How severe is this ticket?", criteria: [
      "Low: routine request",
      "Medium: degraded experience",
      "High: blocked user",
      "Critical: money lost or security issue"
    ])
  }
)

response[:refund_requested].noul  # => 0.95 (yes/no probability, 0..1)
response[:category].choice        # => "billing"
response[:category].probabilities # => { "billing" => 0.88, "technical" => 0.12, "sales" => 0.0 }
response[:severity].score         # => "High: blocked user"
response.usage.input_tokens       # => 296

Typesafe::Jev.evaluate is the one-shot facade with the model pinned to jev-latest. For another model, use Typesafe::Client directly.

Questions

Questions are frozen, immutable value objects. The question id is not in the object; it is the Hash key in the questions: map, and answers come back under the same key.

Class Answers with Criteria
Typesafe::Noul a yes/no probability (noul, 0..1) optional { true: ..., false: ... }
Typesafe::Choice one option + full probability distribution + confidence non-empty { key: "description" }
Typesafe::Score a level + legend + distribution + confidence non-empty ["Level 1", "Level 2", ...]
Typesafe::Noul.new("Does the customer request a refund?",
  criteria: { true: "The customer explicitly asks for their money back",
              false: "The customer does not mention refunds" })

Typesafe::Choice.new("Which category does this ticket belong to?",
  criteria: { billing: "Payment, invoices, refunds", technical: "Bugs and outages" })

Typesafe::Score.new("How severe is this ticket?",
  criteria: ["Low", "Medium", "High", "Critical"])

Invalid input raises ArgumentError at construction time, so bad questions fail fast, before any HTTP call.

Responses

Client#evaluate returns a frozen Typesafe::Response:

  • response[id] (or response.answers): a typed NoulAnswer, ChoiceAnswer or ScoreAnswer; String and Symbol ids both work
  • response.model: the model that performed the evaluation
  • response.usage: Typesafe::Usage with input_tokens / output_tokens
  • response.to_h / response.to_json: the raw API shape

Each answer type exposes its own accessors (#noul, #choice, #probabilities, #confidence, #score, #legend, …) and serializes via #to_h/#to_json.

Errors

Any non-2xx HTTP response raises a typed error. All inherit from Typesafe::APIError (root: Typesafe::Error), which carries #status, #body, #headers, #request_id and #retryable?.

Error Status Extras
Typesafe::BadRequestError 400
Typesafe::AuthenticationError 401
Typesafe::PermissionDeniedError 403
Typesafe::NotFoundError 404
Typesafe::UnprocessableEntityError 422 #errors (validation details)
Typesafe::RateLimitError 429 #retry_after
Typesafe::OverloadedError 529
Typesafe::ServerError 5xx
begin
  Typesafe::Jev.evaluate(state: state, questions: questions)
rescue Typesafe::RateLimitError => e
  sleep(e.retry_after || 1.0)
  retry
rescue Typesafe::OverloadedError
  sleep(2**attempt)
  retry
rescue Typesafe::APIError => e
  raise "typesafe request failed (#{e.status}, request #{e.request_id}): #{e.body}"
end

Configuration

The API key is read from the TYPESAFE_API_KEY environment variable unless passed explicitly:

jev = Typesafe::Jev.new                      # key from ENV
jev = Typesafe::Jev.new(api_key: "sk-...")   # or explicit

client = Typesafe::Client.new(api_key: "sk-...", model: "other-model")
client.evaluate(state:, questions:, model: "one-off-model") # per-call override

Documentation

TypeSafe docs live at docs.typesafe.ai. The full API reference for this gem is on rubydoc.info.

Development

bundle install
bundle exec rake spec   # or: bundle exec rspec

The test suite runs against Ruby 3.1 and 3.4 in CI. See CONTRIBUTING.md for conventions.

License

MIT