Tavus Ruby Client

Gem Version

A Ruby gem for interacting with the Tavus API, providing a simple and intuitive interface for managing Conversational Video Interfaces (CVI).

Features

  • Conversations Management: Create, retrieve, list, end, and delete real-time video conversations
  • Personas Management: Create, retrieve, list, update, and delete AI personas with customizable behavior
  • Replicas Management: Create, train, retrieve, list, rename, and delete AI replicas
  • Objectives Management: Create, retrieve, list, update, and delete conversation objectives
  • Guardrails Management: Create, retrieve, list, update, and delete behavioral guardrails
  • Knowledge Base (Documents): Upload, retrieve, list, update, and delete documents for personas
  • Video Generation: Generate videos from text or audio, retrieve, list, rename, and delete videos
  • Full API Coverage: Support for all Tavus API v2 endpoints
  • Easy Configuration: Simple API key configuration
  • Comprehensive Error Handling: Detailed error classes for different API responses
  • JSON Patch Support: Update personas, objectives, and guardrails using JSON Patch operations (RFC 6902)

Installation

Add this line to your application's Gemfile:

gem 'tavus'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install tavus

Configuration

Global Configuration

Configure the client globally (recommended for Rails applications):

# config/initializers/tavus.rb
Tavus.configure do |config|
  config.api_key = ENV['TAVUS_API_KEY']
  config.base_url = 'https://tavusapi.com' # Optional, defaults to this
  config.timeout = 30 # Optional, defaults to 30 seconds
end

Per-Instance Configuration

You can also configure individual client instances:

client = Tavus::Client.new(
  api_key: 'your-api-key',
  base_url: 'https://tavusapi.com',
  timeout: 30
)

Usage

For more comprehensive examples, check the examples/ directory:

Conversations

Create a Conversation

client = Tavus::Client.new(api_key: 'your-api-key')

# Create a conversation with required parameters
conversation = client.conversations.create(
  replica_id: 'rfe12d8b9597',
  persona_id: 'pdced222244b'
)

# Create a conversation with optional parameters
conversation = client.conversations.create(
  replica_id: 'rfe12d8b9597',
  persona_id: 'pdced222244b',
  conversation_name: 'Interview User',
  callback_url: 'https://yourwebsite.com/webhook',
  audio_only: false,
  conversational_context: 'I want to improve my sales techniques.',
  custom_greeting: 'Hey there!',
  memory_stores: ['anna'],
  document_ids: ['doc_1234567890'],
  document_retrieval_strategy: 'balanced',
  document_tags: ['sales', 'marketing'],
  test_mode: false
)

# Response includes:
# {
#   "conversation_id" => "c123456",
#   "conversation_name" => "Interview User",
#   "status" => "active",
#   "conversation_url" => "https://tavus.daily.co/c123456",
#   "replica_id" => "rfe12d8b9597",
#   "persona_id" => "pdced222244b",
#   "created_at" => "2025-10-04T12:00:00Z"
# }

Get a Conversation

conversation = client.conversations.get('c123456')

# Response includes conversation details with status, URLs, etc.

List Conversations

# List all conversations
conversations = client.conversations.list

# List with pagination and filters
conversations = client.conversations.list(
  limit: 20,
  page: 1,
  status: 'active' # or 'ended'
)

# Response includes:
# {
#   "data" => [...],
#   "total_count" => 123
# }

End a Conversation

result = client.conversations.end('c123456')

Delete a Conversation

result = client.conversations.delete('c123456')

Personas

Create a Persona

# Create a basic persona
persona = client.personas.create(
  system_prompt: 'As a Life Coach, you are a dedicated professional...',
  persona_name: 'Life Coach',
  pipeline_mode: 'full'
)

