适用版本:ChengOS v0.1.0+ | 最后核对:2026-08-12 | 来源:
chengflow-sdk/src/sdk/index.ts、chengflow-sdk/src/sdk/channel-client.ts、chengflow-sdk/src/sdk/ws-client.ts、chengflow-sdk/src/sdk/management-client.ts、chengflow-sdk/src/sdk/session-manager.ts
SDK 是纯 TypeScript,不依赖任何框架。React hooks 和组件建立在它之上,但核心类在任何地方都能用。
import {
ChannelClient, ChannelClientError,
ManagementClient, AuthClient, BrowserAuthSession,
SessionManager, ExecutionMappingStore, WsClient,
} from "@chengflow/sdk";
ChannelConfig
所有客户端接受同一份配置结构:
{
apiBaseUrl: "https://api.example.com/api/v1",
wsBaseUrl: "wss://api.example.com/ws/executions",
workspaceId: "…",
channelId: "weather-app",
boundWorkflowId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
}
workspaceId 是必填的——不填会抛出 VALIDATION_ERROR,而不是回落到某个默认工作区。
ChannelClient
REST 客户端。鉴权由它代办:由 token provider 提供 JWT,刷新是自动的;不可恢复的鉴权失败会通过 auth-expired 通道通知,而不是在某个随机调用点抛出。
const client = new ChannelClient(config);
execute()——你用得最多的方法
const { conversation_id, workflow_id, execution_id } =
await client.execute(channelId, workflowId, message, sessionId?, externalUserId?, attachments?);
它是一个两步 JWT 流程,而不是一个接口:
POST /workspaces/:workspace_id/conversations/resolve → conversation_id
POST /conversations/:id/messages → execution_id
external_user_id 默认是 web-user;external_chat_id 来自 sessionId,缺省时用带时间戳的值。mode 是 workflow_chat,extra_context 携带 channel_id。
execution_id 可能为 null——当这条消息没有触发工作流时。请处理这种情况,别默认一定有运行开始。
其余方法
| 方法 | 作用 |
|---|---|
resolveConversation(workspaceId, req) |
为 (app_id, external_user_id, external_chat_id) 解析或创建会话 |
createMessage(conversationId, req) |
发送消息;role、content,可选 references、model、external_message_id、attachments |
getConversationMessages(conversationId) |
历史消息 |
workflowSupportsAttachments(workflowId) |
工作流是否包含 io/file_upload 节点 |
submitApproval(...) |
提交审批决策与范围 |
resumeExecution(executionId) |
恢复被挂起的执行 |
bulkUpdateMemoryControls(...) |
批量更新记忆控制 |
getExecution(executionId) |
执行详情 |
getExecutionResult(executionId) |
结果载荷 |
界面正是靠 workflowSupportsAttachments 决定要不要显示文件按钮——去问工作流,而不是从配置里猜。
失败会抛出 ChannelClientError,携带错误码、消息和 HTTP 状态,因此你可以按码分支而不用解析文案。
WsClient
const ws = new WsClient({
url: "wss://api.example.com/ws/executions",
tokenProvider: () => localStorage.getItem("access_token"),
});
| 选项 | 默认 |
|---|---|
reconnect |
true |
reconnectInterval |
1000 毫秒 |
reconnectMaxInterval |
30000 毫秒 |
reconnectBackoffRate |
2 |
reconnectMaxAttempts |
Infinity |
reconnectJitter |
true |
heartbeatInterval |
30000 毫秒 |
heartbeatTimeout |
10000 毫秒 |
debug |
false |
tokenProvider 在每次连接之前都会被调用,token 作为 ?token= 追加到 URL。这对长时间打开的页面很关键:只取一次 token 的客户端,重连时会带着一个已过期的令牌。
订阅按作用域进行:
ws.send({ type: "SUBSCRIBE", scope: { type: "conversation", conversationId } });
ws.send({ type: "SUBSCRIBE", scope: { type: "execution", executionId } });
ws.send({ type: "UNSUBSCRIBE", scope: { type: "execution", executionId } });
作用域有 workspace、conversation 和 execution。重连后订阅会自动恢复——不需要你手动重订。
心跳是 PING / PONG,可带可选的 data 字段和时间戳。
字段命名——能省你一个下午的细节
后端把每条消息包在 WsEnvelope 里,type 是 SCREAMING_SNAKE_CASE。而不同消息类型上的事件字段在传输格式里是 snake_case 与 camelCase 混合的。WsClient 会在分发之前统一归一化为 camelCase,因此业务代码只消费 camelCase。
不要针对原始传输结构写代码。
事件
会话作用域:MESSAGE_CREATED、MESSAGE_COMPLETED、WORKFLOW_TRIGGERED、CONVERSATION_CREATED。
执行作用域:EXECUTION_START、EXECUTION_PROGRESS、EXECUTION_COMPLETE、EXECUTION_FAILED、EXECUTION_CANCELLED、EXECUTION_STATE_CHANGED、NODE_STREAM_* 系列,以及审批与智能体评审事件。
SessionManager
它掌管会话映射的浏览器那一半,按 channelId 分键并持久化到 localStorage。
| 方法 | 作用 |
|---|---|
getOrCreateSessionId() |
每个渠道一个稳定的 UUID v4,刷新后依然有效 |
resetSession() |
生成新会话 id 并清除会话绑定——浏览器版的 ~new |
setConversationId(id) / getConversationId() / clearConversationId() |
会话绑定 |
listSessions() / createSession(label?) / renameSession(id, label) |
每个渠道下的多会话 |
togglePinSession(id) / deleteSession(id) |
会话列表管理 |
getActiveSessionId() / setActiveSessionId(id) |
当前是哪一个 |
clear() |
清空该渠道的一切 |
会话 id 映射到后端的 external_chat_id;它与 (workspace_id, app_id) 一起确定一个会话。见渠道路由。
可以注入自定义的 Storage——在浏览器之外 SDK 会回落到内存实现,因此它可测试,也对 SSR 安全。
ManagementClient
用于搭建控制台,而不是聊天窗口。
| 领域 | 方法 |
|---|---|
| 渠道 | listChannels、createChannel、updateChannel、deleteChannel |
| 工作区 | listWorkspaces、createWorkspace |
| 工作流 | listPublishedWorkflows({ workspaceId, limit })、getWorkflowName |
| 连接 | getChannelStatus、getChannelCapabilities、getChannelAuthPattern、connectChannel、completeConnect、disconnectChannel |
| 密钥 | listChannelKeys、deleteChannelKey |
getChannelAuthPattern 返回某个平台需要哪些字段,于是配对表单可以通用地渲染出来,而不必为每个平台硬编码一套表单。connectChannel / completeConnect 对应即时通讯渠道中描述的两步连接生命周期。
AuthClient 与 BrowserAuthSession
AuthClient 处理登录与密码重置。BrowserAuthSession 基于 localStorage 实现 AuthTokenProvider,使用导出的 ACCESS_TOKEN_KEY 和 REFRESH_TOKEN_KEY,并在你不传 provider 时作为默认实现。
如果宿主应用已经掌管令牌,可以自行实现 AuthTokenProvider。
ExecutionMappingStore
跟踪「消息 → 执行」的映射以及该执行的客户端状态——正是它让界面在多个回合同时在飞时,把转圈显示在正确的气泡上。isTerminalExecutionStatus() 和 execution-status 导出的工具负责把后端状态归类成客户端状态。
React 层
<ChatProvider config={config}>
<ChatWindow />
</ChatProvider>
useChannel(config) 是核心 hook,返回:
{ messages, sendMessage, isLoading, connectionStatus, streamingContent,
resetConversation, submitApproval, continueAgentReview,
submitContextMemoryReview, error, supportsAttachments }
ChatProvider 只是把 useChannel 的返回值注入 context。其他 hook:use-websocket、use-conversation、use-channels、use-channel-connection、use-auth。
下一步
- SDK 快速开始——跑通一个聊天窗口的最短路径。
- 集成示例——把这些组合起来。
- WebSocket API——
WsClient之下的协议。

暂无评论内容