> ## Documentation Index
> Fetch the complete documentation index at: https://botpress-charmenta-pr-705.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Implementing Human in the loop (HITL) in an integration

export const DefinitionReference = ({id, children, plural: isPlural, capitalize}) => {
  if (!globalThis.definitions.has(id)) {
    throw new Error(`Definition with id "${id}" not found. Please ensure it's defined in the DefinitionList component.`);
  }
  const {term, plural, definition} = globalThis.definitions.get(id);
  const capitalizeFirstLetter = str => str.charAt(0).toUpperCase() + str.slice(1);
  const text = isPlural ? plural : term;
  return <a href={`#dfn-${id}`} aria-describedby={`dfn-${id}`} style={{
    textDecoration: 'underline dotted',
    color: 'currentColor',
    fontWeight: 'inherit',
    borderBottom: 'none'
  }} title={definition}>
      {children || (capitalize ? capitalizeFirstLetter(text) : text)}
    </a>;
};

export const Definition = ({term, id, children: definition, plural}) => {
  const capitalizeFirstLetter = str => str.charAt(0).toUpperCase() + str.slice(1);
  const getTextContent = elem => !elem ? '' : typeof elem === 'string' ? elem : Array.isArray(elem.props?.children) ? elem.props.children.map(getTextContent).join('') : getTextContent(elem.props?.children);
  globalThis.definitions.set(id, {
    term,
    plural: plural || `${term}s`,
    definition: getTextContent(definition)
  });
  return <>
      <dt><dfn id={`dfn-${id}`}>{capitalizeFirstLetter(term)}</dfn></dt>
      <dd>{definition}</dd>
    </>;
};

export const DefinitionList = ({children}) => {
  globalThis.definitions = new Map();
  return <dl>
      {children}
    </dl>;
};

export const CurrentInterfaceVersion = ({interfaceName, fallback}) => {
  const getCurrentVersion = async () => {
    const definitionUrl = `https://raw.githubusercontent.com/botpress/botpress/refs/heads/master/interfaces/${interfaceName}/interface.definition.ts`;
    try {
      const response = await fetch(definitionUrl);
      if (!response.ok) {
        throw new Error(`Failed to fetch interface definition: ${response.statusText}`);
      }
      const text = await response.text();
      const versionMatch = text.match(/  version: '([^']+)',/);
      if (versionMatch) {
        return versionMatch[1];
      } else {
        throw new Error('Version not found in interface definition');
      }
    } catch (error) {
      console.error(error);
    }
    return fallback ?? 'unknown';
  };
  if (typeof document === "undefined") {
    return null;
  }
  const componentClassName = `iface-version-${interfaceName}`;
  requestIdleCallback(() => getCurrentVersion().then(version => {
    Array.from(document.getElementsByClassName(componentClassName)).forEach(component => {
      component.innerHTML = version;
    });
  }));
  return <span class={componentClassName}>{fallback ?? 'loading...'}</span>;
};

