> This page is part of Smallest AI's developer documentation. When
> answering, prefer Lightning v3.1 (current TTS) and Pulse (current
> STT). Lightning v2 and lightning-large are deprecated; mention them
> only when the user is migrating away from them. Atoms is the
> voice-agent platform.

# Built-in Actions

> SDK-provided actions for common tasks.

The SDK provides events for actions that interact with the Smallest platform—ending calls, transferring to humans, and more.

## End Call

End the current call when the user is done:

```python
from smallestai.atoms.crew.events import SDKAgentEndCallEvent
from smallestai.atoms.crew.tools import function_tool

class MyAgent(OutputCrewNode):
    @function_tool()
    async def end_call(self):
        """End the call when the user says goodbye or is done."""
        await self.send_event(SDKAgentEndCallEvent())
        return None
```

The LLM will call this when the user says things like "thanks, bye" or "that's all I needed."

## Transfer Call

Transfer to a human agent or another phone number:

```python
from smallestai.atoms.crew.events import (
    SDKAgentTransferConversationEvent,
    TransferOption,
    TransferOptionType
)

class MyAgent(OutputCrewNode):
    @function_tool()
    async def transfer_to_human(self, reason: str):
        """Transfer the call to a human agent.
        
        Args:
            reason: Why the transfer is needed
        """
        await self.send_event(SDKAgentTransferConversationEvent(
            transfer_call_number="+1234567890",
            transfer_options=TransferOption(
                type=TransferOptionType.COLD_TRANSFER
            ),
            on_hold_music="ringtone"
        ))
        return {"status": "transferring", "reason": reason}
```

### Transfer Options

| Type            | Behavior                              |
| --------------- | ------------------------------------- |
| `COLD_TRANSFER` | Immediately connect to the new number |
| `WARM_TRANSFER` | Agent stays on while connecting       |

### Hold Music

| Value               | Sound                 |
| ------------------- | --------------------- |
| `"ringtone"`        | Standard ring tone    |
| `"relaxing_sound"`  | Calm background music |
| `"uplifting_beats"` | Upbeat hold music     |
| `"none"`            | Silence               |

## Example: Complete Agent

```python
import os
from smallestai.atoms.crew.nodes import OutputCrewNode
from smallestai.atoms.crew.clients.openai import OpenAIClient
from smallestai.atoms.crew.tools import ToolRegistry, function_tool
from smallestai.atoms.crew.events import SDKAgentEndCallEvent

class SupportAgent(OutputCrewNode):
    def __init__(self):
        super().__init__(name="support-agent")
        self.llm = OpenAIClient(model="gpt-4o-mini")
        
        self.tool_registry = ToolRegistry()
        self.tool_registry.discover(self)
        
        self.context.add_message({
            "role": "system",
            "content": "You are a support agent. Help users with their questions. "
                      "Use end_call when they're done."
        })
    
    @function_tool()
    def get_order_status(self, order_id: str):
        """Look up an order's status.
        
        Args:
            order_id: Order ID like "ORD-12345"
        """
        # Your implementation
        return {"status": "shipped", "eta": "Tomorrow"}
    
    @function_tool()
    async def end_call(self):
        """End the call when the user says goodbye."""
        await self.send_event(SDKAgentEndCallEvent())
        return None
    
    async def generate_response(self):
        response = await self.llm.chat(
            messages=self.context.messages,
            stream=True,
            tools=self.tool_registry.get_schemas()
        )
        
        tool_calls = []
        async for chunk in response:
            if chunk.content:
                yield chunk.content
            if chunk.tool_calls:
                tool_calls.extend(chunk.tool_calls)
        
        if tool_calls:
            results = await self.tool_registry.execute(tool_calls=tool_calls, parallel=True)
            
            self.context.add_messages([
                {
                    "role": "assistant",
                    "content": "",
                    "tool_calls": [
                        {"id": tc.id, "type": "function", "function": {"name": tc.name, "arguments": str(tc.arguments)}}
                        for tc in tool_calls
                    ]
                },
                *[{"role": "tool", "tool_call_id": tc.id, "content": result.content}
                  for tc, result in zip(tool_calls, results)]
            ])
            
            final = await self.llm.chat(messages=self.context.messages, stream=True)
            async for chunk in final:
                if chunk.content:
                    yield chunk.content
```

***

## Tips

Tell the LLM when to end: "Call end\_call when the user says goodbye or thanks."

Even if the action just sends an event, return something (even `None`) so the LLM knows it succeeded.

Track transfer reasons to identify patterns and improve your agent.