Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ __pycache__

# dependencies
node_modules
package-lock.json

# IDEs and editors
/.idea
Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,30 @@ The ElevenLabs Agents Widgets provide an easy way to embed AI agents into any we

Learn how to embed the widget into your website [here](https://elevenlabs.io/docs/agents-platform/customization/widget).

#### Dynamic Variables in Widgets

You can pass dynamic variables to your agent through HTML attributes:

```html
<elevenlabs-convai-widget
agent-id="your-agent-id"
dynamic-variables='{"user_name":"John Doe","account_type":"premium"}'
></elevenlabs-convai-widget>
```

To handle missing required variables, use the `expected-dynamic-variables` and `missing-dynamic-variable-default` attributes:

```html
<elevenlabs-convai-widget
agent-id="your-agent-id"
dynamic-variables='{"user_name":"John Doe","current_plan":"premium"}'
expected-dynamic-variables='["user_name","current_plan","previous_orders","support_history"]'
missing-dynamic-variable-default="null"
></elevenlabs-convai-widget>
```

This automatically fills missing variables (like `previous_orders` and `support_history`) with `null`, preventing conversation failures when your agent's tools require variables you don't have.

### Agents CLI

The ElevenLabs Agents CLI allows you to manage your agents as code, with features like version control, templates, and multi-environment deployments.
Expand Down
54 changes: 54 additions & 0 deletions packages/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,60 @@ const conversation = await Conversation.startSession({
});
```

#### Dynamic Variables

Dynamic variables allow you to pass runtime data to your agent's tools. If your agent has tools configured with dynamic variable references, you can provide these variables during conversation initiation.

**Basic usage:**

```ts
const conversation = await Conversation.startSession({
agentId: "<your-agent-id>",
dynamicVariables: {
user_name: "John Doe",
account_type: "premium",
session_id: "abc123",
},
});
```

**Handling missing required variables:**

If your agent's tools require dynamic variables that you don't always have values for, you can use `expectedDynamicVariables` and `missingDynamicVariableDefault` to automatically fill missing variables with default values:

```ts
const conversation = await Conversation.startSession({
agentId: "<your-agent-id>",

// Variables you have available
dynamicVariables: {
user_name: "John Doe",
current_plan: "premium",
},

// All variables your agent's tools expect
expectedDynamicVariables: [
"user_name",
"current_plan",
"previous_orders", // Will be auto-filled
"support_history", // Will be auto-filled
"preferences", // Will be auto-filled
],

// Default value for missing variables (defaults to null)
missingDynamicVariableDefault: null,
});
```

This prevents conversation failures when tools require variables you don't have. Missing variables will be automatically filled with the specified default value.

**Supported default values:**
- `null` (default)
- Empty string: `""`
- Custom string: `"N/A"`
- Number: `0`
- Boolean: `false`

#### User identification

You can optionally pass a user ID to identify the user in the conversation. This can be your own customer identifier. This will be included in the conversation initiation data sent to the server:
Expand Down
37 changes: 37 additions & 0 deletions packages/client/src/utils/BaseConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,43 @@ export type BaseSessionConfig = {
};
customLlmExtraBody?: unknown;
dynamicVariables?: Record<string, string | number | boolean>;
/**
* List of dynamic variable names that your agent's tools expect.
* Any variables in this list that aren't provided in dynamicVariables will be
* automatically filled with the value specified in missingDynamicVariableDefault.
*
* This is useful when your agent has tools that require dynamic variables,
* but you don't always have values for all of them.
*
* @example
* {
* expectedDynamicVariables: ['clients', 'matters', 'conversation_history'],
* missingDynamicVariableDefault: null,
* dynamicVariables: { clients: 'client data' }
* // Will automatically add: matters: null, conversation_history: null
* }
*/
expectedDynamicVariables?: string[];
/**
* Default value to use for missing dynamic variables when tools require them.
* This helps avoid errors when tools expect dynamic variables that aren't provided.
* Only used when expectedDynamicVariables is specified.
*
* @default null
*
* @example
* // Fill missing dynamic variables with null
* { missingDynamicVariableDefault: null }
*
* @example
* // Fill missing dynamic variables with empty string
* { missingDynamicVariableDefault: "" }
*
* @example
* // Fill missing dynamic variables with a custom value
* { missingDynamicVariableDefault: "N/A" }
*/
missingDynamicVariableDefault?: string | number | boolean | null;
useWakeLock?: boolean;
connectionDelay?: DelayConfig;
textOnly?: boolean;
Expand Down
29 changes: 27 additions & 2 deletions packages/client/src/utils/overrides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,33 @@ export function constructOverrides(
overridesEvent.custom_llm_extra_body = config.customLlmExtraBody;
}

if (config.dynamicVariables) {
overridesEvent.dynamic_variables = config.dynamicVariables;
// Handle dynamic variables with auto-filling of missing required variables
if (config.dynamicVariables || config.expectedDynamicVariables) {
const providedVariables = config.dynamicVariables || {};

// If expectedDynamicVariables is specified, fill in missing ones with default value
if (
config.expectedDynamicVariables &&
config.expectedDynamicVariables.length > 0
) {
const defaultValue = config.missingDynamicVariableDefault ?? null;
const filledVariables: Record<string, string | number | boolean | null> =
{ ...providedVariables };

// Add missing variables with default value
for (const varName of config.expectedDynamicVariables) {
if (!(varName in filledVariables)) {
filledVariables[varName] = defaultValue;
}
}

overridesEvent.dynamic_variables = filledVariables as Record<
string,
string | number | boolean
>;
} else {
overridesEvent.dynamic_variables = providedVariables;
}
}

if (config.userId) {
Expand Down
32 changes: 32 additions & 0 deletions packages/convai-widget-core/src/contexts/session-config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,36 @@ export function SessionConfigProvider({
return undefined;
});

const expectedDynamicVariablesJSON = useAttribute("expected-dynamic-variables");
const expectedDynamicVariables = useComputed(() => {
if (expectedDynamicVariablesJSON.value) {
try {
return JSON.parse(expectedDynamicVariablesJSON.value) as string[];
} catch (e: any) {
console.error(
`[ConversationalAI] Cannot parse expected-dynamic-variables: ${e?.message}`
);
}
}

return undefined;
});

const missingDynamicVariableDefaultAttr = useAttribute("missing-dynamic-variable-default");
const missingDynamicVariableDefault = useComputed(() => {
if (missingDynamicVariableDefaultAttr.value) {
try {
// Try to parse as JSON first (for null, numbers, booleans)
return JSON.parse(missingDynamicVariableDefaultAttr.value);
} catch {
// If JSON parse fails, treat as string
return missingDynamicVariableDefaultAttr.value;
}
}

return null;
});

const { webSocketUrl } = useServerLocation();
const agentId = useAttribute("agent-id");
const signedUrl = useAttribute("signed-url");
Expand All @@ -68,6 +98,8 @@ export function SessionConfigProvider({
const isWebRTC = useWebRTCEnabled.value;
const baseConfig = {
dynamicVariables: dynamicVariables.value,
expectedDynamicVariables: expectedDynamicVariables.value,
missingDynamicVariableDefault: missingDynamicVariableDefault.value,
overrides: overrides.value,
connectionDelay: { default: 300 },
textOnly: textOnly.value,
Expand Down
2 changes: 2 additions & 0 deletions packages/convai-widget-core/src/types/attributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export const CustomAttributeList = [
"server-location",
"language",
"dynamic-variables",
"expected-dynamic-variables",
"missing-dynamic-variable-default",
"show-avatar-when-collapsed",
"override-prompt",
"override-first-message",
Expand Down
44 changes: 44 additions & 0 deletions packages/react-native/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,57 @@ Starts a new conversation session.
- `config.agentId`: ElevenLabs agent ID, not needed if you provide a conversationToken.
- `config.conversationToken`: Optional pre-generated token, used for private agents that require authentication via your ElevenLabs API key.
- `config.userId`: You can optionally pass a user ID to identify the user in the conversation. This can be your own customer identifier. This will be included in the conversation initiation data sent to the server.
- `config.dynamicVariables`: Optional key-value pairs to pass runtime data to your agent's tools.
- `config.expectedDynamicVariables`: Optional array of variable names your agent expects. Any missing variables will be auto-filled.
- `config.missingDynamicVariableDefault`: Default value for missing variables (defaults to `null`). Can be `null`, string, number, or boolean.

**Basic example:**

```typescript
await conversation.startSession({
agentId: "your-agent-id",
});
```

**With dynamic variables:**

```typescript
await conversation.startSession({
agentId: "your-agent-id",
dynamicVariables: {
user_name: "John Doe",
account_type: "premium",
},
});
```

**Auto-filling missing required variables:**

If your agent's tools require dynamic variables you don't always have, use `expectedDynamicVariables` to prevent errors:

```typescript
await conversation.startSession({
agentId: "your-agent-id",

// Variables you have
dynamicVariables: {
user_name: "John Doe",
current_plan: "premium",
},

// All variables your agent expects
expectedDynamicVariables: [
"user_name",
"current_plan",
"previous_orders", // Will be auto-filled with null
"support_history", // Will be auto-filled with null
],

// Optional: customize the default value
missingDynamicVariableDefault: null, // Can also be "", "N/A", 0, false, etc.
});
```

#### `endSession(): Promise<void>`

Ends the current conversation session.
Expand Down
6 changes: 5 additions & 1 deletion packages/react-native/src/ElevenLabsProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children
overrides,
customLlmExtraBody,
dynamicVariables,
expectedDynamicVariables,
missingDynamicVariableDefault,
userId,
} = useConversationSession(callbacksRef, setStatus, setConnect, setToken, setConversationId, tokenFetchUrl);

Expand Down Expand Up @@ -210,6 +212,8 @@ export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children
overrides,
customLlmExtraBody,
dynamicVariables,
expectedDynamicVariables,
missingDynamicVariableDefault,
userId,
});

Expand All @@ -223,7 +227,7 @@ export const ElevenLabsProvider: React.FC<ElevenLabsProviderProps> = ({ children
callbacksRef.current.onError?.(error as string);
}
}
}, [handleParticipantReady, overrides, customLlmExtraBody, dynamicVariables, userId, callbacksRef]);
}, [handleParticipantReady, overrides, customLlmExtraBody, dynamicVariables, expectedDynamicVariables, missingDynamicVariableDefault, userId, callbacksRef]);

const conversation: Conversation = {
startSession,
Expand Down
12 changes: 12 additions & 0 deletions packages/react-native/src/hooks/useConversationSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export const useConversationSession = (
const [dynamicVariables, setDynamicVariables] = useState<
ConversationConfig["dynamicVariables"]
>({});
const [expectedDynamicVariables, setExpectedDynamicVariables] =
useState<ConversationConfig["expectedDynamicVariables"]>(undefined);
const [missingDynamicVariableDefault, setMissingDynamicVariableDefault] =
useState<ConversationConfig["missingDynamicVariableDefault"]>(null);
const [userId, setUserId] = useState<ConversationConfig["userId"]>(undefined);

const startSession = useCallback(
Expand All @@ -36,6 +40,10 @@ export const useConversationSession = (
setOverrides(config.overrides || {});
setCustomLlmExtraBody(config.customLlmExtraBody || null);
setDynamicVariables(config.dynamicVariables || {});
setExpectedDynamicVariables(config.expectedDynamicVariables);
setMissingDynamicVariableDefault(
config.missingDynamicVariableDefault ?? null
);
setUserId(config.userId);

let conversationToken: string;
Expand Down Expand Up @@ -91,6 +99,8 @@ export const useConversationSession = (
setOverrides({});
setCustomLlmExtraBody(null);
setDynamicVariables({});
setExpectedDynamicVariables(undefined);
setMissingDynamicVariableDefault(null);
setUserId(undefined);
setConversationId("");

Expand All @@ -110,6 +120,8 @@ export const useConversationSession = (
overrides,
customLlmExtraBody,
dynamicVariables,
expectedDynamicVariables,
missingDynamicVariableDefault,
userId,
};
};
Loading