---
title: "Assistant Chat"
description: "The Assistant Chat module provides an API for managing ephemeral chat history for an AI assistant. It allows users to retrieve, save, and clear their conversation history, scoped to their user ID a..."
last_updated: "2026-05-06T07:29:41.620964+00:00"
canonical_url: "https://www.doc0.dev/docs/49c89830-117b-4def-8edc-b5bcc50766e0/technical/section-3/assistant-chat"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [apps/api/src/assistant-chat/assistant-chat.service.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.service.ts)
- [apps/api/src/assistant-chat/assistant-chat.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.controller.ts)
- [apps/api/src/assistant-chat/assistant-chat.dto.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.dto.ts)
- [apps/api/src/assistant-chat/upstash-redis.client.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/upstash-redis.client.ts)
- [apps/api/src/assistant-chat/assistant-chat.types.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.types.ts)
- [apps/api/src/assistant-chat/assistant-chat.module.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.module.ts)
</details>

The Assistant Chat module provides an API for managing ephemeral chat history for an AI assistant. It allows users to retrieve, save, and clear their conversation history, scoped to their user ID and organization ID. The history is stored in a Redis-compatible key-value store with a default time-to-live (TTL) of 7 days, designed for session context rather than long-term archiving.

This module integrates with the application's authentication system to ensure that chat history operations are user-scoped and secure. It leverages a flexible Redis client that can connect to an Upstash Redis instance or fall back to an in-memory store for development or testing environments.

## Architecture Overview

The Assistant Chat feature is implemented as a NestJS module, encapsulating its components: a controller for handling API requests, a service for business logic and data manipulation, and DTOs for data validation and transfer. It relies on a Redis client for persistence and integrates with the application's authentication module.

<Callout title="Ephemeral Session Context" variant="info">
The chat history is designed to be ephemeral, with a default Time-To-Live (TTL) of 7 days. This means chat sessions are not intended for long-term storage or searchable archives but rather for maintaining context within recent interactions. The TTL can be configured via the `ASSISTANT_CHAT_TTL_SECONDS` environment variable.
</Callout>


Sources: [apps/api/src/assistant-chat/assistant-chat.module.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.module.ts), [apps/api/src/assistant-chat/assistant-chat.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.controller.ts), [apps/api/src/assistant-chat/assistant-chat.service.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.service.ts)

## API Endpoints

The `AssistantChatController` exposes a set of RESTful endpoints for managing assistant chat history. All endpoints are protected by the `HybridAuthGuard` and require user-scoped authentication. API key authentication is explicitly disallowed for chat history operations.

### Base Path
`/v1/assistant-chat`
Sources: [apps/api/src/assistant-chat/assistant-chat.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.controller.ts)

### Endpoints

| Method | Path      | Description                                                               | Request Body                               | Response Body                                  |
| :----- | :-------- | :------------------------------------------------------------------------ | :----------------------------------------- | :--------------------------------------------- |
| `GET`  | `/history` | Retrieves the current user-scoped assistant chat history.                 | N/A                                        | `{ messages: AssistantChatMessage[] }`         |
| `PUT`  | `/history` | Replaces the current user-scoped assistant chat history with new messages. | `SaveAssistantChatHistoryDto`              | `{ success: true }`                            |
| `DELETE` | `/history` | Deletes the current user-scoped assistant chat history.                   | N/A                                        | `{ success: true }`                            |
Sources: [apps/api/src/assistant-chat/assistant-chat.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.controller.ts)

### Authentication and Authorization

All endpoints are secured using `HybridAuthGuard`. The `AuthContext` decorator is used to extract user and organization information from the authenticated request. A `BadRequestException` is thrown if the `organizationId` or `userId` is missing, or if the request is authenticated via an API key instead of a user JWT.

<Callout title="User-Scoped Access Only" variant="warning">
Assistant chat history operations are strictly limited to user-authenticated requests (Bearer JWT). Requests authenticated with an API key will be rejected with a `BadRequestException`. This ensures that chat history is always tied to a specific user and organization.
</Callout>
Sources: [apps/api/src/assistant-chat/assistant-chat.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.controller.ts)

## Data Models

The core data structure for assistant chat is `AssistantChatMessage`, which represents a single message in the conversation.

### AssistantChatMessage

This type defines the structure of a single message, including its ID, role (user or assistant), text content, and creation timestamp.

