# Duvi documentation Every page, as one file. 26 pages. # Quickstart This guide creates an agent, gives it your content to answer from, and puts it on your website. It takes about ten minutes and one script tag. Source: https://www.duvi.ai/docs/quickstart ## Before you start Building an agent does not draw on your credit balance, so you can complete every step below before a customer sees it. You need three things: - **A verified Duvi account.** The agent list stays locked until you verify the email on the account. - **Content for the agent to read.** Files, a website address, or both. - **Somewhere to paste a script tag.** Your CMS, your theme, or a tag manager. There is no build step and no package to install. ## Create an agent 1. **Name the agent** Open **Agents** and select **New agent**. Enter a name. Duvi creates the agent and opens its builder conversation, which is the default place to finish setup. 2. **Choose a model and a voice** Ask the builder to select a model, plus a transcriber and a voice if the agent will take calls. You can also open Configure and select them directly. Studio adds up the latency of all three so you can see what an answer costs in time before you commit to it. See [Model and voice](https://www.duvi.ai/docs/model-and-voice). Chat mode decides which controls the widget shows: `text` shows a message box, `voice` shows a call button, and `both` shows a message box with a microphone. 3. **Write the system prompt** Say what the agent does, who it is talking to, and what it must never do. Six short labelled sections work better than one long paragraph. See [System prompt](https://www.duvi.ai/docs/system-prompt) for the sections and a worked example. ```text title="system prompt" You answer questions about Duvi plans and credits for customers who already have an account. Answer only from the knowledge you were given. If the answer is not there, say so and offer to take their details. Never quote a price that is not in the price list. ``` > **Keep facts out of the prompt** > > Duvi sends the system prompt with every exchange, so anything pasted into it is billed on every turn. Prices, policies and opening hours belong in [Knowledge](https://www.duvi.ai/docs/knowledge), where retrieval sends only the passages that match the question. ## Add knowledge Open the **Knowledge** tab. Select files from your account library, or add a website address for the agent to crawl. You can use both on the same agent. The crawler reads `robots.txt` first and takes its page list from the sitemaps declared there, so your site decides what gets indexed. See [Knowledge](https://www.duvi.ai/docs/knowledge) for the full crawl rules. Saving re-reads every source from the start. The agent keeps answering from its existing index while the new one builds, so there is no gap in service. The Knowledge tab shows one of four states: Pending, Indexing, Ready or Failed. Wait until the status reads **Ready** before you judge an answer. Pending and Indexing need time. Failed needs you to inspect the source. See [Indexing states](https://www.duvi.ai/docs/knowledge#indexing-states). ## Embed the widget Open **Appearance** before launch if the widget needs your logo, a different color, a clearer launcher label or starter prompts. Appearance changes the website widget only; it does not change the agent’s answers. See [Appearance](https://www.duvi.ai/docs/appearance). Open **Channels** and copy the snippet. Paste it before the closing `body` tag on every page the agent should appear on. ```html title="index.html" ``` Then open **Security** and add your domain under **allowed domains**. Add the `www` version as well if you use it, because Duvi matches on hostname and treats them as separate entries. An empty list lets any site embed your agent. See [Allowed domains](https://www.duvi.ai/docs/security#allowed-domains). > **The agent id is public** > > The agent id appears in the page source of every site you embed on. It opens a conversation with this agent and nothing else: no account access, no files, no credits. The allowed domains list is what limits its use. ## Test the agent Ask the agent five questions you already know the answer to, and one you know it cannot answer. Check two things: that it finds the right fact, and that it says it does not know rather than inventing an answer. See [Testing](https://www.duvi.ai/docs/testing) for the full list, including the difficult conversations worth trying. **** It answers, but from the wrong page Two sources disagree. Open Knowledge, remove the stale source, and save to reindex. If both sources must stay, state in the system prompt which one wins. **** It says it has no information about anything Check the knowledge state. If it reads Failed, Duvi replaced nothing and the agent is answering from an empty index. A scanned file with no text layer is the usual cause. **** The widget does not appear on my site Compare the hostname in your browser address bar against the allowed domains list. Duvi treats `www.example.com` and `example.com` as separate entries. For symptoms across every part of the product, see [Troubleshooting](https://www.duvi.ai/docs/troubleshooting). > **What this costs** > > Building the agent is free. Credits go on the conversations it handles, and the length of each exchange matters more than the number of exchanges. See [Credits](https://www.duvi.ai/docs/credits). --- # Agent builder The builder creates an agent from a conversation. Describe the job, answer its questions, and it writes the configuration. Source: https://www.duvi.ai/docs/builder ## Build an agent in the builder Creating an agent opens a persistent conversation with the builder. Tell it who the agent serves, what it should know, and where it will talk to people. The builder asks for the decisions it cannot infer, writes the configuration, and keeps the conversation for later changes. 1. **Describe the job** Start with the audience, the outcome you want, and the limits that matter. 2. **Answer the gaps** The builder asks only for information it cannot safely infer, such as the opening message or the channel you plan to use. 3. **Review what changed** Configuration changes appear alongside the conversation. Test the agent in Preview before you connect a live channel. The builder is itself a Duvi agent, built with the same prompts, tools and page context available to you. The conversation stays attached to the agent, so returning to it later continues the same thread. ## What the builder can change The builder writes these parts of an agent: | Area | Fields | | ------------ | --------------------------------------- | | Identity | Name, system prompt and first message | | Conversation | Chat mode, model, voice and transcriber | | Knowledge | Website addresses | | Access | Allowed domains | > **The builder does not add files** > > Add files from the account library yourself. The builder does not select or upload them on your behalf. See [Files](https://www.duvi.ai/docs/files). ## Agent sections The agent sections give you exact control over the same agent the builder creates: Configure, Appearance, Knowledge, Tools, Integrations, Preview, Channels, Security, Analytics, Insights, Conversations, Leads and Builder. Changes there update the same agent, so there is no second copy to keep in sync and no import step. Files, custom tools, customer identity, widget appearance, channel setup and the disclaimer are edited in those sections. Appearance is where you set the launcher, color, logo, label and starter prompts. Integrations is where you connect services Duvi already supports. Tools is where you define your own HTTP actions and MCP servers. > **Moving between the two** > > Use the builder to establish intent, then the agent sections for exact values. After either path, run the same test conversation to verify the behaviour that matters. --- # System prompt The system prompt sets how an agent behaves. Knowledge sets what it knows. This page covers the six blocks a prompt needs and what to keep out of it. Source: https://www.duvi.ai/docs/system-prompt ## What belongs in a prompt The system prompt is the **System prompt** box in the **Behaviour** panel on the Configure tab, below the name and the first message. Duvi sends it with **every exchange**, so every sentence in it is billed on every turn of every conversation for as long as the agent runs. A four hundred word prompt on a busy agent is a recurring cost. Facts in a prompt also behave badly. You cannot update them without editing the agent, they arrive with no source attached, and they compete with the passages retrieval found. An agent holding two prices, one in the prompt and one in knowledge, will sometimes quote the wrong one, and the trace cannot tell you why. | Belongs in knowledge | Belongs in the prompt | | ------------------------------------ | --------------------------------------------------------- | | The Pro plan includes ten seats. | Never quote a price that is not in the price list. | | Returns are accepted within 30 days. | If you cannot find a policy, say so and offer a handover. | | The Mumbai office opens at 9am. | Answer in the language the customer wrote in. | > **The test to apply to every sentence** > > Ask whether a colleague would have to change the sentence when the business changes. If yes, it is a fact and belongs in [Knowledge](https://www.duvi.ai/docs/knowledge). If it would still be true after a rebrand, a price rise and a new product line, it is behaviour and belongs in the prompt. ## The six blocks of a prompt Write the prompt as six short sections, each answering one question, in this order. | Block | Answers | Example line | | ---------- | ------------------------ | ------------------------------------------------------------ | | Identity | Who is speaking | You are the assistant on the Northwind website. | | Situation | Where, and to whom | Most visitors arrive from the pricing page. | | Voice | How it sounds | Two sentences at a time. Never say “as an AI”. | | Job | What it is for, in order | Answer from knowledge. If you cannot, take a name and email. | | Boundaries | What it must never do | Never quote a price that is not in the price list. | | Tools | When to call what | Call lookup\_order only after you have an order id. | > Two voice agent platforms arrived at six sections independently. ElevenLabs names them **Personality, Environment, Tone, Goal, Guardrails, Tools**. Vapi names them **Identity, Response guidelines, Guardrails, Context, Workflow, Examples**. The names differ; the shape does not. Duvi uses plainer words for the same blocks. > > **Sources: **[ElevenLabs](https://elevenlabs.io/docs/agents-platform/best-practices/prompting-guide)[Vapi](https://docs.vapi.ai/prompting-guide) ## Why block order matters Identity and Situation are stable, so they sit first and stay put. Job and Boundaries change as you learn what customers ask, so they sit lower, where editing them disturbs less of the prompt. > OpenAI recommends the sequence **Identity, Instructions, Examples, Context**, and separately advises putting content you reuse on every request at the beginning so caching can pay off. Google states that ordering, labelling and delimiters all affect answer quality even when the same information is present either way. > > **Sources: **[OpenAI](https://developers.openai.com/api/docs/guides/prompt-engineering)[Google Cloud](https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/prompts/system-instruction-introduction) Use headings. A prompt broken into six labelled sections is read more reliably than the same words as prose, because the labels tell the model which sentences are rules and which are context. ## Give every rule a reason A bare prohibition is followed narrowly. The same prohibition with its reason attached generalises to cases you never wrote down. | Rule alone | Rule with its reason | | ------------------- | ------------------------------------------------------------------------------------------------------------------- | | Never use ellipses. | Your reply is read aloud by a speech engine, so never use ellipses. The engine does not know how to pronounce them. | > That example is Anthropic’s, and it matches the Duvi case exactly: an agent set to `voice` or `both` is spoken. Their framing is to treat the model as **a brilliant but new employee who lacks context on your norms**, and their rule is to show the prompt to a colleague with no context and ask whether they could follow it. > > **Sources: **[Anthropic](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices) Applied to the boundary above, *never quote a price that is not in the price list, because a wrong price is a commitment we then have to honour or retract* also stops the agent estimating, rounding, or offering a range. The bare version stops only the literal case. ## Add two or three examples Examples steer tone and shape more reliably than adjectives. Writing *be concise and friendly* is vague. Showing one concise, friendly answer is not. Wrap examples in tags so the model does not read them as instructions. ```text title="behaviour, examples block" Customer: do you do anything for small teams You: Yes. The Starter plan covers up to five people. Want me to walk you through what it includes? Customer: whats your uptime SLA You: I do not have an SLA figure in what I can see, so I do not want to guess. Can I take your email and have someone send you the real number? ``` > Anthropic recommends **three to five examples**, wrapped in `` tags, relevant and diverse enough that the model does not learn an unintended pattern. OpenAI recommends two or three and stresses showing a range of inputs rather than variations on one. Both call examples the most reliable lever on output format. > > **Sources: **[Anthropic](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices)[OpenAI](https://developers.openai.com/api/docs/guides/prompt-engineering) > **Make one example a failure** > > The second example above does more work than the first. An agent shown how to decline gracefully declines gracefully. An agent shown only successes invents an answer rather than break the pattern. ## Prompts for voice agents When an agent chat mode is `voice` or `both`, a speech engine reads everything it writes. Four rules apply. - **Cap the reply length in the prompt.** Two or three sentences unless the customer asked for detail, and one question at a time. A long answer is skimmed on a screen and cannot be skimmed on a call. - **Spell out symbols.** Digits and characters such as `@` and `%` are a common source of mispronunciation. Tell the agent to say “forty two dollars and fifty cents” rather than emit `$42.50`. - **Keep tool arguments machine shaped.** If a tool takes an email, the argument must be `rita@example.com`, not “rita at example dot com”. State that in the Tools block and give the format as an example. - **Ban markdown.** Bullets, bold and links read as nothing aloud. If the agent runs on both surfaces, tell it to structure answers with sentences rather than syntax. > ElevenLabs documents that **digits and symbols such as “@” are more likely to cause incorrect pronunciations or voice hallucinations**. Vapi gives the conversions directly: `$42.50` becomes “forty-two dollars and fifty cents”, and a date becomes “March fourth, twenty twenty-five”. Both hold replies to one or two sentences, and both warn that tool parameters still need their real format after you normalise speech. > > **Sources: **[ElevenLabs](https://elevenlabs.io/docs/agents-platform/best-practices/prompting-guide)[Vapi](https://docs.vapi.ai/prompting-guide) The **first message** is a separate field in the same panel. The agent speaks or shows it before the customer says anything, so it carries the offer and the invitation to interrupt. Keep it under two sentences. The disclaimer is a third field, covered in [AI disclaimer](https://www.duvi.ai/docs/security#ai-disclaimer). ## What never belongs in a prompt 1. **Secrets.** No API keys, no internal URLs, no pricing floors you would not say to a customer. Keys belong in [stored keys](https://www.duvi.ai/docs/tools#stored-keys), where Duvi encrypts them and never shows them again. 2. **Facts that change.** They belong in knowledge, where they arrive with a source attached and can be traced. 3. **Instructions the agent cannot act on.** Telling it to check the CRM when no tool reaches the CRM produces an agent that claims it checked. If there is no tool, there is no instruction. > Google states that system instructions **help guide the model to follow instructions but do not fully prevent jailbreaks or leaks**, and recommends caution about putting sensitive information in them. Treat the prompt as readable by the customer. > > **Sources: **[Google Cloud](https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/prompts/system-instruction-introduction) ## Example system prompt Six blocks, roughly two hundred words, for a support agent with an order lookup tool connected. ```text title="behaviour" # Identity You are the assistant on the Northwind website. You are not a person and you say so if asked. # Situation Most visitors are existing customers checking an order or a return. A few are deciding whether to buy. # Voice Two or three sentences at a time. Plain English, no jargon, no markdown. Your reply is read aloud, so write numbers as words and never use ellipses. # Job 1. Answer from the knowledge you were given. 2. For an order question, verify the customer, then call lookup_order. 3. If you cannot answer, say so plainly and offer to take a name and email. 4. Log what you could not answer rather than guessing. # Boundaries Never quote a price, delivery date or policy that is not in your knowledge, because a wrong one becomes a promise we have to honour. Never claim to have checked a system you did not call. Hand over whenever the customer asks, whenever you have failed twice in a row, or whenever the customer is upset. # Tools lookup_order needs an order id and the email on the account. The email must be in the form rita@example.com, not spoken out. If it returns nothing, say the order was not found and offer a handover rather than trying a second time. ``` Every boundary in that prompt carries its reason, which is what keeps a prompt holding at conversation four hundred. ## Test the prompt A prompt is a hypothesis. Both OpenAI and Google describe prompting as test driven and iterative rather than something you get right by writing carefully. Duvi gives you two instruments. - **[Preview](https://www.duvi.ai/docs/testing)** runs the agent as a customer meets it. Ask the five questions you know the answer to, and one you know it cannot answer. - **[The retrieval trace](https://www.duvi.ai/docs/retrieval-trace)** tells you whether a bad answer was a prompt problem or a knowledge problem. If the right passage was retrieved and the answer was still wrong, the prompt is at fault. If the passage never arrived, editing the prompt will not fix it. Run the trace first. Most people rewrite the prompt when the real fault was a page that was never indexed. ## Sources The guidance on this page is drawn from five published references. Where they disagree, this page says so rather than averaging them. **Referenced** - [Prompt engineering](https://developers.openai.com/api/docs/guides/prompt-engineering) - [Prompting best practices](https://platform.claude.com/docs/en/build-with-claude/prompt-engineering/claude-prompting-best-practices) - [System instructions](https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/prompts/system-instruction-introduction) - [Prompting guide](https://elevenlabs.io/docs/agents-platform/best-practices/prompting-guide) - [Prompting guide](https://docs.vapi.ai/prompting-guide) --- # Model and voice A spoken answer passes through three components: a transcriber, a model and a voice. Studio shows the latency of each one before you commit to it. Source: https://www.duvi.ai/docs/model-and-voice ## The three components Every agent carries all three components, and you select each one separately on the Configure tab. Which of them run depends on how the customer reached the agent. | Component | What it does | When it runs | | ----------- | ------------------------------------------------------------------------- | ---------------- | | Transcriber | Turns what the caller said into text. | Voice turns only | | Model | Reads that text with your knowledge and your tools, and writes the reply. | Every turn | | Voice | Speaks the reply back. | Voice turns only | A text-only agent never reaches the transcriber or the voice, but Duvi keeps both saved on the agent. Switching it to voice later is a change of chat mode, not a reconfiguration. ## Latency estimate Studio adds the published latency of the three components you selected and shows the total above them. Treat the total as a floor. It counts the components and nothing else. | Counted | Not counted | | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- | | Transcriber, model and voice, as published by each provider. | Network time to and from the customer, orchestration, retrieval from knowledge, and any tool the model calls. | A tool call is usually the largest single omission, because the agent is waiting on your API rather than on a model. If an answer feels slow and the estimate says otherwise, check [what the agent is calling](https://www.duvi.ai/docs/tools) first. > **Partial estimates** > > If one of the three components publishes no latency, Studio says the estimate is partial and totals only the components that do. The number still compares two choices usefully, but it is not the whole pipeline. ## Latency targets Latency costs you where silence is expensive. On a phone call, every moment before the agent speaks is dead air the caller is sitting in. In a chat window nobody is watching a clock. | Estimated total | On a call | In chat | | --------------- | ---------------------------------------------------------------------------------------------------- | ------------------------- | | Under 800 ms | Sounds like a person drawing breath. Nobody notices it. | Instant. | | 800 ms to 1.5 s | A natural pause. Reads as the agent thinking, not stalling. | Instant. | | 1.5 s to 3 s | The caller starts wondering whether it heard them. Some repeat themselves, which costs another turn. | Still comfortable. | | Over 3 s | The caller talks over the agent, or hangs up. | Noticeable, rarely fatal. | Aim under 1.5 seconds on any agent that takes calls, and leave room under that target. The estimate is a floor: network time and tool calls land on top of it, and a tool waiting on your API can add a second by itself. In text you can spend that budget instead of protecting it. Two seconds in a chat window buys a stronger model at no cost to the customer. ## Choose a model and a voice Models carry an intelligence tier alongside their latency. The tier is a coarse ranking for picking between options, not a benchmark score. | Tier | Use it when | | ------------------ | ------------------------------------------------------------------------------------------ | | Basic, Capable | Answers come from knowledge, the phrasing is simple, and the call needs to feel immediate. | | Strong | Most agents. Handles tool use and multi-step questions without a noticeable pause. | | Advanced, Frontier | Reasoning over long context, or text conversations where a pause costs nothing. | Read the tier against the latency next to it. On a phone call, a Frontier model that takes two seconds to begin speaking sounds worse than a Capable one that starts in three hundred milliseconds, because the caller hears the silence. In text the same pause is invisible. The model you choose also sets the rate you pay. See [Credits](https://www.duvi.ai/docs/credits). Voices list their accent and gender, and most carry a sample you can play before choosing. An agent that will take calls needs a voice: with a model but no voice, it answers and says nothing. ## Chat mode Chat mode decides which controls the website widget shows. It does not change what the agent knows or which tools it can call. | Mode | What the widget shows | | -------------- | -------------------------------- | | Text only | A message box. | | Voice only | A call button. | | Text and voice | A message box with a microphone. | Chat mode applies to the website widget only. A connected phone number always arrives as voice and a WhatsApp number always arrives as text, whatever the mode says, so an agent on those [channels](https://www.duvi.ai/docs/channels) needs the matching components configured. --- # Appearance Appearance controls how the website widget looks before and during a conversation. It does not change what the agent knows, which channels are connected, or who may use it. Source: https://www.duvi.ai/docs/appearance ## What Appearance changes Open the agent, then **Appearance**. These settings apply to the website widget. | Setting | What it changes | | --------------- | ----------------------------------------------------------------------------- | | Launcher | How the agent appears before a visitor opens the conversation. | | Color | The palette used by the launcher and conversation window. | | Logo | The mark shown on the launcher and in the widget. | | Launcher label | The visible label, or the screen reader label when the launcher is icon-only. | | Starter prompts | Suggested first messages shown before a text conversation starts. | Starter prompts appear only for text-capable agents. A voice-only agent has no message box before the call begins, so there is nowhere to show them. ## Preview the widget The preview on Appearance runs the same widget visitors see, in a frame inside Studio. Edits update the preview as you make them, so check both the closed launcher and the open conversation window before saving. Use Preview for the conversation itself. Appearance is for presentation: whether the widget fits your site, whether the label is clear, and whether the first choices a visitor sees are useful. ## Save changes Launcher, color, label and starter prompts stay as a draft until you select **Save changes**. Discard returns them to the last saved version. A logo upload starts when you choose the file, because Studio needs the stored image to show the real widget preview. Replace the logo from the same field if you chose the wrong file. > **Appearance is not access control** > > A logo, label or color never proves who is allowed to use the agent. Use [Security](https://www.duvi.ai/docs/security) for allowed domains and signed-in visitor access. --- # Knowledge Knowledge is everything an agent may answer from. This page covers adding files and websites, how the crawler decides what to read, and the four indexing states. Source: https://www.duvi.ai/docs/knowledge ## Add knowledge The **Knowledge** tab has two buttons and one status. Use **Manage files** to select documents from your account library, and **Manage websites** to add addresses for the agent to crawl. You can use both on the same agent. Saving reads every source again from the start and builds a fresh index. The agent keeps answering from its existing index while that runs, so there is no gap in service and nothing to schedule around. > **Duvi does not reindex on its own** > > Duvi reads a source when you save, and not again. When your prices change or a page is rewritten, open Knowledge and save to reindex. A stale index is the most common cause of a confidently wrong answer. ## Add files Files live once in your account library and are selected per agent, so the same document can serve six agents without being uploaded six times. Removing a file from one agent leaves it in the library for the others. See [Files](https://www.duvi.ai/docs/files) for the library itself. Only completed uploads can be selected. Keep the tab open until an upload finishes. An interrupted upload cannot be used and nothing repairs it, so upload the file again rather than waiting. > **Check that a file was actually read** > > Duvi extracts text from a file, so a scanned document that holds pictures of words indexes as empty and the agent answers as though the file was never added. Nothing warns you. See [Supported file types](https://www.duvi.ai/docs/reference/file-types) for every format, including the ones that fail silently. ## Crawl a website Duvi crawls a website source rather than fetching a single page. The crawler obeys `robots.txt` and takes its page list from your sitemaps, so your site decides what ends up in the index. 1. **Duvi resolves the address first** The crawler follows a redirect from the bare domain to `www` before anything else, so you do not get two half crawls of the same site. 2. **It reads and obeys robots.txt** The crawler checks `robots.txt` before every page. It does not read a path your robots file disallows, whatever that path contains. 3. **A sitemap fills the queue, or the address does** The crawler expands the sitemaps named in `robots.txt` into its page list. If a site declares none, the crawler starts at the address you gave and follows the links it finds. 4. **The address you gave sets the boundary** A bare domain covers the whole site. An address with a path stays beneath that path, so adding one article indexes that article rather than everything its publisher has posted. 5. **It opens each page in a real browser** The crawler captures content drawn by JavaScript, and describes the images it finds so the agent can show them. A sitemap is the most useful thing you can give the crawler, because it names the pages you consider worth reading. To narrow a crawl, use a more specific address or a robots rule. The crawler identifies itself as `DuviBot`. On a staging site that blocks everything, allow `DuviBot` explicitly and leave the rest closed: ```text title="robots.txt on a private staging site" User-agent: DuviBot Allow: / User-agent: * Disallow: / Sitemap: https://example.com/sitemap.xml ``` ## Indexing states One status covers the whole agent rather than one per source. It sits beside **Index** at the top of the Knowledge tab. | Status | What it means | What to do | | -------- | -------------------------------------------------------------------------------- | ------------------------------ | | Pending | Queued. Duvi has read nothing yet. | Wait. | | Indexing | Reading now. The previous index is still answering. | Wait. | | Ready | Duvi read every source and the index is searchable. | Judge answers now, not before. | | Failed | The run stopped. Duvi replaced nothing, so the previous index is still in place. | Find the source that broke it. | There is no partial state. A run either replaces the whole index or leaves the last good one alone, so an agent never answers from half your content. ## Fix an empty or incomplete index Before you change anything, run a [retrieval trace](https://www.duvi.ai/docs/retrieval-trace) from the same tab. The trace searches the index as it stands and shows what comes back, which separates *the material was never indexed* from *the material is there and the agent ignored it*. The two have different fixes. **** The crawl finished but the agent knows almost nothing Check `robots.txt` on the origin, then check that it declares a sitemap. With no sitemap the queue starts nearly empty and the crawl finishes quickly having collected very little. **** A specific page is missing Either `robots.txt` disallows it, or it is absent from the sitemap, or it sits outside the address you gave. All three are decided on your side. **** A file is listed but never quoted Open the file and try to select a sentence. If nothing highlights, it is a scan with no text layer. Run it through OCR and upload the result. For symptoms across every part of the product, see [Troubleshooting](https://www.duvi.ai/docs/troubleshooting). --- # Files Files belong to your account, not to one agent. Upload once, then select which agents may use each file as knowledge. Source: https://www.duvi.ai/docs/files ## The file library The file library is account-wide. You can attach one file to several agents without uploading it several times, and removing it from one agent does not delete it from the library. > **Removing and deleting are different actions** > > Removing a file from an agent changes that agent’s knowledge. Deleting it from the library removes the stored file and affects every agent that still refers to it. ## Upload files Drop files into the library and watch the progress. Keep the tab open until an upload finishes. An interrupted upload cannot be added to an agent, nothing repairs it, and the fix is to upload the file again. Only finished uploads can be selected as knowledge. See [Supported file types](https://www.duvi.ai/docs/reference/file-types) for what a file must contain to be readable, and for the formats that index as nothing. ## Organize files into folders Folders nest, with a breadcrumb back to Files. Organize by product, by team, or by who owns the source, whichever boundary still makes sense once several agents draw on the same material. ## Use files as knowledge Open an agent’s knowledge picker and select completed files from the library. Saving replaces that agent’s file list and starts a fresh index. The previous index keeps answering while the new one builds. See [Indexing states](https://www.duvi.ai/docs/knowledge#indexing-states). ## Storage limits An account gets **5 GB**. Account settings shows how much of it the library is using. Because files are shared, Duvi counts the space once however many agents use the file. An upload that would take you over the limit is refused when it starts. To free space, delete the file from the library. Removing a file from an agent only changes that agent’s knowledge and returns no storage. --- # How an agent answers A Duvi agent runs five steps for every message it receives. This page covers each one, in the order it happens, and what you control at each step. Source: https://www.duvi.ai/docs/how-an-agent-answers ## The five steps of an answer Every time a customer says something, a Duvi agent runs the same five steps in order. | Step | What happens | You control | | --------- | --------------------------------------------------------------------------------------------------- | ---------------- | | Heard | Text arrives from the widget, from WhatsApp, or from a call as it is spoken. | The channel | | Looked up | Duvi matches the question against your indexed knowledge and pulls only the passages that match. | Knowledge | | Assembled | Duvi combines the system prompt, the recent turns and those passages into one request to the model. | Prompt and model | | Acted on | If an action answers better than words, the agent calls it and waits for your endpoint. | Tools | | Answered | The reply streams back as text, or is spoken in the agent voice. | Voice | The middle three steps do the work, and that work is what you pay for. This is why the rest of these docs keep returning to the same shape: keep behaviour in the prompt, keep facts in knowledge, and let retrieval decide what the model sees. ## Why facts belong in knowledge When you save knowledge, Duvi reads every source from the start, splits it into passages, and stores each passage next to a numeric fingerprint of its meaning. Duvi gives a question the same treatment and pulls the passages whose fingerprints sit closest to it. A price list of four hundred rows therefore costs nothing extra to keep in knowledge, because only the rows that match the question ever reach the model. The same four hundred rows pasted into the system prompt are sent on every exchange, to every customer, whether they asked about prices or opening hours. | Belongs in knowledge | Belongs in the prompt | | ---------------------------------- | ---------------------------------------- | | Prices, plans and what is included | Who the agent is talking to | | Policies, warranties, returns | What it must never say | | Opening hours and locations | When to take details instead of guessing | | Manuals and specification sheets | Tone, length and language | | Anything that changes without you | Which source wins when two disagree | ## What happens during a reindex Saving a knowledge change does not take the agent offline. The existing index keeps answering until the new one is complete, then Duvi swaps them at once. If a source fails to read, Duvi replaces nothing and the agent carries on with the index it had. There is no partial state: an agent never answers from half your content. > **In Studio** > > The Knowledge tab shows Pending, Indexing, Ready or Failed. Failed is the only state that needs you. See [Fix an empty or incomplete index](https://www.duvi.ai/docs/knowledge#fix-an-empty-or-incomplete-index) for the usual causes. ## When an agent calls a tool instead An order status, a slot availability or an account balance cannot live in an index, because they change while the conversation is happening. Actions cover those. The agent decides to call an action by reading its description, so write the description for the agent rather than for yourself. You fix everything else in advance: the endpoint, the headers, and where each value comes from. The agent chooses when to call, never what to send. See [HTTP actions](https://www.duvi.ai/docs/reference/actions) for every field, and [Value sources](https://www.duvi.ai/docs/tools#value-sources) for the setting that stops one customer reading another customer record. --- # Retrieval trace A retrieval trace runs a search against an agent index and shows the passages that come back, with the source of each one. Running a trace costs no credits. Source: https://www.duvi.ai/docs/retrieval-trace ## What a trace is An agent does not read your whole knowledge base to answer a question. It searches the index, takes the passages that match, and answers from those. A trace runs that same search on demand and shows you what came back. A trace answers one question you cannot otherwise get at: **when an answer was wrong, was the right material even there?** > **Where to find it** > > The **Knowledge** tab on any agent, under the sources. A trace does not draw on your balance and does not create a conversation. Opening the tab runs one automatically, using the agent’s own name as the question. ## Run a trace Ask the question the way a customer would, not the way your documents are written. *is there anything cheaper for a small team* is a useful query. *Starter plan seat limit* is not, because it already contains the vocabulary you are testing whether the agent needs. Three controls sit above the results. | Control | What it sets | | -------- | --------------------------------------------------------------------------- | | Question | The question the agent should be able to answer. | | Mode | Context, Links or Images. Three kinds of retrieval, which fail differently. | | Top K | How many passages to ask for. Eight by default, one to twelve. | Each run reports how many results came back, how many you asked for, and how long the search took. If nothing matched, the trace says so rather than showing an empty list. Raising Top K is a diagnostic, not a fix. If the passage you wanted appears only at eleven, ten others are outranking it, and the fix is to remove what is crowding it out. ## Trace modes | Mode | Returns | Use it when | | ------- | ----------------------------------- | ------------------------------------------------------------------- | | Context | Passages of text | The agent answered wrongly, or said it did not know. | | Links | Destinations it may send someone to | It pointed at the wrong page, or refused to link at all. | | Images | Pictures it may show | It described something without showing it, or showed the wrong one. | ## Read the results Results are ranked, best match first. Each result carries where it came from, which is the part that matters when something is wrong. Duvi leaves out fields with nothing in them rather than showing them empty. | Field | What it tells you | | ------------ | ------------------------------------------------------------------------------------ | | Source type | Whether the passage came from a crawled website or an uploaded file. | | Content type | The format it was extracted from, such as `text/html` or `application/pdf`. | | Source URL | The page or file it was taken from. Open it and check the passage is still accurate. | | Origin | Which of your knowledge sources it belongs to, when several are attached. | | Media URL | The image itself, in Images mode. | ## What the results mean ### Nothing came back The material is not indexed. Check the knowledge status reads **Ready** rather than Pending, Indexing or Failed. A scanned PDF with no text layer is the usual cause of a silently empty index. See [Indexing states](https://www.duvi.ai/docs/knowledge#indexing-states). Editing the prompt will not help. ### The right passage came back and the answer was wrong This is a prompt problem. See [System prompt](https://www.duvi.ai/docs/system-prompt). Usually the agent was told to be helpful in a way that outweighed being accurate. ### A stale source outranked the current one Two documents disagree and the older one matched better. Remove the stale source and reindex, or state in the prompt which source wins. The Origin field tells you which is which. ### The passage is right but partial The chunk stops mid-table, or the figure you wanted was on the row that got cut. This is a source formatting problem. A price list written as prose survives chunking better than one written as a wide table. ## Limits of a trace > **Retrieval only** > > A trace shows what the agent was given, not what it did with it. It cannot tell you the agent then called the wrong tool, ignored a boundary, or worded the answer badly. For that, open the conversation and read the transcript alongside [Answer quality](https://www.duvi.ai/docs/reference/answer-quality). A trace also runs the search on demand, against the index as it stands. It is not a record of a past conversation. If you have reindexed since the answer you are investigating, the trace can legitimately differ from what the customer got. --- # Agent capabilities A Duvi agent can look things up, show a result, operate your website for a visitor, and save what it learns. This page covers each capability and which channels support it. Source: https://www.duvi.ai/docs/in-conversation ## Grounding Grounding is the rule that a Duvi agent may only present something it can point at a source for. When an agent shows a price, a link or a document, it has to say where that came from. The tools that present information refuse an item that arrives without a source attached, so the agent cannot put a fact on screen that it has nothing to point at. Duvi enforces this in the tool rather than in the prompt, so it holds on the four hundredth conversation as well as the first. If a customer asks about a plan that is not in the price list you uploaded, the agent says it does not know and offers to take their details. It does not produce a number that looks about right. ## Screen control On a website, an agent can operate the page the visitor is already looking at. It reads the current page, gets back the list of elements it is allowed to act on, then clicks, types, selects or scrolls. A visitor who says “just put me on the smallest plan” can have the form filled in front of them. Two limits apply: - **Element references go stale.** When the page changes, the agent map of it is out of date, so it reads the page again before carrying on rather than repeating a click blindly. - **Actions time out after 15 seconds.** The agent gives up on that action and tells the customer rather than going quiet. > **Website only** > > Screen control needs a live browser page, so it does not exist on WhatsApp or on a phone call. An agent taking a call cannot fill in a form for someone. ## Present information The agent produces one result, and each channel presents it in the form that channel supports. A list of three plans arrives as tappable options in WhatsApp and as a spoken sentence on a call. You write the agent once. There is no phone version and chat version of the same answer to keep in step. ## Link and navigation A web agent can offer a link, or take the visitor to a page directly, when that is what they asked for. Duvi checks destinations before the agent uses them. The agent cannot invent a URL and send someone to a page that does not exist. ## Save customer details An agent can record details it picks up during a conversation, on every channel. If someone mentions their order number or their preferred callback time, Duvi keeps it. Saved details and verified identity are different things, and the difference decides what is safe to show. | | What it is | What it is good for | | ----------------- | ------------------------------------ | --------------------------------------------------------------------------------- | | Saved details | Whatever the customer typed or said. | Context, follow-up, routing. Anyone can claim to be anyone, so it proves nothing. | | Verified identity | Signed claims from your own server. | Deciding whether to show private data. This is the one that counts as proof. | A customer saying “I am the account owner” is a saved detail, not authorization. See [Customer identity](https://www.duvi.ai/docs/identity) for how to give the agent something it can trust. ## Capabilities by channel Capabilities differ by channel because the channels differ. A phone call has no screen, and WhatsApp does not let anyone drive a browser. The first three rows work everywhere, so build on those when an agent has to behave the same across channels. | Capability | Website | WhatsApp | Phone | | -------------------------- | ------- | ------------------------------------- | ----- | | Knowledge retrieval | Yes | Yes | Yes | | HTTP and connected tools | Yes | Yes | Yes | | Save customer information | Yes | Yes | Yes | | Verified links | Yes | No | No | | Tappable buttons and lists | No | Yes, as native WhatsApp messages | No | | Send a document | No | Yes, including during a WhatsApp call | No | | Read and control a page | Yes | No | No | --- # Tools Tools let an agent read data that changes while the conversation is happening. This page covers the three kinds of tool, where each value comes from, and how to call your API as the customer. Source: https://www.duvi.ai/docs/tools ## Tool types Duvi supports three kinds of tool. All three attach to a single agent and are described to the model the same way. What differs is who decides which tools exist. | Kind | At the other end | You define | | ---------- | ------------------------------------------------------- | -------------------------------------------- | | Action | One endpoint of yours, one method | Every header, query parameter and body field | | MCP server | A server that publishes its own set of tools | The address and any headers it needs | | Connector | A service Duvi already knows, such as Shopify or Stripe | Which of its tools the agent may use | Actions are the ones you shape field by field, so they have [their own reference](https://www.duvi.ai/docs/reference/actions). Connectors need little more than a button, and the catalogue is in [Connectors](https://www.duvi.ai/docs/connectors). Whatever the kind, the agent reads a description and decides *when* to call. It never decides what the call looks like. > **An MCP server is a wider grant** > > You are trusting whatever tools that server chooses to expose, now and after any change its owner makes without telling you. Point it at servers you control, or vendors you would hand an API key to. ## Value sources Every header, query parameter and body field says where its value comes from. That setting is the safety model. | Value source | Filled by | Trustworthy | | --------------------------- | ------------------------------------------------------ | --------------------------------------- | | Fixed value | You, once, when you define the tool | Yes | | Stored key | Duvi, at call time | Yes | | From the signed-in customer | Duvi, from verified identity. The agent never sees it. | Yes | | From your website | The page the widget is on | No. The visitor can read and change it. | | Ask the customer | The agent, from what was said in conversation | No. It is whatever they claimed. | > **Set identity on any field that selects a record** > > If a value decides *whose* data comes back, it must be **From the signed-in customer**. Set to **Ask the customer**, anyone who guesses a number reads somebody else’s record, and the agent will have done exactly what you told it to. For every field, with its exact shape and the eleven types a value the agent collects can take, see [Value sources](https://www.duvi.ai/docs/reference/actions#value-sources). ## Stored keys A stored key is a named secret belonging to one agent. Create it once, from Credentials or from the tool that needs it, then reference it by name in any tool header. Duvi never shows the value again, to you or to the model. | Operation | Available | | ------------------------ | ----------------------- | | Create a key | Yes | | List key names and dates | Yes | | Read a value back | No, by design | | Update or delete a key | Not currently supported | > **Rotate a credential** > > Because Duvi cannot yet delete keys, rotate by creating the new key, repointing every tool that used the old one, then revoking the old credential at the provider. The superseded key stays in the list. ## Call your API as the customer When your API should return one person’s data rather than everybody’s, it needs to be called as that person. An **integration** turns a signed-in visitor into a token your API will accept, and a tool points at it. | Sign-in | What the call carries | | ----------------------- | ------------------------------------------------------------------------------------------ | | No sign-in | Nothing that identifies a person. Right for public lookups such as stock or opening hours. | | Sign in as the customer | A token minted for this customer, so your endpoint can only return their data. | Signing in as the customer needs a **Token URL**, a **Client ID** and a client secret you have already stored as a key. **Scope** and **Audience** are optional and set by your provider. **Which detail identifies the customer** names the claim to read from the token your identity endpoint returns, which is `sub` unless you say otherwise. On calls there is no browser session to read, so **Fall back to a verified phone number on calls** lets the number the carrier reports stand in as the customer. Treat that as a separate decision from browser identity, because it proves a different thing. The exchange follows RFC 8693 and carries an actor token alongside the customer, naming the agent and the conversation it is acting in. Your authorization server can therefore audit which agent acted, in which conversation, on whose behalf. If Duvi cannot mint a token, it does not make the call. The agent is told it could not authenticate rather than calling your endpoint as nobody. Identity itself is set up in [Customer identity](https://www.duvi.ai/docs/identity). --- # Connectors A connector gives an agent live read access to a service you already use. Connect one and its tools become available in conversation, with no integration to write. Source: https://www.duvi.ai/docs/connectors ## Connector catalogue Connectors attach to one agent, so a public storefront agent and an internal one never share access. Connect the same service to two agents and each holds its own credential. | Connector | What it does | To connect | | ------------------------- | ----------------------------------------------------------------------------------- | ---------------- | | Shopify | Search the catalogue, build a cart and answer questions about returns and shipping. | Nothing to enter | | WooCommerce | Search the product catalogue of a WooCommerce store. | Paste a key | | Wix | Read catalogue and store data from a Wix site. | Sign in | | Salesforce Commerce Cloud | Shopper APIs for catalogue and cart on a B2C Commerce storefront. | Paste a key | | Stripe | Look up payments, customers and subscriptions. | Sign in | | PayPal | Look up transactions and orders. | Sign in | | Notion | Search pages and databases so the agent answers from your own documentation. | Sign in | | Airtable | Read records and schema from your bases. | Sign in | | Webflow | Read sites, collections and CMS items. | Sign in | | Linear | Read issues so a conversation can become tracked work. | Sign in | | monday.com | Read boards and items. | Sign in | | Sentry | Read issues and events for an agent working on an internal platform. | Sign in | | Supabase | Read projects, database schema and analytics. | Sign in | | Cloudflare | Read logs and analytics to answer questions about traffic and errors. | Sign in | | Zapier | Run the Zaps you expose, reaching tools with no connector of their own. | Sign in | ## How connectors authenticate What a service asks of you depends on how that service publishes access. | Kind | What you do | | ---------------- | ----------------------------------------------------------------------------------------------------------- | | Nothing to enter | The store already publishes what an agent needs. Type the address and it is connected. | | Sign in | You are sent to the service, you approve the access, and you land back here. Duvi never sees your password. | | Paste a key | You create a credential in the service and paste it in. It is encrypted and never shown again. | Shopify asks for nothing at all. Every Shopify store already publishes a shopping interface, so the storefront address is the whole setup. ## Connect a service 1. **Open the agent** Go to the agent, then **Integrations**. 2. **Pick the service** The catalogue is grouped by what each service is for. Selecting one opens the provider page with its description, available tools and connection form. 3. **Approve the access** For a sign-in connector, the service takes you through its own approval screen and returns you to the same page. Duvi never sees your password. 4. **Choose the tools** Duvi asks the service what it can do and lists the tools it found. Turn off any tool you would rather the agent never called. ## Read-only access Connectors request read access wherever the service separates reads from writes. Duvi connects Linear with `read`, Sentry with `org:read`, and Airtable with record and schema reads. An agent answering a customer has no reason to delete a repository or refund a payment. Where a service offers no read-only grant, Duvi limits which of its tools an agent may call instead. The catalogue lists what each tool does before you connect it. > **Order lookups need customer identity** > > A connector holds your credential, not your customer’s. A tool that lists orders would list everyone’s, so those tools are left out of customer-facing connectors. To answer *where is my order* safely, identify the visitor first with [customer identity](https://www.duvi.ai/docs/identity). ## Connection states Each connection carries one of three states. A connection that is not working shows the reason at the top of its panel, and the agent carries on without it rather than failing the conversation. | State | What it means | | ----------- | ---------------------------------------------------------------------------------- | | Connecting | Set up, but the service has not confirmed yet. Give it a moment. | | Connected | Working. Its enabled tools are available to the agent. | | Not working | Usually access withdrawn or expired at the service. Reconnect from the same panel. | Two states look like faults and are not: | What you see | What it means | | ----------------------------- | ---------------------------------------------------------------------------------------------------------- | | Connected, no tools listed | The service answered and offered nothing. Usually a feature that still needs switching on at that service. | | Tools listed but never called | The agent had no reason to call one. Ask it something only that service could answer. | For HTTP actions and MCP servers you host yourself, see [Tools](https://www.duvi.ai/docs/tools). --- # Customer identity Customer identity lets your own server tell an agent who a visitor is. The agent can then show private data without taking the visitor’s word for who they are. Source: https://www.duvi.ai/docs/identity ## Identity endpoint On the **Security** tab, under **Customer identity**, set **Your identity endpoint** to an address on the same site that embeds the agent. The widget calls it from the visitor’s browser, so the request arrives with your existing login cookies and you can answer from your own session. Return a short-lived token for a signed-in customer, or an empty object for a visitor with no account. ```json title="signed-in customer" { "identity_token": "" } ``` ```json title="no signed-in customer" {} ``` > **Keep the endpoint on the embedding origin** > > The browser only sends your cookies to your own origin. A cross-origin credential flow is not needed and is harder to get right. A working implementation in Next.js. Point `currentUser` at your real server-side session lookup, install `jose`, and keep the secret on the server. The 60-second token leaves headroom under the 120-second limit. ```typescript title="app/api/duvi-identity/route.ts" import { SignJWT } from 'jose'; import { NextResponse } from 'next/server'; import { currentUser } from '@/lib/auth'; const noStore = { 'cache-control': 'no-store, no-cache, must-revalidate, max-age=0', pragma: 'no-cache', }; export const dynamic = 'force-dynamic'; export const revalidate = 0; export async function GET() { const user = await currentUser(); if (!user) return NextResponse.json({}, { headers: noStore }); const rawSecret = process.env.DUVI_IDENTITY_SECRET; if (!rawSecret) throw new Error('DUVI_IDENTITY_SECRET is required'); const secret = new TextEncoder().encode(rawSecret); const identityToken = await new SignJWT({ email: user.email }) .setProtectedHeader({ alg: 'HS256' }) .setSubject(user.id) .setAudience('duvi') .setIssuedAt() .setExpirationTime('60s') .sign(secret); return NextResponse.json( { identity_token: identityToken }, { headers: noStore }, ); } ``` > **Never cache the identity endpoint** > > A cached response hands one customer another customer’s token, and it fails silently until somebody notices they are signed in as a stranger. Keep the route dynamic and send `no-store` on both the signed-in and the anonymous response. ## Token contract ```json title="JWT payload" { "aud": "duvi", "sub": "customer_4f91", "exp": 1788253500, "plan": "pro" } ``` | Requirement | Contract | | --------------- | ------------------------------------------------------------ | | Algorithm | `HS256` only | | Audience | `aud` must be `duvi` | | Customer | `sub` is required and must remain stable for the same person | | Expiry | `exp` is required; maximum lifetime is 120 seconds | | Clock tolerance | 30 seconds either side | The widget refreshes identity 15 seconds before expiry, so a short lifetime costs you nothing. Duvi keeps any other claims you add and can pass them into tool calls, apart from the reserved JWT claims. ## Signing keys A signing key is the shared secret your endpoint signs with. You create it, so it is whatever value you already keep on your server. Select **Add key**, give it a name and paste the value. Duvi stores it encrypted and never shows it again. An agent can hold several keys, and exactly one is marked **In use**. Duvi verifies tokens against that one. 1. **Add the new key first** Add it alongside the old one. Nothing changes yet, because the old key is still in use. 2. **Start signing with the new value** Deploy the new secret to your own server. 3. **Switch which key is in use** Select **Use this key** on the new one. The old key keeps working right up until you switch, so no customer is rejected part way through the change. > **An identity endpoint cannot be removed** > > Once an identity endpoint is set you can point it at a different address, but you cannot clear it. Plan the address before you save it the first time. ## Require a sign-in By default anyone may open a conversation, and Duvi uses verified identity when it happens to be available. Switching **Access** to **Only signed-in visitors** refuses anyone your endpoint cannot identify, before any model runs. | Access | Behaviour | | ----------------------- | ------------------------------------------------------------------------- | | Anyone | Visitors may start anonymously. Verified identity is used when available. | | Only signed-in visitors | An unidentified visitor is refused before any model call. | The second option becomes selectable only once both an endpoint and a signing key exist. If identity later breaks while it is selected, every visitor is refused and Studio says so at the top of the tab. ## Use claims in tools On any tool field that decides whose data comes back, set the value source to **From the signed-in customer**. The agent never sees that value and cannot invent it. Never use **Ask the customer** for an account id, an order reference tied to an account, or anything else that selects a record. That value is whatever the person on the other end typed. See [Value sources](https://www.duvi.ai/docs/reference/actions#value-sources). To have your own API accept the customer rather than the agent, connect the tool to an integration that signs in as them. That is set up under **Tools** and covered in [Call your API as the customer](https://www.duvi.ai/docs/tools#call-your-api-as-the-customer), including the option to accept a verified phone number on calls. ## Test the setup 1. **Signed out** Confirm the endpoint returns `{}` and the agent applies your anonymous access rule. 2. **Signed in** Confirm the token carries the exact audience, a stable subject and an expiry no more than 120 seconds away. 3. **Private tool** Call a tool with a signed-in customer field and verify your API receives the signed claim, not something typed in chat. 4. **Failure** Break the signature deliberately. A protected conversation must refuse, and a token exchange must stop before your endpoint is called. For symptoms and their causes, see [Troubleshooting](https://www.duvi.ai/docs/troubleshooting#customer-identity). --- # Channels A channel is how a conversation reaches your agent. The agent does not change between them: one prompt, one set of knowledge, one set of tools. Source: https://www.duvi.ai/docs/channels ## The three channels Everything on the **Channels** tab connects a way in. None of it changes what the agent knows or what it is allowed to do, and replies always come back the way the conversation arrived. | Channel | What it is | What you need | | -------- | ------------------------------------------- | -------------------------------------------------------- | | Website | A chat bubble on your own pages. | Somewhere to paste two lines of HTML. | | Phone | The agent answers a number you already own. | A voice-capable Twilio number, and a voice on the agent. | | WhatsApp | The agent replies to your business number. | A WhatsApp Business number, through Pinnacle or Meta. | What an answer can look like does differ by channel. A phone call has no screen and WhatsApp does not let anyone drive a browser. See [Capabilities by channel](https://www.duvi.ai/docs/in-conversation#capabilities-by-channel) for the full table. ## Website Copy the snippet from the Channels tab and paste it before the closing `body` tag on every page the agent should appear on. There is no build step and no package to install. ```html title="index.html" ``` The widget renders as a launcher in the corner of the page, showing a message box, a call button, or both, depending on the chat mode set on Configure. For every attribute the element accepts, see the [widget reference](https://www.duvi.ai/docs/reference/widget). > **Add your domains before you go live** > > You set the domains allowed to open a conversation on the **Security** tab, not in the snippet. Until you add yours, any site can embed the agent and spend your credits. See [Allowed domains](https://www.duvi.ai/docs/security#allowed-domains). ## Phone Bring a number you already have at Twilio. Duvi points it at the agent and buys nothing on your behalf. Your number keeps working as it does now, and calls reach the agent first. 1. **Have a voice number on the account** Buy it in the Twilio console first. Duvi lists only voice-capable numbers, so a messaging-only number will not appear. 2. **Connect, then confirm** Duvi reads the account back to you, including its friendly name, so you can check you connected the account you meant before choosing a number. 3. **Give the agent a voice** A call needs a transcriber and a voice, both on Configure. An agent with a model but no voice answers and says nothing. See [Model and voice](https://www.duvi.ai/docs/model-and-voice). Connecting writes two addresses onto the number at Twilio: one that answers the call, and one that records how it ended. Editing either address in the Twilio console afterwards breaks the link and the number rings out. Reconnect from the Channels tab if that happens. **At Twilio** - [Voice webhooks, and what Twilio sends on each call](https://www.twilio.com/docs/usage/webhooks/voice-webhooks) - [Getting started with webhooks, including console setup](https://www.twilio.com/docs/usage/webhooks/getting-started-twilio-webhooks) ## WhatsApp Connect a WhatsApp Business number through **Pinnacle** or **Meta**. In both cases the connection is real only once a message has arrived, not when you save the form. 1. **Bring the phone number ID** Not the number itself. It is the id your provider lists against the business number, and it is what every request uses. 2. **Paste Duvi values into the provider** Duvi generates a **Callback URL** and a **Verify token**, both shown when you manage the number. Paste them at the provider rather than inventing them there. The provider then calls the address once with the token to prove you own it. 3. **Wait for the handshake** Until it succeeds the number carries a **Needs webhook** badge. Most WhatsApp setups stall here, and the fix is always at the provider. 4. **Send one message in** The badge clears and the agent starts replying. You can pause a number without disconnecting it, and resume later from the same panel. > **Meta can limit a number independently of Duvi** > > Meta rates the quality of a business number and can limit or disable it. When that happens the number shows the reason Meta gave, and the fix is at Meta rather than in Studio. **At Meta** - [Webhooks, payloads and the verification handshake](https://developers.facebook.com/docs/whatsapp/cloud-api/guides/set-up-webhooks) - [Business phone numbers, ids, quality rating and limits](https://developers.facebook.com/docs/whatsapp/cloud-api/phone-numbers) --- # Test an agent Preview runs the real widget against your agent. This page covers the questions to ask, the conversations that expose problems, and what to check before you paste the tag. Source: https://www.duvi.ai/docs/testing ## Preview The **Preview** tab runs the real widget, not a simulation. It loads the same embed script your visitors load, with the same agent id, inside a frame. What you see is what a customer gets. Preview has two controls: a **Desktop** and **Mobile** toggle, and **Open in new tab** for a full-page version you can share with a colleague. Test on Mobile as well as Desktop, because a widget that sits comfortably beside your content on a laptop can cover most of a phone screen. > **Preview costs credits** > > Because Preview runs the real widget, a preview conversation is a real conversation and draws on your balance. Building the agent is free; talking to it is not. To check only whether material is retrievable, use the [retrieval trace](https://www.duvi.ai/docs/retrieval-trace), which runs the search without starting a conversation and costs nothing. ## Six questions to ask Ask these six in order. Five you already know the answer to, and one you know the agent cannot answer. 1. **The one every customer asks** Whatever your team answers twenty times a week. If the agent cannot do this one well, nothing else matters. 2. **One that needs a number** A price, a delivery window, a limit. Numbers are where a confident wrong answer does the most damage, and where a stale source shows up fastest. 3. **One phrased in the customer's words** Use the term a person would use rather than your internal name for the thing. This is the question your site search fails. 4. **One that spans two pages** Something whose answer is half on one page and half on another. Retrieval either brings both or it does not. 5. **A follow-up that depends on the previous answer** Ask “and what about the other one?” without repeating the subject. This tests whether the agent carries context, which is the difference between a conversation and a search box. 6. **One you know it cannot answer** Check that it says it does not know and offers a next step, rather than producing something plausible. ## Test the difficult conversations Happy paths pass by default. These conversations decide whether the agent is safe in front of customers. - **Interrupt it.** On voice, cut in halfway through an answer. It should stop and listen rather than finish its sentence. - **Change the subject.** Mid-topic, ask about something unrelated, then come back. Context should survive the detour. - **Ask it to do something it has no tool for.** It should say it cannot, not claim it did. - **Ask for something private.** If you have not set up [customer identity](https://www.duvi.ai/docs/identity), it should decline rather than accept “I am the account holder” as proof. - **Be difficult.** Be vague, be annoyed, repeat yourself. Check it moves the conversation somewhere rather than looping. - **Ask it what it is.** It should say it is an AI. If you have turned on the [disclaimer](https://www.duvi.ai/docs/security#ai-disclaimer), check that it reads well aloud as well as on screen. ## Diagnose a bad answer Run a trace before you rewrite the prompt. Most bad answers are not prompt problems, and the trace tells you which kind you have in about ten seconds. | What you saw | Check first | | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | | It said it did not know something you published | [Run a trace](https://www.duvi.ai/docs/retrieval-trace). If nothing comes back, it is a knowledge problem, not a prompt problem. | | It gave an out-of-date answer | Trace it and read the Origin field. Two sources probably disagree and the stale one matched better. | | It answered from the right page but got it wrong | This is the [prompt](https://www.duvi.ai/docs/system-prompt). Usually being helpful outranked being accurate. | | It was too long, or unreadable aloud | The Voice block of the prompt. See [Prompts for voice agents](https://www.duvi.ai/docs/system-prompt#prompts-for-voice-agents). | | A tool did nothing, or ran twice | The Tools block, and the action definition itself in [HTTP actions](https://www.duvi.ai/docs/reference/actions). | | The widget did not appear on your own site | [Allowed domains](https://www.duvi.ai/docs/security#allowed-domains). Duvi matches on hostname, so `www` must be listed separately. | ## Pre-launch checklist Run this list once more before the agent is live. - Knowledge status reads **Ready**, not Indexing or Failed. - Your domains are in [allowed domains](https://www.duvi.ai/docs/security#allowed-domains), including the `www` version if you use it. - The first message says something useful, and the disclaimer says what you want it to say. - It declines gracefully on the question you know it cannot answer. - When it cannot help, it does the thing you told it to do next, and you have watched that happen. See [Give the customer a next step](https://www.duvi.ai/docs/leads#give-the-customer-a-next-step). - You have looked at it on a phone. After launch, the list that matters is the questions the agent could not answer. That is in [Conversations and insights](https://www.duvi.ai/docs/insights), and it is written by your customers. --- # Security and access Four controls decide who can reach your agent: the domains it may run on, who may open a conversation, the disclaimer it shows, and where its credentials live. Source: https://www.duvi.ai/docs/security ## Allowed domains The **Security** tab lists the domains permitted to open a conversation with this agent. Duvi refuses requests from anywhere else. Add your domains before you go live. The agent id sits in the page source of every site you embed on, so anyone who reads that source can paste the same two lines onto their own site and spend your credits. An empty list stops nothing, and Studio warns you while it is empty. ### Domain matching rules - **Enter the domain only.** Type `example.com`. You do not need a scheme, a port or a path, and the list shows plain hostnames back to you. - **Subdomains are separate entries.** `www.example.com` and `example.com` are two different hosts. Add both if you use both. This is the most common reason a widget does not appear. - **Duvi compares the hostname only.** Scheme and port are ignored, so `http` and `https` are the same entry, and so is a port used in development. - **`localhost` is accepted**, so you can try the widget before the site is live. - Anything that cannot be read as a domain is rejected when you add it rather than saved dead. > **This is a browser-level control** > > Anything that is not a browser can set an origin header, so the domain list stops casual embedding rather than a determined attacker. The real gate on anything that touches an account is [customer identity](https://www.duvi.ai/docs/identity). ## Access control Also on the Security tab, under **Access**, and independent of the domain list. | Setting | What it means | | ----------------------- | --------------------------------------------------------------------------------------------------------------------- | | Anyone | Visitors do not have to sign in. If your identity endpoint identifies them, the agent uses that. This is the default. | | Only signed-in visitors | Duvi refuses anyone your identity endpoint cannot identify, before the conversation starts. | The second option stays locked until customer identity is working, which means an identity endpoint and one signing key. Studio states that requirement next to the option while it is unavailable. If an agent requires a signed-in visitor while identity is broken, every visitor is refused. Studio says so in red at the top of the tab, because from the outside that looks like an outage rather than a setting. ## AI disclaimer On the **Configure** tab: a **Show a disclaimer** switch and one **Message**, shown before the agent’s first message. It is off by default. Turning it on and leaving the message empty stores nothing, so write the sentence you want people to read. Keep it short and specific. Something in the shape of *replies are generated, check anything important with our team* says what the thing is and what to do about it. The disclaimer is separate from the first message, which is also on Configure. The disclaimer is a standing statement about what the agent is. The first message is what the agent says to open. Writing the disclaimer into the opening line means editing your opening line every time your legal position changes. ## Stored keys Duvi stores the credentials an agent needs per agent, encrypted, and never shows them again once saved. Give a key a name, paste the value once, and afterwards select it by name wherever a tool needs it. Nothing secret belongs anywhere else, and in particular not in the prompt. A system prompt is not a secure store, and a determined visitor can often get its contents repeated back. See [What never belongs in a prompt](https://www.duvi.ai/docs/system-prompt#what-never-belongs-in-a-prompt) and [Stored keys](https://www.duvi.ai/docs/tools#stored-keys). ## The agent id is public The agent id appears in the page source of every site you embed on. It opens a conversation with this agent and nothing else: no account access, no files, no billing, no other agent. The allowed domains list is what limits its use, and that list only applies when it is not empty and the request comes from a browser that sent an origin. Treat the id as public and the domain list as the control. --- # Troubleshooting Find the symptom, get the cause. Most of what looks like a bad model is a source that was never indexed, a domain that was never listed, or a value the agent was allowed to invent. Source: https://www.duvi.ai/docs/troubleshooting ## Start here Two instruments answer most questions before you change anything. Both are free. | Instrument | Tells you | | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | [Retrieval trace](https://www.duvi.ai/docs/retrieval-trace), on the Knowledge tab | Whether the material was in the index at all. Costs nothing and starts no conversation. | | The transcript, under [Conversations](https://www.duvi.ai/docs/insights) | What actually happened, in order, including which tools ran. | > **Run a trace before you edit anything** > > Trace the question that failed. **If the right passage does not come back, it is a knowledge problem** and editing the prompt will not fix it. **If it does come back and the answer was still wrong, it is a prompt problem.** ## Bad answers **** It says it does not know something you have published Trace it. If nothing comes back, the material is not in the index. Check the index state reads **Ready**, then check the source was readable. A scanned PDF is the usual cause and fails silently. See [Supported file types](https://www.duvi.ai/docs/reference/file-types). If the passage does come back, the prompt is overruling it. Look for a boundary written so tightly that the agent declines rather than answers. **** It gives an out-of-date answer Two sources disagree and the stale one matched better. Trace the question and read the origin on each result to find which is which, then remove the stale source and save to reindex. If both have to stay, say which one wins in the prompt. **** It invents a price, a date or a policy There are two causes and the trace separates them. If the figure exists nowhere in your sources, the prompt is missing a boundary: forbid it with the reason attached, as [Give every rule a reason](https://www.duvi.ai/docs/system-prompt#give-every-rule-a-reason) describes. If the figure is in the prompt itself, move it into knowledge, because a fact in a prompt arrives with no source and competes with the passages retrieval found. **** The answer is right but stops half way The passage was cut mid-table. A price list written as wide rows survives chunking badly. Rewrite the source as prose or as short rows, then reindex. **** It is unbearable to listen to on a call The Voice block of the prompt is missing or too weak. Cap the reply length, ban markdown, and spell out symbols and currency. See [Prompts for voice agents](https://www.duvi.ai/docs/system-prompt#prompts-for-voice-agents). **** It loops, repeating the same answer The agent has run out of moves and has not been told what to do next. Add the next step to the Job block: take a name and email, or call a tool. An agent with nowhere to go repeats itself. ## Knowledge and indexing **** The index reads Failed The run stopped and Duvi replaced nothing, so the agent is still answering from the previous index. Remove sources one at a time and save until the run completes. The source that breaks it is almost always a file that cannot be opened or a site that stopped responding. **** The crawl finished but the agent knows almost nothing Check robots.txt on the origin, then check a sitemap is declared in it. With no sitemap the crawler starts at the address you gave and follows links from there, which on a site with thin navigation collects very little. **** One specific page is missing Either robots.txt disallows it, or it is absent from your sitemap, or it sits outside the address you gave. An address with a path stays under that path. All three are decided on your side. **** A file is listed but never quoted Open it and try to select a sentence. If nothing highlights, it carries no text layer and indexed as empty. See [Formats that index as nothing](https://www.duvi.ai/docs/reference/file-types#formats-that-index-as-nothing). **** An upload never finishes An interrupted upload stays incomplete and cannot be used as knowledge. Nothing repairs it, so upload the file again rather than waiting. ## The website widget **** It does not appear on your site at all Almost always the domain. Duvi matches on hostname, so `www.example.com` and `example.com` are two entries and adding one does not add the other. Compare the hostname in your browser address bar against the list on the Security tab. If the list is correct, check the two lines are on the page before the closing `body` tag, and that your CMS has not stripped the script tag. **** It works on your site but not inside another page The widget refuses to render inside a frame unless that frame is marked to allow it. See [Frames and style isolation](https://www.duvi.ai/docs/reference/widget#frames-and-style-isolation). **** Page variables are not reaching your tools The attribute must be valid JSON with an object at the top level. Duvi ignores anything else and warns in the browser console. Only strings, numbers and booleans survive. Duvi withholds a tool entirely when a field set to come from your website has no matching page variable. **** It answers in text but the call button does nothing Voice needs both a transcriber and a voice chosen on Configure. An agent with a model but no voice answers and says nothing. ## Tools and connectors **** A tool never fires The description is the only thing the agent reads when deciding. Write it as one sentence about when to use the tool, in the words your customers use. Then state in the Tools block of the prompt what must be true before calling it. **** A tool fires but the call fails Open the transcript and read the tool activity. The agent sees the status and the body, so a readable error body is what lets it recover gracefully. Check that a `GET` action is not carrying body parameters, which Duvi ignores. **** A connector shows Not working The reason is shown at the top of its panel. Access withdrawn or expired at the service is the common one, and reconnecting from the same panel fixes it. The agent carries on without that connector rather than failing conversations. **** A connector is Connected but lists no tools The service answered and offered nothing, usually because a feature still needs switching on at that service. Nothing in Studio changes this. **** A customer sees another customer’s data Check every tool field that decides whose record comes back. If any is set to **Ask the customer**, the agent is passing whatever the person on the other end claimed. It must be **From the signed-in customer**, which the agent cannot see or invent. See [Value sources](https://www.duvi.ai/docs/reference/actions#value-sources). ## Customer identity **** Every visitor is being refused The agent is set to **Only signed-in visitors** while identity is not working, so nobody gets in. Studio says so in red at the top of the Security tab. Either fix the endpoint or set access back to **Anyone**. **** A signed-in customer is treated as anonymous Work down this list in order. - The endpoint is on the same origin as the page, so the browser sends your existing cookies. - The token is signed `HS256` with the key currently marked **In use**. - Its audience is exactly `duvi`. - Its expiry is no more than 120 seconds away, and your server clock is right. Tolerance is 30 seconds either side. **** One customer occasionally sees another customer’s session Your identity endpoint is being cached. Send `no-store` on both the signed-in and the anonymous response, and keep the route dynamic. See [Customer identity](https://www.duvi.ai/docs/identity). **** You need to change the signing key Add the new key, then switch which one is in use. The old key keeps working until you switch, so nothing is rejected part way through. You cannot remove an identity endpoint once set, only point it somewhere else. ## Phone and WhatsApp **** The number rings out The webhooks on the number did not save, or were edited afterwards in the provider console. Duvi writes them onto the number itself, so changing them there breaks the link. Reconnect from the Channels tab. **** A number does not appear when connecting Duvi lists only voice-capable numbers, and buys nothing on your behalf. Buy the number at the provider first. **** WhatsApp stays on Needs webhook The provider has not called your webhook back yet. Duvi generates both the webhook address and the verify token, and you paste them at the provider rather than inventing them there. **** WhatsApp was working and stopped Meta rates business numbers and can limit or disable one on its own. The connection shows the reason the provider gave, and the fix is at Meta rather than in Studio. ## Credits **** Conversations are refused for insufficient credits Duvi checks the balance when a conversation opens and again on each message. An empty balance stops the agent rather than returning a lower quality answer. Top up, or turn on **Top up automatically**. **** Automatic top-ups stopped happening Repeated failures stop the attempts rather than retrying forever, and the form shows how many failed. Fix the card, then save again to reset the counter. **** The balance fell faster than expected Length matters more than message count, and Duvi sends the system prompt again on every turn. A price list pasted into a prompt is billed to every customer who asks about anything. Check the breakdown by agent and by channel on Billing. Preview also costs credits, because it runs the real widget. A retrieval trace does not. --- # Conversations and insights Studio gives you three views of the same conversations: one transcript in full, the whole system in numbers, and the patterns in between. Source: https://www.duvi.ai/docs/insights Every view on this page reads the same underlying conversations. What changes is how far back you are standing. - **Conversations** is one customer, in full. Use it when you know something went wrong and you need to see it. - **Analytics** is the whole system in numbers. Use it to find out whether the thing you saw happens to everyone. - **Insights** is the pattern across many conversations. Use it when you do not yet know what is wrong. The usual direction is right to left. A pattern in Insights tells you what to measure, Analytics tells you how widespread it is, and one transcript tells you why. ## Conversations The conversation browser is the source record and the only place you see exactly what was said. Filter the list, open the full transcript, and read the ratings and session duration. Read one transcript before you change anything. A summary tells you an answer was rated poorly; only the transcript tells you the customer had already asked the same thing twice. | Use it to | Look at | | ------------------------ | ------------------------------------------ | | Reproduce one failure | The ordered transcript and tool activity | | Compare channel behavior | Surface, modality and session duration | | Find explicit feedback | Customer ratings attached to conversations | ## Analytics Analytics aggregates conversation volume, response latency and tool timing. It tells you whether something is systemic or whether you happened to read the one bad transcript. For what counts as a good or bad latency number, see [Latency targets](https://www.duvi.ai/docs/model-and-voice#latency-targets). The same number is a serious problem on a phone call and fine in a chat window. Compare these figures against your own history rather than against an outside benchmark. > **Read latency in context** > > A slow tool can dominate an otherwise fast answer. Compare total response latency with tool timing before changing the model. ## Insights Duvi analyses every conversation for four signals. Across a few hundred conversations they become a map of what your customers want and where the agent is getting in the way. | Signal | Question it answers | | --------- | ---------------------------------------------- | | Outcome | Did the customer accomplish the apparent goal? | | Sentiment | How did the interaction feel to the customer? | | Quality | Was the answer supported, relevant and useful? | | Topics | What are customers repeatedly asking about? | Topics is usually the signal that pays for itself. It surfaces the question customers keep asking that nobody on your side thought to write down, which is normally a gap in knowledge rather than a fault in the agent. ## Answer quality The poorly answered queue collects every conversation where Duvi detected something going wrong: the agent made something up, gave no answer, gave wrong information, went off topic, repeated itself, or formatted the reply badly. Open the transcript first. The same symptom has different causes, and the fix differs for each one. | Evidence | Likely next change | | ------------------------------------ | ----------------------------------------------------- | | Missing or stale facts | Improve knowledge and reindex | | Correct tool, bad result | Fix the connected endpoint or value mapping | | Wrong behavior despite good evidence | Clarify the system prompt or tool description | | Channel-specific failure | Check the channel link and its supported capabilities | --- # Leads A lead is a conversation the agent came away from with an email address or a phone number. The Leads tab lists them, and every row links back to its transcript. Source: https://www.duvi.ai/docs/leads ## What a lead is A visitor becomes a lead the moment the agent has **an email address or a phone number** for them. Not a name, not an intent, not a long conversation. Until one of those two arrives, the conversation stays a conversation and lives under [Conversations](https://www.duvi.ai/docs/insights). ## How an agent captures details There is no form. The agent captures details because it asked for them in the course of the conversation, so what you get depends on what you told it to do. An agent whose prompt says *if you cannot answer, offer to take a name and email* produces leads. One that does not, will not. Lead capture is therefore a [prompt](https://www.duvi.ai/docs/system-prompt) decision rather than a setting. Put the ask in the Job block, and say when to make it. > **Saved details are not verified identity** > > Duvi saves anything a customer types as context. It is useful for follow-up and it proves nothing: someone can give you any email they like. Before an agent shows anything private, it needs a signed claim from your own server. See [Customer identity](https://www.duvi.ai/docs/identity). ## Give the customer a next step Pick one of these three and write it into the prompt, so a customer the agent cannot help always leaves with a next step. | Give the customer | How you set it up | | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | A promise that someone will come back to them | Ask for a name and email in the Job block of the [prompt](https://www.duvi.ai/docs/system-prompt). The result appears here as a lead, with the transcript attached. | | A ticket already raised on their behalf | Give the agent an [HTTP action](https://www.duvi.ai/docs/reference/actions) that writes to your helpdesk or posts to a team channel, and say in the Tools block when to call it. | | A number to ring, or a page to open | Put your contact details in [Knowledge](https://www.duvi.ai/docs/knowledge), so the agent gives the real one with a source behind it. | > **Say when to hand over, not just what to do** > > An agent told only to *offer a handover if needed* rarely decides that anything is needed. Give it conditions: after two failures in a row, whenever the customer asks for a person, whenever they sound upset. Then test it by being difficult. See [Test the difficult conversations](https://www.duvi.ai/docs/testing#test-the-difficult-conversations). ## The Leads table The **Leads** tab shows one row per person, newest activity first. Duvi shows anything the agent did not capture as a dash rather than leaving it blank, so a partial capture is visible. | Column | What it holds | | ------------- | -------------------------------------------------------------------------------------------------------- | | Name | What they gave. Falls back to the email, then the phone number, then *Unnamed*, so a row is never blank. | | Phone | The number, if one was given. | | Email | The address, if one was given. | | Where | The location they mentioned, if any. | | Channel | Website, Phone or WhatsApp. | | Messages | How many messages the *customer* sent. A proxy for how engaged they were before handing over a contact. | | Last activity | When the conversation was last touched. | | Conversation | Opens the transcript this lead came from. | The list pages as you scroll, twenty rows at a time, so a busy agent does not load thousands of rows to show you the first ten. A lead with a transcript attached is worth more than a form submission, because whoever follows up already knows what the person asked, what they were offered, and where the conversation stopped. ## Send leads to your CRM The Leads tab is a record, not a destination. To put a lead in your CRM at the moment it is captured, give the agent an [HTTP action](https://www.duvi.ai/docs/reference/actions) that writes to your system and tell it in the Tools block when to call it. The agent then creates the record during the conversation rather than leaving you to export a list later. No connector does this for you. The connector catalogue is read-oriented, so a write to your own system goes through an action you define. See [Tools](https://www.duvi.ai/docs/tools). --- # Credits and usage Credits are the unit Duvi bills your account in. This page covers what consumes them, where to review usage, and what happens when the balance runs out. Source: https://www.duvi.ai/docs/credits ## What a credit is Credits are the unit Duvi bills your account in. Every agent on the account draws on the same balance, on every channel, so there is one number to watch rather than one per agent. The cost of a conversation depends on the model, the length of each exchange, and whether it is text or voice. A short answer from a small model costs a fraction of a long exchange with a large one, and voice costs more than text because it adds transcription and speech to the same answer. Studio shows the rate for the model you selected, and your plan sets the terms. > **Length matters more than message count** > > Duvi sends the system prompt again with every exchange, so a price list pasted into the prompt is billed on every turn. Facts belong in [Knowledge](https://www.duvi.ai/docs/knowledge), where retrieval sends only the passages that match a question. ## What consumes credits An agent consumes credits when it handles a conversation, charged to the account that owns the agent rather than to whoever is talking to it. Setting an agent up, changing its configuration, and connecting a channel or a tool consume nothing. Duvi records every charge against the agent and the channel it came from, which is what makes the breakdown in Studio possible. > **Studio is the current position** > > What draws on the balance grows as the platform does. The balance, the recent transactions and the breakdown in Studio are the answer to what something cost, not this page. ## Review usage Billing shows four views over the credit ledger, each covering a time window you select. | View | What it shows | | ------------- | --------------------------------------------------------------------------------- | | Transactions | Every purchase, grant, usage, refund and adjustment, with the balance after each. | | Usage series | Spent, added and event count per hour, day, week or month. | | Usage summary | This window against the one before it, plus burn per day and days remaining. | | Breakdown | The same spend split by agent or by channel. | **Days remaining** divides your current balance by the average daily spend in the selected window. ## Insufficient credits Duvi checks the balance at two points. In both cases it refuses the request rather than returning a lower quality answer. | Check | Result | | ----------------------- | ----------------------------------------------------------------------------------------- | | Starting a conversation | Duvi refuses with an insufficient credits error. The widget does not open a conversation. | | During a conversation | Duvi rejects the next message. A response already streaming completes. | To avoid interruption, keep a buffer or turn on automatic top-up. ## Automatic top-up On Billing, **Top up automatically** buys more credits on your saved card when the balance runs low. It is off until you turn it on. | Setting | What it means | Accepts | | ------------- | ------------------------------------- | ----------------- | | Top up below | The balance that triggers a purchase. | 1 to 5000 credits | | Buy this many | Credits bought each time it fires. | 5 to 5000 credits | > **Set the trigger above a full day of spend** > > A threshold smaller than a busy hour will not save you. Read the burn rate on the usage summary and set the trigger above a full day of it, so a purchase has time to clear before the balance is gone. Duvi records every attempt with its outcome and reason, and emails you when a charge fails rather than failing quietly. Repeated failures stop the attempts instead of retrying forever. The form shows how many failed, and saving again after you fix the card resets the count. --- # Account and sessions Manage how you sign in to Studio, recover access, and control the devices that currently hold an account session. Source: https://www.duvi.ai/docs/account ## Sign in Studio supports email and password sign-in and Google sign-in. Use the same email consistently so your work stays attached to the intended account. ## Verify the email Email registrations require verification, and the agent list stays locked until the email is verified. If the message expires or never arrives, return to the verification screen and resend it. Use the newest message, because an earlier link may no longer be valid. ## Passwords A password must be 8 to 64 characters, contain no spaces, and include an uppercase letter, a lowercase letter, a number and a special character. **Forgot password** sends a reset link, and the reset screen applies the same rules. > **After a reset** > > Review active sessions and revoke any device you no longer recognize. ## Profile Account settings holds your profile details. Changes apply to Studio account surfaces and do not alter an agent’s public name or voice. ## Active sessions Every signed-in device appears with its browser, operating system, IP address, created time, last-used time, and whether it is the current device. Revoke one device without interrupting your current work, or sign out everywhere when credentials may have been exposed. ## Storage Account settings shows the storage consumed by the shared file library. Attaching one file to several agents does not create duplicate stored copies. Deleting the library file is what releases its storage. See [Files](https://www.duvi.ai/docs/files). --- # Website widget The website widget is one script and one custom element. This page lists every attribute it accepts and every behaviour it is responsible for. Source: https://www.duvi.ai/docs/reference/widget ## Install Place the script and the custom element on the pages where the agent should appear. ```html title="HTML" ``` ## The widget on this site Ceronica, the assistant available across this website, is a live Duvi agent delivered through this widget. It is the same public integration shown above. ## Attributes | Attribute | Required | What it does | | ----------- | -------- | -------------------------------------------- | | `agent-id` | Yes | Names the agent that opens the conversation. | | `variables` | No | A JSON object of non-sensitive page context. | > **Chat mode is set on the agent** > > `chat_mode` is configured on the agent, not as a widget attribute. ## Page variables `variables` must be valid JSON whose top level is an object. Names use 1 to 64 letters, digits or underscores. Values may be strings, numbers or booleans, and Duvi drops anything else. Invalid JSON is ignored with a console warning. Changing the attribute reconnects the widget. ```html title="HTML" ``` > **Page variables are public** > > Page variables live in browser markup. Never put secrets, authorization decisions or trusted customer identity in them. ## Conversation threads A visitor can hold several conversation threads. The widget keeps the current thread and lets the visitor return to earlier ones without merging their histories. ## Text and voice The agent response mode can be text, voice or both. Voice also requires a configured transcriber and voice on the agent. The widget does not override those choices locally. ## Ratings The widget can collect a rating on the conversation. Duvi attaches the result to that conversation, where it appears in the conversation browser. ## Frames and style isolation The widget isolates its UI in a shadow root, so host-page styles do not leak into it. It refuses to render inside an iframe unless the frame element carries `data-digiiq-allow-widget`, and it marks itself so screen control ignores the widget’s own interface. --- # HTTP actions An action is an HTTP request an agent may make during a conversation. You define the endpoint once, and the agent decides when calling it would answer the question. Source: https://www.duvi.ai/docs/reference/actions ## Action fields Everything the agent knows about your endpoint is on this form. The description is the important field: it is the only thing the agent reads when deciding whether this action is the right one. **tool\_name — string** Lowercase, no spaces. The agent refers to the action by this name in its own reasoning, so `check_credit_balance` reads better than `tool2`. **description — string** One sentence saying when to use the action, in the language your customers use. This is the biggest single lever on whether the action fires at the right moment. **endpoint\_url — string** An absolute `https` url. Duvi uses it exactly as given. There is no path templating, so values are added as query parameters, headers or a body rather than substituted into the path. **method — enum — Defaults to GET** `GET`, `POST`, `PUT`, `PATCH` or `DELETE`. **headers — value\[]** Sent on every call. Anything sensitive belongs here as a stored key rather than a fixed value, so Duvi never shows the secret again after you save it. **query\_parameters — value\[]** Appended to the url. Same shape as headers. **body\_parameters — value\[]** Sent as JSON. Ignored on `GET`, so a `GET` action carrying body parameters is almost always a mistake. **integration\_id — string** Links the action to an integration that signs the call in as the customer. Set this when the endpoint returns data belonging to one person. See [Call your API as the customer](https://www.duvi.ai/docs/tools#call-your-api-as-the-customer). ## Value sources Every header, query parameter and body field takes its value from one of five places. This setting decides what the agent is allowed to supply. | value\_type | value holds | Filled by | | ----------- | ---------------------------------- | -------------------------------- | | `static` | A literal string | You | | `reference` | One of the type names below | The agent, in conversation | | `secret` | The id of a stored key | Duvi, at call time | | `identity` | No value field at all | Duvi, from the verified customer | | `client` | The name of a widget page variable | Your embedding page | > **Use identity on any field that selects a record** > > If a value decides whose data comes back, it must be `identity`. A `reference` value is whatever the person on the other end says it is, so anyone who guesses a number reads somebody else’s record. Duvi withholds a tool that requires a `client` value when the embedding page did not supply that variable. Page variables are visible to the visitor and provide context, not verified identity. See [Page variables](https://www.duvi.ai/docs/reference/widget#page-variables). Duvi adds one header of its own on every call, `x-chat-id`, carrying the id of the conversation the call came from. Use it to correlate your logs with a chat. ## Reference value types A `reference` value is typed. The agent keeps asking until what it has fits the type, and Duvi never makes the call with a half filled field. `string`, `number`, `boolean`, `date`, `uuid`, `email`, `url`, `array[string]`, `array[number]`, `array[boolean]`, `array[object]`. ```json title="the definition" { "tool_name": "check_credit_balance", "description": "looks up how many credits an account has left", "endpoint_url": "https://api.duvi.ai/v1/credits", "method": "GET", "headers": [ { "key": "Authorization", "value_type": "secret", "value": "6f1c9a2e-..." }, { "key": "X-Customer-Id", "value_type": "identity" } ], "query_parameters": [ { "key": "account_id", "value_type": "reference", "value": "string" } ] } ``` ```json title="what the agent sends" GET /v1/credits?account_id=A-40192 Host: api.duvi.ai Authorization: Bearer X-Customer-Id: X-Chat-Id: 4f2ab8c1-... ``` ## Failure behaviour The agent sees the status and the body. It tells the customer something went wrong rather than inventing a result, so a readable error body produces a better recovery. | Response | What the customer hears | | -------------- | ------------------------------------------------------------------------------------------- | | `2xx` | The answer, phrased in the agent voice. | | `4xx` | That it could not look it up, plus one attempt to correct the input if a field looks wrong. | | `5xx`, timeout | That the system is unavailable, and an offer to take details instead. | | No token | With an integration set, a failed token exchange stops the call before it is made. | --- # Supported file types A Duvi agent answers from text. This page lists every format Duvi extracts text from, the formats that fail silently, and the storage you get. Source: https://www.duvi.ai/docs/reference/file-types ## Supported formats Duvi decides the format from the file type your browser reports, and from the extension when that is missing. | Extension | What Duvi extracts | | --------------- | ----------------------------------------------------------------------------------------------------------- | | `.pdf` | The text layer. Nothing is read from a page that holds only an image of words. | | `.docx` | The document text. Styling, headers and footers are dropped. | | `.html`, `.htm` | Visible body text. Scripts, styles and markup are stripped out. | | `.txt`, `.md` | The file, as written. | | `.json`, `.csv` | The raw text. Duvi does not interpret structure, so a CSV is read as lines rather than as rows and columns. | Duvi reads anything not listed as plain text. That is correct for a text file under an unfamiliar extension and wrong for a compressed format, which the next section covers. ## Formats that index as nothing These files upload and appear in your library. They index as nothing, and the agent then answers as though the file was never added. | File | Why | What to do instead | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | | A scanned PDF | Pictures of words carry no text layer. Open it and try to select a sentence: if nothing highlights, there is nothing to read. | Run it through OCR and upload the result. | | `.xlsx`, `.pptx` | Both are compressed archives, so reading them as text produces nothing usable. | Export to `.csv` or `.pdf` first. | | `.doc`, `.rtf` | Older Word formats. Duvi hands them to the modern Word reader, which usually cannot open them. | Save as `.docx`. | | Images | Duvi does not read a standalone image file. It does describe images found while crawling a website. | Put the picture on a page and add the page as a website source. | | Password-protected files | Duvi cannot open them. | Remove the password and upload again. | > **Confirm a file was read** > > After a file finishes indexing, run a [retrieval trace](https://www.duvi.ai/docs/retrieval-trace) for a phrase you know is inside it. If the passage comes back, Duvi read it. This is the only way to be sure, because a file that extracted nothing looks exactly like a file that extracted fine. ## Storage limits | Limit | Value | | -------------------- | ----------------------------------------------------------- | | Storage per account | 5 GB | | Size of any one file | No separate cap. A single file may use the whole allowance. | | File name | Anything without a `/`. | Duvi counts the allowance once per stored file, not once per agent that uses it, so attaching the same document to six agents costs the space of one. An upload that would take you over the limit is refused when it starts rather than part way through. Removing a file from an agent frees nothing. Deleting it from the library is what returns the space. See [Files](https://www.duvi.ai/docs/files). ## Web pages Duvi reads a website source with a crawler rather than a parser, so different rules apply. The crawler renders each page in a real browser, which captures content drawn by JavaScript, and it describes the images it finds so the agent can show them. | Behaviour | Detail | | -------------------- | ------------------------------------------------------------------------------------------------------------ | | Identifies itself as | `DuviBot` | | Obeys robots.txt | Always, checked before every page. A disallowed path is not read whatever it contains. | | Finds pages via | The sitemaps named in `robots.txt`. With none declared, it starts at the address you gave and follows links. | | Stays within | The address you gave. A bare domain covers the site; an address with a path stays under that path. | See [Crawl a website](https://www.duvi.ai/docs/knowledge#crawl-a-website) for how to point the crawler at a site and narrow what it collects. --- # Answer quality Duvi assesses every conversation after it ends. This is the complete vocabulary: one outcome, one sentiment, a score out of five, and any number of issue codes. Source: https://www.duvi.ai/docs/reference/answer-quality ## Outcomes Exactly one per conversation. The outcome says what the conversation was, not how well it went. | Shown as | What it means | | ------------- | --------------------------------------------------------------------------------------------------------- | | Resolved | The customer got what they came for. | | Unresolved | The customer wanted something the agent could not give them. | | Enquiry taken | The agent could not answer, but captured a way to follow up. See [Leads](https://www.duvi.ai/docs/leads). | | Abandoned | The customer left mid-conversation. | | Off topic | Never about anything the agent is for. Excluded from most quality judgements. | > **Read Unresolved first** > > A resolved conversation tells you the agent worked. An unresolved one tells you what your website does not explain, written by a customer in their own words. ## Issue codes Zero or more per conversation, and independent of the outcome. A conversation can be Resolved and still carry an issue. | Shown as | What it means | Usually fixed by | | ----------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | Made something up | The agent stated something it had no source for. | [Trace the question](https://www.duvi.ai/docs/retrieval-trace). If the material was there, tighten the Boundaries block. | | No answer | The agent could not answer at all. | [Knowledge](https://www.duvi.ai/docs/knowledge), not the prompt. | | Wrong information | The agent answered, and the answer was incorrect. | A stale source outranking a current one. | | Off topic reply | The answer did not address the question. | Retrieval returning near misses. Trace it. | | Repeated itself | The agent said the same thing again instead of moving forward. | A missing next step in the Job block, or a tool it needed and did not have. | | Poor formatting | Hard to read, or hard to listen to. | The Voice block. See [Prompts for voice agents](https://www.duvi.ai/docs/system-prompt#prompts-for-voice-agents). | ## Sentiment One per conversation: **Positive**, **Neutral** or **Negative**. Sentiment describes the customer tone, not the agent performance. Read sentiment against outcome rather than on its own. A negative conversation that ends Resolved is usually someone who arrived annoyed and left sorted. A positive one that ends Unresolved is someone who was polite about not getting an answer. ## Quality score A single number out of five, shown as `4 / 5`. It can be absent, and an absent score means not assessed rather than zero. > **Two different scores out of five** > > The quality score is Duvi’s assessment of the conversation. The **rating** shown as stars elsewhere is the *customer’s* own rating, left through the widget. Both run one to five and they are not the same measurement. Averages by topic and by sentiment are available. A single conversation scoring three tells you little; a topic averaging three across two hundred conversations tells you which part of your knowledge to fix first. For where this is displayed and how to filter it, see [Conversations and insights](https://www.duvi.ai/docs/insights). --- # Glossary One word per idea, and the label Studio puts on screen for it. Where these docs and the product have used two words for one thing, this page is the one that wins. Source: https://www.duvi.ai/docs/glossary ## Agent terms | Term | On screen | What it means | | ------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Agent | Agent | One assistant: its prompt, its knowledge, its tools and the channels it answers on. The unit everything else attaches to. | | System prompt | System prompt, in the **Behaviour** panel on Configure | Standing instructions about how to behave. Sent with every exchange. Not the place for facts. See [System prompt](https://www.duvi.ai/docs/system-prompt). | | First message | First message | What the agent opens with, before the customer has said anything. Older wording called this the greeting. | | Disclaimer | Disclaimer | A standing line shown before the first message, saying replies are generated. Off until you turn it on. | | Chat mode | Text only, Voice only, Text and voice | Which controls the website widget shows. It does not change what the agent knows or can do. | | Appearance | Appearance | The widget’s launcher, color, logo, label and starter prompts. See [Appearance](https://www.duvi.ai/docs/appearance). | | Builder | Builder | The conversation that configures an agent for you. The agent sections remain available for exact edits. | ## Knowledge terms | Term | On screen | What it means | | --------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Knowledge | Knowledge | Everything an agent may answer from. Two kinds: files picked from your library, and websites saved on the agent. | | Source | Files, Websites | One file or one website address you added. | | Index | Index, with a state beside it | The searchable form of your sources. Rebuilt from scratch whenever you save. | | Index state | Pending, Indexing, Ready, Failed | One state for the whole agent, not one per source. See [Indexing states](https://www.duvi.ai/docs/knowledge#indexing-states). | | Passage | A result in a trace | A fragment of a source. Retrieval returns passages rather than whole documents, which is why a long price list costs nothing to keep. | | Retrieval | | Searching the index for the passages that match a question, and sending only those to the model. | | Retrieval trace | The panel on the Knowledge tab | A search you run yourself, showing what retrieval returns and where each passage came from. See [Retrieval trace](https://www.duvi.ai/docs/retrieval-trace). | | Top K | Top K | How many passages a trace asks for. One to twelve, eight by default. | | Grounding | | The rule that an agent may only present something it can point at a source for. | ## Tool terms | Term | On screen | What it means | | ------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | Tool | Tools | Anything the agent can call during a conversation. Covers all three kinds below. | | Action | Action | One HTTP request to an endpoint of yours, shaped field by field. See [HTTP actions](https://www.duvi.ai/docs/reference/actions). | | MCP server | MCP server | A server that publishes its own set of tools. A wider grant than a single action. | | Connector | Integrations | A service Duvi already knows how to talk to, such as Shopify or Stripe. See [Connectors](https://www.duvi.ai/docs/connectors). | | Value source | Ask the customer, Fixed value, From the signed-in customer, From your website, Stored key | Where one field on a tool call gets its value. The setting that decides whether a customer can read another customer’s record. | | Stored key | Stored key | A secret saved once against an agent, referenced by name afterwards and never shown again. | | Page variable | `variables` on the embed element | Context your own page hands the widget. Visible to the visitor, so never proof of anything. | ## Channel and access terms | Term | On screen | What it means | | ----------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Channel | Website, Phone, WhatsApp | How a conversation reaches the agent. | | Widget | Website | The script tag and element you paste on your own pages. See [Website widget](https://www.duvi.ai/docs/reference/widget). | | Agent id | The id in the snippet | Names which agent answers. Public, and not a credential. See [The agent id is public](https://www.duvi.ai/docs/security#the-agent-id-is-public). | | Allowed domains | Allowed domains | The domains permitted to open a conversation. An empty list allows every site. Older wording called these allowed origins. | | Access | Anyone, Only signed-in visitors | Who may open a conversation at all. | | Customer identity | Customer identity | Signed proof from your own server about who the visitor is. The only thing that counts as proof. See [Customer identity](https://www.duvi.ai/docs/identity). | | Saved details | Leads | Whatever the customer typed or said. Useful, and proof of nothing. | > **Saved details are claims, identity is proof** > > Anyone can type any email address; only your server can sign a token. Never show anything private on the strength of a saved detail. ## Conversation terms | Term | On screen | What it means | | ------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Conversation | Conversations | One exchange with one customer, kept in full. | | Lead | Leads | A conversation the agent came away from with an email address or a phone number. See [Leads](https://www.duvi.ai/docs/leads). | | Outcome | Resolved, Unresolved, Enquiry taken, Abandoned, Off topic | What the conversation was. Exactly one per conversation. | | Issue | Made something up, No answer, Wrong information, Off topic reply, Repeated itself, Poor formatting | What went wrong. Any number per conversation, including none. | | Quality score | A number out of five | Duvi’s assessment of the conversation. Not the same as the star rating, which is the customer’s. See [Answer quality](https://www.duvi.ai/docs/reference/answer-quality). | | Credit | Credits | The unit the account is billed in. One balance for every agent and every channel. See [Credits](https://www.duvi.ai/docs/credits). | ---