fix: 给kook适配器实现send_streaming方法(降级到普通文本消息发送)来修复启用了流逝输出后可能llm消息发不出去的bug#7749
fix: 给kook适配器实现send_streaming方法(降级到普通文本消息发送)来修复启用了流逝输出后可能llm消息发不出去的bug#7749shuiping233 wants to merge 1 commit intoAstrBotDevs:masterfrom
send_streaming方法(降级到普通文本消息发送)来修复启用了流逝输出后可能llm消息发不出去的bug#7749Conversation
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- In
send_streaming, you consume thegeneratorand then callsuper().send_streaming(generator, use_fallback)after it’s already exhausted; if the intention is to fully fall back to a single non-streaming send, you should likely return afterawait self.send(buffer)and skip the super call, or rebuild a new generator for the parent call. - The
use_fallbackparameter insend_streamingis currently unused; either wire it into the logic (e.g., conditionally delegating tosuper().send_streaming) or remove it to avoid confusion. - The current approach concatenates the entire streaming content into memory (
buffer.chain.extend(...)), which may be problematic for very long streams; consider either chunked sends or a size guard to prevent unbounded accumulation.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `send_streaming`, you consume the `generator` and then call `super().send_streaming(generator, use_fallback)` after it’s already exhausted; if the intention is to fully fall back to a single non-streaming send, you should likely return after `await self.send(buffer)` and skip the super call, or rebuild a new generator for the parent call.
- The `use_fallback` parameter in `send_streaming` is currently unused; either wire it into the logic (e.g., conditionally delegating to `super().send_streaming`) or remove it to avoid confusion.
- The current approach concatenates the entire streaming content into memory (`buffer.chain.extend(...)`), which may be problematic for very long streams; consider either chunked sends or a size guard to prevent unbounded accumulation.
## Individual Comments
### Comment 1
<location path="astrbot/core/platform/sources/kook/kook_event.py" line_range="225-226" />
<code_context>
+ if not buffer:
+ return None
+ buffer.squash_plain()
+ await self.send(buffer)
+ return await super().send_streaming(generator, use_fallback)
</code_context>
<issue_to_address>
**issue (bug_risk):** Avoid double-processing and using an already-consumed generator in `send_streaming`.
Here the generator is fully consumed into `buffer`, sent once via `self.send(buffer)`, and then passed to `super().send_streaming(generator, use_fallback)` after it is already exhausted. This makes the superclass call effectively a no-op or fragile if it expects a fresh stream, and risks duplicate or inconsistent output if it also sends content.
Given the docstring that KOOK does not support streaming and this method should fall back to a normal `send`, consider either:
- Only aggregating and calling `await self.send(buffer)` (remove the `super().send_streaming` call), or
- Skipping manual aggregation and just `return await super().send_streaming(generator, use_fallback)` if the base class already provides the fallback.
This avoids using an exhausted generator and prevents double-sending.
</issue_to_address>
### Comment 2
<location path="astrbot/core/platform/sources/kook/kook_event.py" line_range="218-219" />
<code_context>
+ """KOOK 平台不支持流式输出, 调用此方法将回退到普通`send`方法"""
+ buffer = None
+ async for chain in generator:
+ if not buffer:
+ buffer = chain
+ else:
+ buffer.chain.extend(chain.chain)
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Use explicit `is None` check for `buffer` to avoid relying on `MessageChain` truthiness.
Since `buffer` starts as `None`, using `if not buffer:` will also trigger if `MessageChain` is a valid but falsy value (e.g., empty if it implements `__bool__`/`__len__`). That changes behavior between `None` and an empty chain. Use `if buffer is None:` to distinguish the initial state from an empty `MessageChain` and make the intent explicit.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| await self.send(buffer) | ||
| return await super().send_streaming(generator, use_fallback) |
There was a problem hiding this comment.
issue (bug_risk): Avoid double-processing and using an already-consumed generator in send_streaming.
Here the generator is fully consumed into buffer, sent once via self.send(buffer), and then passed to super().send_streaming(generator, use_fallback) after it is already exhausted. This makes the superclass call effectively a no-op or fragile if it expects a fresh stream, and risks duplicate or inconsistent output if it also sends content.
Given the docstring that KOOK does not support streaming and this method should fall back to a normal send, consider either:
- Only aggregating and calling
await self.send(buffer)(remove thesuper().send_streamingcall), or - Skipping manual aggregation and just
return await super().send_streaming(generator, use_fallback)if the base class already provides the fallback.
This avoids using an exhausted generator and prevents double-sending.
| if not buffer: | ||
| buffer = chain |
There was a problem hiding this comment.
suggestion (bug_risk): Use explicit is None check for buffer to avoid relying on MessageChain truthiness.
Since buffer starts as None, using if not buffer: will also trigger if MessageChain is a valid but falsy value (e.g., empty if it implements __bool__/__len__). That changes behavior between None and an empty chain. Use if buffer is None: to distinguish the initial state from an empty MessageChain and make the intent explicit.
There was a problem hiding this comment.
Code Review
This pull request implements the send_streaming method for the KOOK platform. Since KOOK does not natively support streaming, the implementation aggregates chunks from an asynchronous generator into a single message buffer before sending. A review comment correctly identified a logic error where the generator is exhausted during aggregation, making the subsequent call to the superclass method with the same generator ineffective.
| await self.send(buffer) | ||
| return await super().send_streaming(generator, use_fallback) |
There was a problem hiding this comment.
在此处调用 super().send_streaming(generator, use_fallback) 是不正确的,因为 generator 已经在前面的 async for 循环中被完全耗尽(exhausted)。父类方法将接收到一个空的生成器,这可能导致预期的逻辑(如指标统计或默认处理)失效。由于你已经通过 await self.send(buffer) 发送了聚合后的消息,且 self.send 内部已经调用了 super().send() 来处理通用的发送逻辑(如指标上报),因此这里不需要再调用父类的流式发送方法。
| await self.send(buffer) | |
| return await super().send_streaming(generator, use_fallback) | |
| await self.send(buffer) |
Modifications / 改动点
如题,我看到别的适配器里也有这么做的,那我就抄来了)
相关issue:
Screenshots or Test Results / 运行截图或测试结果
Checklist / 检查清单
😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
/ 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in
requirements.txtandpyproject.toml./ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到
requirements.txt和pyproject.toml文件相应位置。😮 My changes do not introduce malicious code.
/ 我的更改没有引入恶意代码。