> ## Documentation Index
> Fetch the complete documentation index at: https://koreai-content-gov.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Platform SDKs Overview

The Agent Platform provides two SDKs: the **Web SDK** to embed agent chat and voice interactions in web applications and the **ABL SDK** for programmatic access to parse, validate, and compile ABL agent definitions.

## Web SDK

The Agent Platform Web SDK (`@koreai/artemis-web-sdk`) provides a TypeScript/JavaScript library for embedding agent chat and voice interactions in web applications. The SDK supports vanilla JavaScript, React hooks, and a web component for drop-in integration.

The browser-facing SDK does not send the public `pk_*` key directly to `/ws/sdk`. It first exchanges the key for a short-lived SDK session token on `POST /api/v1/sdk/init`, then authenticates SDK HTTP routes with `X-SDK-Token` and the SDK WebSocket with `Sec-WebSocket-Protocol: sdk-auth,<token>`.

### Install Web SDK

```bash theme={null}
npm i @koreai/artemis-web-sdk
```

The package includes the core `AgentSDK` constructor, chat and voice clients, React provider/hooks/components, custom elements, rich content renderers, attachment upload, feedback, auth challenge UI, and template utilities.

### Quick Start

#### Vanilla JavaScript

```typescript theme={null}
import { AgentSDK } from '@koreai/artemis-web-sdk';

const sdk = new AgentSDK({
  projectId: 'your-project-id',
  apiKey: 'pk_your-public-key',
  endpoint: 'https://agents.kore.ai',
});

await sdk.connect();

// Send a chat message
const chat = sdk.chat();
chat.on('message', (msg) => console.log(msg.content));
await chat.send('Hello, I need help!');
```

#### React

```tsx theme={null}
import { AgentProvider, useChat, useVoice } from '@koreai/artemis-web-sdk/react';

function App() {
  return (
    <AgentProvider
      projectId="your-project-id"
      apiKey="pk_your-public-key"
      endpoint="https://agents.kore.ai"
    >
      <ChatWidget />
    </AgentProvider>
  );
}

function ChatWidget() {
  const { messages, isTyping, sendMessage, isConnected } = useChat();

  return (
    <div>
      {messages.map((msg) => (
        <div key={msg.id}>
          <strong>{msg.role}:</strong> {msg.content}
        </div>
      ))}
      {isTyping && <div>Agent is typing...</div>}
      <button onClick={() => sendMessage('Hello!')} disabled={!isConnected}>
        Send
      </button>
    </div>
  );
}
```

#### Web Component

```html theme={null}
<script src="https://agents.kore.ai/sdk/agent-widget.js"></script>

<agent-widget project-id="your-project-id" api-key="pk_your-public-key" mode="chat"></agent-widget>
```

***

### AgentSDK

The main SDK class. Creates and manages connections, chat clients, and voice clients.

#### Constructor

```typescript theme={null}
new AgentSDK(config: SDKConfig)
```

**SDKConfig**

| Property    | Type    | Required | Default     | Description                        |
| ----------- | ------- | -------- | ----------- | ---------------------------------- |
| `projectId` | string  | Yes      | --          | Project ID to connect to           |
| `apiKey`    | string  | Yes      | --          | Public API key (starts with `pk_`) |
| `endpoint`  | string  | No       | Same origin | Platform base URL                  |
| `debug`     | boolean | No       | `false`     | Enable debug logging to console    |

#### Methods