# Create a persona with advanced configuration
persona = client.personas.create(
  system_prompt: 'As a Life Coach...',
  persona_name: 'Life Coach',
  pipeline_mode: 'full',
  context: 'Here are a few times that you have helped...',
  default_replica_id: 'rfe12d8b9597',
  document_ids: ['d1234567890', 'd2468101214'],
  document_tags: ['product_info', 'company_policies'],
  layers: {
    llm: {
      model: 'tavus-gpt-4o',
      base_url: 'your-base-url',
      api_key: 'your-api-key',
      tools: [
        {
          type: 'function',
          function: {
            name: 'get_current_weather',
            description: 'Get the current weather in a given location',
            parameters: {
              type: 'object',
              properties: {
                location: {
                  type: 'string',
                  description: 'The city and state, e.g. San Francisco, CA'
                },
                unit: {
                  type: 'string',
                  enum: ['celsius', 'fahrenheit']
                }
              },
              required: ['location']
            }
          }
        }
      ]
    },
    tts: {
      tts_engine: 'cartesia',
      external_voice_id: 'external-voice-id',
      voice_settings: {
        speed: 0.5,
        emotion: ['positivity:high', 'curiosity']
      },
      tts_emotion_control: 'false',
      tts_model_name: 'sonic'
    },
    perception: {
      perception_model: 'raven-0',
      ambient_awareness_queries: [
        'Is the user showing an ID card?',
        'Does the user appear distressed or uncomfortable?'
      ]
    },
    stt: {
      stt_engine: 'tavus-turbo',
      participant_pause_sensitivity: 'low',
      participant_interrupt_sensitivity: 'low',
      hotwords: 'This is a hotword example',
      smart_turn_detection: true
    }
  }
)

# Response includes:
# {
#   "persona_id" => "p5317866",
#   "persona_name" => "Life Coach",
#   "created_at" => "2025-10-04T12:00:00Z"
# }

Get a Persona

persona = client.personas.get('p5317866')

List Personas

# List all personas
personas = client.personas.list

# List with pagination and filters
personas = client.personas.list(
  limit: 20,
  page: 1,
  persona_type: 'user' # or 'system'
)

# Response includes:
# {
#   "data" => [...],
#   "total_count" => 123
# }

Update a Persona (JSON Patch)

# Update multiple fields using patch operations
operations = [
  { op: 'replace', path: '/persona_name', value: 'Wellness Advisor' },
  { op: 'replace', path: '/default_replica_id', value: 'r79e1c033f' },
  { op: 'replace', path: '/context', value: 'Updated context...' },
  { op: 'replace', path: '/layers/llm/model', value: 'tavus-gpt-4o' },
  { op: 'add', path: '/layers/tts/tts_emotion_control', value: 'true' },
  { op: 'remove', path: '/layers/stt/hotwords' }
]

result = client.personas.patch('p5317866', operations)

# Helper method to build patch operations
operation = client.personas.build_patch_operation(
  '/persona_name',
  'New Name',
  operation: 'replace'
)

# Convenient method to update a single field
result = client.personas.update_field(
  'p5317866',
  '/persona_name',
  'New Name'
)

Delete a Persona

result = client.personas.delete('p5317866')

Replicas

Create a Replica

# Create a replica for conversational video
replica = client.replicas.create(
  train_video_url: 'https://my-bucket.s3.amazonaws.com/training-video.mp4',
  replica_name: 'My Replica',
  model_name: 'phoenix-3', # Optional, defaults to phoenix-3
  consent_video_url: 'https://my-bucket.s3.amazonaws.com/consent-video.mp4', # Optional
  callback_url: 'https://yourwebsite.com/webhook'
)

# Response includes:
# {
#   "replica_id" => "r783537ef5",
#   "status" => "started"
# }

Get a Replica

# Get basic replica info
replica = client.replicas.get('r783537ef5')

# Get detailed replica info with verbose flag
replica = client.replicas.get('r783537ef5', verbose: true)

List Replicas

# List all replicas
replicas = client.replicas.list

# List with filters
replicas = client.replicas.list(
  limit: 20,
  page: 1,
  replica_type: 'user', # or 'system'
  replica_ids: 're1074c227,r243eed46c',
  verbose: true
)

Rename a Replica

client.replicas.rename('r783537ef5', 'Updated Replica Name')

Delete a Replica

# Soft delete
client.replicas.delete('r783537ef5')

# Hard delete (irreversible - deletes all assets)
client.replicas.delete('r783537ef5', hard: true)

Objectives

Create Objectives

objectives = client.objectives.create(
  data: [
    {
      objective_name: 'Gather User Feedback',
      objective_prompt: 'Ask the user about their experience with the product',
      confirmation_mode: 'automatic',
      modality: 'verbal'
    }
  ]
)

Get an Objective

objective = client.objectives.get('o12345')

List Objectives

objectives = client.objectives.list(limit: 20, page: 1)

Update an Objective

operations = [
  { op: 'replace', path: '/data/0/objective_name', value: 'Updated Objective' },
  { op: 'replace', path: '/data/0/confirmation_mode', value: 'manual' }
]