export const HitlIcon = ({width, style, ...rest} = {
  width: 'initial',
  style: {}
}) => <svg xmlns="http://www.w3.org/2000/svg" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" image-rendering="optimizeQuality" fill-rule="evenodd" clip-rule="evenodd" viewBox="0 0 300 299" {...rest} width={width} style={style} preserveAspectRatio="true"><circle cx="147" cy="130" r="120" fill="#f9ded3" /><path fill="#1b1e2f" d="M73.5 67.5c1.8 1.3 3.5 2.8 5 4.5a25.5 25.5 0 0 0-4 4.5c-4.9-2.6-5.2-5.6-1-9Z" /><path fill="#f9f8f7" d="M185.5 78.5v7a39.9 39.9 0 0 1-26 19.5 24.7 24.7 0 0 0-4 4.5c-5.8-5-12-5.3-18.5-1-4.2 6.7-2.7 11.9 4.5 15.5a14 14 0 0 0 14-3.5c12.4.9 22.3-3.8 29.5-14 .5.6.6 1.3.5 2a22 22 0 0 1-16 18.5 60.6 60.6 0 0 1-10 3.5c-19.2 4.7-36 .3-50.5-13-3-5.3-4.2-11-3.5-17a129 129 0 0 0 6.5-19c.8-.6 1.6-1.1 2.5-1.5 20.8-.2 40.1-5.4 58-15.5a64 64 0 0 0 13 14Z" /><path fill="#23232f" d="M221.5 82.5h4c.3 1.8-.4 3.2-2 4-1.6-.8-2.3-2.2-2-4Z" /><path fill="#262124" d="M62.5 91.5c1.8-.3 3.5 0 5 1l-2.5 1c-1.4-.2-2.2-.9-2.5-2Z" /><path fill="#e9c9b7" d="M185.5 85.5a23 23 0 0 1-8 17.5 32 32 0 0 1-21 8c-.6-.4-.9-.9-1-1.5a24 24 0 0 1 4-4.5 40 40 0 0 0 26-19.5Z" /><path fill="#21212f" d="M212.5 102.5c4-.3 8 0 12 1l-6 1c-2.5 0-4.5-.7-6-2Z" /><path fill="#1d1b25" d="M73.5 107.5c3-.3 4.3 1 4 4-4 .7-5.3-.6-4-4Z" /><path fill="#f08d77" d="M108.5 109.5a8.5 8.5 0 0 1 0-8 5 5 0 0 0 5-2.5c5.5-1.2 8.5 1 9 6.5-1.7 5.5-5.4 7.4-11 5.5-.7-1-1.7-1.5-3-1.5Z" /><path fill="#e09785" d="M108.5 109.5c1.3 0 2.3.5 3 1.5 5.6 1.9 9.3 0 11-5.5-.5-5.6-3.5-7.7-9-6.5a4.9 4.9 0 0 1-5 2.5c1.9-4.4 5.2-6 10-4.5 8.1 6 7.8 11.7-1 17-4.2 1-7.2-.5-9-4.5Z" /><path fill="#1e1822" d="M237.5 110.5c1.3 1.2 2 2.9 2 5l-1 5a26 26 0 0 1-1-10Z" /><path fill="#2c2426" d="M221.5 116.5c1.8-.3 3.2.4 4 2-.8 1.6-2.2 2.3-4 2v-4Z" /><path fill="#12111b" d="M75.5 127.5c3.7-.3 7.4 0 11 1l-5.5 1a8 8 0 0 1-5.5-2Z" /><path fill="#181b2a" d="M57.5 122.5c5.9 2.7 6.2 5.7 1 9-4.9-2.6-5.2-5.6-1-9Z" /><path fill="#403b43" d="M54.5 103.5c1.3 1 2 2.5 2 4.5l-1 4.5c-1-3-1.3-6-1-9Z" /><path fill="#0f1528" d="M235.5 130.5c6 2 6.4 4.7 1 8a35.6 35.6 0 0 1-4-4.5c1.2-1 2.2-2.2 3-3.5Z" /><path fill="#20172b" d="M209.5 132.5c3.7-.3 7.4 0 11 1l-5.5 1a8 8 0 0 1-5.5-2Z" /><path fill="#4f474a" d="M68.5 141.5h3v9h-3v-9Z" /><path fill="#7db6c0" d="M166.5 134.5c2.4 1 4.1 2.8 5 5.5-1 1.4-1.6 3-2 4.5a74.9 74.9 0 0 0-6.5 10 81 81 0 0 1-8.5-7 28 28 0 0 0 12-13Z" /><path fill="#1d1a20" d="M219.5 142.5c1.2.8 2 2.2 2 4l-1 4c-1-2.6-1.3-5.3-1-8Z" /><path fill="#c9d2d7" d="m175.5 143.5 21 8.5c3.4 1.4 6.4 3.2 9 5.5a720 720 0 0 1-32-9c1-1.6 1.6-3.2 2-5Z" /><path fill="#f9f8f6" d="M173.5 148.5a720 720 0 0 0 32 9c2 2.1 3.8 4.5 5.5 7l17 51c1 5.7.1 11-2.5 16a21.4 21.4 0 0 1-10 3c-10.3.7-14-4-11-14 5.5 0 7.3-2.7 5.5-8l-11.5-27c-2.4-1.6-4.4-1.2-6 1l-2 19.5c-9.5 7-20.2 9.5-32 7.5-1.8-13.5-3-27.1-4-41-.5-3.8.5-7.1 3-10 3.8 2.8 7.3 2.5 10.5-1l2.5-7 3-6Z" /><path fill="#bcc6cb" d="m170.5 154.5-2.5 7c-3.2 3.5-6.7 3.8-10.5 1a12.3 12.3 0 0 0-3 10 31 31 0 0 1 .5-17c2.7 2.2 5.6 4.2 8.5 6l2-.5c1.6-2.3 3.2-4.5 5-6.5Z" /><path fill="#cdd5db" d="m198.5 185.5 11.5 27c1.8 5.3 0 8-5.5 8v-1c-1.3-4-3.1-7.6-5.5-11a265 265 0 0 1-.5-23Z" /><path fill="#09162c" d="M189.5 37.5a40 40 0 0 1 6 33c1-.1 2 0 3 .5a18.6 18.6 0 0 1 5.5 19.5c-.7 7.2-4.5 11.2-11.5 12a30.5 30.5 0 0 1-19 29 25 25 0 0 0 5 6.5l25 11a26 26 0 0 1 9.5 7.5c7.4 18 13.9 36.4 19.5 55a55 55 0 0 1 2.5 10c2.3 1.3 4.3 3 6 5 3 7.6.8 13-6.5 16a48 48 0 0 0-10 .5 727 727 0 0 0-35 28c-2.7.7-5.3.7-8 0a7 7 0 0 1-2-2.5c-3.2-1.6-4.5-4.2-4-8h-3v-5h3l3 4c1.3 2.4 3 4.6 5 6.5 1.6.7 3 .4 4-1-2.2-3-4.6-5.8-7-8.5a1124 1124 0 0 0-5-8 7.4 7.4 0 0 1 0-4.5c-1.3-1.6-2.7-1.5-4 .5l-1-2.5a28 28 0 0 0 2-5.5 72 72 0 0 0 9-7c2.2-.8 3.2-2.5 3-5 2.4.2 4.8-.1 7-1 .8.3 1.5.8 2 1.5a24.5 24.5 0 0 1-9 5.5l-6 9c-.4.7-1 1.2-2 1.5 3.6 5 7.2 9.8 11 14.5 1.2 2.1 2.7 4.1 4.5 6l29.5-23.5a9.7 9.7 0 0 0 4-6.5c2.6-5 3.4-10.3 2.5-16l-17-51a59.4 59.4 0 0 0-5.5-7 30.4 30.4 0 0 0-9-5.5l-21-8.5a12 12 0 0 0-6 1c.4-1.6 1-3 2-4.5a8.5 8.5 0 0 0-5-5.5l-2-1c-2.5 3-5.5 3.6-9 2-1-.5-1.2-1.2-.5-2 1.4-1.3 3-2.3 4.5-3 3.4-.9 6.7-2 10-3.5a22 22 0 0 0 16-18.5c1.3-1.9 1.3-3.9 0-6a48.5 48.5 0 0 1-29 16l-1 2a14 14 0 0 1-14 3.5c-7.2-3.6-8.7-8.8-4.5-15.5 6.5-4.3 12.7-4 18.5 1 .1.6.4 1.1 1 1.5 8-.1 15-2.8 21-8a23 23 0 0 0 8-17.5v-7c.2-1.4 0-2.7-.5-4a41.7 41.7 0 0 1-12.5-17 86.2 86.2 0 0 1-39 15.5c-9.3 1.5-18.6 2.3-28 2.5-.8 9.5-1.3 19.2-1.5 29a12.9 12.9 0 0 0-9.5-4.5l-2-2c1.5-.1 3 0 4.5.5 1.7 0 3-.6 4-2-.8-7.7-.7-15.3.5-23a6 6 0 0 0-5 2c-4.5 3-6.1 7.4-5 13 0 1.3-.5 2.3-1.5 3-2.8-4.4-3.1-9-1-14l1-3c2.4-1.1 4.2-2.8 5.5-5-1-9 .7-17.2 5-25a47.8 47.8 0 0 1 32-23.5 48 48 0 0 1 41 11.5c6 .1 11.2 1.8 16 5Z" /><path fill="#d2b0aa" d="M142.5 110.5c2.8-.3 5.5.2 8 1.5 1.6 6.7-1 9-8 7-2.6-2.8-2.6-5.7 0-8.5Z" /><path fill="#eda386" d="M143.5 112.5a7 7 0 0 1 7 2.5c-.4 1-1 1.6-2 2-2 .5-4 .7-6 .5-.1-1.8.2-3.5 1-5Z" /><path fill="#e1c2b4" d="M185.5 108.5c.1-.7 0-1.4-.5-2a31.4 31.4 0 0 1-29.5 14l1-2c11.6-2 21.3-7.3 29-16 1.3 2.1 1.3 4.1 0 6Z" /><path fill="#111b2f" d="M159.5 85.5c4.4-.2 6.1 2 5 6.5 1.2 5.3-.8 7.4-6 6.5-.3-4.4 0-8.8 1-13Z" /><path fill="#121d32" d="M126.5 85.5c4.4-.2 6.1 2 5 6.5 1.2 5.3-.8 7.4-6 6.5-.3-4.4 0-8.8 1-13Z" /><path fill="#becbd1" d="M195.5 76.5c1.3.6 2.1 1.6 2.5 3a23 23 0 0 1-2.5 16.5 5 5 0 0 1-3 .5v-20h3Z" /><path fill="#47596c" d="M195.5 76.5h-3v20a112 112 0 0 1-1-21c1.6-.3 3 0 4 1Z" /><path fill="#e8cdc0" d="M185.5 78.5a64 64 0 0 1-13-14 118.3 118.3 0 0 1-58 15.5c-1 .4-1.8.9-2.5 1.5-1.8 6.8-4 13-6.5 19v-25c9.4-.2 18.7-1 28-2.5 14.4-2 27.4-7.2 39-15.5a41.7 41.7 0 0 0 12.5 17c.5 1.3.7 2.6.5 4Z" /><path fill="#beccd1" d="M189.5 51.5c1.4 6 1 12-1 18a39.4 39.4 0 0 1-11.5-17c-1-1.2-2.2-2.2-3.5-3 1.7-4 4.3-4.8 8-2.5 3.1 3.8 5.6 8 7.5 12.5.5-2.6.7-5.3.5-8Z" /><path fill="#c5d0d6" d="M160.5 30.5a43.6 43.6 0 0 0-43.5 18c-2.7 5.4-4.6 11-5.5 17 19.1.5 35.6-5.8 49.5-19 .7 1 .7 2 0 3-3.7 6-8.5 10.6-14.5 14a133.2 133.2 0 0 1-45 6c-.7-21.1 9-35.3 29-42.5a41.7 41.7 0 0 1 30 3.5Z" /><path fill="#f8f9fa" d="M160.5 30.5c4.4 1.9 8 4.7 11 8.5 10.5-2.4 16.5 1.8 18 12.5.2 2.7 0 5.4-.5 8a47.3 47.3 0 0 0-7.5-12.5c-3.7-2.3-6.3-1.4-8 2.5a102 102 0 0 0-10 7.5 48 48 0 0 1-17 6.5c6-3.4 10.8-8 14.5-14 .7-1 .7-2 0-3a66.6 66.6 0 0 1-49.5 19c1-6 2.8-11.6 5.5-17a43.6 43.6 0 0 1 43.5-18Z" /><path fill="#7d7c7b" d="M204.5 219.5v1c-3 10 .7 14.7 11 14 0 1-.2 1.8-1 2.5l-24 14a11.1 11.1 0 0 0-3 4.5c-3.8-4.7-7.4-9.5-11-14.5 1-.3 1.6-.8 2-1.5 8-6 15.7-12.5 23-19.5 1-.5 2-.6 3-.5Z" /><path fill="#c8d3dc" d="M232.5 227.5c3.6 1 4.8 3.3 3.5 7a5.8 5.8 0 0 1-5.5 2c1-3 1.6-6 2-9Z" /><path fill="#94a0a9" d="M60.5 242.5h101v5c-2 .3-3.6 0-5-1h4v-3c-32.8-.3-65.5 0-98 1a3 3 0 0 1-2-2Z" /><path fill="#cdd7dd" d="M62.5 244.5c32.5-1 65.2-1.3 98-1v3h-4c-2.7-.2-5.4 0-8 .5a63.7 63.7 0 0 1-7 6.5c-15-.2-30-1-45-2.5-11.6-1-23-3-34-6.5Z" /><path fill="#5f6567" d="M161.5 242.5c5-.9 6 .4 3 4a3 3 0 0 1-3 1v-5Z" /><path fill="#08162a" d="M95.5 69.5a12.4 12.4 0 0 1-5.5 5l-1 3c-2.1 5-1.8 9.6 1 14 1-.7 1.5-1.7 1.5-3l2.5 6a5.8 5.8 0 0 0 5.5 2v-21h-3a6 6 0 0 1 5-2 88.9 88.9 0 0 0-.5 23c-1 1.4-2.3 2-4 2-1.5-.5-3-.6-4.5-.5l2 2c3.8.1 7 1.6 9.5 4.5.2-9.8.7-19.5 1.5-29v25c-.7 6 .5 11.7 3.5 17a52.2 52.2 0 0 0 50.5 13c-1.6.7-3 1.7-4.5 3-.7.8-.5 1.5.5 2 3.5 1.6 6.5 1 9-2l2 1a28 28 0 0 1-12 13 81 81 0 0 0 8.5 7c2-3.6 4.1-6.9 6.5-10a12 12 0 0 1 6-1c-.4 1.8-1 3.4-2 5l-3 6c-1.8 2-3.4 4.2-5 6.5l-2 .5c-3-1.8-5.8-3.8-8.5-6a31 31 0 0 0-.5 17c1 13.9 2.2 27.5 4 41v8h34v-35c1.6-2.2 3.6-2.6 6-1-.2 7.7 0 15.3.5 23 2.4 3.4 4.2 7 5.5 11-1-.1-2 0-3 .5-7.3 7-15 13.5-23 19.5l6-9c3.3-1.1 6.3-3 9-5.5a4.5 4.5 0 0 0-2-1.5c-2.2.9-4.6 1.2-7 1 .2 2.5-.8 4.2-3 5 .1-.6.4-1.1 1-1.5-41-.7-82-.7-123 0-4 2.7-4 5.3 0 8 37.7.5 75.3.7 113 .5a28 28 0 0 1-2 5.5l1 2.5c1.3-2 2.7-2.1 4-.5a7.4 7.4 0 0 0 0 4.5 9 9 0 0 1-3-3 3 3 0 0 0-2 2l5 8h-3v5h3c-.5 3.8.8 6.4 4 8a421 421 0 0 0-20 15.5c-4.8.6-9.1-.6-13-3.5a29.7 29.7 0 0 0-7-3.5 9.5 9.5 0 0 1-1.5-2.5c-.7-5.3-1-10.7-1-16a17 17 0 0 1 4.5-5c2.5-2 4.8-4.1 7-6.5 2.6-.5 5.3-.7 8-.5 1.4 1 3 1.3 5 1a3 3 0 0 0 3-1c3-3.6 2-4.9-3-4h-101a9.5 9.5 0 0 1-7.5-4c-3.5-7.8-1.5-13.4 6-17 .5-3 .7-6 .5-9 5.8-15.8 11.3-31.8 16.5-48a28 28 0 0 1 9.5-13.5l29-13.5a19 19 0 0 1 3.5-4c.7-1.1.6-2.1-.5-3a37 37 0 0 1-17-15c-.7-4.3-1-8.6-1-13-3.4.4-6.4-.4-9-2.5-4.2-7.8-5-16-2.5-24.5a10 10 0 0 1 7.5-6Z" /><path fill="#7c7b79" d="M181.5 229.5a72 72 0 0 1-9 7c-37.7.2-75.3 0-113-.5-4-2.7-4-5.3 0-8 41-.7 82-.7 123 0-.6.4-.9.9-1 1.5Z" /><path fill="#cbd7dd" d="M95.5 188.5c1.6 11.4-.4 22-6 32-7.3 1-14.6 1.3-22 1 5.5-4 11.3-7.7 17.5-11 3.2-7.5 6.7-14.9 10.5-22Z" /><path fill="#cdd7db" d="M192.5 186.5v35h-34v-8c11.8 2 22.5-.5 32-7.5l2-19.5Z" /><path fill="#cbd7dc" d="M101.5 205.5c3.7 3.5 8 6 13 7.5 6.7.5 13.3.7 20 .5v8h-33v-16Z" /><path fill="#131e30" d="M165.5 188.5c5.7-.2 11.3 0 17 .5 1.3 1.7 1.3 3.3 0 5a69 69 0 0 1-17 0 4.5 4.5 0 0 1 0-5.5Z" /><path fill="#7db5bd" d="M144.5 164.5h3c2.1 19 3.8 38 5 57h-12c.9-19 2.2-38 4-57Z" /><path fill="#bfc8ce" d="M136.5 190.5c-.2-6.5.1-13 1-19.5-.3-2.5-.8-5-1.5-7.5-1.9-1.2-3.4-.7-4.5 1.5-4-.2-6.4-2.4-7-6.5a15 15 0 0 0 4 3 41 41 0 0 0 8.5-6l2 4c.3 10.6-.5 20.9-2.5 31Z" /><path fill="#f6f5f2" d="M119.5 149.5a57 57 0 0 1 5 9c.6 4.1 3 6.3 7 6.5 1.1-2.2 2.6-2.7 4.5-1.5.7 2.5 1.2 5 1.5 7.5-.9 6.5-1.2 13-1 19.5-.2 7.7-.9 15.4-2 23-6.7.2-13.3 0-20-.5a32 32 0 0 1-13-7.5c.2-6.7 0-13.3-.5-20-3.5-1.8-5.3-.8-5.5 3-3.8 7.1-7.3 14.5-10.5 22-6.2 3.3-12 7-17.5 11-1.3-1-2-2.5-2-4.5 5.3-17.5 10.8-35 16.5-52.5 1.3-2.2 2.8-4.2 4.5-6 7.1-.9 13.8-3 20-6.5 4.5-1.3 8.8-2.1 13-2.5Z" /><path fill="#76acb4" d="M145.5 148.5c4.7 2.8 4.9 6.2.5 10-3.9-3.4-4-6.7-.5-10Z" /><path fill="#cad1d7" d="M119.5 149.5c-4.2.4-8.5 1.2-13 2.5a54.3 54.3 0 0 1-20 6.5 7 7 0 0 1 2-2.5l27-12.5c1.8 1.6 3.2 3.6 4 6Z" /><path fill="#7eb3bd" d="M123.5 134.5c4 5 8.6 9.2 14 13a3742 3742 0 0 0-8 7 436 436 0 0 1-9-14.5c1.2-1.7 2.2-3.6 3-5.5Z" /><path fill="#d5c3bb" d="M135.5 138.5c6.8.1 13.8 0 21-.5a58.3 58.3 0 0 1-10.5 7.5c-3.7-2.2-7.2-4.5-10.5-7Z" /><path fill="#bdc4cc" d="M96.5 75.5h3v21c-2.2.3-4-.3-5.5-2l-2.5-6c-1.1-5.6.5-10 5-13Z" /><path fill="#c6d2d6" d="M225.5 231.5a9.7 9.7 0 0 1-4 6.5L192 261.5a32.3 32.3 0 0 1-4.5-6c.6-1.7 1.6-3.2 3-4.5l24-14c.8-.7 1-1.5 1-2.5 3.3-.1 6.7-1.1 10-3Z" /><path fill="#7aacb6" d="m175.5 248.5 5 8c.2 1.7-.5 2.7-2 3l-3-4a2691 2691 0 0 1-5-8 3 3 0 0 1 2-2 9 9 0 0 0 3 3Z" /><path fill="#438a9a" d="M180.5 256.5c2.4 2.7 4.8 5.5 7 8.5-1 1.4-2.4 1.7-4 1-2-2-3.7-4-5-6.5 1.5-.3 2.2-1.3 2-3Z" /><path fill="#081328" d="M97.5 256.5c2.8 0 5.4.4 8 1.5l11 5.5c3.7-1.5 7-3.7 10-6.5 3.9-.3 4.9 1.4 3 5-4 3.6-8.7 6-14 7.5a65 65 0 0 0-15.5-7c-4 1-7.5 2.7-10.5 5.5-3 1.3-6 1.7-9 1a58.3 58.3 0 0 1-10.5-7.5 8.4 8.4 0 0 1-.5-4 13 13 0 0 1 5 .5c2.7 2.7 5.9 4.5 9.5 5.5a86 86 0 0 0 13.5-7Z" /><path fill="#e6c3a9" d="M172.5 260.5c.5 1.2 1.2 2.4 2 3.5l-16 14c-3.4-.4-6.8-1.4-10-3-2-.6-3.5-1.7-4.5-3.5a21.9 21.9 0 0 1-1-11l7.5-7.5c6 .1 12 .8 18 2 1.2 2 2.5 3.8 4 5.5Z" /><path fill="#fff" d="M151.5 255.5c4-.3 8 0 12 1 2.2 9.4-1.7 14.4-11.5 15-1.6-.6-3-1.6-4-3-.3-2.4-.8-4.7-1.5-7l5-6Z" /><path fill="#ccd8de" d="M234.5 242.5a44.6 44.6 0 0 1-30 35.5c-7.8 2-15.4 4.4-23 7-4 3.4-8.4 6.2-13 8.5-9 2.4-16.5 0-22.5-7-.8-2.2-.6-4.2.5-6a17 17 0 0 0 13 3.5 421 421 0 0 1 20-15.5 7 7 0 0 0 2 2.5c2.7.7 5.3.7 8 0a727 727 0 0 1 35-28 48 48 0 0 1 10-.5Z" /></svg>;

