渠道是 Think Agent 进行对话的界面:浏览器 WebSocket、messenger webhook(Telegram、Slack 等)、语音,或你自己的自定义传输。渠道将 messengers 泛化为统一词汇,以便应用按渠道策略(不同系统提示词、收窄工具集、步数上限)并投递带外通知,无论轮次从哪个界面到达。
每个 Think Agent 始终有隐式 web 渠道(浏览器客户端使用的 WebSocket 聊天)。用 configureChannels() 声明额外渠道 — 并覆盖 web 策略。getMessengers() 返回的 messenger 会自动吸收为 messenger 渠道,现有 messenger 应用无需改动。
重写 configureChannels() 返回渠道 id 到 ChannelDefinition 的映射。id 用于在轮次上选择渠道:
import { Think, messengerChannel } from "@cloudflare/think";
import { telegram } from "@chat-adapter/telegram";
export class Assistant extends Think {
configureChannels() {
return {
// Override policy for the built-in web channel.
web: {
kind: "web",
ingress: { transport: "websocket" },
instructions: "You are chatting in a web app. Use markdown freely.",
},
// A voice channel with tighter limits.
voice: {
kind: "voice",
ingress: { transport: "voice" },
instructions: "Keep replies short and speakable. No markdown.",
maxTurns: 3,
},
// A messenger channel (Chat SDK webhook).
telegram: messengerChannel(
telegram({
/* adapter config */
}),
),
};
}
}import { Think, messengerChannel } from "@cloudflare/think";
import { telegram } from "@chat-adapter/telegram";
export class Assistant extends Think<Env> {
configureChannels() {
return {
// Override policy for the built-in web channel.
web: {
kind: "web",
ingress: { transport: "websocket" },
instructions: "You are chatting in a web app. Use markdown freely.",
},
// A voice channel with tighter limits.
voice: {
kind: "voice",
ingress: { transport: "voice" },
instructions: "Keep replies short and speakable. No markdown.",
maxTurns: 3,
},
// A messenger channel (Chat SDK webhook).
telegram: messengerChannel(
telegram({
/* adapter config */
}),
),
};
}
}ChannelDefinition 字段如下:
| 字段 | 类型 | 描述 |
|---|---|---|
kind |
"web" | "messenger" | "voice" | "custom" |
界面类别。 |
ingress |
{ transport: "websocket" | "voice" } 或 webhook messenger 规范 |
轮次如何到达。messengerChannel() 为你构建 webhook 形式。 |
instructions |
string | (ctx: ChannelContext) => string | Promise<string> |
该渠道轮次的系统提示词前缀。 |
tools |
(all: ToolSet) => ToolSet |
为该渠道收窄已组装工具集(仅过滤 — 不能添加工具)。 |
maxTurns |
number |
该渠道每轮的模型步数上限。 |
capabilities |
ChannelCapabilities |
界面能力(流式、消息编辑)。web 有默认值。 |
conversation |
messenger 对话模式或解析器 | Messenger 线程路由(见 Messengers)。 |
delivery |
渠道投递策略 | Messenger 投递策略。 |
用 defineChannels() 辅助函数做类型推断,用 messengerChannel() 将 Chat SDK 适配器定义包装为 kind: "messenger" 渠道。
| 种类 | 入口 | 说明 |
|---|---|---|
web |
{ transport: "websocket" } |
始终存在。仅在 configureChannels() 中声明以设置策略;不能移除。 |
messenger |
webhook(messengerChannel(...)) |
输入 messenger 运行时。等价于 getMessengers() 条目。 |
voice |
{ transport: "voice" } |
应用策略与轮次上下文;带外投递尚未接入。 |
custom |
应用自定义 | 自定义传输。今日与 voice 相同的投递限制。 |
渠道策略在 beforeTurn 之前作为可覆盖的默认值应用,因此 beforeTurn 重写仍优先:
instructions前缀到该轮次的基础系统提示词。tools过滤已组装工具集(只能移除 —getTools()接口负责添加)。maxTurns限制模型步数:beforeTurn的maxSteps优先,然后渠道maxTurns,然后实例maxSteps默认。
向 runTurn()(或 chat())传入 channel 在指定渠道上运行轮次。渠道 id 会盖章到用户消息,因此续写或恢复的轮次会重新解析同一渠道并重新应用其策略:
export class Assistant extends Think {
async speak() {
await this.runTurn({ input: "Read this out loud", channel: "voice" });
}
}export class Assistant extends Think<Env> {
async speak() {
await this.runTurn({ input: "Read this out loud", channel: "voice" });
}
}轮次内,活动渠道为 this.activeChannel(ChannelContext,含 channelId、kind,相关时有 messenger 详情)。无 channel 的轮次无渠道上下文,不应用渠道策略。
deliverNotice() 向渠道 发送消息而不启动模型轮次。用于状态更新(「你的导入已完成」)或已呈现操作的 回复附件 — 不运行推理、不进入轮次队列,因此可在工具 execute 内安全调用:
export class Assistant extends Think {
async notify() {
await this.deliverNotice("Your export is ready to download.");
await this.deliverNotice("Background research finished.", {
informModel: true, // also record it in the transcript so the next turn knows
});
}
}export class Assistant extends Think<Env> {
async notify() {
await this.deliverNotice("Your export is ready to download.");
await this.deliverNotice("Background research finished.", {
informModel: true, // also record it in the transcript so the next turn knows
});
}
}type DeliverNoticeOptions = {
channel?: string; // defaults to the active turn's channel, else "web"
informModel?: boolean; // also write to the model-visible transcript (default false)
kind?: "final" | "interim" | "notice" | "command"; // wire tag (default "notice")
thread?: string; // required for out-of-turn delivery to a multi-thread messenger
};行为取决于目标渠道:
web— 通知始终追加到对话记录(这是其唯一渲染路径)。informModel仅控制措辞。messenger— 通知发布到提供方。轮次外需传thread定位对话。informModel: true时也会写入对话记录。voice/custom— 带外投递会抛出异常,这些界面尚无投递目标。
重写 renderAttachment(attachment) 将操作回复附件转为通知;Think 在轮次结束时调用,并将渲染文本作为尾随 interim 通知投递。返回 undefined 跳过某附件类型。
configureChannels() 包装 getMessengers() — 不替换。每个 getMessengers() 条目成为 kind: "messenger" 渠道,Messengers 指南中的内容(Telegram 设置、webhook 路由、对话目标、投递与恢复)继续适用。configureChannels() 中与 getMessengers() id 冲突的渠道 id 是错误。仅 messenger 的应用继续用 getMessengers();当你还需要 web/voice/custom 策略或带外通知时用 configureChannels()。
渠道活动报告在 channel 可观测性通道:
import { subscribe } from "agents/observability";
const unsubscribe = subscribe("channel", (event) => {
// event.type is one of:
// "channel:resolved" — a turn resolved a registered channel
// "channel:delivered" — a turn's final reply was delivered
// "notice:delivered" — deliverNotice() succeeded
// "notice:failed" — deliverNotice() threw
});import { subscribe } from "agents/observability";
const unsubscribe = subscribe("channel", (event) => {
// event.type is one of:
// "channel:resolved" — a turn resolved a registered channel
// "channel:delivered" — a turn's final reply was delivered
// "notice:delivered" — deliverNotice() succeeded
// "notice:failed" — deliverNotice() threw
});| 成员 | 描述 |
|---|---|
configureChannels() |
返回渠道映射。默认 {}(仅隐式 web 渠道)。 |
deliverNotice(text, options?) |
向渠道发送带外消息,无模型轮次。 |
activeChannel |
进行中轮次的 ChannelContext,或 undefined。 |
renderAttachment(attachment) |
将回复附件映射为渠道通知文本(或 undefined 跳过)。 |
defineChannels(channels) |
渠道映射类型推断的恒等辅助函数。 |
messengerChannel(definition) |
将 Chat SDK 适配器包装为 kind: "messenger" 渠道。 |
- Messengers — Chat SDK webhook 设置与投递详解。
- 操作 — 为
renderAttachment()记录回复附件。 - 语音 — 实时语音界面。