| Method           | Returns         | Description                                           |                            |
| ---------------- | --------------- | ----------------------------------------------------- | -------------------------- |
| `connect()`      | `Promise<void>` | Establish WebSocket connection to the platform        |                            |
| `disconnect()`   | `void`          | Close the connection and clean up resources           |                            |
| `chat()`         | `ChatClient`    | Get the chat client instance (created on first call)  |                            |
| `voice()`        | `VoiceClient`   | Get the voice client instance (created on first call) |                            |
| `isConnected()`  | `boolean`       | Check if the SDK is connected                         |                            |
| `getSessionId()` | \`string        | null\`                                                | Get the current session ID |

#### Static Methods

| Method                  | Returns    | Description                                                    |
| ----------------------- | ---------- | -------------------------------------------------------------- |
| `AgentSDK.init(config)` | `AgentSDK` | Create and store an SDK instance globally (for web components) |

#### Events

| Event          | Payload                 | Description                      |
| -------------- | ----------------------- | -------------------------------- |
| `connected`    | `void`                  | WebSocket connection established |
| `disconnected` | `void`                  | WebSocket connection closed      |
| `error`        | `{ error: Error }`      | Connection or runtime error      |
| `sessionStart` | `{ sessionId: string }` | New session started              |
| `sessionEnd`   | `void`                  | Session ended                    |

```typescript theme={null}
sdk.on('connected', () => {
  console.log('Connected to platform');
});

sdk.on('error', ({ error }) => {
  console.error('SDK error:', error.message);
});

sdk.on('sessionStart', ({ sessionId }) => {
  console.log('Session started:', sessionId);
});
```

***

### ChatClient

Handles text messaging with streaming support. Obtained via `sdk.chat()`.

#### Methods

| Method                   | Returns           | Description                                         |
| ------------------------ | ----------------- | --------------------------------------------------- |
| `send(text, options?)`   | `Promise<string>` | Send a message. Returns the message ID              |
| `uploadAttachment(file)` | `Promise<string>` | Upload a file attachment. Returns the attachment ID |
| `getMessages()`          | `Message[]`       | Get all messages in the conversation                |
| `getIsTyping()`          | `boolean`         | Check if the agent is currently responding          |
| `clearMessages()`        | `void`            | Clear the local message history                     |

#### send() Options

```typescript theme={null}
interface SendMessageOptions {
  /** Pre-uploaded attachment IDs to include with the message */
  attachmentIds?: string[];
  /** Optional per-message metadata for the current turn only */
  metadata?: Record<string, unknown>;
}
```

**Example: send with attachments**

```typescript theme={null}
const chat = sdk.chat();

// Upload a file first
const attachmentId = await chat.uploadAttachment(fileInput.files[0]);

// Send message with attachment
await chat.send('Please analyze this document', {
  attachmentIds: [attachmentId],
});
```

**Example: send with per-message metadata**

```typescript theme={null}
await chat.send('Look up this account', {
  metadata: {
    accountId: 'acct_123',
    context: { tier: 'gold' },
  },
});
```

Per-message metadata is validated server-side and is available only for that turn. Use `session.messageMetadata` as the canonical prompt/template path. `message_metadata` remains available as the tool-context alias for `context_access.read`.

#### Events

| Event                | Payload                                      | Description                              |
| -------------------- | -------------------------------------------- | ---------------------------------------- |
| `message`            | `Message`                                    | New message received (user or assistant) |
| `messageChunk`       | `{ messageId: string, chunk: string }`       | Streaming text chunk from assistant      |
| `typing`             | `{ isTyping: boolean }`                      | Agent typing indicator changed           |
| `messageSent`        | `{ messageId: string }`                      | User message was sent                    |
| `attachmentUploaded` | `{ attachmentId: string, filename: string }` | File upload completed                    |
| `attachmentError`    | `{ filename: string, error: string }`        | File upload failed                       |
| `error`              | `{ error: Error }`                           | Chat error                               |

```typescript theme={null}
const chat = sdk.chat();

chat.on('message', (msg) => {
  if (msg.role === 'assistant') {
    console.log('Agent:', msg.content);
    if (msg.richContent?.markdown) {
      renderMarkdown(msg.richContent.markdown);
    }
    if (msg.actions) {
      renderActions(msg.actions);
    }
  }
});

