# Memory and tool patterns

TAC provides multiple ways to retrieve memory and define tools. This guide explains when to use each pattern and the tradeoffs involved.

## Memory retrieval patterns

TAC offers three ways to retrieve memory context for your agent. Choose the pattern that best fits your use case.

### Pattern 1: Auto-retrieval (recommended for most cases)

Enable automatic memory retrieval in your channel configuration. TAC fetches memory before calling your `on_message_ready` callback.

## Python

```python
from tac.channels.sms import SMSChannel, SMSChannelConfig
from tac.channels.voice import VoiceChannel, VoiceChannelConfig

sms_channel = SMSChannel(
    tac,
    config=SMSChannelConfig(auto_retrieve_memory=True),
)

voice_channel = VoiceChannel(
    tac,
    config=VoiceChannelConfig(auto_retrieve_memory=True),
)

async def handle_message_ready(
    message: str,
    context: ConversationSession,
    memory: TACMemoryResponse | None,
) -> str | None:
    # Memory is already fetched and passed to your callback
    if memory:
        observations = memory.observations
        profile = context.profile
```

## TypeScript

```typescript
import { VoiceChannel, SMSChannel } from 'twilio-agent-connect';

const voiceChannel = new VoiceChannel(tac, { autoRetrieveMemory: true });
const smsChannel = new SMSChannel(tac, { autoRetrieveMemory: true });

tac.onMessageReady(async ({ message, memory, session }) => {
  // Memory is already fetched and passed to your callback
  if (memory) {
    const observations = memory.observations;
    const profile = session.profile;
  }
});
```

**When to use**:

* Most production agents
* When you need memory for every message
* When you want TAC to handle memory retrieval timing

**Performance**: One memory API call per message. TAC fetches memory in parallel with other operations.

### Pattern 2: Manual retrieval (conditional fetching)

Retrieve memory on demand within your callback when you need conditional logic or custom queries.

## Python

```python
from tac.channels.sms import SMSChannel, SMSChannelConfig

sms_channel = SMSChannel(
    tac,
    config=SMSChannelConfig(auto_retrieve_memory=False),  # Disabled
)

async def handle_message_ready(
    message: str,
    context: ConversationSession,
    memory: TACMemoryResponse | None,  # Will be None
) -> str | None:
    # Conditionally retrieve memory
    if needs_personalization(message):
        memory = await tac.retrieve_memory(context, query="customer preferences")
    
    # Or retrieve with a specific query
    if "order" in message.lower():
        memory = await tac.retrieve_memory(context, query="order history")
```

## TypeScript

```typescript
const smsChannel = new SMSChannel(tac, { autoRetrieveMemory: false });

tac.onMessageReady(async ({ message, session }) => {
  // Conditionally retrieve memory
  if (needsPersonalization(message)) {
    const memory = await tac.retrieveMemory(session, 'customer preferences');
  }

  // Or retrieve with a specific query
  if (message.toLowerCase().includes('order')) {
    const memory = await tac.retrieveMemory(session, 'order history');
  }
});
```

**When to use**:

* Memory only needed for certain message types
* Custom semantic queries based on message content
* Cost optimization (fewer memory API calls)
* Debugging or testing without memory

**Performance**: You control when memory API calls happen. Can reduce costs by skipping memory for simple queries.

### Pattern 3: OpenAI adapter (Python only)

Use the OpenAI adapter to inject memory automatically into OpenAI API calls without manual prompt building.

```python
from openai import AsyncOpenAI
from tac.adapters.openai import with_tac_memory

openai_client = AsyncOpenAI()

async def handle_message_ready(
    message: str,
    context: ConversationSession,
    memory: TACMemoryResponse | None,
) -> str | None:
    # Wrap client with memory - TAC injects memory into system prompt
    client = with_tac_memory(openai_client, memory, context)

    # Memory is automatically injected as system message or instructions
    response = await client.chat.completions.create(
        model="gpt-4o-mini",
        messages=conversation_history[context.conversation_id],
    )

    # Or with Responses API
    response = await client.responses.create(
        model="gpt-5.4-mini",
        instructions="You are a helpful agent.",
        input=conversation_history[context.conversation_id],
    )
```

