← Создание агентов на Cloudflare / agents / harnesses / think
Каналы
Канал представляет собой способ связи, через который агент Think общается: WebSocket браузера, webhook мессенджера (Telegram, Slack и так далее), голос или ваш собственный транспорт. Каналы обобщают мессенджеры в единый словарь, чтобы можно было применять политику для каждого канала (другой системный промпт, суженный набор инструментов, ограничение числа шагов) и доставлять уведомления out-of-band независимо от того, через какую поверхность пришёл ход.
У каждого Think agent всегда есть неявный web канал (WebSocket-чат, которым пользуются ваши клиенты в браузере). Дополнительные каналы вы объявляете, а также переопределяете web политику: с configureChannels(). Messenger, возвращённые из getMessengers() автоматически поглощаются как messenger каналы, поэтому существующие приложения-мессенджеры продолжают работать без изменений.
Настройка каналов
Переопределить configureChannels() чтобы вернуть отображение идентификатора канала на 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 */
}),
),
};
}
}A ChannelDefinition содержит следующие поля:
| Поле | Тип | Описание |
|---|---|---|
kind |
"web" | "messenger" | "voice" | "custom" |
Категория поверхности. |
ingress |
{ transport: "websocket" | "voice" } или спецификацию мессенджера webhook |
Как поступают ходы. messengerChannel() формирует форму webhook за вас. |
instructions |
string | (ctx: ChannelContext) => string | Promise<string> |
Добавляется в начало системного промпта для ходов в этом канале. |
tools |
(all: ToolSet) => ToolSet |
Сузьте собранный набор инструментов для этого канала (только фильтрация, инструменты добавлять нельзя). |
maxTurns |
number |
Ограничение числа шагов модели на канал за один ход. |
capabilities |
ChannelCapabilities |
Отображаемые возможности (потоковая передача, редактирование сообщений). По умолчанию для web. |
conversation |
режим переписки в мессенджере или resolver | Маршрутизация тредов мессенджера (см. Мессенджеры). |
delivery |
политика доставки канала | Политика доставки мессенджера. |
Используйте defineChannels() вспомогательную функцию для вывода типов и messengerChannel() чтобы обернуть определение адаптера Chat SDK как kind: "messenger" канал.
Типы каналов
| Тип | Ingress | Примечания |
|---|---|---|
web |
{ transport: "websocket" } |
Всегда присутствует. Объявите его в configureChannels() только для установки политики; удалить её нельзя. |
messenger |
вебхук (messengerChannel(...)) |
Передаётся в рантайм messenger. Эквивалентно getMessengers() запись. |
voice |
{ transport: "voice" } |
Применяет политику и контекст хода; доставка out-of-band пока не подключена. |
custom |
определяется приложением | Для собственного транспорта. Те же ограничения доставки, что и у voice сегодня. |
Политика для отдельных каналов
Политика канала применяется как переопределяемое значение по умолчанию перед beforeTurn выполняется, поэтому beforeTurn переопределение всё равно имеет приоритет:
instructionsдобавляется перед базовым системным промптом для этого хода.toolsфильтрует собранный набор инструментов (он может только убирать инструменты:getTools()seam добавляет их).maxTurnsограничивает количество шагов модели:beforeTurn:maxStepsпобеждает, тогда каналmaxTurns, затем экземплярmaxStepsпо умолчанию.
Выберите канал для хода
Передайте channel к runTurn() (или chat()) для запуска хода в определённом канале. 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, и подробности мессенджера, если это уместно). Ход без 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" канал и всё, что в Мессенджеры руководство (настройка Telegram, маршрутизация вебхуков, цели диалогов, доставка и восстановление) продолжает действовать. ID канала в configureChannels() который конфликтует с getMessengers() id является ошибкой. Продолжайте использовать getMessengers() для приложений только для мессенджеров; используйте configureChannels() когда вам также нужен web/voice/custom политику или уведомления out-of-band.
Observability
Активность канала отображается на 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?) |
Отправьте сообщение out-of-band в канал без хода модели. |
activeChannel |
ChannelContext для выполняющегося хода, либо undefined. |
renderAttachment(attachment) |
Сопоставить вложение ответа с текстом уведомления канала (или undefined чтобы пропустить). |
defineChannels(channels) |
Вспомогательная функция идентификации для вывода типа channel-map. |
messengerChannel(definition) |
Оберните адаптер Chat SDK как kind: "messenger" канал. |
См. также
- Мессенджеры : Подробно о настройке и доставке вебхуков Chat SDK.
- Действия : записывает вложения ответа для
renderAttachment(). - Голос : поверхности для речи в реальном времени.