client.objectives.patch('o12345', operations)

# Or update a single field
client.objectives.update_field('o12345', '/data/0/objective_name', 'New Name')

Delete an Objective

client.objectives.delete('o12345')

Guardrails

Create Guardrails

guardrails = client.guardrails.create(
  name: 'Healthcare Compliance Guardrails',
  data: [
    {
      guardrails_prompt: 'Never discuss competitor products or share sensitive medical information',
      modality: 'verbal',
      callback_url: 'https://your-server.com/webhook'
    }
  ]
)

Get Guardrails

guardrails = client.guardrails.get('g12345')

List Guardrails

guardrails = client.guardrails.list(limit: 20, page: 1)

Update Guardrails

operations = [
  { op: 'replace', path: '/data/0/guardrails_prompt', value: 'Updated guardrails prompt' },
  { op: 'add', path: '/data/0/callback_url', value: 'https://new-server.com/webhook' }
]

client.guardrails.patch('g12345', operations)

# Or update a single field
client.guardrails.update_field('g12345', '/data/0/guardrails_prompt', 'New prompt')

Delete Guardrails

client.guardrails.delete('g12345')

Documents (Knowledge Base)

Create a Document

# Upload from URL
document = client.documents.create(
  document_url: 'https://example.com/document.pdf',
  document_name: 'Product Documentation',
  callback_url: 'https://your-server.com/webhook',
  tags: ['product', 'documentation'],
  properties: { department: 'sales', priority: 'high' }
)

# Supported formats: .pdf, .txt, .docx, .doc, .png, .jpg, .pptx, .csv, .xlsx
# Also supports website URLs for snapshots

Get a Document

document = client.documents.get('d290f1ee-6c54-4b01-90e6-d701748f0851')

List Documents

# List all documents
documents = client.documents.list

# List with filters
documents = client.documents.list(
  limit: 20,
  page: 0,
  sort: 'descending',
  status: 'ready',
  tags: 'product,documentation'
)

Update a Document

client.documents.update(
  'd290f1ee-6c54-4b01-90e6-d701748f0851',
  document_name: 'Updated Document Name',
  tags: ['updated', 'important']
)

Delete a Document

client.documents.delete('d290f1ee-6c54-4b01-90e6-d701748f0851')

Videos

Generate a Video

# Generate video from text script
video = client.videos.create(
  replica_id: 'r783537ef5',
  script: 'Hello from Tavus! Enjoy your new replica',
  video_name: 'My First Video',
  background_url: 'https://yourwebsite.com/',
  callback_url: 'https://yourwebsite.com/webhook'
)

# Or use the convenient method
video = client.videos.generate_from_text(
  replica_id: 'r783537ef5',
  script: 'Hello from Tavus!',
  video_name: 'My Video'
)

# Generate video from audio file
video = client.videos.generate_from_audio(
  replica_id: 'r783537ef5',
  audio_url: 'https://my-bucket.s3.amazonaws.com/audio.mp3',
  video_name: 'Audio Video'
)

# Advanced options
video = client.videos.create(
  replica_id: 'r783537ef5',
  script: 'Hello!',
  fast: true, # Use fast rendering
  transparent_background: true, # Requires fast: true
  watermark_image_url: 'https://s3.amazonaws.com/watermark.png',
  background_source_url: 'https://my-bucket.s3.amazonaws.com/background.mp4'
)

# Response includes:
# {
#   "video_id" => "abcd123",
#   "status" => "queued",
#   "hosted_url" => "https://tavus.video/abcd123"
# }

Get a Video

# Get basic video info
video = client.videos.get('abcd123')

# Get detailed info with thumbnails
video = client.videos.get('abcd123', verbose: true)

# Response includes download_url, stream_url, hosted_url when ready

List Videos

videos = client.videos.list(limit: 20, page: 1)

Rename a Video

client.videos.rename('abcd123', 'New Video Name')

Delete a Video

# Soft delete
client.videos.delete('abcd123')

# Hard delete (irreversible - deletes all assets)
client.videos.delete('abcd123', hard: true)

Error Handling

The gem provides specific error classes for different API responses:

begin
  conversation = client.conversations.create(replica_id: 'invalid')
rescue Tavus::AuthenticationError => e
  # Handle authentication errors (401)
  puts "Authentication failed: #{e.message}"
