mcpField
A
adk-frontend

adk-frontend

github.com/botpress开发121.7k 次安装1 周前更新
代码仓库

关于 adk-frontend

为使用 Botpress ADK 构建前端的开发者提供集成指导,涵盖认证、客户端管理、类型生成和 Bot 动作调用。内容围绕 TypeScript 模式及 React 相关状态管理方案组织。

主要功能

  1. 01Cookie 与 OAuth 认证模式
  2. 02使用 Zustand 缓存客户端
  3. 03导入 ADK 生成的类型
  4. 04类型安全地调用 Bot 动作
  5. 05错误处理与乐观更新

适用场景

  1. 01在前端实现 Botpress 登录与路由保护
  2. 02复用工作区或 Bot 级客户端
  3. 03同步 Bot 动作的 TypeScript 类型
  4. 04在界面中调用动作并处理异步状态

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/botpress/skills --skill adk-frontend

安装后在 Claude Code 中输入/adk-frontend确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
authentication.md
botpress-client.md
calling-actions.md
data-fetching.md
overview.md
project-setup.md
realtime-updates.md
recommended-stack.md
service-layer.md
state-management.md
type-generation.md

详细介绍

ADK 前端集成

当用户询问如何构建与 Botpress ADK 机器人连接的前端应用时,请使用此技能。内容涵盖身份验证模式、类型安全的 API 调用、客户端配置,以及集成生成的类型。

什么是 ADK 前端集成?

使用 Botpress ADK 构建机器人时,通常需要一个与其交互的前端应用。此技能提供经过生产环境验证的模式,用于:

  • 身份验证 - 通过 OAuth 流程存储基于 Cookie 的 PAT
  • 客户端管理 - 使用 Zustand store 模式缓存和复用客户端
  • 类型生成 - 使用 ADK 生成的类型,确保完整的类型安全
  • Action 调用 - 调用机器人 action,并妥善处理错误和乐观更新
关键技术
  • @botpress/client - Botpress API 的官方 TypeScript 客户端
  • 三斜线引用 - 用于导入生成类型的 TypeScript 模式
  • React Query - 用于管理变更和缓存(可选,但推荐)
  • Zustand - 用于客户端状态管理

何时使用此技能

当用户提出以下前端相关问题时,启用此技能:

身份验证问题
  • “如何从前端向 Botpress 进行身份验证?”
  • “个人访问令牌(PAT)是什么?”
  • “令牌应该存储在 Cookie 还是 localStorage 中?”
  • “如何实现 OAuth 登录流程?”
  • “如何根据身份验证状态保护路由?”
  • “如何处理令牌过期?”
客户端设置问题
  • “如何初始化 Botpress 客户端?”
  • “管理多个客户端实例的最佳方式是什么?”
  • “为什么要使用客户端 store?”
  • “如何创建工作区范围与机器人范围的客户端?”
  • “普通客户端和 Zai 客户端有什么区别?”
类型生成问题
  • “如何获取机器人 action 的类型?”
  • “什么是三斜线引用?”
  • “如何导入生成的类型?”
  • “.adk 类型文件在哪里?”
  • “如何保持机器人和前端的类型同步?”
  • “为什么 TypeScript 找不到我的 action 类型?”
调用 Action 的问题
  • “如何从前端调用机器人 action?”
  • “client.callAction() 的语法是什么?”
  • “调用 action 时如何处理错误?”
  • “如何实现乐观更新?”
  • “如何串联多个 action 调用?”
  • “如何将 React Query 与机器人 action 配合使用?”

可用文档

./references/ 中的文档文件:

核心集成模式
  • authentication.md - 完整的身份验证系统,涵盖 PAT、Cookie、OAuth 和路由保护
  • botpress-client.md - 客户端初始化、Zustand store 模式和 Zai 客户端设置
  • calling-actions.md - 类型安全的 action 调用、变更、错误处理和乐观更新
  • type-generation.md - 三斜线引用、生成的类型和维护类型安全
