***

title: Key Concepts
subtitle: Core concepts for understanding the Sunny Agents SDK
slug: concepts
description: Learn about conversations, messages, artifacts, and authentication in the Sunny Agents SDK.
---------------------

For clean Markdown of any page, append .md to the page URL. For a complete documentation index, see https://docs.sunnyhealthai.com/ask-sunny/llms.txt. For full documentation content, see https://docs.sunnyhealthai.com/ask-sunny/llms-full.txt.

Understanding these core concepts will help you build effective healthcare concierge experiences with the Sunny Agents SDK. Whether you're building provider search, appointment booking, or health information tools, these concepts form the foundation of your application.

## Environments

The SDK connects to different endpoints depending on your environment:

| Environment    | WebSocket (Chat API)                       | Sunny Central (Partner Portal)                                                   |
| -------------- | ------------------------------------------ | -------------------------------------------------------------------------------- |
| **Staging**    | `wss://chat.api.sunnyhealthai-staging.com` | [platform.sunnyhealthai-staging.com](https://platform.sunnyhealthai-staging.com) |
| **Production** | `wss://chat.api.sunnyhealthai.com`         | [platform.sunnyhealthai.com](https://platform.sunnyhealthai.com)                 |

The default `websocketUrl` is the staging URL. Override it for production via the `websocketUrl` option in `createSunnyChat`. Use the same environment for Sunny Central and the WebSocket URL (staging credentials with staging chat, production with production).

## Conversations

A **conversation** is a collection of messages between a patient (or healthcare user) and the AI concierge. Each conversation has:

* **ID**: A unique identifier (UUID)
* **Title**: Optional human-readable title (can be auto-generated)
* **Messages**: Array of messages in chronological order
* **Quick Responses**: Optional suggested responses for the user

When authenticated via `createSunnyChat`, conversations are automatically persisted on the server.

```typescript
interface ConversationState {
  id: string;
  title?: string | null;
  messages: SunnyAgentMessage[];
  quickResponses?: string[];
}
```

## Messages

A **message** represents a single exchange in a conversation. Messages have:

* **ID**: Unique identifier
* **Role**: `'user'`, `'assistant'`, or `'system'`
* **Text**: The message content
* **Created At**: Timestamp
* **Is Streaming**: Whether the message is currently being streamed
* **Output Items**: Rich content items (artifacts, approval requests, etc.)
* **Feedback**: Optional user feedback (positive/negative)

```typescript
interface SunnyAgentMessage {
  id: string;
  role: 'user' | 'assistant' | 'system';
  text: string;
  createdAt: string;
  isStreaming?: boolean;
  outputItems?: SunnyAgentMessageItem[];
  feedback?: boolean | null;
}
```

### Message Roles

* **User**: Messages sent by the user
* **Assistant**: Messages generated by the AI
* **System**: System-level messages (rarely used)

## Artifacts

**Artifacts** are rich content objects delivered inline in message text via the WebSocket. Common examples include:

* **Doctor Profiles**: Healthcare provider information with NPI, specialty, ratings, etc.
* **Structured Data**: Custom data objects specific to your use case

Artifacts are delivered inline in message text via the WebSocket. The backend expands artifact tags JIT during streaming; clients receive the full artifact JSON (`item_content`, `item_type`) embedded in message text--no separate fetch required.

## Authentication

The SDK supports two authentication modes, both configured through `createSunnyChat`:

### Token Exchange

For applications with custom authentication providers. Your app provides an ID token and the SDK exchanges it for an access token:

1. Your app provides an ID token via `idTokenProvider`
2. SDK exchanges it for an access token
3. Access token is used for WebSocket authentication
4. Token is automatically refreshed when expired

```typescript
const chat = createSunnyChat({
  container: document.getElementById("chat"),
  partnerIdentifier: "acme-health",
  publicKey: "pk-sunnyagents_abc_xyz",
  authType: "tokenExchange",
  idTokenProvider: async () => localStorage.getItem("id_token"),
});
```

### Passwordless

Email or SMS-based authentication without passwords. The SDK renders a verification UI in the chat:

```typescript
const chat = createSunnyChat({
  container: document.getElementById("chat"),
  partnerIdentifier: "acme-health",
  publicKey: "pk-sunnyagents_abc_xyz",
  authType: "passwordless",
});
```

## Connection Lifecycle

The SDK manages WebSocket connections automatically:

1. **Config fetch**: `createSunnyChat` calls `GET /sdk/config` to retrieve auth settings
2. **Auth activation**: SDK activates the chosen auth mode (token exchange or passwordless)
3. **Connection**: WebSocket connects when the user sends their first message
4. **Authentication**: SDK sends `auth.upgrade` message with credentials
5. **Messaging**: Send/receive messages in real-time
6. **Reconnection**: Automatically reconnect on failure
7. **Cleanup**: Close connection when `chat.destroy()` is called

## Events

The SDK uses an event-driven architecture. Subscribe to events via `chat.client` to update your UI:

* **`snapshot`**: Emitted when state changes
* **`conversationCreated`**: New conversation created
* **`messagesUpdated`**: Messages updated
* **`streamingDelta`**: Text streaming in real-time
* **`streamingDone`**: Streaming completed
* **`quickResponses`**: Quick response suggestions available

```typescript
const chat = createSunnyChat({
  container: document.getElementById("chat"),
  partnerIdentifier: "acme-health",
  publicKey: "pk-sunnyagents_abc_xyz",
  authType: "passwordless",
});

chat.client.on("snapshot", (snapshot) => {
  // Update UI with latest state
});

chat.client.on("streamingDelta", ({ conversationId, messageId, text }) => {
  // Update UI with streaming text
});
```

## MCP Approvals

**MCP (Model Context Protocol) Approvals** allow users to approve or reject tool execution requests. When the AI needs to execute a tool, it sends an approval request:

```typescript
await chat.client.sendMcpApproval(
  conversationId,
  approvalRequestId,
  true,
  "Looks good"
);

await chat.client.sendMcpApproval(
  conversationId,
  approvalRequestId,
  false,
  "Not needed"
);
```

The `approvalRequestId` is the `id` field of the `mcp_approval_request` output item in the message's `outputItems` array.

## File Attachments

Send files as base64-encoded attachments:

```typescript
await chat.client.sendMessage("Analyze this image", {
  files: [
    {
      filename: "image.png",
      content: "base64-encoded-content",
    },
  ],
});
```

## State Management

The SDK maintains state internally. Access it via `chat.client`:

```typescript
const snapshot = chat.client.getSnapshot();
// {
//   conversations: ConversationState[],
//   activeConversationId: string | null
// }
```

State updates trigger events, allowing you to keep your UI in sync.

## Learn more

<CardGroup cols={2}>
  <Card title="Authentication" icon="duotone lock" href="/authentication">
    Set up authenticated sessions with Auth0, Firebase, or custom providers
  </Card>

  <Card title="Artifacts" icon="duotone box" href="/artifacts">
    Parse and render rich content delivered inline
  </Card>

  <Card title="Quickstart" icon="duotone rocket" href="/quickstart">
    Get up and running in minutes
  </Card>

  <Card title="API Reference" icon="duotone code" href="/api-reference">
    REST and WebSocket API schemas
  </Card>
</CardGroup>