Metadata-Version: 2.4
Name: sarvam-conv-ai-sdk
Version: 1.0.2
Summary: A Python SDK for building multilingual, context-aware conversational agents on Sarvam's Samvaad platform.
License-Expression: MIT
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic>=2.11.7
Dynamic: license-file

# Sarvam Conv AI SDK

The **Sarvam Conversational AI SDK** is a Python package that helps developers build and extend conversational agents. It provides core components to manage conversation flow, language preferences, and messaging, making it easier to develop interactive and context-aware AI experiences.

---

## Overview

The Sarvam Conv AI SDK enables developers to create tools that can:

* Facilitate agentic capabilities like API calling in the middle of a conversation.
* Manage agent-specific variables and state across interactions
* Control and modify the language used during conversations
* Send dynamic messages to both the user and the underlying language model (LLM)

---

## Installation

Install the SDK via pip:

```bash
pip install sarvam-conv-ai-sdk
```

---

## Example Usage

```python
import httpx
from pydantic import Field
from sarvam_conv_ai_sdk import (
    SarvamToolLanguageName,
    SarvamOnEndTool,
    SarvamOnStartTool,
    SarvamTool,
    SarvamOnStartToolContext,
    SarvamToolContext,
    SarvamOnEndToolContext,
    SarvamToolOutput
)

class OnStart(SarvamOnStartTool):
    async def run(self, context: SarvamOnStartToolContext):
        user_id = context.get_user_identifier()
        async with httpx.AsyncClient() as client:
            response = await client.get(f"https://sarvam-flights.com/users/{user_id}")
            response.raise_for_status()
            user_data = response.json()

        source_destination = user_data.get("home_city")
        context.set_agent_variable("source_destination", source_destination)
        context.set_agent_variable("passenger_name", user_data.get("name"))
        context.set_initial_language_name(SarvamToolLanguageName.ENGLISH)
        context.set_initial_bot_message(
            f"Hello! Would you like to book a flight from {source_destination}? Where would you like to go?",
        )
        return context


class BookFlight(SarvamTool):
    """Book a flight based on the user's travel preferences."""

    destination: str = Field(description="City of destination")
    travel_date: str = Field(description="Date of travel (YYYY-MM-DD)")

    async def run(self, context: SarvamToolContext) -> SarvamToolOutput:
        source_destination = context.get_agent_variable("source_destination")
        booking_data = {
            "source": source_destination,
            "destination": self.destination,
            "travel_date": self.travel_date,
            "passenger_name": context.get_agent_variable("passenger_name"),
        }

        async with httpx.AsyncClient() as client:
            response = await client.post(
                "https://sarvam-flights.com/book", json=booking_data
            )
            response.raise_for_status()
            booking_result = response.json()

        if booking_result.get("status") == "confirmed":
            context.set_agent_variable("booking_id", booking_result.get("booking_id"))
            context.set_end_conversation()
            return SarvamToolOutput(
                message_to_user=f"Flight booked successfully to {self.destination}!",
                context=context
            )
        else:
            return SarvamToolOutput(
                message_to_llm="Booking failed. Please suggest similar destinations.",
                context=context
            )


class OnEnd(SarvamOnEndTool):
    async def run(self, context: SarvamOnEndToolContext):
        feedback = context.get_agent_variable("feedback")
        negative_words = ["bad", "poor", "disappointed", "unhappy", "problem"]
        is_negative = any(word in feedback.lower() for word in negative_words)
        context.set_agent_variable("feedback_sentiment", is_negative)
        return context
```

---

## Base Classes

The SDK exposes three base classes for tool development:

### 1. `SarvamTool`

Primary base class for all operational tools invoked during conversation flow.

**Example:**

```python
class MyCustomTool(SarvamTool):
    """Brief description of the tool's purpose."""

    tool_variable: type = Field(description="Description of this input parameter")

    async def run(self, context: SarvamToolContext) -> SarvamToolOutput:
        # Custom tool logic
        return SarvamToolOutput(
            message_to_user="Response to user",
            message_to_llm="Context for LLM",
            context=context
        )
```

### 2. `SarvamOnStartTool`

Executed at the beginning of a conversation, typically for initialization. The class **must** be named `OnStart`.

### 3. `SarvamOnEndTool`

Executed at the end of a conversation, typically for cleanup or post-processing. The class **must** be named `OnEnd`.

---

## Context Classes and Methods

### `SarvamToolContext`

The context object passed to `SarvamTool.run()` methods.

#### Variable Management