架构与设置
  • overview.md - 架构概述、何时使用 ADK 前端以及项目结构
  • project-setup.md - Vite + React 脚手架、TypeScript 配置和环境设置
  • recommended-stack.md - 推荐的技术栈及其理由
数据与状态模式
  • service-layer.md - 用于封装带类型 API 调用的服务层模式
  • data-fetching.md - TanStack Query 模式、变更和乐观更新
  • state-management.md - Zustand 与 TanStack Query 的比较,以及何时使用各自方案
  • realtime-updates.md - 轮询策略、间隔级别和性能注意事项

如何回答前端问题

前端问题通常属于以下类别:

1. 身份验证实现

当用户询问身份验证时,请参考 authentication.md 中的完整模式:

核心概念:

  • 在 Botpress Cloud 中生成 PAT
  • 基于 Cookie 的存储(而非 localStorage)
  • 使用 React Context API 的 AuthContext
  • 通过 cli-login 实现 OAuth 回调流程
  • 使用 TanStack Router 保护路由
  • 同时从 Botpress API 和机器人表中获取个人资料

回复模式:

  1. 说明身份验证策略(Cookie 与 localStorage)
  2. 展示 AuthProvider 的实现
  3. 演示 OAuth 流程
  4. 提供路由保护示例
  5. 强调安全最佳实践
2. 客户端设置与管理

当用户询问客户端配置时,请参考 botpress-client.md:

核心概念:

  • 使用 apiUrl、workspaceId、token、botId 初始化客户端
  • 使用 Zustand store 缓存客户端
  • 用于复用的动态客户端键
  • 工作区范围与机器人范围的客户端
  • 为 Zai 操作延长超时时间

回复模式:

  1. 展示 clientsStore.ts 模式
  2. 说明客户端缓存的工作原理
  3. 演示 getApiClient() 的用法
  4. 展示何时使用工作区范围或机器人范围的客户端
  5. 说明用于 AI 操作的 getZaiClient()
3. 类型生成与导入

当用户询问类型时,请参考 type-generation.md:

核心概念:

  • ADK 在开发/构建期间于 .adk/ 目录中生成类型
  • 使用三斜杠指令引用外部类型
  • 生成的文件:action-types.d.ts、table-types.d.ts、workflow-types.d.ts
  • 创建类型别名以简化代码
  • 通过 adk dev 保持类型同步

回复模式:

  1. 说明 ADK 如何生成类型
  2. 展示三斜杠引用语法
  3. 演示如何导入生成的类型
  4. 提供创建类型别名的示例
  5. 展示类型如何自动保持同步
4. 调用机器人操作

当用户询问如何调用操作时,请参考 calling-actions.md:

核心概念:

  • client.callAction() 签名
  • 使用 BotActionDefinitions 实现类型安全的输入/输出
  • 可复用操作调用的服务层模式
  • 使用 useMutation 管理加载状态和错误处理
  • 使用乐观更新即时反馈 UI
  • 链接多个操作(顺序执行与并行执行)

回复模式:

  1. 展示基本的 callAction() 语法
  2. 演示类型安全的服务函数
  3. 提供 useMutation 示例
  4. 展示错误处理模式
  5. 在适用时说明乐观更新

常见模式参考

身份验证流程
// 1. Cookie helpers
function setCookie(name: string, value: string, days = 365)
function getCookie(name: string): string | null
function deleteCookie(name: string)

// 2. AuthContext
interface AuthContextType {
  token: string | null
  isAuthenticated: boolean
  userProfile: UserProfile | null
  isLoadingProfile: boolean
  login: (token: string) => void
  logout: () => void
}