chat.on('messageChunk', ({ messageId, chunk }) => {
  appendToMessage(messageId, chunk);
});

chat.on('typing', ({ isTyping }) => {
  showTypingIndicator(isTyping);
});
```

#### Message Type

```typescript theme={null}
interface Message {
  id: string;
  role: 'user' | 'assistant' | 'system';
  content: string;
  timestamp: Date;
  metadata?: Record<string, unknown>;
  richContent?: RichContent;
  actions?: ActionSet;
  attachments?: AttachmentRef[];
}
```

#### RichContent Type

Multi-format content variants delivered alongside the plain text response:

```typescript theme={null}
interface RichContent {
  markdown?: string;
  adaptive_card?: string;
  html?: string;
  slack?: string;
  ag_ui?: string;
  whatsapp?: string;
}
```

#### ActionSet Type

Interactive action elements the agent sends for user input:

```typescript theme={null}
interface ActionSet {
  elements: ActionElement[];
  submit_label?: string;
  submit_id?: string;
}

interface ActionElement {
  id: string;
  type: 'button' | 'select' | 'input';
  label: string;
  value?: string;
  description?: string;
  options?: Array<{ id: string; label: string; description?: string }>;
  input_type?: 'text' | 'number' | 'date' | 'time' | 'email';
  placeholder?: string;
  required?: boolean;
}
```

#### AttachmentRef Type

```typescript theme={null}
interface AttachmentRef {
  id: string;
  filename: string;
  mimeType: string;
  sizeBytes: number;
  category: 'image' | 'document' | 'audio' | 'video';
}
```

***

### VoiceClient

Handles voice interactions via WebSocket audio pipeline with optional WebRTC. Obtained via `sdk.voice()`.

The voice client supports two modes:

* **Pipeline mode**: Client-side VAD (Voice Activity Detection) captures PCM16 audio, sends it via WebSocket for server-side STT/LLM/TTS processing, and plays back MP3 audio responses.
* **Realtime mode**: Native audio I/O via realtime LLM providers with PCM16 streaming.

#### Methods

| Method         | Returns         | Description                                              |
| -------------- | --------------- | -------------------------------------------------------- |
| `start()`      | `Promise<void>` | Start voice interaction (requests microphone permission) |
| `stop()`       | `void`          | Stop voice interaction and release audio resources       |
| `toggleMute()` | `boolean`       | Toggle microphone mute. Returns the new mute state       |
| `getState()`   | `VoiceState`    | Get the current voice state                              |
| `getInfo()`    | `VoiceInfo`     | Get full voice status information                        |

#### Static Methods

| Method                      | Returns   | Description                                  |
| --------------------------- | --------- | -------------------------------------------- |
| `VoiceClient.isSupported()` | `boolean` | Check if the browser supports voice features |

#### Voice States

```typescript theme={null}
type VoiceState =
  | 'idle' // Not active
  | 'connecting' // Establishing connection
  | 'ready' // Connected, waiting for speech
  | 'listening' // Detecting speech
  | 'processing' // Processing user speech
  | 'speaking' // Playing agent response
  | 'error'; // Error state