| Field     | Type     | Description                                | Example               |
| :-------- | :------- | :----------------------------------------- | :-------------------- |
| `id`      | `string` | Unique identifier for the message.         | `msg_abc123`          |
| `role`    | `'user' \| 'assistant'` | The sender of the message.                 | `user`                |
| `text`    | `string` | The content of the message.                | `How do I invite a teammate?` |
| `createdAt` | `number` | Unix epoch timestamp in milliseconds.      | `1735781554000`       |
Sources: [apps/api/src/assistant-chat/assistant-chat.types.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.types.ts), [apps/api/src/assistant-chat/assistant-chat.dto.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.dto.ts)

### Data Transfer Objects (DTOs)

The `assistant-chat.dto.ts` file defines DTOs used for API request bodies and Swagger documentation.


Sources: [apps/api/src/assistant-chat/assistant-chat.dto.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.dto.ts)

## Service Logic

The `AssistantChatService` handles the core business logic for chat history management, including interaction with the Redis client and data validation.

### Key Generation

A unique key is generated for each user's chat history in Redis, combining the organization ID and user ID. This ensures data isolation between different users and organizations.

```typescript
const getAssistantChatKey = ({
  organizationId,
  userId,
}: GetAssistantChatKeyParams): string => {
  return `assistant-chat:v1:${organizationId}:${userId}`;
};
```
Sources: [apps/api/src/assistant-chat/assistant-chat.service.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.service.ts#L16-L21)

### History Operations

-   **`getHistory(params)`**: Retrieves the chat history for a given user and organization. It fetches raw data from Redis and then uses a Zod schema (`StoredMessagesSchema`) for safe parsing and validation. If parsing fails, an empty array is returned.
-   **`saveHistory(params, messages)`**: Stores the provided chat messages for a user and organization. It first validates the incoming messages against `StoredMessagesSchema` to maintain data integrity in the cache. The data is stored with a configurable TTL.
-   **`clearHistory(params)`**: Deletes the chat history associated with a user and organization from Redis.
Sources: [apps/api/src/assistant-chat/assistant-chat.service.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.service.ts#L29-L57)

### Data Validation

The `AssistantChatService` uses Zod schemas to ensure the integrity and shape of the stored chat messages.
-   `StoredMessageSchema`: Validates individual chat messages.
-   `StoredMessagesSchema`: Validates an array of `StoredMessageSchema` objects.
Sources: [apps/api/src/assistant-chat/assistant-chat.service.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/assistant-chat.service.ts#L8-L14)

## Redis Client

The `upstash-redis.client.ts` file provides an abstraction over Redis interactions. It dynamically chooses between an actual Upstash Redis client and an in-memory implementation based on environment variables.


Sources: [apps/api/src/assistant-chat/upstash-redis.client.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/upstash-redis.client.ts#L23-L34)

### `assistantChatRedisClient`

This client object provides `get`, `set`, and `del` methods, abstracting the underlying storage mechanism. It's used by the `AssistantChatService` to interact with the chat history store.

<Accordions>
<Accordion title="In-Memory Redis Implementation Details">
The `InMemoryRedis` class provides a basic in-memory key-value store that mimics the behavior of a Redis client for `get`, `set`, and `del` operations. It supports an optional `ex` (expire) parameter for `set` operations, which sets a time-to-live for stored keys. This implementation is primarily for local development or testing when an external Redis instance is not available.

```typescript
class InMemoryRedis {
  private storage = new Map<string, { value: unknown; expiresAt?: number }>();

  async get<T = unknown>(key: string): Promise<T | null> {
    const record = this.storage.get(key);
    if (!record) return null;
    if (record.expiresAt && record.expiresAt <= Date.now()) {
      this.storage.delete(key);
      return null;
    }
    return record.value as T;
  }

  async set(
    key: string,
    value: unknown,
    options?: { ex?: number },
  ): Promise<'OK'> {
    const expiresAt = options?.ex ? Date.now() + options.ex * 1000 : undefined;
    this.storage.set(key, { value, expiresAt });
    return 'OK';
  }

  async del(key: string): Promise<number> {
    const existed = this.storage.delete(key);
    return existed ? 1 : 0;
  }
}
```
Sources: [apps/api/src/assistant-chat/upstash-redis.client.ts](https://github.com/blade47/comp/blob/main/apps/api/src/assistant-chat/upstash-redis.client.ts#L9-L31)
</Accordion>
</Accordions>

## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/49c89830-117b-4def-8edc-b5bcc50766e0/llms.txt) for all pages in this wiki.
