fix(weixin): chunk long replies for iLink limits

This commit is contained in:
cuidong233 2026-08-24 12:20:07 +08:00
parent dea9a8f2d1
commit 868372fb04
5 changed files with 36 additions and 4 deletions

View file

@ -46,7 +46,7 @@ Connect IM bots to DeepSeek Harness by scanning a QR code, using an App Manifest
| Channel | Setup | Messaging and replies |
| --- | --- | --- |
| Feishu | Create a bot by QR code, or bind one with App ID + App Secret | Persistent connection for incoming messages; streaming cards show thinking, tool progress, and replies |
| WeChat | Scan a QR code to bind a WeChat bot | Tencent iLink long polling for sending and receiving messages |
| WeChat | Scan a QR code to bind a WeChat bot | Tencent iLink long polling for sending and receiving messages; long replies are sent in 1,800-character chunks |
| DingTalk | Create a bot by QR code, or bind one with Client ID + Client Secret | DingTalk Stream connection; streaming replies through AI Cards |
| WeCom | Create an intelligent bot by QR code, or bind one with Bot ID + Secret | Official WebSocket connection; native thinking state, tool progress, and streaming replies |
| QQ | Create a bot with mobile QQ QR scanning, or bind one with AppID + AppSecret | WebSocket connection; private chats show typing and receive one Markdown reply, while mentioned group chats receive only the final answer |

View file

@ -49,7 +49,7 @@ Connect IM bots to DeepSeek Harness by scanning a QR code, using an App Manifest
| 渠道 | 接入方式 | 消息与回复 |
| --- | --- | --- |
| 飞书 | 扫码创建机器人,或使用 App ID + App Secret 手动绑定 | 长连接接收消息;通过飞书流式卡片显示思考、工具进度和回答 |
| 微信 | 使用微信扫码绑定机器人 | 腾讯 iLink 长轮询收发消息 |
| 微信 | 使用微信扫码绑定机器人 | 腾讯 iLink 长轮询收发消息;长回复会按 1,800 字符分段发送 |
| 钉钉 | 扫码创建机器人,或使用 Client ID + Client Secret 手动绑定 | 钉钉 Stream 长连接;通过 AI Card 流式显示回答 |
| 企业微信 | 使用企业微信 App 扫码创建智能机器人,或使用 Bot ID + Secret 手动绑定 | 官方 WebSocket 长连接;原生显示“正在思考中”、工具执行进度和流式回答 |
| QQ | 使用手机 QQ 扫码创建机器人,或使用 AppID + AppSecret 手动绑定 | WebSocket 长连接;私聊显示“正在输入”并以单条 Markdown 回复,群聊被 @ 后只发送最终答案 |

File diff suppressed because one or more lines are too long

View file

@ -184,7 +184,7 @@ export class WeixinHarnessBridge {
status = createWeixinBridgeStatus(),
logger = console,
replyTimeoutMs = 600_000,
maxMessageChars = 4_000,
maxMessageChars = 1_800,
signal,
}) {
if (!api || typeof api.sendText !== 'function') throw new TypeError('Weixin API is required');

View file

@ -150,6 +150,38 @@ test('Weixin bridge hands a native file source to the current Harness turn', asy
assert.deepEqual(sent, ['文件已收到']);
});
test('Weixin splits long replies below the iLink text limit', async () => {
const fixture = stateFixture();
fixture.sessions.set('p2p:owner-user', 'session-long-reply');
const chunks = [];
const answer = '答案'.repeat(1_000);
const bridge = new WeixinHarnessBridge({
api: {
sendText: async ({ text }) => {
chunks.push(text);
return { messageId: `weixin-long-${chunks.length}` };
},
},
baseUrl: 'https://ilinkai.weixin.qq.com',
token: 'token',
ownerUserId: 'owner-user',
harness: {
sessionExists: async () => true,
ask: async () => answer,
},
state: fixture.state,
});
const receipt = await bridge.accept(message('weixin-long-reply', '生成一段长回答'));
assert.ok(chunks.length > 1);
assert.ok(chunks.every((chunk) => chunk.length <= 1_800));
assert.equal(chunks.join(''), answer);
assert.equal(receipt.providerMessageIds.length, chunks.length);
assert.equal(bridge.status.messagesReplied, 1);
assert.equal(bridge.status.lastMessageError, null);
});
test('Weixin starts a native-file download before an earlier queued turn finishes', async () => {
const fixture = stateFixture();
fixture.sessions.set('p2p:owner-user', 'session-prefetch-file');