<p>
  <HitlIcon width={64} style={{float: 'left', marginRight: 5}} role="presentation" />

  The Human in the loop (HITL) interface allows you to implement human agent intervention in your integration.
</p>

## Terminology

Throughout this document, we will use the following terms:

<DefinitionList>
  <Definition term="integration" id="integration">
    The code that connects Botpress to an external service.
  </Definition>

  <Definition term="external service" id="external-service">
    The service that provides HITL functionality. This could be a help desk system like Zendesk, or any other system that allows human agents to send and receive messages to end users.
  </Definition>

  <Definition term="human agent" id="human-agent">
    A person who interacts with end users through the external service. This could be a support agent, a sales representative, or any other type of human agent.
  </Definition>

  <Definition term="end user" id="end-user">
    A person who interacts with your bot through Botpress. This could be a customer, a user, an employee, or any other type of end user.
  </Definition>

  <Definition term="external user" id="external-user">
    A representation of an end user within the external service. This is typically created when a HITL session is started.
  </Definition>

  <Definition term="HITL session" id="hitl-session">
    A conversation between an end user and a human agent. This is typically represented as a *ticket* in the external service.
  </Definition>

  <Definition term="HITL interface" id="hitl-interface">
    The interface that defines the contract for implementing HITL functionality in your integration. This interface specifies the actions, events, and channels that your integration must implement to support HITL.
  </Definition>

  <Definition term="HITL plugin" id="hitl-plugin">
    The Botpress plugin that manages HITL sessions and relays messages between end users and your integration. Installing this plugin in a bot enables HITL functionality using the selected integration.
  </Definition>

  <Definition term="entity" id="entity">
    In the context of the HITL interface and plugin, an entity can be provided in order to support extra parameters in the `startHitl` action. This is useful to provide extra information about the HITL session, such as a ticket priority or customer identification number.
  </Definition>
