chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:34:48 +08:00
commit 77bb5bf71f
3762 changed files with 353249 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
import * as sdk from '@botpress/sdk'
import * as genenv from './.genenv'
import chat from './bp_modules/chat'
import hitl from './bp_modules/hitl'
import zendesk from './bp_modules/zendesk'
export default new sdk.BotDefinition({
configuration: {
schema: sdk.z.object({}),
},
states: {},
events: {},
recurringEvents: {},
user: {
tags: {
email: {
title: 'Email',
description: 'The email of the user',
},
},
},
conversation: {},
})
.addIntegration(chat, {
enabled: true,
configuration: {},
})
.addIntegration(zendesk, {
enabled: true,
configuration: {
apiToken: genenv.HITLOOPER_ZENDESK_API_TOKEN,
email: genenv.HITLOOPER_ZENDESK_EMAIL,
organizationSubdomain: genenv.HITLOOPER_ZENDESK_ORGANIZATION_SUBDOMAIN,
},
})
.addPlugin(hitl, {
configuration: {
flowOnHitlStopped: false,
useHumanAgentInfo: false,
},
dependencies: {
hitl: {
integrationAlias: 'zendesk',
integrationInterfaceAlias: 'hitl<hitlTicket>',
},
},
})
+13
View File
@@ -0,0 +1,13 @@
import rootConfig from '../../eslint.config.mjs'
export default [
...rootConfig,
{
languageOptions: {
parserOptions: {
project: ['./tsconfig.json'],
tsconfigRootDir: import.meta.dirname,
},
},
},
]
+28
View File
@@ -0,0 +1,28 @@
{
"name": "@bp-bots/hit-looper",
"scripts": {
"postinstall": "genenv -o ./.genenv/index.ts -e HITLOOPER_ZENDESK_API_TOKEN -e HITLOOPER_ZENDESK_EMAIL -e HITLOOPER_ZENDESK_ORGANIZATION_SUBDOMAIN",
"check:type": "tsc --noEmit",
"check:bplint": "bp lint",
"build": "bp add -y && bp build"
},
"private": true,
"dependencies": {
"@botpress/client": "workspace:*",
"@botpress/sdk": "workspace:*"
},
"devDependencies": {
"@botpress/cli": "workspace:*",
"@botpress/common": "workspace:*",
"@botpress/sdk": "workspace:*",
"@botpresshub/chat": "workspace:*",
"@botpresshub/hitl-plugin": "workspace:*",
"@botpresshub/zendesk": "workspace:*",
"@bpinternal/genenv": "0.0.1"
},
"bpDependencies": {
"chat": "../../integrations/chat",
"zendesk": "../../integrations/zendesk",
"hitl": "../../plugins/hitl"
}
}
+15
View File
@@ -0,0 +1,15 @@
# HIT Looper
## Description
This is a bot that implements the Human In The Loop (HITL) pattern. Talk to this bot as a customer in Telegram. When sending the message `/start_hitl`, the bot will connect you to an agent in Zendesk. The agent will be able to reply to you and send you back to the bot when the conversation is over.
## Usage
1. Create a new bot using the Botpress Dashboard or the Botpress CLI.
2. Install the Telegram and Zendesk integrations using the command `bp add telegram && bp add zendesk`.
3. Build the bot using command `bp build`.
4. Deploy the bot using command `bp deploy`.
5. In the botpress Dashboard, enable and configure the integrations Telegram and Zendesk.
6. Talk to the bot as a customer in Telegram and ask to start a HITL session by sending the message `/start_hitl`.
7. Login to Zendesk and reply back to yourself as an agent.
+22
View File
@@ -0,0 +1,22 @@
import { MessageHandlerProps, EventHandlerProps } from '.botpress'
export class Responder {
public constructor(private _props: MessageHandlerProps | EventHandlerProps) {}
public static from(props: MessageHandlerProps | EventHandlerProps) {
return new Responder(props)
}
public async respond({ conversationId, text, userId }: { conversationId: string; text: string; userId?: string }) {
await this._props.client.createMessage({
conversationId,
userId: this._props.ctx.botId,
tags: {},
type: 'text',
payload: {
text,
userId,
},
})
}
}
+107
View File
@@ -0,0 +1,107 @@
import { Conversation } from '@botpress/client'
import { Responder } from './api-utils'
import * as bp from '.botpress'
const BOT_MESSAGE = [
'Hi, I am a bot.',
'I cannot answer your questions.',
'Type `/start_hitl` to talk to a human agent.',
'Have fun :)',
].join('\n')
type MessageSource = 'from_patient' | 'from_agent'
const getMessageSource = (conversation: Conversation): MessageSource => {
if (conversation.integration === 'zendesk') {
return 'from_agent'
}
return 'from_patient'
}
const bot = new bp.Bot({ actions: {} })
bot.on.message('*', async (props) => {
const source = getMessageSource(props.conversation)
if (source !== 'from_agent') {
return
}
const { conversation: downstreamConversation } = props
await Responder.from(props).respond({
conversationId: downstreamConversation.id,
text: 'HITL is currently disabled.',
})
})
bot.on.message('*', async (props) => {
const source = getMessageSource(props.conversation)
if (source !== 'from_patient') {
return
}
const { conversation: upstreamConversation, user: upstreamUser } = props
const _randFrom = <TValueType extends unknown>(...values: TValueType[]): TValueType =>
values[Math.floor(Math.random() * values.length)]!
if (props.message.type === 'text' && props.message.payload.text.trim() === '/start_hitl') {
await props.client.updateUser({
id: upstreamUser.id,
tags: {
email: upstreamUser.tags.email ?? 'john.doe@botpress.com',
},
name: 'John Doe',
pictureUrl: 'https://upload.wikimedia.org/wikipedia/en/e/e7/Steve_%28Minecraft%29.png',
})
await bot.actionHandlers['hitl#startHitl']({
...props,
input: {
title: `Hitl request ${Date.now()}`,
description: 'I have a problem',
hitlSession: { priority: _randFrom('low', 'high', 'urgent') },
conversationId: upstreamConversation.id,
userId: upstreamUser.id,
},
})
return
}
if (props.message.type === 'text' && props.message.payload.text.trim() === '/stop_hitl') {
await bot.actionHandlers['hitl#stopHitl']({
...props,
input: {
conversationId: upstreamConversation.id,
},
})
return
}
await Responder.from(props).respond({
conversationId: upstreamConversation.id,
text: BOT_MESSAGE,
})
})
bot.on.event('*', async (props) => {
const payload = props.event.payload as Record<string, unknown>
let conversationId: string | undefined = undefined
if (props.event.conversationId) {
conversationId = props.event.conversationId
} else if ('conversationId' in payload && typeof payload.conversationId === 'string') {
conversationId = payload.conversationId
}
if (!conversationId) {
return
}
await Responder.from(props).respond({
conversationId,
text: BOT_MESSAGE,
})
})
export default bot
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"paths": { "*": ["./*"] },
"outDir": "dist"
},
"include": [".botpress/**/*", "src/**/*", "*.ts"]
}