rescue Tavus::BadRequestError => e
  # Handle bad request errors (400)
  puts "Bad request: #{e.message}"
rescue Tavus::NotFoundError => e
  # Handle not found errors (404)
  puts "Resource not found: #{e.message}"
rescue Tavus::ValidationError => e
  # Handle validation errors (422)
  puts "Validation failed: #{e.message}"
rescue Tavus::RateLimitError => e
  # Handle rate limit errors (429)
  puts "Rate limit exceeded: #{e.message}"
rescue Tavus::ServerError => e
  # Handle server errors (5xx)
  puts "Server error: #{e.message}"
rescue Tavus::ApiError => e
  # Handle any other API errors
  puts "API error: #{e.message}"
rescue Tavus::ConfigurationError => e
  # Handle configuration errors
  puts "Configuration error: #{e.message}"
end

API Reference

Conversations

Method Description
create(replica_id:, persona_id:, **options) Create a new conversation
get(conversation_id) Get a conversation by ID
list(**options) List all conversations
end(conversation_id) End a conversation
delete(conversation_id) Delete a conversation

Personas

Method Description
create(system_prompt:, **options) Create a new persona
get(persona_id) Get a persona by ID
list(**options) List all personas
patch(persona_id, operations) Update a persona using JSON Patch
build_patch_operation(field, value, operation:) Build a JSON Patch operation
update_field(persona_id, field, value) Update a single field
delete(persona_id) Delete a persona

Replicas

Method Description
create(train_video_url:, **options) Create a new replica
get(replica_id, verbose: false) Get a replica by ID
list(**options) List all replicas
rename(replica_id, replica_name) Rename a replica
delete(replica_id, hard: false) Delete a replica

Objectives

Method Description
create(data:) Create new objectives
get(objectives_id) Get an objective by ID
list(**options) List all objectives
patch(objectives_id, operations) Update an objective using JSON Patch
build_patch_operation(field, value, operation:) Build a JSON Patch operation
update_field(objectives_id, field, value) Update a single field
delete(objectives_id) Delete an objective

Guardrails

Method Description
create(name:, data:) Create new guardrails
get(guardrails_id) Get guardrails by ID
list(**options) List all guardrails
patch(guardrails_id, operations) Update guardrails using JSON Patch
build_patch_operation(field, value, operation:) Build a JSON Patch operation
update_field(guardrails_id, field, value) Update a single field
delete(guardrails_id) Delete guardrails

Documents (Knowledge Base)

Method Description
create(document_url:, **options) Upload a new document
get(document_id) Get a document by ID
list(**options) List all documents
update(document_id, **options) Update document metadata
delete(document_id) Delete a document

Videos

Method Description
create(replica_id:, **options) Generate a new video
generate_from_text(replica_id:, script:, **options) Generate video from text
generate_from_audio(replica_id:, audio_url:, **options) Generate video from audio
get(video_id, verbose: false) Get a video by ID
list(**options) List all videos
rename(video_id, video_name) Rename a video
delete(video_id, hard: false) Delete a video

JSON Patch Operations

Several resources (Personas, Objectives, and Guardrails) support updates via JSON Patch operations following RFC 6902. This allows for precise, atomic updates to specific fields.

Supported Operations

  • add: Add a new field or array element
  • remove: Remove a field or array element
  • replace: Replace an existing field value
  • copy: Copy a value from one location to another
  • move: Move a value from one location to another
  • test: Test that a value at a location equals a specified value

Examples

# Replace a single field
operations = [
  { op: 'replace', path: '/persona_name', value: 'New Name' }
]

# Multiple operations in one request
operations = [
  { op: 'replace', path: '/persona_name', value: 'Updated Name' },
  { op: 'add', path: '/layers/tts/tts_emotion_control', value: 'true' },
  { op: 'remove', path: '/layers/stt/hotwords' }
]

# Update nested fields
operations = [
  { op: 'replace', path: '/layers/llm/model', value: 'tavus-gpt-4o' }
]

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install.

CI/CD

This project uses GitHub Actions for continuous integration:

  • Tests: Runs on Ruby 2.7, 3.0, 3.1, 3.2, and 3.3
  • Linting: RuboCop style checking
  • Security: Bundle audit for dependency vulnerabilities

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/vbrazo/tavus.

License

The gem is available as open source under the terms of the MIT License.

Resources

Changelog

See CHANGELOG.md for a detailed list of changes and version history.