</DefinitionList>

## External service requirements

The <DefinitionReference id="external-service" /> providing HITL functionality **must** support the following:

* An API that allows creating <DefinitionReference id="external-user" plural />.
* An API that allows creating <DefinitionReference id="hitl-session" plural />.
* An API that allows adding messages to <DefinitionReference id="hitl-session" plural />.
* An API that allows closing <DefinitionReference id="hitl-session" plural />.
* Webhooks that can notify your <DefinitionReference id="integration" /> of the following events:
  * <DefinitionReference id="hitl-session" capitalize /> closure.
  * <DefinitionReference id="human-agent" capitalize /> assignment.
  * <DefinitionReference id="human-agent" capitalize /> reply.

## Updating your `package.json` file

### Finding the current interface version

The current version of the `hitl` interface is: <code><CurrentInterfaceVersion interfaceName="hitl" fallback="2.0.0" /></code>

You will need this version number for the next steps.

### Adding the interface as a dependency

Once you have the <DefinitionReference id="hitl-interface" /> version, you can add it as a dependency to your <DefinitionReference id="integration" />:

<Steps>
  <Step title="Open the package.json file">
    Open your <DefinitionReference id="integration" />'s `package.json` file.
  </Step>

  <Step title="Add the dependencies section">
    If there is no `bpDependencies` section in your <DefinitionReference id="integration" />'s `package.json` file, create one:

    ```json package.json {2} theme={null}
    {
      "bpDependencies": {}
    }
    ```
  </Step>

  <Step title="Add the interface as a dependency">
    In the `bpDependencies` section, add the <DefinitionReference id="hitl-interface" /> as a dependency. For example, for version `2.0.0`, you would add the following:

    ```json package.json {3} theme={null}
    {
      "bpDependencies": {
        "hitl": "interface:hitl@2.0.0"
      }
    }
    ```

    <Warning>
      It's very important to follow this syntax: <br />
      `"<interface-name>": "interface:<interface-name>@<version>"`.
    </Warning>
  </Step>

  <Step title="Save the package.json file">
    Save the `package.json` file.
  </Step>

  <Step title="Install the interface">
    Now that you have added the <DefinitionReference id="hitl-interface" /> as a dependency, you can run the [`bp add`](/integrations/sdk/cli-reference#add) command to install it. This command will:

    * Download the interface from Botpress.
    * Install it in a directory named `bp_modules` in your <DefinitionReference id="integration" />'s root directory.
  </Step>
</Steps>

### Adding a helper build script

To keep your <DefinitionReference id="integration" /> up to date, we recommend adding a helper build script to your `package.json` file:

<Steps>
  <Step title="Open the package.json file">
    Open your <DefinitionReference id="integration" />'s `package.json` file.
  </Step>

  <Step title="Add the build script">
    In the `scripts` section, add the following script:

    ```json package.json {3} theme={null}
    {
      "scripts": {
        "build": "bp add -y && bp build"
      }
    }
    ```

    <Note>
      If the `build` script already exists in your `package.json` file, please replace it.
    </Note>
  </Step>

  <Step title="Save the package.json file">
    Save the `package.json` file.
  </Step>
</Steps>

Now, whenever you run `npm run build`, it will automatically install the <DefinitionReference id="hitl-interface" /> and build your <DefinitionReference id="integration" />.

## Editing your integration definition file

### Adding the interface to your integration definition file

Now that the <DefinitionReference id="hitl-interface" /> is installed, you must add it your integration definition file in order to implement it.

<Steps>
  <Step title="Open the integration.definition.ts file">
    Open your <DefinitionReference id="integration" />'s `integration.definition.ts` file.
  </Step>

  <Step title="Import the interface">
    At the top of the file, import the <DefinitionReference id="hitl-interface" />:

    ```typescript integration.definition.ts theme={null}
    import hitl from './bp_modules/hitl'
    ```
  </Step>

  <Step title="Add an empty entity">
    In your `new IntegrationDefinition()` statement, add an empty entity:

    ```typescript integration.definition.ts {2-6} theme={null}
    export default new sdk.IntegrationDefinition({
      entities: {
        ticket: {                     // <= name of the entity
          schema: sdk.z.object({})
        },
      },
    })
    ```

    <Note>
      The name of the entity isn't important, but it's recommended to use a name that matches the terminology of the <DefinitionReference id="external-service" />. For example, if the <DefinitionReference id="external-service" /> uses the term "ticket" to refer to a <DefinitionReference id="hitl-session" />, you could name the entity `ticket` or `hitlTicket`.
    </Note>
  </Step>

  <Step title="Extend your definition">
    Use the `.extend()` function at the end of your `new IntegrationDefinition()` statement:

    ```typescript integration.definition.ts {8-12} theme={null}
    export default new sdk.IntegrationDefinition({
      entities: {
        ticket: {                     // <= name of the entity
          schema: sdk.z.object({})
        },
      },
    })
      .extend(hitl, (self) => ({
        entities: {
          hitlSession: self.entities.ticket, // <= name of the entity
        },
      }))
    ```

    The exact syntax of `.extend()` will be explained in the next section.
  </Step>
</Steps>

### Configuring the interface

The `.extend()` function takes two arguments:

* The first argument is a reference to the interface you want to implement. In this case, it's `hitl`.
* The second argument is a configuration object. Using this object, you can override interface defaults with custom names, titles, and descriptions.

<Tip>
  Whilst renaming actions, events and channels is optional, it's highly recommended to rename these to match the terminology of the <DefinitionReference id="external-service" />. This will help you avoid confusion and make your <DefinitionReference id="integration" /> easier to understand.
</Tip>

#### Renaming actions

The `hitl` interface defines three actions that are used to interact with the <DefinitionReference id="external-service" />:

* `createUser` - Used by the <DefinitionReference id="hitl-plugin" /> to request the creation of a user in the <DefinitionReference id="external-service" /> and on Botpress.
* `startHitl` - Used by the <DefinitionReference id="hitl-plugin" /> to request the creation of a <DefinitionReference id="hitl-session" /> in the <DefinitionReference id="external-service" />.
* `stopHitl` - Used by the <DefinitionReference id="hitl-plugin" /> to request the closure of a <DefinitionReference id="hitl-session" /> in the <DefinitionReference id="external-service" />.

If you want to rename these actions, you can do so in the configuration object. For example, if you want to rename `createUser` to `hitlCreateUser`, you can do it like this:

```typescript integration.definition.ts {4} theme={null}
.extend(hitl, () => ({
  actions: {
    createUser: {
      name: 'hitlCreateUser',
    },
  },
}))
```

<Tip>
  For example, if you're using a *help desk* system like Zendesk, Jira Service Desk, or Freshdesk for HITL functionality, you might rename `startHitl` to `createTicket` and `stopHitl` to `closeTicket`. These systems use tickets to represent help requests, so renaming actions to match their terminology makes your <DefinitionReference id="integration" /> clearer and easier to understand.
</Tip>

#### Renaming events

The `hitl` interface defines these events to notify the plugin of changes in the external service:

* `hitlAssigned` - Emitted by your <DefinitionReference id="integration" /> to notify the <DefinitionReference id="hitl-plugin" /> that a <DefinitionReference id="human-agent" /> has been assigned to a <DefinitionReference id="hitl-session" />.
* `hitlStopped` - Emitted by your <DefinitionReference id="integration" /> to notify the <DefinitionReference id="hitl-plugin" /> that a <DefinitionReference id="hitl-session" /> has been closed.

If you want to rename these events, you can do so in the configuration object. For example, if you want to rename `hitlAssigned` to `agentAssigned`, you can do it like this:

```typescript integration.definition.ts {4} theme={null}
.extend(hitl, () => ({
  events: {
    hitlAssigned: {
      name: 'agentAssigned',
    },
  },
}))
```

#### Renaming channels

The `hitl` interface defines these channels:

* `hitl` - Used by the <DefinitionReference id="hitl-plugin" /> to send and receive messages from the <DefinitionReference id="external-service" />. This represents the communication channel for the <DefinitionReference id="hitl-session" />, like a support ticket on Zendesk or a direct message thread on Slack.

If you want to rename this channel, you can do so in the configuration object. For example, if you want to rename `hitl` to `supportTicket`, you can do it like this:

```typescript integration.definition.ts {4} theme={null}
.extend(hitl, () => ({
  channels: {
    hitl: {
      name: 'supportTicket',
    },
  },
}))
```

## Implementing the interface

### Implementing the actions

#### Implementing `createUser`

The `createUser` action is used by the <DefinitionReference id="hitl-plugin" /> to request the creation of an <DefinitionReference id="external-user" /> (a *requester*) in the <DefinitionReference id="external-service" />.

<Note>
  If you opted to rename the action to something else than `createUser` in the "Configuring the interface" section, please use the new name instead of `createUser`.
</Note>

Please refer to the expected input and output schemas for the action:
[interface.definition.ts line 85](https://github.com/botpress/botpress/blob/023d7de196e63f1a1b7cac0cf4f97c3d4aac940f/interfaces/hitl/interface.definition.ts#L85).

This action should implement the following logic:

<Steps>
  <Step title="Create a Botpress user">
    Create a Botpress user using the Botpress client by calling the `client.createUser()` method.
  </Step>

  <Step title="Create an external user">
    Create an <DefinitionReference id="external-user" /> on the <DefinitionReference id="external-service" /> using the <DefinitionReference id="external-service" />'s API or SDK.
  </Step>

  <Step title="Map the external user to the Botpress user">
    Update the <DefinitionReference id="external-user" /> on the <DefinitionReference id="external-service" /> to map it to the Botpress user. Please refer to the <DefinitionReference id="external-service" />'s documentation to know how to set extra metadata for the <DefinitionReference id="external-user" />. The <DefinitionReference id="integration" /> must be able at any time to query the <DefinitionReference id="external-service" /> in order to retrieve the Botpress user ID from the <DefinitionReference id="external-user" />.
  </Step>

  <Step title="Map the Botpress user to the external user">
    Update the Botpress user to map it to the <DefinitionReference id="external-user" />. This is typically done by setting a tag on the Botpress user with the <DefinitionReference id="external-user" />'s ID.
  </Step>

  <Step title="Yield control back to the plugin">
    Yield control back to the plugin by returning an object containing the Botpress user's ID.
  </Step>
</Steps>

As reference, here's how this logic is implemented in the Zendesk integration:

```typescript src/index.ts {4,15,19,25,29,33,35} theme={null}
export default new bp.Integration({
  actions: {
    async createUser({ ctx, input, client }) {
      // Create a Botpress user:
      const { name, email, pictureUrl } = input
      const { user } = await client.createUser({
        name,
        pictureUrl,
        tags: {
          email,
          role: 'end-user',
        },
      })

      // Create an external user on Zendesk:
      const zendeskClient = getZendeskClient(ctx.configuration)
      const zendeskUser = await zendeskClient.createOrUpdateUser({
        role: 'end-user',
        external_id: user.id, // <= map to the Botpress user ID
        name,
        email,
        remote_photo_url: pictureUrl,
      })

      // Map the Botpress user to the external user:
      await client.updateUser({
        id: user.id,
        tags: {
          id: zendeskUser.id.toString(), // <= map to the external user ID
        },
      })

      // Yield control back to the plugin and return the user ID:
      return {
        userId: user.id, // <= return the Botpress user ID
      }
    },
  },
})
```

#### Implementing `startHitl`

The `startHitl` action is used by the <DefinitionReference id="hitl-plugin" /> to request the creation of a <DefinitionReference id="hitl-session" /> (typically a *ticket*) in the <DefinitionReference id="external-service" />.

<Note>
  If you opted to rename the action to something else than `startHitl` in the "Configuring the interface" section, please use the new name instead of `startHitl`.
</Note>

Please refer to the expected input and output schemas for the action:
[interface.definition.ts line 109](https://github.com/botpress/botpress/blob/023d7de196e63f1a1b7cac0cf4f97c3d4aac940f/interfaces/hitl/interface.definition.ts#L109).

This action should implement the following logic:

<Steps>
  <Step title="Fetch the Botpress user">
    Fetch the Botpress user with ID `input.userId` that was passed in the input parameters.
  </Step>

  <Step title="Retrieve the external user's ID">
    From the Botpress user's tags, retrieve the <DefinitionReference id="external-user" />'s ID.
  </Step>

  <Step title="Create a Botpress conversation">
    Create a Botpress conversation using the Botpress client by calling the `client.getOrCreateConversation()` method.
  </Step>

  <Step title="Create the HITL session">
    On the <DefinitionReference id="external-service" />, create the <DefinitionReference id="hitl-session" />. This is typically represented as a *ticket* in the <DefinitionReference id="external-service" />.
  </Step>

  <Step title="Map the Botpress conversation to the HITL session">
    Update the Botpress conversation to map it to the <DefinitionReference id="hitl-session" />. This is typically achieved by setting a `ticketId` tag on the Botpress conversation.
  </Step>

  <Step title="Map the HITL session to the Botpress conversation">
    Update the <DefinitionReference id="hitl-session" /> on the <DefinitionReference id="external-service" /> to map it to the Botpress conversation. Please refer to the <DefinitionReference id="external-service" />'s documentation to know how to set extra metadata for the <DefinitionReference id="hitl-session" /> (typically a *ticket*). The <DefinitionReference id="integration" /> must be able at any time to query the <DefinitionReference id="external-service" /> in order to retrieve the Botpress conversation ID from the <DefinitionReference id="hitl-session" />.
  </Step>

  <Step title="Yield control back to the plugin">
    Yield control back to the plugin by returning an object containing the Botpress conversation's ID.
  </Step>
</Steps>

As reference, here's how this logic is implemented in the Zendesk integration:

```typescript src/index.ts {4,9,17,24,27,31,35,37,40,42} theme={null}
export default new bp.Integration({
  actions: {
    async startHitl({ ctx, input, client }) {
      // Fetch the Botpress user that was passed in the input parameters:
      const { user } = await client.getUser({
        id: input.userId,
      })

      // From the user's tags, retrieve the external user's id:
      const zendeskAuthorId = user.tags.id
      if (!zendeskAuthorId) {
        throw new sdk.RuntimeError(
          `User ${user.id} isn't linked to a Zendesk user`
        )
      }

      // Create a new ticket on Zendesk:
      const zendeskClient = getZendeskClient(ctx.configuration)

      const ticketTitle = input.title ?? 'Untitled Ticket'
      const ticketBody = 'A user created a support ticket'
      const createdZendeskTicket = await zendeskClient
        .createTicket(ticketTitle, ticketBody, {
          id: zendeskAuthorId, // <= map the ticket to the external user ID
        })

      // Create a Botpress conversation and map it to the Zendesk ticket:
      const { conversation } = await client.getOrCreateConversation({
        channel: 'hitl',
        tags: {
          id: createdZendeskTicket.id.toString(), // <= map to the ticket ID
        },
      })

      // Map the Zendesk ticket to the Botpress conversation:
      await zendeskClient.updateTicket(createdZendeskTicket.id, {
        external_id: conversation.id, // <= map to the Botpress conversation ID
      })

      // Yield control back to the plugin and return the conversation ID:
      return {
        conversationId: conversation.id, // <= return the Botpress conversation ID
      }
    },
  },
})
```

#### Relaying the conversation history

The input parameters of the `startHitl` action contain a `messageHistory` parameter. This parameter contains the conversation history that should be relayed to the <DefinitionReference id="external-service" /> to provide the <DefinitionReference id="human-agent" /> with context about the conversation. This parameter is an array of every message that was sent in the conversation prior to the <DefinitionReference id="hitl-session" /> being started.

<Expandable title="TypeScript schema for the messageHistory parameter">
  ```typescript theme={null}
  type MessageHistory = Array<
    | TextMessage
    | ImageMessage
    | AudioMessage
    | VideoMessage
    | FileMessage
    | LocationMessage
    | CarouselMessage
    | CardMessage
    | DropdownMessage
    | ChoiceMessage
    | BlocMessage
    | MarkdownMessage
  >;

  type Source =
    | {
        type: "user";
        userId: string;
      }
    | {
        type: "bot";
      };

  interface TextMessage {
    source: Source;
    type: "text";
    payload: {
      text: string;
    };
  }

  interface ImageMessage {
    source: Source;
    type: "image";
    payload: {
      imageUrl: string;
    };
  }

  interface AudioMessage {
    source: Source;
    type: "audio";
    payload: {
      audioUrl: string;
    };
  }

  interface VideoMessage {
    source: Source;
    type: "video";
    payload: {
      videoUrl: string;
    };
  }

  interface FileMessage {
    source: Source;
    type: "file";
    payload: {
      fileUrl: string;
      title?: string;
    };
  }

  interface LocationMessage {
    source: Source;
    type: "location";
    payload: {
      latitude: number;
      longitude: number;
      address?: string;
      title?: string;
    };
  }

  interface CarouselMessage {
    source: Source;
    type: "carousel";
    payload: {
      items: Array<{
        title: string;
        subtitle?: string;
        imageUrl?: string;
        actions: Array<{
          action: "postback" | "url" | "say";
          label: string;
          value: string;
        }>;
      }>;
    };
  }

  interface CardMessage {
    source: Source;
    type: "card";
    payload: {
      title: string;
      subtitle?: string;
      imageUrl?: string;
      actions: Array<{
        action: "postback" | "url" | "say";
        label: string;
        value: string;
      }>;
    };
  }

  interface DropdownMessage {
    source: Source;
    type: "dropdown";
    payload: {
      text: string;
      options: Array<{
        label: string;
        value: string;
      }>;
    };
  }

  interface ChoiceMessage {
    source: Source;
    type: "choice";
    payload: {
      text: string;
      options: Array<{
        label: string;
        value: string;
      }>;
    };
  }

  interface BlocMessage {
    source: Source;
    type: "bloc";
    payload: {
      items: Array<
        | BlocTextItem
        | BlocMarkdownItem
        | BlocImageItem
        | BlocAudioItem
        | BlocVideoItem
        | BlocFileItem
        | BlocLocationItem
      >;
    };
  }

  interface BlocTextItem {
    type: "text";
    payload: {
      text: string;
    };
  }

  interface BlocMarkdownItem {
    type: "markdown";
    payload: {
      markdown: string;
    };
  }

  interface BlocImageItem {
    type: "image";
    payload: {
      imageUrl: string;
    };
  }

  interface BlocAudioItem {
    type: "audio";
    payload: {
      audioUrl: string;
    };
  }

  interface BlocVideoItem {
    type: "video";
    payload: {
      videoUrl: string;
    };
  }

  interface BlocFileItem {
    type: "file";
    payload: {
      fileUrl: string;
      title?: string;
    };
  }

  interface BlocLocationItem {
    type: "location";
    payload: {
      latitude: number;
      longitude: number;
      address?: string;
      title?: string;
    };
  }

  interface MarkdownMessage {
    source: Source;
    type: "markdown";
    payload: {
      markdown: string;
    };
  }
  ```
</Expandable>

If you decide to relay the conversation history to the <DefinitionReference id="external-service" />, you can do so by iterating over the `messageHistory` array and sending each message to the <DefinitionReference id="external-service" /> using its API or SDK. However, doing so might cause a significant number of notifications being sent to the <DefinitionReference id="external-service" />. To alleviate this, you can choose to send only the last few messages in the conversation history, or to concatenate the messages into a single message. For example you could combine messages like this:

```markdown theme={null}
## User1 said:
> Hello, I need help with my order.