```

#### VoiceInfo Type

```typescript theme={null}
interface VoiceInfo {
  state: VoiceState;
  isMuted: boolean;
  currentTranscript: string;
  hasMicPermission?: boolean;
}
```

#### VoiceClientOptions

```typescript theme={null}
interface VoiceClientOptions {
  enableBargeIn?: boolean; // Default: true
  sampleRate?: number; // Default: 16000
  deviceId?: string; // Specific audio input device
  vadConfig?: {
    positiveSpeechThreshold?: number;
    negativeSpeechThreshold?: number;
    redemptionMs?: number;
    minSpeechMs?: number;
    preSpeechPadMs?: number;
  };
}
```

#### Events

| Event                 | Payload                                                   | Description                   |
| --------------------- | --------------------------------------------------------- | ----------------------------- |
| `stateChange`         | `{ state: VoiceState, previousState: VoiceState }`        | Voice state changed           |
| `transcription`       | `{ text: string, isFinal: boolean, confidence?: number }` | Speech-to-text result         |
| `transcriptionFinal`  | `{ text: string, confidence: number }`                    | Final transcription           |
| `responseStart`       | `{ messageId: string }`                                   | Agent started speaking        |
| `responseChunk`       | `{ messageId: string, text: string }`                     | Agent speech text chunk       |
| `responseEnd`         | `{ messageId: string, text: string }`                     | Agent finished speaking       |
| `speaking`            | `{ isSpeaking: boolean }`                                 | Audio playback state changed  |
| `volumeChange`        | `{ level: number }`                                       | Microphone volume level (0-1) |
| `ready`               | `void`                                                    | Voice client is ready         |
| `error`               | `{ error: Error }`                                        | Voice error                   |
| `micPermissionDenied` | `void`                                                    | Microphone permission denied  |
| `bargeIn`             | `void`                                                    | User interrupted agent speech |
| `vadAvailable`        | `{ available: boolean }`                                  | VAD availability changed      |

**Voice interaction example**

```typescript theme={null}
const voice = sdk.voice();

voice.on('stateChange', ({ state }) => {
  updateUI(state);
});

voice.on('transcription', ({ text, isFinal }) => {
  updateTranscript(text, isFinal);
});

voice.on('responseEnd', ({ text }) => {
  console.log('Agent said:', text);
});

voice.on('error', ({ error }) => {
  console.error('Voice error:', error.message);
});

// Start listening
await voice.start();

// Mute/unmute
const isMuted = voice.toggleMute();
```

***

### React Hooks

The React integration provides a context provider and hooks for state management.

#### AgentProvider

Wrap your application with `AgentProvider` to initialize the SDK:

```tsx theme={null}
import { AgentProvider } from '@koreai/artemis-web-sdk/react';

<AgentProvider
  projectId="your-project-id"
  apiKey="pk_your-public-key"
  endpoint="https://agents.kore.ai"
  debug={false}
>
  {children}
</AgentProvider>;
```

#### useAgent()

Access the full SDK context:

```typescript theme={null}
const {
  sdk, // AgentSDK | null
  isConnected, // boolean
  sessionId, // string | null
  error, // Error | null
  chat, // ChatClient | null
  messages, // Message[]
  isTyping, // boolean
  sendMessage, // (text: string) => Promise<void>
  voice, // VoiceClient | null
  voiceState, // VoiceState
  startVoice, // () => Promise<void>
  stopVoice, // () => void
  toggleMute, // () => boolean
  isMuted, // boolean
} = useAgent();
```

#### useChat()

Access chat-specific state:

```typescript theme={null}
const {
  messages, // Message[]
  isTyping, // boolean
  sendMessage, // (text: string) => Promise<void>
  isConnected, // boolean
} = useChat();
```

**Example**

```tsx theme={null}
import { useChat } from '@koreai/artemis-web-sdk/react';

function ChatView() {
  const { messages, isTyping, sendMessage, isConnected } = useChat();

  const handleSend = async (text: string) => {
    await sendMessage(text);
  };

  return (
    <div>
      {messages.map((msg) => (
        <div key={msg.id} className={msg.role}>
          {msg.content}
        </div>
      ))}
      {isTyping && <div>Agent is typing...</div>}
    </div>
  );
}
```

#### useVoice()

Access voice-specific state:

```typescript theme={null}
const {
  voiceState, // VoiceState
  startVoice, // () => Promise<void>
  stopVoice, // () => void
  toggleMute, // () => boolean
  isMuted, // boolean
  isConnected, // boolean
} = useVoice();
```

**Example**

```tsx theme={null}
import { useVoice } from '@koreai/artemis-web-sdk/react';