// 3. OAuth Flow
// Redirect: https://app.botpress.cloud/cli-login?redirect=...
// Callback: /auth/callback?pat=bp_pat_...
// Store PAT in cookie and navigate to app
客户端存储模式
// stores/clientsStore.ts
const useClientsStore = create<ClientsState>()((set, get) => ({
  APIClients: {},
  getAPIClient: (props) => {
    const key = props?.botId ? `${props.workspaceId}-${props.botId}` : (props?.workspaceId ?? DEFAULT_API_CLIENT_KEY)

    const cached = get().APIClients[key]
    if (cached) return cached

    const newClient = new APIClient({
      apiUrl: API_BASE_URL,
      workspaceId: props?.workspaceId,
      token: getPat() ?? '',
      botId: props?.botId,
    })

    set((state) => ({
      APIClients: { ...state.APIClients, [key]: newClient },
    }))

    return newClient
  },
}))

export const getApiClient = (props?) => useClientsStore.getState().getAPIClient(props)
类型导入模式
// types/index.ts
/// <reference path="../../../bot/.adk/action-types.d.ts" />
/// <reference path="../../../bot/.adk/table-types.d.ts" />

import type { BotActionDefinitions } from '@botpress/runtime/_types/actions'
import type { TableDefinitions } from '@botpress/runtime/_types/tables'

// Create type aliases
export type SendMessageAction = BotActionDefinitions['sendMessage']
export type TicketTableRow = TableDefinitions['TicketsTable']['Output']
操作调用模式
// services/bot-service.ts
export async function sendMessage(input: SendMessageAction['input']) {
  const client = getApiClient({ botId, workspaceId })
  const result = await client.callAction({
    type: 'sendMessage',
    input,
  })
  return result.output as SendMessageAction['output']
}

// Component usage with useMutation
const { mutate: send, isPending } = useMutation({
  mutationFn: sendMessage,
  onSuccess: () => {
    toast.success('Message sent')
    queryClient.invalidateQueries({ queryKey: ['messages'] })
  },
  onError: (error) => {
    toast.error('Failed to send message')
  },
})

此技能可回答的问题示例

入门问题
  • “如何将我的 React 应用连接到 Botpress 机器人?”
  • “什么是 Personal Access Token?”
  • “在哪里可以找到我的 workspace ID 和 bot ID?”
  • “如何安装 @botpress/client?”
身份验证问题
  • “应该如何存储身份验证令牌?”
  • “如何实现登录/登出?”
  • “如何保护需要身份验证的路由?”
  • “应该使用 Cookie 还是 localStorage?”
  • “如何处理 OAuth 回调?”
类型安全问题
  • “如何获取机器人的 TypeScript 类型?”
  • “什么是三斜杠引用?”
  • “为什么 TypeScript 找不到我的操作类型?”
  • “如何保持类型同步?”
  • “生成的类型文件在哪里?”
实现问题
  • “如何调用机器人操作?”
  • “如何从前端查询机器人表?”
  • “如何处理加载状态?”
  • “如何实现乐观更新?”
  • “如何链接多个操作调用?”
高级问题
  • “如何在前端使用 Zai?”
  • “工作区范围的客户端和机器人范围的客户端有什么区别?”
  • “如何实现客户端缓存?”
  • “如何处理令牌过期?”
  • “如何实现重试逻辑?”

响应格式

回答时:

  1. 先给出简洁的说明(1-2 个段落)
  2. 提供参考资料中的可运行代码示例
  3. 注明文件引用(例如:“来自 authentication.md:60-85”)
  4. 在相关时强调安全注意事项
  5. 指出常见陷阱以及避免方法
  6. 链接到相关主题,供读者深入探索
示例回答结构
Question: "How do I authenticate users in my frontend?"

Answer:
The recommended pattern uses cookie-based PAT storage with OAuth flow.
Here's the complete implementation:

1. Cookie Helpers (authentication.md:89-111)
   [code example]

2. AuthContext Setup (authentication.md:64-76)
   [code example]

3. OAuth Flow (authentication.md:473-533)
   [code example]

Key Security Considerations:
- Use SameSite=Lax for CSRF protection
- Always use HTTPS in production
- Never log PATs to console
- Implement token expiration handling

Related Topics:
- Route protection: authentication.md:369-467
- Profile fetching: authentication.md:304-347
- Client initialization: botpress-client.md:29-51

始终需要引用的关键模式

回答问题时,务必对照文档确认以下模式:

1. 客户端管理
// ✅ CORRECT - Use client store
const client = getApiClient({ workspaceId, botId })

// ❌ WRONG - Create new client every time
const client = new Client({ apiUrl, workspaceId, token, botId })
2. 类型导入
// ✅ CORRECT - Triple-slash at top of file
/// <reference path="../../../bot/.adk/action-types.d.ts" />
import type { BotActionDefinitions } from '@botpress/runtime/_types/actions'

// ❌ WRONG - No triple-slash reference
import type { BotActionDefinitions } from '@botpress/runtime/_types/actions'
3. 操作调用
// ✅ CORRECT - Service layer with types
export async function sendMessage(input: SendMessageAction['input']) {
  const client = getApiClient({ botId, workspaceId })
  const result = await client.callAction({ type: 'sendMessage', input })
  return result.output as SendMessageAction['output']
}

// ❌ WRONG - Direct call in component
const result = await client.callAction({ type: 'sendMessage', input: data })
4. 身份验证存储
// ✅ CORRECT - Cookie with SameSite
document.cookie = `token=${value};expires=${expires};path=/;SameSite=Lax`

// ❌ WRONG - localStorage without security
localStorage.setItem('token', value)

需要强调的最佳实践

回答时,务必提及相关的最佳实践:

安全
  • 在生产环境中始终使用 HTTPS
  • 使用启用了 SameSite 保护的 Cookie
  • 切勿记录 PAT 或令牌
  • 实现令牌过期处理
  • 尽可能使用 HttpOnly Cookie(SSR)
类型安全
  • 始终使用 ADK 生成的类型
  • 创建类型别名,让代码更简洁
  • 正确使用三斜杠引用
  • 使用 adk dev 确保类型保持同步
  • 为所有操作输入和输出添加类型
性能
  • 使用 Zustand store 缓存客户端
  • 无需执行 bot 操作时,使用限定于工作区的客户端
  • 实现乐观更新,提升用户体验
  • 使用 React Query 管理缓存
  • 并行运行相互独立的操作
错误处理
  • 始终处理 401(令牌过期)错误
  • 在发生错误时向用户提供反馈
  • 为暂时性故障实现重试逻辑
  • 以恰当方式记录错误(切勿记录令牌)
  • 异步操作期间显示加载状态
代码组织
  • 使用服务层调用操作
  • 将类型集中在单个文件中
  • 将身份验证逻辑放在 context 中
  • 将客户端配置与使用分开
  • 在多个组件间复用服务函数

常见问题排查

请准备好协助解决以下常见问题:

“Cannot find module '@botpress/runtime/_types/actions'”
  • 检查三斜杠引用路径
  • 确认 .adk/ 目录存在
  • 重启 TypeScript 服务器
  • 确保已运行 adk dev/build
“修改 bot 后类型未更新”
  • 重启 adk dev
  • 删除 .adk/ 并重新构建
  • 重启 TypeScript 服务器
  • 检查 bot 是否存在编译错误
“重新加载后身份验证失败”
  • 实现重新加载重试逻辑(authentication.md:191-220)
  • 检查 Cookie 是否过期
  • 确认令牌是否已正确获取
  • 检查是否存在 CORS 问题
“长时间运行的操作导致客户端超时”
  • 对 AI 操作使用带有延长超时时间的 getZaiClient()
  • 不要对 Zai 操作使用常规客户端
  • 考虑将操作拆分为更小的部分

总结

本技能涵盖了 Botpress ADK 前端集成的完整内容:

核心主题:

  1. 使用 PAT 和 Cookie 进行身份验证
  2. 使用 Zustand 管理客户端
  3. 使用三斜杠引用生成和导入类型
  4. 以完整的类型安全性调用 bot 操作

适用场景:

  • 任何前端集成问题
  • 身份验证和安全模式
  • 类型安全和生成的类型
  • 客户端设置和配置
  • 操作调用和错误处理

核心原则: 始终提供可用于生产环境的模式,并强调类型安全、安全性和可维护性。

评论

支持 Markdown