SDKs & toolsRuby SDK

Ruby SDK

⚠️
Preview — this feature is being built; the design below is the spec.

The syntic gem is the planned official Ruby client. It is generated from the OpenAPI description and adds idiomatic helpers: blocks for streaming, enumerators for pagination, a tool runner and batch waiting. It is in the second release wave; see Other languages.

Today, use Net::HTTP as shown in Quickstart: Ruby. That code keeps working after the gem ships.

Install

bundle add syntic
RequirementValue
Ruby3.1 or newer
Gemsyntic on RubyGems
Dependenciesnet-http (standard library), connection_pool

Create a client

require "syntic"
 
client = Syntic::Client.new # reads SYNTIC_API_KEY and SYNTIC_BASE_URL
 
client = Syntic::Client.new(
  api_key: ENV.fetch("SYNTIC_API_KEY"),
  base_url: "https://app.syntic.ai/v1",
  max_retries: 3,
  timeout: 300
)
OptionDefaultNotes
api_keyENV["SYNTIC_API_KEY"]Private key or workload identity token.
base_urlENV["SYNTIC_BASE_URL"], else https://app.syntic.ai/v1
versionThe release’s API versionSent as syntic-version.
betas[]Sent as syntic-beta; methods that need a flag add it.
max_retries2rate_limit, overloaded, api_error and network errors.
timeout600 seconds

A first request

reply = client.chat.completions.create(
  model: "Amara S1.2",
  max_tokens: 200,
  messages: [
    { role: "system", content: "Answer in one sentence." },
    { role: "user", content: "Why is the sky blue?" }
  ]
)
puts reply.choices.first.message.content
puts "#{reply.usage.total_tokens} tokens, request #{reply.request_id}"

Streaming

final = client.chat.completions.stream(
  model: "Amara Quick",
  messages: [{ role: "user", content: "Write a haiku about rain." }]
) do |text|
  print text
end
puts "\n#{final.usage.total_tokens} tokens"

The block receives text pieces; the return value is the assembled completion. Breaking out of the block closes the connection.

Tool loop

get_order = Syntic::Tool.define(
  name: "get_order",
  description: "Look up an order by its id.",
  parameters: { order_id: { type: "string", description: "Order id such as 88123", required: true } }
) { |order_id:| { order_id: order_id, status: "shipped" } }
 
result = client.tools.run(
  model: "Amara S1.2",
  messages: [{ role: "user", content: "Where is order 88123?" }],
  tools: [get_order],
  max_rounds: 8
)
puts result.final_message.content

Exceptions raised inside a tool are sent back to the model as error results.

Errors

Exceptionerror.type
Syntic::InvalidRequestErrorinvalid_request
Syntic::AuthenticationErrorauthentication
Syntic::PermissionDeniedErrorpermission
Syntic::NotFoundErrornot_found
Syntic::QuotaExhaustedErrorquota_exhausted
Syntic::RateLimitErrorrate_limit
Syntic::OverloadedErroroverloaded
Syntic::InternalServerErrorapi_error
Syntic::ConnectionErrorNo response received

All API errors inherit from Syntic::APIError with status, type, code, param, details and request_id.

begin
  client.chat.completions.create(model: "Amara S1.2", messages: [])
rescue Syntic::QuotaExhaustedError => e
  puts "Paused until #{e.details["resets_at"]}"
rescue Syntic::InvalidRequestError => e
  puts "#{e.code} #{e.param} #{e.request_id}"
end

Pagination

client.agents.list(limit: 50).auto_paging_each do |agent|
  puts "#{agent.id} #{agent.name}"
end

Files, batches, agents and admin

file = client.files.upload(path: "contract.pdf", purpose: "document")
 
batch = client.batches.create(input_file_id: file.id)
batch = client.batches.wait(batch.id, poll_interval: 30)
 
session = client.sessions.create(agent_id: "agt_01JC4R8W6Q2N9X3T5V7Y")
client.sessions.stream(session.id) do |event|
  puts event.content if event.type == "message.completed"
end
 
admin = Syntic::AdminClient.new # reads SYNTIC_ADMIN_KEY
admin.users.list.auto_paging_each { |u| puts u.email }

Raw responses

raw = client.chat.completions.with_raw_response.create(model: "Amara Quick", messages: messages)
puts raw.headers["x-syntic-billing-source"]
reply = raw.parse
Was this page helpful?