From ad43a1c38775d16b34321e37444b76f710fa7144 Mon Sep 17 00:00:00 2001 From: Chloe Quijano Date: Wed, 18 Mar 2026 11:01:25 -0400 Subject: [PATCH 1/3] create hitl group, update links and add guide --- docs.json | 13 +- .../manage-your-agent/human-handoff.mdx | 2 +- .../{hitl.mdx => hitl/introduction.mdx} | 10 +- .../hitl/time-to-first-agent-response.mdx | 123 ++++++++++++++++++ studio/concepts/agents/hitl-agent.mdx | 2 +- studio/concepts/nodes/autonomous-node.mdx | 2 +- 6 files changed, 142 insertions(+), 10 deletions(-) rename integrations/integration-guides/{hitl.mdx => hitl/introduction.mdx} (93%) create mode 100644 integrations/integration-guides/hitl/time-to-first-agent-response.mdx diff --git a/docs.json b/docs.json index f5a72d3c..d2382648 100644 --- a/docs.json +++ b/docs.json @@ -296,7 +296,14 @@ "/integrations/integration-guides/plus-google-analytics", "/integrations/integration-guides/googlecalendar", "/integrations/integration-guides/gsheets", - "/integrations/integration-guides/hitl", + { + "group": "HITL", + "icon": "/integrations/integration-guides/assets/icons/hitl.svg", + "pages": [ + "/integrations/integration-guides/hitl/introduction", + "/integrations/integration-guides/hitl/time-to-first-agent-response" + ] + }, "/integrations/integration-guides/hubspot", "/integrations/integration-guides/hunter", "/integrations/integration-guides/improvement", @@ -650,6 +657,10 @@ { "source": "/integrations/functional-integrations/:slug*", "destination": "/integrations/integration-guides/:slug*" + }, + { + "source": "/integrations/integration-guides/hitl", + "destination": "/integrations/integration-guides/hitl/introduction" } ], "integrations": { diff --git a/get-started/manage-your-agent/human-handoff.mdx b/get-started/manage-your-agent/human-handoff.mdx index c870fe89..777e0e23 100644 --- a/get-started/manage-your-agent/human-handoff.mdx +++ b/get-started/manage-your-agent/human-handoff.mdx @@ -9,7 +9,7 @@ If you want to allow a live agent to join your agent's conversations, you can co To get started using Human Handoff, you need to install and configure the official Human-in-the-Loop (HITL) integration: - + Install and configure the official integration Plus diff --git a/integrations/integration-guides/hitl.mdx b/integrations/integration-guides/hitl/introduction.mdx similarity index 93% rename from integrations/integration-guides/hitl.mdx rename to integrations/integration-guides/hitl/introduction.mdx index dab90bf7..e19ddd7d 100644 --- a/integrations/integration-guides/hitl.mdx +++ b/integrations/integration-guides/hitl/introduction.mdx @@ -1,9 +1,7 @@ --- title: Human-in-the-Loop (HITL) -description: >- - Allow a live agent to participate directly in the bot's - conversation. -icon: '/integrations/integration-guides/assets/icons/hitl.svg' +description: Allow a live agent to participate directly in the bot's conversation. +sidebarTitle: Setup --- {/* vale off */} @@ -90,12 +88,12 @@ First, install the official HITL integration: Start HITL Card Start HITL Card diff --git a/integrations/integration-guides/hitl/time-to-first-agent-response.mdx b/integrations/integration-guides/hitl/time-to-first-agent-response.mdx new file mode 100644 index 00000000..f71ea81d --- /dev/null +++ b/integrations/integration-guides/hitl/time-to-first-agent-response.mdx @@ -0,0 +1,123 @@ +--- +title: Measure HITL Response Time +description: Measure the Time to First Agent Response for conversations in HITL. +sidebarTitle: Measure HITL Response Time +--- + +## Prerequisites + + + You will need: + + - A [Botpress Plus plan](https://botpress.com/pricing) or higher + - The [HITL integration and plugin configured](/integrations/integration-guides/hitl/introduction) so agents can join conversations + + +This guide explains how to measure the **Time to First Agent Response** for conversations handed off to a human agent via [Human-in-the-Loop (HITL)](/integrations/integration-guides/hitl/introduction). The metric captures how long a user waited from the moment they requested a human agent to the moment an agent was assigned. + +The result is stored as a formatted string in a conversation variable and can be displayed in a Text card, forwarded to a server, or saved to a Botpress table. + +## 1. Create conversation variables + + + + Create the following two variables in your bot, scoped as **Conversation** variables: + + | Variable Name | Type | Description | + | :---------------------- | :----- | :----------------------------------------------------- | + | `hitlRequestTimestamp` | number | Unix timestamp (ms) of when the HITL request was made | + | `hitlTimingDisplay` | string | Formatted summary string of the timing result | + + In Botpress Studio, go to **Variables** → **+ New Variable**, set the scope to **Conversation**, and configure each entry as described above. + + + +## 2. Capture the request timestamp + +Before your **Start HITL** card, insert an **Execute Code** card that records when the user was handed off to HITL: + + + + Add an **Execute Code** card before the **Start HITL** card and use the following code: + + ```js + conversation.hitlRequestTimestamp = Date.now() + ``` + + This stores the exact moment the user was handed off to HITL, in milliseconds since the Unix epoch. + + + +## 3. Calculate and format the wait time + +After your **Start HITL** card, insert another **Execute Code** card that computes the time until an agent was assigned and formats the result: + + + + Add an **Execute Code** card after the **Start HITL** card and use the following code: + + ```js + const { conversation: upstream } = await client.getConversation({ id: event.conversationId }) + const downstreamConvId = upstream.tags?.['hitl#downstream'] + + if (downstreamConvId) { + const { conversation: downstream } = await client.getConversation({ id: downstreamConvId }) + const assignedAtMs = parseInt(downstream.tags?.['hitl:assignedAt'] || '0') + + if (assignedAtMs) { + const requestTime = new Date(conversation.hitlRequestTimestamp) + const assignedTime = new Date(assignedAtMs) + + const diffMs = assignedAtMs - Number(conversation.hitlRequestTimestamp) + const diffMins = Math.floor(diffMs / 60000) + const diffSecs = Math.floor((diffMs % 60000) / 1000) + + const fmt = (d) => + d.toLocaleTimeString('en-US', { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + hour12: true, + timeZone: 'America/New_York' + }) + + conversation.hitlTimingDisplay = + `HITL Request Time: ${fmt(requestTime)}\n` + + `HITL Assignment Time: ${fmt(assignedTime)}\n` + + `Wait Time: ${diffMins}m ${diffSecs}s` + } + } + ``` + + + - Fetches the upstream conversation using the current conversation ID. + - Resolves the downstream HITL conversation via the `hitl#downstream` tag (set automatically by Botpress when a handoff is initiated). + - Reads the `hitl:assignedAt` tag from the downstream conversation (timestamp of when an agent accepted and assigned). + - Computes the wait time between the request and assignment. + - Formats and stores the result in `conversation.hitlTimingDisplay`. + + + +Once the code runs, `conversation.hitlTimingDisplay` will contain a message in this format: + +``` +HITL Request Time: 8:28:07 PM +HITL Assignment Time: 8:28:31 PM +Wait Time: 0m 24s +``` + + + Times are displayed in the America/New_York timezone. Update the `timeZone` value in the `fmt` function if your team operates in a different timezone. + + +## 4. Use the data + +The `conversation.hitlTimingDisplay` variable is available for the rest of your flow. You can: + +- **Display it in chat**: Add a **Text** card and reference `{{conversation.hitlTimingDisplay}}` to send the summary to the conversation (useful for testing and QA). +- **Log it to a Botpress Table**: Use an **Update Table Row** or **Insert Table Row** card to persist the data for reporting. +- **Send it to an external system**: Use an **Execute Code** card with an `axios` or `fetch` call to forward the values to your analytics platform, CRM, or data warehouse. + + + You can now measure Time to First Agent Response for HITL conversations and use the result in your bot flow, tables, or external systems. + diff --git a/studio/concepts/agents/hitl-agent.mdx b/studio/concepts/agents/hitl-agent.mdx index 77dc865d..b183ffde 100644 --- a/studio/concepts/agents/hitl-agent.mdx +++ b/studio/concepts/agents/hitl-agent.mdx @@ -4,7 +4,7 @@ description: Allows human intervention in the bot's conversations and decision-m --- - The Human-in-the-loop (HITL) Agent is **deprecated** and is no longer available to new accounts. Please use the [HITL Plugin](/integrations/integration-guides/hitl) instead. + The Human-in-the-loop (HITL) Agent is **deprecated** and is no longer available to new accounts. Please use the [HITL Plugin](/integrations/integration-guides/hitl/introduction) instead. If you have a HITL Agent enabled, it will remain available for the time being. However, if you disable the Agent, you won't be able to restore it. diff --git a/studio/concepts/nodes/autonomous-node.mdx b/studio/concepts/nodes/autonomous-node.mdx index 829943b9..aea470d3 100644 --- a/studio/concepts/nodes/autonomous-node.mdx +++ b/studio/concepts/nodes/autonomous-node.mdx @@ -206,7 +206,7 @@ You can view a full list of tools your bot currently has access to in the [Inspe - This prompt tells the Autonomous Node to start a [Human-in-the-loop (HITL)](/integrations/integration-guides/hitl) session when the user indicates they'd like to speak to a live agent: + This prompt tells the Autonomous Node to start a [Human-in-the-loop (HITL)](/integrations/integration-guides/hitl/introduction) session when the user indicates they'd like to speak to a live agent: ```markdown Instructions wrap When the user indicates they'd like to speak to a live agent, use `hitl.startHitl`. From bc3aec92c2f0cda19088107eeab122a54c1e6f71 Mon Sep 17 00:00:00 2001 From: Chloe Quijano Date: Wed, 18 Mar 2026 11:07:07 -0400 Subject: [PATCH 2/3] nit: grammar --- .../integration-guides/hitl/time-to-first-agent-response.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/integration-guides/hitl/time-to-first-agent-response.mdx b/integrations/integration-guides/hitl/time-to-first-agent-response.mdx index f71ea81d..456b14cd 100644 --- a/integrations/integration-guides/hitl/time-to-first-agent-response.mdx +++ b/integrations/integration-guides/hitl/time-to-first-agent-response.mdx @@ -112,7 +112,7 @@ Wait Time: 0m 24s ## 4. Use the data -The `conversation.hitlTimingDisplay` variable is available for the rest of your flow. You can: +The `conversation.hitlTimingDisplay` variable is available for the rest of your Workflow. You can: - **Display it in chat**: Add a **Text** card and reference `{{conversation.hitlTimingDisplay}}` to send the summary to the conversation (useful for testing and QA). - **Log it to a Botpress Table**: Use an **Update Table Row** or **Insert Table Row** card to persist the data for reporting. From 329f2e360bbcbd3e3df0da8bf28599eea437e3e9 Mon Sep 17 00:00:00 2001 From: Chloe Quijano Date: Wed, 18 Mar 2026 14:16:50 -0400 Subject: [PATCH 3/3] update based on comments, fix formatting --- .../hitl/time-to-first-agent-response.mdx | 133 ++++++++---------- 1 file changed, 61 insertions(+), 72 deletions(-) diff --git a/integrations/integration-guides/hitl/time-to-first-agent-response.mdx b/integrations/integration-guides/hitl/time-to-first-agent-response.mdx index 456b14cd..022708e0 100644 --- a/integrations/integration-guides/hitl/time-to-first-agent-response.mdx +++ b/integrations/integration-guides/hitl/time-to-first-agent-response.mdx @@ -15,88 +15,77 @@ sidebarTitle: Measure HITL Response Time This guide explains how to measure the **Time to First Agent Response** for conversations handed off to a human agent via [Human-in-the-Loop (HITL)](/integrations/integration-guides/hitl/introduction). The metric captures how long a user waited from the moment they requested a human agent to the moment an agent was assigned. -The result is stored as a formatted string in a conversation variable and can be displayed in a Text card, forwarded to a server, or saved to a Botpress table. +The result is stored as a formatted string in a conversation variable and can be sent using a [Text Card](/studio/concepts/cards/send-messages#text), [sent to an external system](/studio/concepts/cards/execute-code), or [saved to a Botpress table](/studio/concepts/cards/tables#insert-record). ## 1. Create conversation variables - - - Create the following two variables in your bot, scoped as **Conversation** variables: +Create the following two variables in your bot, scoped as **Conversation** variables: - | Variable Name | Type | Description | - | :---------------------- | :----- | :----------------------------------------------------- | - | `hitlRequestTimestamp` | number | Unix timestamp (ms) of when the HITL request was made | - | `hitlTimingDisplay` | string | Formatted summary string of the timing result | +| Variable Name | Type | Description | +| :---------------------- | :----- | :----------------------------------------------------- | +| `hitlRequestTimestamp` | number | Unix timestamp (ms) of when the HITL request was made | +| `hitlTimingDisplay` | string | Formatted summary string of the timing result | - In Botpress Studio, go to **Variables** → **+ New Variable**, set the scope to **Conversation**, and configure each entry as described above. - - +In Botpress Studio, go to **Variables** → **+ New Variable**, set the scope to **Conversation**, and configure each entry as described above. ## 2. Capture the request timestamp -Before your **Start HITL** card, insert an **Execute Code** card that records when the user was handed off to HITL: +Before your [Start HITL](/integrations/integration-guides/hitl/introduction#step-3-add-the-start-hitl-card-to-your-workflow) Card, insert an [Execute Code](/studio/concepts/cards/execute-code) Card that records when the user was handed off to HITL. Use the following code: - - - Add an **Execute Code** card before the **Start HITL** card and use the following code: +```js +conversation.hitlRequestTimestamp = Date.now() +``` - ```js - conversation.hitlRequestTimestamp = Date.now() - ``` +This stores the exact moment the user was handed off to HITL, in milliseconds since the [Unix Epoch](https://en.wikipedia.org/wiki/Unix_time). - This stores the exact moment the user was handed off to HITL, in milliseconds since the Unix epoch. - - + + The **Unix Epoch** is January 1, 1970 at 00:00:00 UTC. Timestamps in "milliseconds since the Unix epoch" are the number of milliseconds elapsed since that moment. + ## 3. Calculate and format the wait time -After your **Start HITL** card, insert another **Execute Code** card that computes the time until an agent was assigned and formats the result: - - - - Add an **Execute Code** card after the **Start HITL** card and use the following code: - - ```js - const { conversation: upstream } = await client.getConversation({ id: event.conversationId }) - const downstreamConvId = upstream.tags?.['hitl#downstream'] - - if (downstreamConvId) { - const { conversation: downstream } = await client.getConversation({ id: downstreamConvId }) - const assignedAtMs = parseInt(downstream.tags?.['hitl:assignedAt'] || '0') - - if (assignedAtMs) { - const requestTime = new Date(conversation.hitlRequestTimestamp) - const assignedTime = new Date(assignedAtMs) - - const diffMs = assignedAtMs - Number(conversation.hitlRequestTimestamp) - const diffMins = Math.floor(diffMs / 60000) - const diffSecs = Math.floor((diffMs % 60000) / 1000) - - const fmt = (d) => - d.toLocaleTimeString('en-US', { - hour: '2-digit', - minute: '2-digit', - second: '2-digit', - hour12: true, - timeZone: 'America/New_York' - }) - - conversation.hitlTimingDisplay = - `HITL Request Time: ${fmt(requestTime)}\n` + - `HITL Assignment Time: ${fmt(assignedTime)}\n` + - `Wait Time: ${diffMins}m ${diffSecs}s` - } - } - ``` - - - - Fetches the upstream conversation using the current conversation ID. - - Resolves the downstream HITL conversation via the `hitl#downstream` tag (set automatically by Botpress when a handoff is initiated). - - Reads the `hitl:assignedAt` tag from the downstream conversation (timestamp of when an agent accepted and assigned). - - Computes the wait time between the request and assignment. - - Formats and stores the result in `conversation.hitlTimingDisplay`. - - +After your [Start HITL](/integrations/integration-guides/hitl/introduction#step-3-add-the-start-hitl-card-to-your-workflow) Card, insert another [Execute Code](/studio/concepts/cards/execute-code) Card that computes the time until an agent was assigned and formats the result. Use the following code: + +```js +const { conversation: upstream } = await client.getConversation({ id: event.conversationId }) +const downstreamConvId = upstream.tags?.['hitl#downstream'] + +if (downstreamConvId) { + const { conversation: downstream } = await client.getConversation({ id: downstreamConvId }) + const assignedAtMs = parseInt(downstream.tags?.['hitl:assignedAt'] || '0') + + if (assignedAtMs) { + const requestTime = new Date(conversation.hitlRequestTimestamp) + const assignedTime = new Date(assignedAtMs) + + const diffMs = assignedAtMs - Number(conversation.hitlRequestTimestamp) + const diffMins = Math.floor(diffMs / 60000) + const diffSecs = Math.floor((diffMs % 60000) / 1000) + + const fmt = (d) => + d.toLocaleTimeString('en-US', { + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + hour12: true, + timeZone: 'America/New_York' + }) + + conversation.hitlTimingDisplay = + `HITL Request Time: ${fmt(requestTime)}\n` + + `HITL Assignment Time: ${fmt(assignedTime)}\n` + + `Wait Time: ${diffMins}m ${diffSecs}s` + } +} +``` + +What this code does: + +- Fetches the upstream conversation using the current conversation ID. +- Resolves the downstream HITL conversation via the `hitl#downstream` tag (set automatically by Botpress when a handoff is initiated). +- Reads the `hitl:assignedAt` tag from the downstream conversation (timestamp of when an agent accepted and assigned). +- Computes the wait time between the request and assignment. +- Formats and stores the result in `conversation.hitlTimingDisplay`. Once the code runs, `conversation.hitlTimingDisplay` will contain a message in this format: @@ -114,10 +103,10 @@ Wait Time: 0m 24s The `conversation.hitlTimingDisplay` variable is available for the rest of your Workflow. You can: -- **Display it in chat**: Add a **Text** card and reference `{{conversation.hitlTimingDisplay}}` to send the summary to the conversation (useful for testing and QA). -- **Log it to a Botpress Table**: Use an **Update Table Row** or **Insert Table Row** card to persist the data for reporting. -- **Send it to an external system**: Use an **Execute Code** card with an `axios` or `fetch` call to forward the values to your analytics platform, CRM, or data warehouse. +- **Display it in chat**: Add a [Text](/studio/concepts/cards/send-messages#text) Card and reference `{{conversation.hitlTimingDisplay}}` to send the summary to the conversation (useful for testing and QA). +- **Log it to a Botpress Table**: Use an [Update Table Row](/studio/concepts/cards/tables#update-record) or [Insert Table Row](/studio/concepts/cards/tables#insert-record) Card to persist the data for reporting. +- **Send it to an external system**: Use an [Execute Code](/studio/concepts/cards/execute-code) Card with an `axios` or `fetch` call to forward the values to your analytics platform, CRM, or data warehouse. - You can now measure Time to First Agent Response for HITL conversations and use the result in your bot flow, tables, or external systems. + You can now measure Time to First Agent Response for HITL conversations and use the result in your bot Workflows, tables, or external systems.