Tama Ruby

tama-rb is the Ruby client for Tama APIs. It provides namespace-aware Faraday services, strict immutable response models, typed errors, and incremental server-sent event parsing.

Installation

Add the gem to your bundle:

gem "tama-rb", "~> 0.1.0"

Then run bundle install and load the client with:

require "tama"

Ruby 3.2 or newer is required.

Client Setup

Create a client with the base URL for the API namespace being used:

client = Tama::Client.new(
  base_url: "https://api.example.com/provision",
  headers: {"Authorization" => "Bearer token"},
  timeout: 300,
  retries: 2
)

Timeouts are expressed in seconds. Global headers are merged with per-request headers, with per-request values taking precedence. Retries use faraday-retry for retryable requests and statuses. The default transport is Faraday's Net::HTTP adapter.

An existing connection can be injected when custom Faraday middleware or an adapter is needed. The injected connection is used as configured; base_url is still required for request URL construction and namespace validation.

connection = Faraday.new do |faraday|
  faraday.request :json
  faraday.request :retry, max: 3
  faraday.adapter :net_http
end

client = Tama::Client.new(
  base_url: "https://api.example.com/perception",
  connection: connection
)

Namespace URLs

The final base URL path segment is validated for each operation. Prefixes such as /api/v1 are preserved.

Namespace Operations
provision Neural space/class/operation, perception chain lookup
ingest Memory entity creation
perception Perception concept listing
agentic Agentic message creation and streaming

Use separate clients when an application calls multiple namespaces.

Neural

client = Tama::Client.new(base_url: "https://api.example.com/provision")

space = client.neural.get_space("my-space")
klass = client.neural.get_class(space, "article")

operation = client.neural.create_class_operation(
  klass,
  chain_ids: ["chain-1", "chain-2"],
  node_type: "compute"
)

get_class accepts a Tama::Neural::Space or a space ID. create_class_operation accepts a Tama::Neural::Klass or class ID and either a hash or Tama::Neural::OperationParams.

Memory

client = Tama::Client.new(base_url: "https://api.example.com/ingest")

entity = client.memory.create_entity(
  klass,
  identifier: "article-123",
  record: {title: "Tama with Ruby"},
  validate_record: true
)

validate_record defaults to true. A Tama::Memory::EntityParams object can be passed instead of a hash.

Perception

Chain lookup uses a provision client:

client = Tama::Client.new(base_url: "https://api.example.com/provision")
chain = client.perception.get_chain(space, "summarize")

get_chain accepts a Tama::Neural::Space or space ID. Concept listing uses a perception client and supports query parameters:

client = Tama::Client.new(base_url: "https://api.example.com/perception")

concepts = client.perception.list_concepts(
  "entity-123",
  query: {limit: 20, offset: 0, relation: "reply"}
)

Agentic

client = Tama::Client.new(base_url: "https://api.example.com/agentic")

message = client.agentic.create_message(
  recipient: "user-123",
  identifier: "message-123",
  content: "Hello",
  index: 1,
  author: {identifier: "agent-1", source: "system"},
  thread: {identifier: "thread-1"}
)

Message class defaults are user-message, actor, and thread. A Tama::Agentic::MessageParams object can also be supplied.

Streaming

Streaming requires either callback: or a block. Each handler call receives one decoded JSON event. The parser buffers fragmented chunks, supports LF and CRLF separators, multiline data: fields, multiple events per chunk, and [DONE].

response = client.agentic.create_message(message_attributes, stream: true) do |event|
  puts event.inspect
end

The streaming form returns the successful Faraday::Response. Non-streaming creation parses the API's top-level JSON response into a Tama::Agentic::Message.

Request Options

Every operation accepts headers: and timeout: request options where applicable:

space = client.neural.get_space(
  "my-space",
  headers: {"X-Request-ID" => "request-1"},
  timeout: 30
)

Dynamic path segments are percent-encoded. Query parameters should be passed only through query: on list_concepts.

Models

Response and parser models are immutable Ruby Data objects:

  • Tama::Neural::Space, Tama::Neural::Klass, Tama::Neural::Operation, Tama::Neural::OperationParams
  • Tama::Memory::Entity, Tama::Memory::EntityParams
  • Tama::Perception::Chain, Tama::Perception::Concept, Tama::Perception::Generator
  • Tama::Agentic::Message, Tama::Agentic::MessageParams, Tama::Agentic::Author, Tama::Agentic::Thread
  • Tama::Broadcast and Tama::Broadcast::Event, Metadata, Step, Concept, Thought, Chain, Branch, Flow, OriginEntity

Broadcast payloads are parsed without making an HTTP request. Top-level event and step values are required:

broadcast = Tama::Broadcast.parse(
  event: {name: "step.updated", domain: "workflow"},
  step: {id: "step-1", concepts: []}
)

Response models also expose .parse(hash_or_json). Invalid JSON, required fields, types, enums, or nested models raise rather than creating partial empty models.

Errors

Failures raise subclasses of Tama::Error:

  • Tama::Error::ConfigurationError for malformed client configuration
  • Tama::Error::InvalidNamespaceError for a mismatched final base URL segment
  • Tama::Error::ValidationError for local parameters and HTTP 422 responses; inspect errors
  • Tama::Error::NotFoundError for HTTP 404 responses
  • Tama::Error::HTTPError for other non-2xx responses; inspect status and body
  • Tama::Error::TransportError for Faraday transport failures; inspect cause
  • Tama::Error::ParseError for malformed JSON, response envelopes, models, or SSE events

All HTTP statuses from 200 through 299 are successful. Neural, Memory, and Perception model endpoints require the API's exact { "data": ... } response envelope; Agentic message creation uses its top-level response object.

Development

bin/setup
bundle exec rspec
bundle exec standardrb
bundle exec rake build

bin/console starts an IRB session with Tama loaded.

Releasing

Releases use RubyGems Trusted Publishing, so the repository does not store a long-lived RubyGems API key.

Before the first release, create a pending trusted publisher at https://rubygems.org/profile/oidc/pending_trusted_publishers with:

  • Gem name: tama-rb
  • Repository owner: upmaru
  • Repository name: tama-rb
  • Workflow filename: publish.yml
  • GitHub environment: release

Create the release environment in the GitHub repository settings. After updating Tama::VERSION and CHANGELOG.md, publish by pushing a matching version tag:

git tag v0.1.0
git push origin v0.1.0

The first successful workflow run publishes the gem and converts the pending publisher into a trusted publisher. RubyGems organizations are currently in private beta; organization ownership requires beta access followed by transferring the published gem to the organization.

License

The gem is available under the MIT License.