* `get_agent_variable(variable_name: str) -> Any`
  Retrieve the value of a variable.

* `set_agent_variable(variable_name: str, value: Any) -> None`
  Update a variable's value.

#### Language Control

* `get_current_language() -> SarvamToolLanguageName`
  Returns the current language preference.

* `change_language(language: SarvamToolLanguageName) -> None`
  Update the language preference.

#### Conversation Flow

* `set_end_conversation() -> None`
  Explicitly end the conversation.

---

### `SarvamOnStartToolContext`

The context object passed to `SarvamOnStartTool.run()` methods.

#### Variable Management

* `get_agent_variable(variable_name: str) -> Any`
  Retrieve the value of a variable.

* `set_agent_variable(variable_name: str, value: Any) -> None`
  Update a variable's value.

#### User Information

* `get_user_identifier() -> str`
  Get the user identifier.

#### Initialization Methods

* `set_initial_bot_message(message: str) -> None`
  Set the first message sent by the agent when the conversation starts.

* `set_initial_state_name(state_name: str) -> None`
  Set the initial state from which the agent should start.

* `set_initial_language_name(language: SarvamToolLanguageName) -> None`
  Define the initial language preference for the user.

---

### `SarvamOnEndToolContext`

The context object passed to `SarvamOnEndTool.run()` methods.

#### Variable Management

* `get_agent_variable(variable_name: str) -> Any`
  Retrieve the value of a variable.

* `set_agent_variable(variable_name: str, value: Any) -> None`
  Update a variable's value.

#### User Information

* `get_user_identifier() -> str`
  Get the user identifier.

#### Interaction Transcript

* `get_interaction_transcript() -> Optional[InteractionTranscript]`
  Retrieve the conversation history containing user and agent messages in English.

**Example transcript:**
```python
[
    InteractionTurn(role=<InteractionTurnRole.AGENT: 'agent'>, en_text='Hello! How can I help you today?'),
    InteractionTurn(role=<InteractionTurnRole.USER: 'user'>, en_text='I need to book a flight'),
    InteractionTurn(role=<InteractionTurnRole.AGENT: 'agent'>, en_text='I can help you with that. Where would you like to go?'),
    InteractionTurn(role=<InteractionTurnRole.USER: 'user'>, en_text='I want to go to Mumbai'),
    InteractionTurn(role=<InteractionTurnRole.AGENT: 'agent'>, en_text='Great! When would you like to travel?')
]
```

---

## Return Types

### `SarvamToolOutput`

The return type for `SarvamTool.run()` methods. Contains:

* `message_to_user: Optional[str]` - Message that is sent directly to the user
* `message_to_llm: Optional[str]` - Message that is sent to the LLM, which then responds
* `context: SarvamToolContext` - The updated context object

**Note:** At least one of `message_to_llm` or `message_to_user` must be set.

**Important:** When both `message_to_user` and `message_to_llm` are set, only the `message_to_user` is actually sent to the user, but the `message_to_llm` overrides the `message_to_user` when adding to the chat thread for the LLM's context.

---

## Supported Languages

The SDK supports multilingual conversations using the `SarvamToolLanguageName` enum. Available languages include:

* Bengali
* Gujarati
* Kannada
* Malayalam
* Tamil
* Telugu
* Punjabi
* Odia
* Marathi
* Hindi
* English

---

## Best Practices

1. **Always implement `run()`**: The `run()` method is the entry point for tool execution logic.
2. **Use `Field()` for parameters**: Ensures type safety and adds descriptive metadata necessary for LLM to use in the prompt.
3. **Gracefully handle errors**: Avoid accessing unset variables or using invalid types.
4. **Return the appropriate type**: `SarvamTool.run()` must return `SarvamToolOutput`, while `SarvamOnStartTool.run()` and `SarvamOnEndTool.run()` return their respective context objects.
5. **Write meaningful docstrings**: Clearly describe what each tool is intended to do as this directly impacts the performance of tool calling capabilities of the agent.
6. **Use async operations for I/O**: For the best performance, use `async/await` for external API calls to avoid blocking.
7. **Use context methods**: Use the provided context methods for variable management, language control, and messaging instead of directly accessing context attributes.

---

## Error Handling

The SDK includes built-in error handling for common scenarios:

* **Variable not found**: Raises ValueError when accessing undefined variables
* **Variable not defined**: Raises ValueError when setting variables that haven't been initialized
* **Non-serializable values**: Raises ValueError when variable values cannot be JSON serialized
* **Invalid output**: Raises ValueError when `SarvamToolOutput` is created without at least one message
