Skip to main content
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

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

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

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

<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

new AgentSDK(config: SDKConfig)
SDKConfig
PropertyTypeRequiredDefaultDescription
projectIdstringYesProject ID to connect to
apiKeystringYesPublic API key (starts with pk_)
endpointstringNoSame originPlatform base URL
debugbooleanNofalseEnable debug logging to console

Methods

MethodReturnsDescription
connect()Promise<void>Establish WebSocket connection to the platform
disconnect()voidClose the connection and clean up resources
chat()ChatClientGet the chat client instance (created on first call)
voice()VoiceClientGet the voice client instance (created on first call)
isConnected()booleanCheck if the SDK is connected
getSessionId()`stringnull`Get the current session ID

Static Methods

MethodReturnsDescription
AgentSDK.init(config)AgentSDKCreate and store an SDK instance globally (for web components)

Events

EventPayloadDescription
connectedvoidWebSocket connection established
disconnectedvoidWebSocket connection closed
error{ error: Error }Connection or runtime error
sessionStart{ sessionId: string }New session started
sessionEndvoidSession ended
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

MethodReturnsDescription
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()booleanCheck if the agent is currently responding
clearMessages()voidClear the local message history

send() Options

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
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
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

EventPayloadDescription
messageMessageNew 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
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

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:
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:
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

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

MethodReturnsDescription
start()Promise<void>Start voice interaction (requests microphone permission)
stop()voidStop voice interaction and release audio resources
toggleMute()booleanToggle microphone mute. Returns the new mute state
getState()VoiceStateGet the current voice state
getInfo()VoiceInfoGet full voice status information

Static Methods

MethodReturnsDescription
VoiceClient.isSupported()booleanCheck if the browser supports voice features

Voice States

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

interface VoiceInfo {
  state: VoiceState;
  isMuted: boolean;
  currentTranscript: string;
  hasMicPermission?: boolean;
}

VoiceClientOptions

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

EventPayloadDescription
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)
readyvoidVoice client is ready
error{ error: Error }Voice error
micPermissionDeniedvoidMicrophone permission denied
bargeInvoidUser interrupted agent speech
vadAvailable{ available: boolean }VAD availability changed
Voice interaction example
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:
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:
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:
const {
  messages, // Message[]
  isTyping, // boolean
  sendMessage, // (text: string) => Promise<void>
  isConnected, // boolean
} = useChat();
Example
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:
const {
  voiceState, // VoiceState
  startVoice, // () => Promise<void>
  stopVoice, // () => void
  toggleMute, // () => boolean
  isMuted, // boolean
  isConnected, // boolean
} = useVoice();
Example
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:
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:
interface WidgetTheme {
  primaryColor?: string;
  textColor?: string;
  backgroundColor?: string;
  borderRadius?: number;
  fontFamily?: string;
  darkMode?: boolean;
}
Configure via attributes:
<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:
// 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

TypeDescription
response_startAgent started generating a response
response_chunkIncremental text from the agent
response_endAgent finished responding (includes fullText, richContent, actions)
errorError occurred during processing
session_startNew session established
session_endSession 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:
{
  "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.