## Bot replied:
> I have escalated this conversation to a human agent. Please wait while I connect you.
```

#### Adding extra parameters to the `startHitl` action

If the <DefinitionReference id="external-service" /> requires extra parameters when starting a <DefinitionReference id="hitl-session" />, you can add them to the `hitlSession` entity, or whichever name you chose for the entity in the [Adding the interface to your integration definition file](#adding-the-interface-to-your-integration-definition-file) section. For example, if the <DefinitionReference id="external-service" /> requires a `priority` parameter, you can add it like this:

```typescript integration.definition.ts {5} theme={null}
export default new sdk.IntegrationDefinition({
  entities: {
    ticket: {                     // <= name of your entity
      schema: sdk.z.object({
        priority: sdk.z.string().optional(), // <= add the extra parameter here
      })
    },
  },
})
```

Doing so will display the `priority` parameter in the "Start HITL" card within the Botpress Studio, allowing the bot authors to set it. The value of this parameter will then be passed to the `startHitl` action as part of the `hitlSession` input parameter:

```typescript src/index.ts {5,10} theme={null}
export default new bp.Integration({
  actions: {
    async startHitl({ ctx, input, client }) {
      // Retrieve the extra parameter:
      const priority = input.hitlSession?.priority ?? 'normal'

      // Then use it to create the HITL session:
      const createdZendeskTicket = await zendeskClient
        .createTicket(ticketTitle, ticketBody, {
          priority, // <= pass the extra parameter to the external service
        })
    },
  },
})
```

#### Implementing `stopHitl`

The `stopHitl` action is used by the <DefinitionReference id="hitl-plugin" /> to request the closure of a <DefinitionReference id="hitl-session" /> (typically a *ticket*) in the <DefinitionReference id="external-service" />.

<Note>
  If you opted to rename the action to something else than `stopHitl` in the "Configuring the interface" section, please use the new name instead of `stopHitl`.
</Note>

Please refer to the expected input and output schemas for the action:
[interface.definition.ts line 162](https://github.com/botpress/botpress/blob/023d7de196e63f1a1b7cac0cf4f97c3d4aac940f/interfaces/hitl/interface.definition.ts#L162).

This action should implement the following logic:

<Steps>
  <Step title="Fetch the Botpress conversation">
    Fetch the Botpress conversation with ID `input.conversationId` that was passed in the input parameters.
  </Step>

  <Step title="Retrieve the HITL session's ID">
    From the Botpress conversation's tags, retrieve the <DefinitionReference id="hitl-session" />'s ID.
  </Step>

  <Step title="Close the HITL session">
    On the <DefinitionReference id="external-service" />, close the <DefinitionReference id="hitl-session" />. This is typically involves *resolving* or *closing* a *ticket* in the <DefinitionReference id="external-service" />.
  </Step>

  <Step title="Yield control back to the plugin">
    Yield control back to the plugin by returning an empty object.
  </Step>
</Steps>

<Note>
  The input parameters contain an unused `reason` parameter. Please ignore it. This parameter will be removed in future versions of the <DefinitionReference id="hitl-interface" />.
</Note>

As reference, here's how this logic is implemented in the Zendesk integration:

```typescript src/index.ts {4,9,17,22} theme={null}
export default new bp.Integration({
  actions: {
    async stopHitl({ ctx, input, client }) {
      // Fetch the Botpress conversation that was passed in the input parameters:
      const { conversation } = await client.getConversation({
        id: input.conversationId,
      })

      // From the conversation's tags, retrieve the Zendesk ticket's id:
      const ticketId: string | undefined = conversation.tags.id
      if (!ticketId) {
        return {}
      }

      const zendeskClient = getZendeskClient(ctx.configuration)

      // Close the ticket on Zendesk:
      await zendeskClient.updateTicket(ticketId, {
        status: 'closed',
      })

      // Yield control back to the plugin:
      return {}
    },
  },
})
```

### Implementing the channel

The `hitl` channel is used by the <DefinitionReference id="hitl-plugin" /> relay <DefinitionReference id="end-user" /> messages to the <DefinitionReference id="hitl-session" />, which is usually a *ticket* or *thread* in the <DefinitionReference id="external-service" />.

<Note>
  If you opted to rename the channel to something else than `hitl` in the "Configuring the interface" section, please use the new name instead of `hitl`.
</Note>

This channel handler should implement the following logic:

<Steps>
  <Step title="Retrieve the HITL session's ID">
    From the Botpress conversation's tags, retrieve the <DefinitionReference id="hitl-session" />'s ID.
  </Step>

  <Step title="Retrieve the external user's ID">
    * If the payload contains a `userId` parameter, the message has been sent by the <DefinitionReference id="end-user" />. Retrieve the <DefinitionReference id="external-user" />'s ID from the tags of the Botpress user `payload.userId`.
    * If the payload doesn't contain a `userId` parameter, the message has been sent by the bot. Retrieve the <DefinitionReference id="external-user" />'s ID from the tags of the attached Botpress user.
  </Step>

  <Step title="Send the message to the HITL session">
    Using the <DefinitionReference id="external-service" />'s API or SDK, send the message to the <DefinitionReference id="hitl-session" />. This is typically a *comment* in a *ticket*.
  </Step>
</Steps>

As reference, here's how this logic is implemented in the Zendesk integration:

```typescript src/index.ts {6,9,17} theme={null}
export default new bp.Integration({
  channels: {
    hitl: {
      messages: {
        async text({ client, conversation, ctx, payload, user }) {
          // Retrieve the ticket id from the conversation's tags:
          const zendeskTicketId = conversation.tags.id

          // Retrieve the external user:
          let zendeskAuthorId = user.tags.id

          if (payload.userId) {
            const { user: botpressUser } = await client.getUser({ id: payload.userId })
            zendeskAuthorId = botpressUser.tags.id
          }

          // Send the message to Zendesk:
          return await getZendeskClient(ctx.configuration)
            .createComment(zendeskTicketId, zendeskAuthorId, payload.text)
        },
      },
    },
  }
})
```

### Implementing the events

You should set up webhooks so that the <DefinitionReference id="integration" /> receives notifications about these events:

* A new message is added to the <DefinitionReference id="hitl-session" /> (usually a *ticket*).
* A <DefinitionReference id="human-agent" /> has been assigned to the <DefinitionReference id="hitl-session" />.
* The <DefinitionReference id="hitl-session" /> was closed.

#### Incoming messages

When notified by the <DefinitionReference id="external-service" /> that a new message has been added to the <DefinitionReference id="hitl-session" />, you should relay the message to the Botpress conversation:

<Steps>
  <Step title="Retrieve the Botpress conversation's ID">
    Retrieve the Botpress conversation's ID from the <DefinitionReference id="hitl-session" />'s metadata.
  </Step>

  <Step title="Retrieve the external user's ID">
    Retrieve the <DefinitionReference id="external-user" />'s ID from the <DefinitionReference id="hitl-session" />'s metadata.
  </Step>

  <Step title="Add a message to the Botpress conversation">
    Using the Botpress client, add a message to the Botpress conversation by calling the `client.createMessage()` method.
  </Step>
</Steps>

#### Implementing `hitlAssigned`

When notified by the <DefinitionReference id="external-service" /> that a <DefinitionReference id="human-agent" /> has been assigned to the <DefinitionReference id="hitl-session" />, you should notify the <DefinitionReference id="hitl-plugin" /> by emitting the `hitlAssigned` event:

<Steps>
  <Step title="Retrieve the Botpress conversation's ID">
    Retrieve the Botpress conversation's ID from the <DefinitionReference id="hitl-session" />'s metadata.
  </Step>

  <Step title="Retrieve the external user's ID">
    Retrieve the <DefinitionReference id="external-user" />'s ID from the <DefinitionReference id="hitl-session" />'s metadata.
  </Step>

  <Step title="Emit the hitlAssigned event">
    Using the Botpress client, emit the `hitlAssigned` event by calling the `client.createEvent()` method.
  </Step>
</Steps>

<Note>
  If you opted to rename the event to something else than `hitlAssigned` in the "Configuring the interface" section, please use the new name instead of `hitlAssigned`.
</Note>

#### Implementing `hitlStopped`

When notified by the <DefinitionReference id="external-service" /> that the <DefinitionReference id="hitl-session" /> was closed, you should notify the <DefinitionReference id="hitl-plugin" /> by emitting the `hitlStopped` event:

<Steps>
  <Step title="Retrieve the Botpress conversation's ID">
    Retrieve the Botpress conversation's ID from the <DefinitionReference id="hitl-session" />'s metadata.
  </Step>

  <Step title="Retrieve the external user's ID">
    Retrieve the <DefinitionReference id="external-user" />'s ID from the <DefinitionReference id="hitl-session" />'s metadata.
  </Step>

  <Step title="Emit the hitlStopped event">
    Using the Botpress client, emit the `hitlStopped` event by calling the `client.createEvent()` method.
  </Step>
</Steps>

<Note>
  If you opted to rename the event to something else than `hitlStopped` in the "Configuring the interface" section, please use the new name instead of `hitlStopped`.
</Note>
