# D-ID Agent

> Embed a talking AI avatar in your PandaSuite project with the D-ID Agent component. The conversational chatbot speaks to your visitors with a face and a voice, its Client Tools become events, and it can navigate your screens, search your data, and answer back with Return a value.

https://docs.pandasuite.com/essentials/components/d-id-agent/

**The D-ID Agent component embeds a conversational AI avatar, a chatbot with a face and a voice, inside your project. The visitor speaks to it, and the agent can act on your project in return: change screen, read your data, run any action you have configured.**

> **Note**
>
> This component requires a [D-ID](https://www.d-id.com/) account and an agent
> already created in D-ID Studio. The avatar, the voice, the personality and the
> knowledge base stay on D-ID: the component brings that agent into your project
> and connects it to your screens and your data. To act on your project, the
> agent must be a V4 (Expressive) agent.

## How the AI agent and your project fit together

Most components wait for your project to tell them what to do. This one also works the other way around, and that is the idea worth holding on to before anything else.

The division of work is simple:

- **D-ID owns the conversation.** The agent listens, understands, decides what to say, and says it with the face and voice you chose in D-ID Studio. The examples below use a museum guide, but the same pattern fits a product catalogue, a training app, or a reception kiosk.
- **PandaSuite owns the application.** Your screens, your collections, your [Datastore](https://docs.pandasuite.com/essentials/data/datastore/), your actions.

The agent is driven by an AI model, and the hinge between the two worlds is a **Client Tool**. On D-ID, a Client Tool is a capability you promise the agent: a name, a description, and a list of arguments. The agent does not know how the tool works. It only knows that when the conversation calls for it, it may ask for the tool to be run, with arguments filled in from what the visitor said.

In PandaSuite, that promise becomes an **event of the component**. The agent calls the tool, the event fires with the tool's arguments, and the actions you attached to that event run. If the agent expects something back, one of those actions answers it.

So a complete round trip looks like this:

**The visitor asks** → **The agent calls a tool** → **The event fires** → **Your actions run** → **Return a value answers** → **The agent speaks**

Everything below is a way of setting up one part of that loop.

## Add and configure the component

Click **Components** and add the **D-ID Agent** component to your screen. It is a visual component: it displays the official D-ID interface, avatar and controls included, in the area you give it.

### Step 1: Enter your API key

In the **Properties** panel, paste your **API key**. You will find it in your D-ID account, under **Settings** > **API Key**.

[Image: The D-ID Agent properties panel: API key, Agent with its Refresh button, Custom domains, Auto connect, Orientation and External ID]

> **Info**
>
> The API key is used in PandaSuite Studio only: to list your agents, to read
> and write the agent's tools and prompt, and to create the access key your published project
> will use. It is never included in the published project, and never reaches
> your visitors.

### Step 2: Pick your agent

Click **Refresh** next to the **Agent** property. The component asks D-ID for the agents of your key and fills the drop-down list. Pick the one you want.

Next to each name, the list shows the agent's type. Pick an `expressive` one: only V4 (Expressive) agents call Client Tools. A `talk` or `clip` agent still speaks, but it never acts on your project, and the component reminds you of it under **Client tools**.

Click **Refresh** again whenever you create a new agent in D-ID Studio, so the list catches up.

If the list stays empty, the key does not belong to the account that owns the agent. Check it in your D-ID account and press **Refresh** again.

### Step 3: Synchronize

Double-click the component to open it, then press **Sync**.

You are now inside the component. **Sync**, the client tools and the agent prompt live here. The **Properties** panel and the **Actions** panel stay outside: use the breadcrumb at the top of the workspace to come back out. You will move between the two several times.

Synchronizing is the moment the component learns what your agent can do. In one pass, it:

- refreshes the list of your agents, the way **Refresh** does, and stops if the selected one is no longer there,
- reads the agent's **Client Tools** and declares each one as an event of the component,
- reads the agent's prompt into the **Agent prompt** field,
- creates, or reuses, the D-ID **Client Key** that lets your published project talk to the agent,
- uses the agent's thumbnail as the component's image when it can read it, so you recognize it on the workspace.

You should now see the agent's name at the top of the component, the date of the last synchronization, and the list of its client tools with their arguments.

[Image: Component after a sync: agent name and Synced date, Sync button, Agent prompt field, and the list_screens and change_screen client tools]

> **Warning**
>
> Press **Sync** again after changing the **Agent** property. The configuration
> is bound to the agent it was synchronized for, so until you do, the component
> refuses to run and displays the reason.
>
> Press it also after changing a tool or the prompt on D-ID. That case fails
> quietly instead: the component keeps the definitions of the last
> synchronization, so a newly added argument simply never reaches your actions.

## Let the AI agent act on your project

### A Client Tool is an event

After a synchronization, each of the agent's client tools appears in the **Actions** panel of the component, exactly like a native trigger event. Attach whatever actions you want to it.

[Image: The trigger picker of the component: the native triggers, then the client tools list_screens and change_screen as triggers of their own]

The tool's arguments travel with the event. Inside any action of that list, open the data binding window and choose **From the selected event**: the arguments are there, under their own names, ready to be bound. An argument whose name would clash with a reserved one appears under an alias, which the tool's card spells out.

**Example.** A Museum Explorer app has a tool `search_exhibits(query)`. A visitor says "do you have anything about volcanoes?", the agent calls `search_exhibits` with `query` set to `volcanoes`, and the `search_exhibits` event fires in your project carrying that word. You attach an action that runs a [Search](https://docs.pandasuite.com/essentials/components/search/), and you bind its **Search Term** with **From the selected event** → **query**.

That gets the search running, but the agent still hears nothing about volcanoes. Telling it what you found is a separate step, and the next section.

### Answer the agent with Return a value

Some tool calls are questions. The agent asks, waits, and speaks what it gets back.

To answer, add the [Return a value](https://docs.pandasuite.com/essentials/interactions/interactive-actions/#return-a-value) action to the event's action list and fill its **Response** parameter. Bind it to anything your project can produce: a collection, a field of a Datastore, the result of a search, a plain constant.

[Image: Return a value on the list_screens trigger, Response bound to the screen list, beside the Actions panel showing both tools]

A list holds at most one **Return a value**: once you have added it, Studio stops offering it for that list. Place it wherever you like in the list. It answers the call, and the actions after it still run, so you can answer quickly and keep working.

> **Tip**
>
> Some tools are pure questions and need nothing else. A tool that simply tells the
> agent what your project holds is a single action: **Return a value**, with
> **Response** bound to the collection behind it.

If an event has no **Return a value**, the agent receives a plain `ok` once the action list has finished, unless one of those actions failed, in which case the agent is told the call failed. That is the right answer for a tool that does something rather than reporting something, such as changing screen.

### Name your tools in the agent prompt

This is the step that surprises people, so it is worth stating plainly: **a tool that nothing in the prompt points to stays unused.** A perfectly synchronized tool, with perfect actions behind it, waits until the instructions give the agent a reason to reach for it.

Naming the tool is the surest way, and the one to fall back on when the agent ignores a tool you expected it to use. Inviting the behaviour works too, when the tool's own description is explicit enough: an agent told to navigate through the screens to illustrate its points will find a tool described as "Change the screen to illustrate what you are saying". What never works is silence.

The **Agent prompt** field in the component shows the agent's instructions as D-ID holds them, read at the last synchronization. Edit them there and press **Save prompt**: the text is saved on D-ID, for this agent.

Write the tools into the instructions in plain language, the way you would brief a new guide:

> When a visitor asks what there is to see, call `list_screens` and describe the results. When they choose one, call `change_screen` with the matching screen so the app follows the conversation.

> **Note**
>
> D-ID writes marks such as `$[knowledge_search]` into the instructions when a
> tool is inserted from its own editor. That is how D-ID names the tool in the
> prompt: delete one and the agent stops calling that tool. Leave them as they
> are.

### Create a Client Tool without leaving PandaSuite

You do not have to leave PandaSuite to give the agent a new capability. In the component, press **Create client tool**. A panel opens with:

- **Name**: the name the agent will use. Letters, digits, `_` and `-`, up to 64 characters. No spaces and no accents: write `list_screens`, not `list screens`.
- **Description**: what the tool does, in the agent's own terms, from 1 to 500 characters. This is what the agent reads when it decides whether to call it.
- **Arguments**: one row per argument, each with a name, a type, a description and a **Required** checkbox. An argument name starts with a letter, then holds letters, digits or `_`. No `-` here, unlike the tool name.

[Image: Client tool editor for change_screen: Name, Description, a Screen argument of type Page, Required checked, then Save changes]

Press **Save changes**. The tool is created on your D-ID account, attached to your agent, and declared as an event of the component in one go.

Five argument types are available, because an argument has to be something a language model can produce:

| Type          | What the agent sends                    | Typical use                                                 |
| ------------- | --------------------------------------- | ----------------------------------------------------------- |
| **String**    | text                                    | a search query, a name, a free-form answer                  |
| **Number**    | a number                                | a quantity, a year, a rating                                |
| **Boolean**   | `true` or `false`                       | a yes or no                                                 |
| **Page**      | a screen of your project                | navigation, guided tours, "take me to the volcanoes"        |
| **Reference** | an item of a collection of your project | an exhibit, a product, a question: "tell me about this one" |

The first three are ordinary values. The last two point into your project, and that is where things get interesting.

**Page** arrives in your actions as a real screen, so you can bind it straight into **Change screen**. The agent still needs to know which screens exist: give a `change_screen` tool one argument of type **Page**, pair it with a `list_screens` tool that hands out the screens, and point the prompt at both.

**Reference** does for your data what **Page** does for your screens, and it deserves a section of its own.

### Let the agent pick an item of a collection

A large museum guide does not give each exhibit its own screen. A collection holds the exhibits, and a single detail screen shows whichever one is selected. To open that screen on the right exhibit, the agent has to point to an item of the collection. That is what a **Reference** argument does.

When you choose **Reference** as the type of an argument, a second list appears below it, **Choose a collection**, offering the collections of your [Datastore](https://docs.pandasuite.com/essentials/data/datastore/). Pick the one the argument points to. If your project has none yet, the list says so: add a Datastore first.

In your actions, the argument arrives under **From the selected event** as a real [Reference](https://docs.pandasuite.com/essentials/data/data-types/#reference), and you use it like any other. Bind it as it is, open its fields (the binding window [follows the reference](https://docs.pandasuite.com/essentials/data/data-binding/#following-a-reference), so `exhibit` then `name` gives the name of the chosen exhibit), or save it in a **Reference** property of your Datastore with **Create/Update Data (Local)** so that a [detail page](https://docs.pandasuite.com/essentials/data/dynamic-page-from-collection-item/) shows that exhibit.

As with screens, the agent cannot choose among exhibits it has never seen, and the pattern is the same. A `list_exhibits` tool, answered by **Return a value** with its **Response** bound to the collection, hands the agent every exhibit along with its identifier. A `show_exhibit` tool takes that identifier back through its `exhibit` argument. The list travels in the answer, and only the choice travels in the argument.

The collection is a setting of your project, not of the tool. The same tool can point to another collection on another agent or in another project, and changing it with **Edit** affects this project alone. That is also why a tool attached from D-ID Studio shows `no collection` next to its argument: press **Edit** and choose one.

### Add a tool your account already has

A tool does not belong to an agent. It lives on your D-ID account, where any of your agents can use it: the `list_exhibits` tool you wrote for one guide works just as well for the next. Rather than creating it again, press **Add existing tool**. The component suggests the same thing if you try to create a tool under a name your account already uses.

The panel lists the tools of your account that this agent does not have yet. Search, check the ones you want, and press **Add to the agent**. A tool with a **Reference** argument first asks for its collection, since that choice belongs to this project. The tools arrive together or not at all: if one of them cannot be added, nothing changes and the panel tells you which one.

One thing stays behind: a value fixed on an argument in D-ID Studio. It was set for the other agent, so set it again for this one in D-ID Studio if you need it, then press **Sync**.

### Edit, detach or delete a tool

Since tools are shared, every change raises the same question: does it concern this agent, or every agent of your account? Each button answers it plainly.

**Edit** reopens the panel on the tool's definition. Saving rewrites the tool on D-ID, and every agent that uses it gets the new version.

**Detach** concerns this agent only. The tool leaves the agent, its event and actions leave your project, and the tool stays on your account, ready to come back through **Add existing tool**.

**Delete from your account**, at the bottom of the **Edit** panel, concerns every agent. The tool is removed from all of them, then deleted on D-ID, along with its event and actions in this project. A project that used it with another agent keeps its actions: at its next synchronization, the tool shows up there as **Not on the agent**.

**Detach** and **Delete from your account** both ask for a second click before they act.

Before any write, the component re-reads D-ID and refuses to overwrite something that changed there since your last synchronization. When that happens, press **Sync** and edit again.

A tool marked **Not on the agent** is one your project still knows but the agent no longer has, for example because it was detached in D-ID Studio. Its event and its actions are kept, and you decide: **Add to the agent** puts it back, **Remove** drops it from your project and leaves D-ID alone. Renaming a tool on D-ID never costs you your actions.

> **Info**
>
> A tool created in D-ID Studio with an argument shape this editor cannot
> express stays editable here for its name and its description. Its arguments
> are edited in D-ID Studio.

## Drive the AI agent from your project

The conversation is not one-way. Use **Interact with a component** on the D-ID Agent component to reach:

| Action         | What it does                                                    |
| -------------- | --------------------------------------------------------------- |
| **Speak**      | Makes the agent say a **Text**, which can be bound to your data |
| **Play audio** | Makes the agent play an audio file from an **Audio URL**        |
| **Interrupt**  | Stops the agent from speaking immediately                       |
| **Microphone** | **Mute**, **Unmute** or **Toggle** the visitor's microphone     |
| **Speaker**    | **Mute**, **Unmute** or **Toggle** the agent's audio output     |

**Speak** is how you make the agent say a text out loud: greet a visitor by name, read out a result, or comment on where the app just went. It speaks to the visitor in the agent's own voice, so the text can come from anywhere in your project.

## React to the conversation

### Trigger events

Besides the client tools, the component fires these [trigger events](https://docs.pandasuite.com/essentials/interactions/triggers/):

| Event                      | Fires when                                                                            | Carries                                        |
| -------------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------- |
| **Session started**        | the connection to the agent is established                                            |                                                |
| **Session ended**          | the connection is closed, lost or fails                                               | **Reason**: `disconnected`, `closed` or `fail` |
| **Agent started speaking** | the agent starts speaking                                                             |                                                |
| **Agent stopped speaking** | the agent stops speaking                                                              |                                                |
| **Agent thinking**         | the agent starts generating a response                                                |                                                |
| **Error**                  | D-ID reports an error, or an action could not run because the agent is not loaded yet | **Code** and **Message**                       |

### Exposed properties

The component exposes four values for [data binding](https://docs.pandasuite.com/essentials/data/data-binding/), under **From a component**. For most interfaces, the first two are all you need:

- **Is connected**: true while the session is live.
- **Is talking**: true while the agent is speaking.

Bind them to a listening indicator, to a pulse around the avatar, or to the visibility of a subtitle area. The two raw values are there when you want finer control:

- **Connection state**: `new`, `connecting`, `connected`, `completed`, `disconnecting`, `disconnected`, `closed`, `fail`. Both `connected` and `completed` mean the session is live: browsers differ on which one they end up reporting.
- **Activity**: `IDLE`, `TALKING`, `LOADING`, `BUFFERING`.

## Component properties

| Property           | Description                                                                                                                           |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| **API key**        | Your D-ID API key. Used in PandaSuite Studio only, never published.                                                                   |
| **Agent**          | The agent to embed. Press **Refresh** to list the agents of your key.                                                                 |
| **Custom domains** | Your own origins where the published project runs, scheme included, for example `https://kiosk.example`. Use **+ Add** for each one.  |
| **Auto connect**   | Connects to the agent as soon as the component is displayed, without waiting for the visitor to press the connect button.             |
| **Orientation**    | **Vertical** or **Horizontal** layout of the D-ID interface.                                                                          |
| **External ID**    | Optional visitor or session identifier passed to D-ID, to link the conversation to your own user. Read once when the component loads. |

> **Tip**
>
> **External ID** is read a single time, when the component loads. Bind it to a
> value that already exists at that moment, such as a Datastore field written at
> launch, rather than to something the visitor produces later on the screen.

## Publish your project

D-ID restricts an agent to the addresses it is allowed to run on. Synchronizing creates a **Client Key** that covers those addresses, or reuses one that already does.

The PandaSuite ones are handled for you: the PandaSuite Studio origin, the web viewer, and the local address used by the iOS and Android viewers. You only declare what PandaSuite cannot know.

If you publish on a [custom domain](https://docs.pandasuite.com/essentials/web-publishing/custom-domain/), or [embed your project in your own website](https://docs.pandasuite.com/essentials/web-publishing/embed-into-a-website/), add that origin to **Custom domains** with **+ Add**, then press **Sync** again so the key covers it.

> **Warning**
>
> A project [shared as a template](https://docs.pandasuite.com/essentials/project-management/share-your-project-as-template/)
> arrives without the API key, on purpose. Whoever reuses it enters their own
> key, picks their own agent and presses **Sync**. Their events and actions are
> preserved, and any tool missing from their agent is offered for creation.

## A complete example: an AI avatar that guides the visitor

The goal: a visitor asks the avatar what there is to see, and the app follows the conversation.

Before you start: your **API key** is entered, an **Agent** is picked, you have pressed **Sync** once, and you are inside the component. The project holds a collection of exhibits and one screen per exhibit.

**1. Create the tool that lists the exhibits.**

In the component, press **Create client tool**. Name it `list_screens`, describe it as "Lists the PandaSuite project screens", and leave the **Arguments** list empty. Press **Save changes**.

**2. Answer it.**

Come back out with the breadcrumb, select the component, open **Actions** and click the **+** button. Your client tools are in the trigger list, alongside **Session started**. Choose `list_screens`, then add a single action: **Return a value**. Bind its **Response** parameter to the list of your project's screens, under **From project** in the binding window, so the agent learns which screens it can ask for.

**3. Create the tool that navigates.**

Go back inside the component and press **Create client tool** again. Name it `change_screen`, describe it as "Change the screen to illustrate what you are saying", and add one argument: `Screen`, type **Page**, described as "The representation of a PandaSuite screen, obtained by the list\_screens tool", **Required**.

**4. Make it navigate.**

Back in **Actions**, on the `change_screen` trigger, add **Change screen**. Studio lists it as **Go to screen** once it is in place: same action, other name. Click the name of the destination parameter to open the binding window, then choose **From the selected event** → **Screen**. No **Return a value** is needed here: this tool acts, it does not report, so the plain `ok` the agent receives when the list has run is the right answer.

**5. Tell the agent about both.**

In **Agent prompt**, add a paragraph that names them, then press **Save prompt**:

> You are a museum guide. When the visitor asks what there is to see, call `list_screens` and present the results in your own words. When the visitor picks one, call `change_screen` with the matching screen.

**6. Test.**

The agent does not run in the Studio preview, so save your project and open its **share link** in a web browser. Press the connect button on the avatar (or set **Auto connect** to **Yes** beforehand), and allow the microphone when the browser asks. Ask the avatar what there is to see. It should list your screens, and take you to the right one when you choose it.

If nothing happens, check the prompt first: it is the usual cause. To see whether a call lands at all, attach a temporary **Change screen state** action to the event, so you can watch it fire.

## Best practices and limitations

- **Describe tools for the agent, not for yourself.** The name and the description are the only things the agent reads when it decides to call a tool. "Open the screen of an exhibit" earns a call; "nav handler v2" does not.
- **Keep answers small.** The answer reaches the agent as text, capped at 15 KiB. Anything longer is cut off silently, and a cut structured answer arrives broken. Return the handful of fields the agent needs to speak, not your whole database.
- **One tool, one job.** An agent chooses between tools by their descriptions. Two tools that overlap make that choice unreliable.
- **The component reads its tools once, when it loads.** A tool you add does not reach a project that is already running, and reconnecting does not help. Synchronize, save your project, then reload your share link.
- **The agent does not run in the Studio preview.** In the preview, the component shows a message instead of the avatar. To talk to your agent, open your [share link](https://docs.pandasuite.com/essentials/project-management/test-and-preview-your-project/) in a web browser. If the preview stays on **Finding an available agent** and shows no message, your project uses an older version of the component: press **Update the component** in its properties.
- **The microphone is the browser's decision.** Browsers grant microphone access only on a secure `https` address, and only once the visitor allows it. Test the published project on its real address.
- **Re-export an app published before this.** Every viewer now carries answers back to the agent, but an app keeps running the viewer it was exported with. On an older export the event still fires and your actions still run, yet no tool call comes back to the agent, not even one without a **Return a value** that would simply have answered `ok`. Re-exporting is the fix.
- **Avatar, voice, personality, greetings and knowledge stay on D-ID.** Edit them in D-ID Studio and they take effect on the next connection, with no **Sync** needed. **Sync** brings back only the tools, the prompt and the agent's picture.

## See also

- [Data binding](https://docs.pandasuite.com/essentials/data/data-binding/) to feed the agent's answers from your project.
- [Interactive actions](https://docs.pandasuite.com/essentials/interactions/interactive-actions/) for everything an event can trigger.
- [Screens](https://docs.pandasuite.com/essentials/layout/screens/) and [Collection](https://docs.pandasuite.com/essentials/data/collection/) for the two things an agent most often needs to talk about.
- [Custom components](https://docs.pandasuite.com/essentials/components/custom-components/) if you want to build a component that declares its own events the same way.
