@shelf/agent-experience-sdk
v1.0.1
Published
SDK for embedding Shelf Agent Experience into host platforms.
Maintainers
Keywords
Readme
Agent Experience SDK
The Agent Experience SDK embeds Shelf Agent Experience into an external agent desktop. It renders the AX widget iframe, passes conversation state into the widget, and exposes typed methods and events for host-side integrations.
Installation
pnpm add @shelf/agent-experience-sdkimport {AX_SDK} from '@shelf/agent-experience-sdk';
import type {Message, SDKConfig, WidgetEvents} from '@shelf/agent-experience-sdk';Quick Start
const config = {
baseUrl: 'https://{subdomain}.shelf.io',
configId: 'agent-experience-default',
telemetry: {
system: 'genesys',
location: 'conversation_widget',
conversationType: 'chat',
},
conversation: {
conversationId: 'conv-123',
state: 'open',
},
messages: [
{
id: 'msg-1',
type: 'customer',
text: 'I need help with my order',
createdAt: '2026-05-07T12:00:00.000Z',
origin: 'history',
},
],
context: {
locale: 'en-US',
customerTier: 'enterprise',
},
} satisfies SDKConfig;
await AX_SDK.render(config, document.getElementById('ax-widget')!);
AX_SDK.on('reply:selected', payload => {
console.log(payload.text);
});
await AX_SDK.appendMessages([
{
id: 'msg-2',
type: 'agent',
text: 'I can help with that.',
origin: 'realtime',
},
]);
AX_SDK.close();Configuration
render(config, container) accepts an SDKConfig object.
Required Fields
| Field | Type | Description |
|-------------|-------------|----------------------------------------------------------------------------------------------------------------------------------------|
| baseUrl | string | Shelf Cortex origin or widget URL. For example, https://{account}.shelf.io
| configId | string | Published Agent Experience configuration id to load. This is fixed for one rendered session. Close and render again to switch configs. |
| telemetry | Telemetry | Host platform and channel metadata used by AX telemetry and runtime behavior. |
Optional Fields
| Field | Type | Description |
|----------------|---------------------------|------------------------------------------------------------------------------|
| conversation | Conversation | Initial conversation identity and state. |
| messages | Message[] | Initial transcript. Missing origin values are treated as history. |
| context | Record<string, unknown> | Runtime context such as locale, account, queue, brand, or customer metadata. ||
| settings | SDKSettings | Optional host-controlled intelligence toggles. |
Telemetry
type Telemetry = {
system: 'genesys' | 'kustomer' | '...'; // Host platform or system name integrating the AX
conversationType: 'chat' | 'voice' | 'email' | 'messaging';
};Conversation
type Conversation = {
conversationId?: string;
state?: 'closed' | 'open';
};Messages
type Message = {
id: string;
type: 'customer' | 'agent';
text: string;
createdAt?: string;
createdByUser?: {
id: string;
name?: string;
};
origin: 'history' | 'realtime';
};Use origin: 'history' for transcript messages that already existed before the widget was rendered. Use
origin: 'realtime' for live messages appended after render.
Settings
type SDKSettings = {
intelligence?: {
manualSummaryTriggerEnabled?: boolean;
replySelectionEnabled?: boolean;
};
};manualSummaryTriggerEnabled controls whether the host allows manual summary requests. replySelectionEnabled controls
whether reply selection events should be enabled for the current session.
Methods
AX_SDK.render(config, container)
Renders the AX widget iframe into an HTMLElement or selector string. The method resolves after the underlying iframe
render completes; it does not wait for the widget ready event.
await AX_SDK.render(config, '#ax-widget');Only one widget can be rendered by this singleton SDK at a time. Call AX_SDK.close() before rendering a new session.
AX_SDK.setConversation(conversation)
Replaces the current conversation object and sends the updated props to the widget.
await AX_SDK.setConversation({
conversationId: 'conv-456',
state: 'transferred',
});Use this when the host moves the mounted widget to another conversation or when conversation state changes.
AX_SDK.appendMessages(messages)
Appends live messages to the current message list and sends the full normalized list to the widget. Missing origin
values are treated as realtime.
await AX_SDK.appendMessages([
{
id: 'msg-3',
type: 'customer',
text: 'Can you resend the invoice?',
origin: 'realtime',
},
]);Use render(..., {messages}) or setConversation(...) for transcript replacement. Use appendMessages(...) for
incremental live updates.
AX_SDK.setContext(context)
Replaces the runtime context object and sends it to the widget.
await AX_SDK.setContext({
locale: 'en-US',
queue: 'billing',
customerTier: 'enterprise',
});Context values must be serializable across iframe boundaries.
AX_SDK.generateSummary()
Requests summary generation inside the widget
const summary = await AX_SDK.generateSummary();AX_SDK.detectWrapupCodes(codes)
Sends the available wrap-up codes to the widget for AI-assisted detection.
await AX_SDK.detectWrapupCodes([
{
id: 'refund',
name: 'Refund requested',
description: 'The customer asked for a refund or return.',
},
]);Each code must include id and name; description is optional.
AX_SDK.request(params)
Makes an authenticated Shelf API request through the widget session, using the currently logged-in AX user.
const user = await AX_SDK.request<{ name: string }>({
method: 'GET',
url: 'auth/v1/user',
});Request params:
type RequestParams = {
url: string;
method: 'PATCH' | 'PUT' | 'DELETE' | 'GET' | 'POST';
body?: Record<string, unknown> | BodyInit | null;
headers?: Record<string, string>;
};AX_SDK.on(eventName, handler)
Subscribes to a widget event and returns a cancellable subscription.
const subscription = AX_SDK.on('wrapup:selected', payload => {
console.log(payload.code, payload.comment);
});
subscription.cancel();Call render(...) before subscribing.
AX_SDK.once(eventName, handler)
Subscribes to one occurrence of a widget event and then removes the listener.
AX_SDK.once('ready', payload => {
console.log(payload.widgetVersion);
});The returned subscription can still be cancelled before the event fires.
AX_SDK.close()
Closes the widget instance, clears SDK state, and allows another render(...) call.
AX_SDK.close();AX_SDK.version
Returns the SDK package version.
console.log(AX_SDK.version);Events
| Event | Payload | Description |
|----------------------|--------------------------------------------------------|--------------------------------------------------|
| ready | {user, widgetVersion, protocolVersion, capabilities} | Widget runtime is ready. |
| summary:requested | {} | User requested a summary from inside the widget. |
| reply:selected | {text} | User selected a suggested reply. |
| wrapup:selected | {id?, code, comment?} | User selected a wrap-up code. |
| conversation-close | {summary, wrapupCode} | Widget emitted close-time conversation details. |
| content:open | {href?, entityId?, label?} | User opened content from AX. |
| error | {message} | Widget emitted an error event. |
Full Host Example
import {AX_SDK} from '@shelf/agent-experience-sdk';
import type {Message, SDKConfig} from '@shelf/agent-experience-sdk';
const container = document.querySelector<HTMLElement>('#ax-widget');
const initialMessages: Message[] = transcript.map(item => ({
id: item.id,
type: item.author === 'agent' ? 'agent' : 'customer',
text: item.text,
createdAt: item.createdAt,
createdByUser: item.userId
? {
id: item.userId,
name: item.userName,
}
: undefined,
origin: 'history',
}));
const config: SDKConfig = {
baseUrl: 'https://{account}.shelf.io',
configId: 'agent-experience-default',
telemetry: {
system: 'genesys',
location: 'conversation_widget',
conversationType: 'chat',
},
conversation: {
conversationId: currentConversation.id,
state: currentConversation.state,
},
messages: initialMessages,
context: {
locale: currentAgent.locale,
queue: currentConversation.queueName,
customerId: currentConversation.customerId,
},
settings: {
intelligence: {
manualSummaryTriggerEnabled: true,
replySelectionEnabled: true,
},
},
};
await AX_SDK.render(config, container);
const subscriptions = [
AX_SDK.on('ready', payload => {
console.log('AX ready', payload.widgetVersion);
}),
AX_SDK.on('reply:selected', payload => {
insertReplyIntoComposer(payload.text);
}),
AX_SDK.on('wrapup:selected', payload => {
setWrapupCode(payload.code, payload.comment);
}),
AX_SDK.on('conversation-close', payload => {
saveCloseDetails(payload.summary, payload.wrapupCode);
}),
AX_SDK.on('content:open', payload => {
openKnowledgeContent(payload.href ?? payload.entityId);
}),
AX_SDK.on('error', payload => {
console.error(payload.message);
}),
];
hostConversation.onMessage(async message => {
await AX_SDK.appendMessages([
{
id: message.id,
type: message.author === 'agent' ? 'agent' : 'customer',
text: message.text,
createdAt: message.createdAt,
origin: 'realtime',
},
]);
});
hostConversation.onContextChange(async context => {
await AX_SDK.setContext(context);
});
hostConversation.onClose(() => {
subscriptions.forEach(subscription => subscription.cancel());
AX_SDK.close();
});