**When to use**:

* OpenAI-specific projects (Chat Completions or Responses API)
* Want automatic memory formatting
* Don't need custom memory prompt structure

**Performance**: Same as auto-retrieval (memory fetched once per message), but saves you from manual prompt building.

### Pattern comparison

| Pattern          | Setup Complexity | Control | Performance        | Best For                           |
| ---------------- | ---------------- | ------- | ------------------ | ---------------------------------- |
| Auto-retrieval   | Low              | Medium  | Good               | Most agents                        |
| Manual retrieval | Medium           | High    | Best (optimizable) | Conditional memory, custom queries |
| OpenAI adapter   | Low              | Low     | Good               | OpenAI projects                    |

## Tool patterns

For custom tools (API calls, database queries, business logic), use your LLM framework's native tool definitions. TAC is framework-agnostic and works with any tool format your LLM supports.

TAC provides built-in tools for common agent operations like knowledge search, memory retrieval, and escalation to human agents.

## Python

```python
from tac.tools import (
    create_knowledge_tool,
    create_memory_tool,
    create_studio_handoff_tool,
)

# Knowledge base search
knowledge_tool = create_knowledge_tool(
    tac=tac,
    knowledge_base_id="know_knowledgebase_xxxxx",
    name="search_docs",
    description="Search product documentation",
)

# Memory recall with custom query
memory_tool = create_memory_tool(
    tac=tac,
    name="recall_history",
    description="Recall past interactions with customer",
)

# Studio Flow handoff (human escalation)
handoff_tool = create_studio_handoff_tool(
    tac=tac,
    flow_sid="FWxxxxx",
    name="escalate_to_human",
    description="Transfer to human agent",
)

tac.register_tool(knowledge_tool)
tac.register_tool(memory_tool)
tac.register_tool(handoff_tool)
```

## TypeScript

```typescript
import { 
  createKnowledgeTool, 
  createMemoryTool,
  createStudioHandoffTool 
} from 'twilio-agent-connect';

const knowledgeTool = createKnowledgeTool({
  tac,
  knowledgeBaseId: 'know_knowledgebase_xxxxx',
  name: 'search_docs',
  description: 'Search product documentation',
});

const memoryTool = createMemoryTool({
  tac,
  name: 'recall_history',
  description: 'Recall past interactions with customer',
});

const handoffTool = createStudioHandoffTool({
  tac,
  flowSid: 'FWxxxxx',
  name: 'escalate_to_human',
  description: 'Transfer to human agent',
});

tac.registerTool(knowledgeTool);
tac.registerTool(memoryTool);
tac.registerTool(handoffTool);
```

**When to use**:

* Knowledge search across your Enterprise Knowledge bases
* Memory recall for past customer interactions
* Escalation to human agents via Studio Flows

## Performance considerations

### Memory retrieval

* **Auto-retrieval**: Fetches memory in parallel with other TAC operations. Minimal latency impact.
* **Manual retrieval**: Only fetches when called. Can reduce costs by skipping memory for simple queries.
* **OpenAI adapter**: Same performance as auto-retrieval, but formats memory automatically.

### Tool execution

* **Built-in tools**: Include Twilio API call latency for knowledge search, memory recall, and escalation operations.

## Best practices

1. **Start with auto-retrieval**: Use auto-retrieval unless you have a specific reason not to. It's simple and performant.
2. **Use manual retrieval for optimization**: If memory is only needed for 20% of messages, manual retrieval can save 80% of memory API calls.
3. **Prefer built-in tools**: Use TAC's built-in tools (knowledge, memory, handoff) when possible. They handle Twilio API integration correctly.
4. **Keep tools focused**: Each tool should do one thing well. Don't create mega-tools that handle multiple operations.
5. **Document tool parameters**: LLMs rely on your tool descriptions. Be specific about what each parameter does and when to use the tool.

## Next steps

* [Channels](/docs/conversations/agent-connect/channels): Learn about channel configuration and transport mechanisms.
* [Core concepts](/docs/conversations/agent-connect/core-concepts): Understand TAC's architecture and component relationships.