function VoiceControls() {
  const { voiceState, startVoice, stopVoice, toggleMute, isMuted } = useVoice();

  return (
    <div>
      <p>Status: {voiceState}</p>
      <button onClick={startVoice} disabled={voiceState !== 'idle'}>
        Start
      </button>
      <button onClick={stopVoice} disabled={voiceState === 'idle'}>
        Stop
      </button>
      <button onClick={toggleMute}>{isMuted ? 'Unmute' : 'Mute'}</button>
    </div>
  );
}
```

***

### File Uploads

Upload files for agent processing:

```javascript theme={null}
const chat = sdk.chat();

// Upload a file
const file = new File(['content'], 'document.pdf', {
  type: 'application/pdf',
});
const attachmentId = await chat.uploadAttachment(file);

// Send message with attachment
await chat.send('Please analyze this document', {
  attachmentIds: [attachmentId],
});
```

#### Supported File Types

* **Images:** jpeg, png, gif, webp, svg
* **Documents:** pdf, docx, xlsx, pptx, txt, csv
* **Audio:** mp3, wav, ogg, m4a
* **Video:** mp4, webm

#### Upload Limits

* Maximum file size: 25 MB per file
* Maximum files per message: 10

***

### Styling and Theming

#### Widget Theming

Customize the web component appearance:

```typescript theme={null}
interface WidgetTheme {
  primaryColor?: string;
  textColor?: string;
  backgroundColor?: string;
  borderRadius?: number;
  fontFamily?: string;
  darkMode?: boolean;
}
```

Configure via attributes:

```html theme={null}
<agent-widget
  project-id="your-project-id"
  api-key="pk_your-public-key"
  mode="unified"
  position="bottom-right"
></agent-widget>
```

#### Widget Positions

* `bottom-right` (default)
* `bottom-left`
* `top-right`
* `top-left`

#### Widget Modes

* `chat` -- Text-only chat interface
* `voice` -- Voice-only interface
* `unified` -- Combined chat and voice interface

***

### TypedEventEmitter

All SDK classes extend `TypedEventEmitter` for type-safe event handling:

```typescript theme={null}
// Subscribe to events
sdk.on('connected', callback);

// Subscribe once
sdk.once('connected', callback);

// Unsubscribe
sdk.off('connected', callback);

// Remove all listeners
sdk.removeAllListeners();
```

***

### WebSocket Message Types

The SDK communicates with the platform over WebSocket. These types are used internally but documented for advanced use cases.

#### Server Message Types

| Type             | Description                                                               |
| ---------------- | ------------------------------------------------------------------------- |
| `response_start` | Agent started generating a response                                       |
| `response_chunk` | Incremental text from the agent                                           |
| `response_end`   | Agent finished responding (includes `fullText`, `richContent`, `actions`) |
| `error`          | Error occurred during processing                                          |
| `session_start`  | New session established                                                   |
| `session_end`    | Session ended                                                             |

***

### API Key Management

Public API keys (`pk_` prefix) are scoped to a project and provide limited permissions for SDK usage. They are safe to expose in client-side code.

#### Creating an API Key

1. Go to **Project > Settings > API Keys**.
2. Click **Create API key**.
3. Set the allowed origins (for CORS protection).
4. Copy the key -- it is displayed only once.

#### Origin Restrictions

Configure allowed origins to prevent unauthorized use of your API key:

```json theme={null}
{
  "allowedOrigins": ["https://your-app.example.com", "https://staging.your-app.example.com"]
}
```

The runtime validates the `Origin` header on every SDK request and rejects requests from unlisted origins.

***

### Authentication and Verified Identity

Public API keys cover anonymous and low-assurance chat. For verified user identity, sensitive-data flows, and customer-issued tokens, configure SDK authentication end to end across Studio, the browser SDK, the customer backend, and the runtime.

[Learn more: SDK end-to-end auth setup guide](/agent-platform/sdk/sdk-end-to-end-auth-setup).

***
