消息路由
消息路由层负责将 Agent 的回复通过正确的通道、以正确的格式、在正确的限制内投递给用户。
出站投递流程
Source: src/infra/outbound/deliver.ts
Channel Handler
typescript
// src/infra/outbound/deliver.ts (simplified)
interface OutboundSendDeps {
sendWhatsApp: SendFunction;
sendTelegram: SendFunction;
sendDiscord: SendFunction;
sendSlack: SendFunction;
sendSignal: SendFunction;
sendIMessage: SendFunction;
// ...
}
function createChannelHandler(channel: string) {
return {
chunker: resolveChunker(channel), // Text splitting function
chunkerMode: resolveChunkerMode(channel), // "text" | "markdown"
textChunkLimit: resolveChunkLimit(channel),
sendText: (opts) => /* ... */,
sendMedia: (opts) => /* ... */,
sendPayload: (opts) => /* ... */,
};
}每个通道的 handler 包含:
| 属性 | 说明 |
|---|---|
chunker | 文本分块函数(null = 不分块) |
chunkerMode | 分块模式:"text" 或 "markdown" |
textChunkLimit | 单条消息最大字符数 |
sendText() | 发送纯文本 |
sendMedia() | 发送媒体附件 |
sendPayload() | 发送结构化内容 |
分块策略
Source: src/auto-reply/chunk.ts
长消息需要拆分成多条发送。分块策略分两种:
文本分块
typescript
// Simple text chunking
function chunkByParagraph(text: string, limit: number): string[] {
// Split by paragraphs
// Respect limit per chunk
// Avoid splitting mid-sentence
}Markdown 分块
typescript
// Markdown-aware chunking
function chunkMarkdownTextWithMode(
text: string,
limit: number,
mode: "text" | "markdown"
): string[] {
// Preserve code blocks across chunks
// Keep link syntax intact
// Maintain list structure
// Handle heading boundaries
}Markdown 分块更智能,会:
- 不在
```代码块中间断开 - 不在
[link](url)中间断开 - 在段落或标题边界处优先断开
- 保持列表的连续性
各通道限制
| 通道 | 文本限制 | 分块模式 |
|---|---|---|
| Telegram | 4000 字符 | markdown |
| Discord | 2000 字符 | markdown |
| 因平台而异 | text | |
| Slack | 因配置而异 | markdown |
| Signal | 因平台而异 | text |
| iMessage | 因平台而异 | text |
幂等性
Source: src/gateway/server-methods/send.ts
消息发送支持幂等性去重,防止网络重试导致的重复消息:
typescript
// Idempotency deduplication
if (idempotencyKey && seen.has(idempotencyKey)) {
return respond(true, seen.get(idempotencyKey));
}出站依赖桥接
Source: src/cli/deps.ts
CLI 层的依赖通过 createOutboundSendDeps() 桥接到基础设施层:
typescript
// src/cli/deps.ts (simplified)
interface CliDeps {
sendMessageWhatsApp: SendFunction;
sendMessageTelegram: SendFunction;
sendMessageDiscord: SendFunction;
sendMessageSlack: SendFunction;
sendMessageSignal: SendFunction;
sendMessageIMessage: SendFunction;
}
function createDefaultDeps(): CliDeps {
// Create concrete implementations
}
function createOutboundSendDeps(deps: CliDeps): OutboundSendDeps {
// Bridge CLI deps → infra OutboundSendDeps
}这种桥接模式让 CLI 和基础设施层可以独立测试。
小结
deliverOutboundPayloads()是出站投递的统一入口- 每个通道通过
createChannelHandler()提供发送函数和分块策略 - 分块策略分 text 和 markdown 两种模式,Markdown 模式保持语法完整性
- 幂等性去重 通过
idempotencyKey缓存防止重复消息 - CLI 依赖通过 桥接模式 连接到基础设施层
下一章:Agent 概述