feat(qqbot): group chat support, C2C streaming, chunked media upload, and architecture refactor#70624
Conversation
Greptile SummaryThis PR adds group chat support, C2C streaming delivery, chunked media upload, and a significant architectural refactor to The Confidence Score: 5/5Safe to merge; all remaining findings are P2 style/improvement suggestions with no blocking defects. No P0 or P1 issues found. The three comments are P2: a FIFO ordering note for mixed command+chat batches (by-design behavior), synchronous file I/O on the activation reader (acknowledged in comments, acceptable for current scale), and Chinese-language comments in an otherwise English codebase. The new code is well-tested and the refactor is purely structural where claimed. extensions/qqbot/src/engine/messaging/streaming-c2c.ts (1190 LOC, Chinese comments) and extensions/qqbot/src/engine/gateway/message-queue.ts (drainGroupBatch ordering) deserve a close read by a reviewer familiar with QQ Bot group semantics. Prompt To Fix All With AIThis is a comment left during a code review.
Path: extensions/qqbot/src/engine/gateway/message-queue.ts
Line: 296-320
Comment:
**Command ordering breaks FIFO within a mixed batch**
In `drainGroupBatch`, all slash commands are drained from the batch first and processed before any normal messages, regardless of their original position in the queue. For example, a burst of `[normal1, /stop, normal2]` is processed as `[/stop, merged(normal1+normal2)]`. A `/stop` or `/config` that arrived after conversational context runs before that context reaches the AI — which can cause the command to operate on stale state.
If preserving insertion order matters for command–message interleaving (e.g. "run /setup, then respond to 'hello'"), consider a strict FIFO pass where each message is processed in sequence, or at minimum process commands after the normal messages that preceded them in the queue.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/qqbot/src/engine/group/activation.ts
Line: 127-145
Comment:
**Synchronous file I/O on every group message**
`createNodeSessionStoreReader` calls `fs.existsSync` + `fs.readFileSync` synchronously on the Node.js event loop on every inbound group message. The inline comment acknowledges this but dismisses it as "acceptable." For a high-traffic group or large sessions file, repeated sync I/O will block the event loop and delay all other pending work.
Consider caching the parsed result with a short TTL (e.g. 1–2 seconds), using `fs.promises` with a try/catch, or accepting the stat-then-read race in exchange for non-blocking behavior.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/qqbot/src/engine/messaging/streaming-c2c.ts
Line: 1-20
Comment:
**Chinese-language comments in an English codebase**
`streaming-c2c.ts` (1190 LOC) contains extensive inline comments written in Chinese, including the module-level docblock, most section headings, and inline annotations throughout the `FlushController` and `StreamingController` classes. The rest of the codebase and all other files in this PR use English.
This creates a documentation split that makes the file significantly harder for non-Chinese-speaking contributors to review, debug, or maintain. Consider translating the comments to English to stay consistent with the project's documentation language.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "feat(qqbot): enhance account management ..." | Re-trigger Greptile |
| * | ||
| * For group peers we prefer to drop a bot-authored message so human | ||
| * input never gets lost. Falling back to dropping the oldest keeps the | ||
| * queue bounded when all members are bots. | ||
| */ | ||
| const evictOne = (queue: QueuedMessage[], isGroup: boolean): QueuedMessage | undefined => { | ||
| if (isGroup) { | ||
| const botIdx = queue.findIndex((m) => m.senderIsBot); | ||
| if (botIdx >= 0) { | ||
| return queue.splice(botIdx, 1)[0]; | ||
| } | ||
| } | ||
| return queue.shift(); | ||
| }; | ||
|
|
||
| /** Run a single message, capturing errors in the log. */ | ||
| const processOne = async (msg: QueuedMessage, peerId: string, label: string): Promise<void> => { | ||
| try { | ||
| await handleMessageFnRef!(msg); | ||
| } catch (err) { | ||
| log?.error(`${label} error for ${peerId}: ${formatErrorMessage(err)}`); | ||
| } | ||
| }; | ||
|
|
||
| /** |
There was a problem hiding this comment.
Command ordering breaks FIFO within a mixed batch
In drainGroupBatch, all slash commands are drained from the batch first and processed before any normal messages, regardless of their original position in the queue. For example, a burst of [normal1, /stop, normal2] is processed as [/stop, merged(normal1+normal2)]. A /stop or /config that arrived after conversational context runs before that context reaches the AI — which can cause the command to operate on stale state.
If preserving insertion order matters for command–message interleaving (e.g. "run /setup, then respond to 'hello'"), consider a strict FIFO pass where each message is processed in sequence, or at minimum process commands after the normal messages that preceded them in the queue.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/qqbot/src/engine/gateway/message-queue.ts
Line: 296-320
Comment:
**Command ordering breaks FIFO within a mixed batch**
In `drainGroupBatch`, all slash commands are drained from the batch first and processed before any normal messages, regardless of their original position in the queue. For example, a burst of `[normal1, /stop, normal2]` is processed as `[/stop, merged(normal1+normal2)]`. A `/stop` or `/config` that arrived after conversational context runs before that context reaches the AI — which can cause the command to operate on stale state.
If preserving insertion order matters for command–message interleaving (e.g. "run /setup, then respond to 'hello'"), consider a strict FIFO pass where each message is processed in sequence, or at minimum process commands after the normal messages that preceded them in the queue.
How can I resolve this? If you propose a fix, please make it concise.| * the sessions file is typically a handful of kilobytes. | ||
| * | ||
| * Any I/O or JSON error is swallowed and returned as `null` so the | ||
| * gating pipeline falls back to the config default. | ||
| */ | ||
| export function createNodeSessionStoreReader(): SessionStoreReader { | ||
| return { | ||
| read: ({ cfg, agentId }) => { | ||
| try { | ||
| const storePath = resolveSessionStorePath(cfg, agentId); | ||
| if (!fs.existsSync(storePath)) { | ||
| return null; | ||
| } | ||
| const raw = fs.readFileSync(storePath, "utf-8"); | ||
| return JSON.parse(raw) as Record<string, { groupActivation?: string }>; | ||
| } catch { | ||
| return null; | ||
| } | ||
| }, |
There was a problem hiding this comment.
Synchronous file I/O on every group message
createNodeSessionStoreReader calls fs.existsSync + fs.readFileSync synchronously on the Node.js event loop on every inbound group message. The inline comment acknowledges this but dismisses it as "acceptable." For a high-traffic group or large sessions file, repeated sync I/O will block the event loop and delay all other pending work.
Consider caching the parsed result with a short TTL (e.g. 1–2 seconds), using fs.promises with a try/catch, or accepting the stat-then-read race in exchange for non-blocking behavior.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/qqbot/src/engine/group/activation.ts
Line: 127-145
Comment:
**Synchronous file I/O on every group message**
`createNodeSessionStoreReader` calls `fs.existsSync` + `fs.readFileSync` synchronously on the Node.js event loop on every inbound group message. The inline comment acknowledges this but dismisses it as "acceptable." For a high-traffic group or large sessions file, repeated sync I/O will block the event loop and delay all other pending work.
Consider caching the parsed result with a short TTL (e.g. 1–2 seconds), using `fs.promises` with a try/catch, or accepting the stat-then-read race in exchange for non-blocking behavior.
How can I resolve this? If you propose a fix, please make it concise.| /** | ||
| * QQ Bot 流式消息控制器(简化版) | ||
| * | ||
| * 核心原则: | ||
| * 1. 绝对不修改原始内容(不 trim、不 strip),避免 PREFIX MISMATCH | ||
| * 2. 媒体标签同步等待发送完成 | ||
| * 3. 碰到富媒体标签(包括未闭合前缀)时,先终结当前流式会话再处理 | ||
| * 4. 纯空白分片处理: | ||
| * - 首分片空白 → 暂停发送(不开启流式),但内容保留 | ||
| * - 被媒体标签打断或结束时,如果还都是空白 → 不发送 | ||
| * - 结束时已有活跃流式会话(之前有非空白分片)→ 可以发送当前空白分片 | ||
| * 5. 回复边界检测:通过前缀匹配判断(而非仅长度缩短), | ||
| * 如果新文本不是上次处理文本的前缀延续,视为新消息 | ||
| */ | ||
|
|
||
| import { getNextMsgSeq } from "../api/routes.js"; | ||
| import type { GatewayAccount } from "../types.js"; | ||
| import { | ||
| StreamInputMode, | ||
| StreamInputState, |
There was a problem hiding this comment.
Chinese-language comments in an English codebase
streaming-c2c.ts (1190 LOC) contains extensive inline comments written in Chinese, including the module-level docblock, most section headings, and inline annotations throughout the FlushController and StreamingController classes. The rest of the codebase and all other files in this PR use English.
This creates a documentation split that makes the file significantly harder for non-Chinese-speaking contributors to review, debug, or maintain. Consider translating the comments to English to stay consistent with the project's documentation language.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/qqbot/src/engine/messaging/streaming-c2c.ts
Line: 1-20
Comment:
**Chinese-language comments in an English codebase**
`streaming-c2c.ts` (1190 LOC) contains extensive inline comments written in Chinese, including the module-level docblock, most section headings, and inline annotations throughout the `FlushController` and `StreamingController` classes. The rest of the codebase and all other files in this PR use English.
This creates a documentation split that makes the file significantly harder for non-Chinese-speaking contributors to review, debug, or maintain. Consider translating the comments to English to stay consistent with the project's documentation language.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d793a3037a
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
|
||
| return { | ||
| type: last.type, | ||
| senderId: last.senderId, |
There was a problem hiding this comment.
Preserve sender identity when merging group batches
This merged turn always takes senderId from the last message, even when batch contains multiple different senders. Downstream access control (runAccessStage) authorizes by event.senderId, so in groupAllowFrom mode an unauthorized member's earlier message can be merged into an authorized member's later message and still be processed by the model/history path. Split merges by sender (or re-run access checks per source message) before constructing a single queued event.
Useful? React with 👍 / 👎.
| for (const cmd of commands) { | ||
| log?.debug?.( | ||
| `Processing command independently for ${peerId}: ${(cmd.content ?? "").trim().slice(0, 50)}`, | ||
| ); | ||
| await processOne(cmd, peerId, "Command processor"); |
There was a problem hiding this comment.
Keep group command execution in FIFO arrival order
Commands are drained first for the whole batch, and only then are non-command messages merged and processed. That reorders mixed batches (e.g. normal text followed by /stop gets executed as /stop first), which changes command semantics and can apply control actions to the wrong logical turn. Preserve original queue order by processing ordered segments instead of globally prioritizing commands.
Useful? React with 👍 / 👎.
| const maxConcurrent = Math.min( | ||
| prepareResp.concurrency ? prepareResp.concurrency : DEFAULT_CONCURRENT_PARTS, | ||
| MAX_CONCURRENT_PARTS, | ||
| ); |
There was a problem hiding this comment.
Clamp server-provided part concurrency to >= 1
prepareResp.concurrency is only capped with Math.min, so negative values are accepted. The limiter loop uses i += maxConcurrent; a non-positive value prevents progress and can hang chunked uploads indefinitely. Guard this with a lower bound (e.g. Math.max(1, ...)) before calling runWithConcurrency.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9879eae3e0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const commandAuthorized = | ||
| deps.allowTextCommands !== false && isSenderAllowedForCommands(event.senderId, deps); |
There was a problem hiding this comment.
Derive group command bypass auth from access decision
runGroupGateStage recomputes commandAuthorized from allowFrom via isSenderAllowedForCommands, instead of using the access-stage policy result that later populates inbound.commandAuthorized (resolveCommandAuthorized in access-stage.ts). In groupPolicy=open with an empty allowFrom, this marks any sender as authorized for bypass, so /... messages can skip mention-gating without @bot and still enter downstream processing even though command execution is unauthorized. Use the same access-derived authorization in both places to avoid this policy split.
Useful? React with 👍 / 👎.
| const channels = (cfg.channels ?? {}) as Record<string, unknown>; | ||
| const qqbot = (channels.qqbot ?? {}) as Record<string, unknown>; |
There was a problem hiding this comment.
Persist created qqbot config objects before mutation
applyRequireMentionUpdate initializes channels/qqbot with ?? {} but never writes those objects back to cfg, so when either cfg.channels or channels.qqbot is missing, mutations happen on detached temporaries and the interaction update is silently dropped despite changed=true. This makes /claw_cfg require-mention updates no-op for valid runtime setups that rely on env-provided accounts or sparse config files.
Useful? React with 👍 / 👎.
9879eae to
0617ba7
Compare
0617ba7 to
ce90112
Compare
|
Codex automated review: keeping this open. Keep this PR open. Current main has QQBot group @message, media, logs, and storage groundwork, but it does not already contain the PR's central changes: non-@ group-message ingestion/history/activation, official C2C stream_messages delivery, chunked upload dispatch, or the broad adapter/pipeline refactor. The PR is in-repo bundled QQBot plugin work, but it is large and still needs maintainer review, security review, and likely splitting before merge. Best possible solution: Keep this PR open for maintainer review, but ask the contributor to rebase on current main, resolve the P1/P2 review findings, and split the work into smaller reviewable PRs: chunked upload, official C2C streaming, group-message/history behavior, remote config/commands, and mechanical adapter/pipeline refactor. If maintainers only want the behavior, preserve those pieces without forcing the full refactor into one merge. What I checked:
Remaining risk / open question:
Codex Review notes: model gpt-5.5, reasoning high; reviewed against a35ad200d1d1. |
2f1198d to
4f1eb23
Compare
…unked upload support This commit enhances the media upload functionality by introducing a unified `sendMedia` method that consolidates the previous separate methods for sending images, voice messages, videos, and files. Key changes include: - Added `uploadChunked` function for future chunked media uploads, currently marked as not implemented. - Introduced `MediaSource` abstraction to handle various media types (URLs, base64, local files, buffers) uniformly. - Updated existing media handling logic to utilize the new `sendMedia` method, ensuring consistent media processing across different types. - Enhanced error handling and validation for media uploads, including MIME type checks and file size limits. These changes aim to streamline the media upload process and prepare for future enhancements in handling larger files through chunked uploads.
…pport This commit updates the media upload functionality by implementing chunked upload support for larger files. Key changes include: - Revised the `SKILL.md` documentation to clarify media file size limits and local file path requirements. - Introduced a new test suite for the chunked media upload functionality, ensuring robust error handling and upload processes. - Updated the media handling logic to enforce per-file-type upload ceilings, allowing for seamless integration of chunked uploads. - Enhanced error handling for daily upload limits, providing user-friendly messages when limits are exceeded. These improvements aim to streamline the media upload process and accommodate larger files effectively.
This commit introduces support for the QQ C2C official `stream_messages` API, enabling single-message typing-style updates. Key changes include: - Updated the configuration schema to include a new `c2cStreamApi` boolean option for enabling the C2C streaming API. - Enhanced the `QQBotAccountConfig` interface to accommodate the new streaming option. - Implemented a `StreamingController` to manage the lifecycle of C2C stream messages, ensuring proper handling of media tags and message boundaries. - Updated the outbound dispatch logic to utilize the new streaming capabilities, allowing for more dynamic message delivery in one-to-one chats. These enhancements aim to improve the responsiveness and interactivity of message delivery within the QQBot framework.
…ecture - Implement group message history tracking with pending history buffer (record on skip, render on @-mention reply) - Add mention detection and gating: explicit @bot, implicit quote-reply, ignoreOtherMentions, configurable activation mode (mention/always) - Add group activation resolution with session store persistence - Add message queue with per-peer FIFO and group message merging (batch multiple rapid messages into one merged payload) - Add deliver debounce to merge rapid outbound text bursts into single messages, with media flush and maxWait cap - Add group config resolution: per-group prompt, history limit, wildcard and specific group overrides - Enrich history attachments with local paths from processAttachments so that history context renders downloaded paths instead of ephemeral QQ CDN URLs - Merge ports/ directory into adapter/ as single entry point - Expand EngineAdapters to 5 required ports: history, mentionGate, audioConvert, outboundAudio, commands - Remove global register/get singletons in favor of constructor injection and one-time init - Add createEngineAdapters() in bridge/gateway.ts as single assembly point - Extract monolithic buildInboundContext into 11 discrete stages: access, content, quote, refidx, group-gate, envelope, assembly - Extract group chat modules: history, mention, activation, message-gating, deliver-debounce - Extract config/group.ts, utils/attachment-tags.ts
…trol This commit introduces the `/bot-streaming` command, allowing users to enable or disable streaming for message delivery in C2C chats. Key changes include: - Implementation of the `isStreamingConfigEnabled` function to check the current streaming configuration. - Command handler for `/bot-streaming` that provides usage instructions and manages the streaming state. - Updates to the command's response messages to inform users of the current streaming status and how to toggle it. These enhancements aim to improve user experience by providing a straightforward way to manage streaming message delivery in private chats.
…update support - Extract INTERACTION_CREATE handler from gateway.ts into a dedicated interaction-handler.ts module for better separation of concerns - Add config query (type=2001) and config update (type=2002) interaction branches that read/write claw_cfg via runtime.config API - Register INTERACTION intent (1<<26) in FULL_INTENTS to receive INTERACTION_CREATE events from the gateway - Add InteractionType constants (CONFIG_QUERY, CONFIG_UPDATE) - Extend GatewayPluginRuntime with optional config API (loadConfig, writeConfigFile) for interaction handler access - Add QQBotAccountConfigView interface for typed config field access - Extend acknowledgeInteraction to accept optional data payload for rich ACK responses (e.g. claw_cfg snapshot) - Export getFrameworkVersion from slash-commands-impl for version reporting in config snapshots - Remove unused eslint-disable directive in streaming-media-send.ts
- Introduced `toGatewayAccount` function to map resolved QQBot accounts to the engine's gateway account structure. - Added `persistAccountCredentialSnapshot` function to streamline credential backup during gateway events. - Updated the `qqbotPlugin` to utilize the new account mapping and credential persistence functions, improving the handling of account data. - Enhanced logging functionality by modifying the `EngineLogger` interface to support metadata in log messages. - Implemented new commands for managing logs and clearing storage, providing users with better control over their data and system resources. - Registered multiple built-in commands for improved user interaction, including `/bot-logs` for exporting logs and `/bot-clear-storage` for managing downloaded files. - Updated configuration schemas to reflect new options and improve clarity for users.
- Replace unnecessary `else` after `return` in outbound-media-send.ts (6 occurrences) - Use `Number.parseInt` instead of global `parseInt` in outbound.ts and streaming-media-send.ts - Use `Number.isNaN` instead of global `isNaN` in register-basic.ts - Prefer `**` over `Math.pow` in media-chunked.ts - Convert interface with call signature to function type in commands.port.ts - Update api-client.ts allowlist line number (108→124) and add media-chunked.ts:552 to raw-fetch allowlist
- inbound-attachments.test: replace removed registerAudioConvertAdapter with AudioConvertPort, pass audioConvert in ProcessContext - inbound-pipeline.self-echo.test: add required adapters field to InboundPipelineDeps mock (history, mentionGate, audioConvert, outboundAudio, commands) - outbound-dispatch.test: add required skipped field to InboundContext
- inbound-pipeline.self-echo.test: self-echo blocking was moved upstream; update test to expect non-blocked pipeline behavior - outbound-dispatch.test: TTS voice path now uses unified sendMedia instead of sendVoiceMessage; add sendMedia mock and update assertion - format-ref-entry.test: attachment format changed from [image: ...] to MEDIA: tag syntax via renderAttachmentTags; update expected output
…eConfigFile
Replace all usages of deprecated runtime config methods:
- loadConfig() → current()
- writeConfigFile(cfg) → replaceConfigFile({ nextConfig, afterWrite })
Updated files:
- bridge/narrowing.ts: writeOpenClawConfigThroughRuntime
- adapter/commands.port.ts: ApproveRuntimeGetter type signature
- commands/builtin/register-approve.ts: loadExecConfig, writeExecConfig, reset
- commands/builtin/register-streaming.ts: config read/write
- gateway/interaction-handler.ts: config query/update handlers
- gateway/types.ts: GatewayPluginRuntime.config interface
… and architecture refactor (openclaw#70624) * feat(qqbot): implement unified media upload handling and introduce chunked upload support This commit enhances the media upload functionality by introducing a unified `sendMedia` method that consolidates the previous separate methods for sending images, voice messages, videos, and files. Key changes include: - Added `uploadChunked` function for future chunked media uploads, currently marked as not implemented. - Introduced `MediaSource` abstraction to handle various media types (URLs, base64, local files, buffers) uniformly. - Updated existing media handling logic to utilize the new `sendMedia` method, ensuring consistent media processing across different types. - Enhanced error handling and validation for media uploads, including MIME type checks and file size limits. These changes aim to streamline the media upload process and prepare for future enhancements in handling larger files through chunked uploads. * feat(qqbot): enhance media upload capabilities with chunked upload support This commit updates the media upload functionality by implementing chunked upload support for larger files. Key changes include: - Revised the `SKILL.md` documentation to clarify media file size limits and local file path requirements. - Introduced a new test suite for the chunked media upload functionality, ensuring robust error handling and upload processes. - Updated the media handling logic to enforce per-file-type upload ceilings, allowing for seamless integration of chunked uploads. - Enhanced error handling for daily upload limits, providing user-friendly messages when limits are exceeded. These improvements aim to streamline the media upload process and accommodate larger files effectively. * feat(qqbot): add C2C streaming API support for message delivery This commit introduces support for the QQ C2C official `stream_messages` API, enabling single-message typing-style updates. Key changes include: - Updated the configuration schema to include a new `c2cStreamApi` boolean option for enabling the C2C streaming API. - Enhanced the `QQBotAccountConfig` interface to accommodate the new streaming option. - Implemented a `StreamingController` to manage the lifecycle of C2C stream messages, ensuring proper handling of media tags and message boundaries. - Updated the outbound dispatch logic to utilize the new streaming capabilities, allowing for more dynamic message delivery in one-to-one chats. These enhancements aim to improve the responsiveness and interactivity of message delivery within the QQBot framework. * feat(qqbot): implement group chat support and unify adapter/DI architecture - Implement group message history tracking with pending history buffer (record on skip, render on @-mention reply) - Add mention detection and gating: explicit @bot, implicit quote-reply, ignoreOtherMentions, configurable activation mode (mention/always) - Add group activation resolution with session store persistence - Add message queue with per-peer FIFO and group message merging (batch multiple rapid messages into one merged payload) - Add deliver debounce to merge rapid outbound text bursts into single messages, with media flush and maxWait cap - Add group config resolution: per-group prompt, history limit, wildcard and specific group overrides - Enrich history attachments with local paths from processAttachments so that history context renders downloaded paths instead of ephemeral QQ CDN URLs - Merge ports/ directory into adapter/ as single entry point - Expand EngineAdapters to 5 required ports: history, mentionGate, audioConvert, outboundAudio, commands - Remove global register/get singletons in favor of constructor injection and one-time init - Add createEngineAdapters() in bridge/gateway.ts as single assembly point - Extract monolithic buildInboundContext into 11 discrete stages: access, content, quote, refidx, group-gate, envelope, assembly - Extract group chat modules: history, mention, activation, message-gating, deliver-debounce - Extract config/group.ts, utils/attachment-tags.ts * feat(qqbot): add /bot-streaming command for C2C message streaming control This commit introduces the `/bot-streaming` command, allowing users to enable or disable streaming for message delivery in C2C chats. Key changes include: - Implementation of the `isStreamingConfigEnabled` function to check the current streaming configuration. - Command handler for `/bot-streaming` that provides usage instructions and manages the streaming state. - Updates to the command's response messages to inform users of the current streaming status and how to toggle it. These enhancements aim to improve user experience by providing a straightforward way to manage streaming message delivery in private chats. * feat(qqbot): extract interaction handler and add remote config query/update support - Extract INTERACTION_CREATE handler from gateway.ts into a dedicated interaction-handler.ts module for better separation of concerns - Add config query (type=2001) and config update (type=2002) interaction branches that read/write claw_cfg via runtime.config API - Register INTERACTION intent (1<<26) in FULL_INTENTS to receive INTERACTION_CREATE events from the gateway - Add InteractionType constants (CONFIG_QUERY, CONFIG_UPDATE) - Extend GatewayPluginRuntime with optional config API (loadConfig, writeConfigFile) for interaction handler access - Add QQBotAccountConfigView interface for typed config field access - Extend acknowledgeInteraction to accept optional data payload for rich ACK responses (e.g. claw_cfg snapshot) - Export getFrameworkVersion from slash-commands-impl for version reporting in config snapshots - Remove unused eslint-disable directive in streaming-media-send.ts * feat(qqbot): enhance account management and logging capabilities - Introduced `toGatewayAccount` function to map resolved QQBot accounts to the engine's gateway account structure. - Added `persistAccountCredentialSnapshot` function to streamline credential backup during gateway events. - Updated the `qqbotPlugin` to utilize the new account mapping and credential persistence functions, improving the handling of account data. - Enhanced logging functionality by modifying the `EngineLogger` interface to support metadata in log messages. - Implemented new commands for managing logs and clearing storage, providing users with better control over their data and system resources. - Registered multiple built-in commands for improved user interaction, including `/bot-logs` for exporting logs and `/bot-clear-storage` for managing downloaded files. - Updated configuration schemas to reflect new options and improve clarity for users. * fix(qqbot): resolve oxlint errors and update raw-fetch allowlist - Replace unnecessary `else` after `return` in outbound-media-send.ts (6 occurrences) - Use `Number.parseInt` instead of global `parseInt` in outbound.ts and streaming-media-send.ts - Use `Number.isNaN` instead of global `isNaN` in register-basic.ts - Prefer `**` over `Math.pow` in media-chunked.ts - Convert interface with call signature to function type in commands.port.ts - Update api-client.ts allowlist line number (108→124) and add media-chunked.ts:552 to raw-fetch allowlist * docs(qqbot): translate streaming-c2c.ts header comments to English * feat(qqbot): add voiceMediaTypes * feat: restore dispatch changes * fix(qqbot): align test files with updated engine interfaces after rebase - inbound-attachments.test: replace removed registerAudioConvertAdapter with AudioConvertPort, pass audioConvert in ProcessContext - inbound-pipeline.self-echo.test: add required adapters field to InboundPipelineDeps mock (history, mentionGate, audioConvert, outboundAudio, commands) - outbound-dispatch.test: add required skipped field to InboundContext * fix(qqbot): update test assertions to match refactored engine interfaces - inbound-pipeline.self-echo.test: self-echo blocking was moved upstream; update test to expect non-blocked pipeline behavior - outbound-dispatch.test: TTS voice path now uses unified sendMedia instead of sendVoiceMessage; add sendMedia mock and update assertion - format-ref-entry.test: attachment format changed from [image: ...] to MEDIA: tag syntax via renderAttachmentTags; update expected output * refactor(qqbot): migrate from deprecated config API to current/replaceConfigFile Replace all usages of deprecated runtime config methods: - loadConfig() → current() - writeConfigFile(cfg) → replaceConfigFile({ nextConfig, afterWrite }) Updated files: - bridge/narrowing.ts: writeOpenClawConfigThroughRuntime - adapter/commands.port.ts: ApproveRuntimeGetter type signature - commands/builtin/register-approve.ts: loadExecConfig, writeExecConfig, reset - commands/builtin/register-streaming.ts: config read/write - gateway/interaction-handler.ts: config query/update handlers - gateway/types.ts: GatewayPluginRuntime.config interface * feat(qqbot): update package.json * fix(qqbot): replace deprecated config-runtime import with config-types subpath Bundled plugin lint requires focused plugin-sdk subpaths. - gateway.ts: openclaw/plugin-sdk/config-runtime → config-types - narrowing.ts: openclaw/plugin-sdk/config-runtime → config-types * feat(qqbot): group chat support, C2C streaming, chunked media upload, and architecture refactor (openclaw#70624) (thanks @cxyhhhhh) --------- Co-authored-by: Bobby <[email protected]> Co-authored-by: sliverp <[email protected]>
… and architecture refactor (openclaw#70624) * feat(qqbot): implement unified media upload handling and introduce chunked upload support This commit enhances the media upload functionality by introducing a unified `sendMedia` method that consolidates the previous separate methods for sending images, voice messages, videos, and files. Key changes include: - Added `uploadChunked` function for future chunked media uploads, currently marked as not implemented. - Introduced `MediaSource` abstraction to handle various media types (URLs, base64, local files, buffers) uniformly. - Updated existing media handling logic to utilize the new `sendMedia` method, ensuring consistent media processing across different types. - Enhanced error handling and validation for media uploads, including MIME type checks and file size limits. These changes aim to streamline the media upload process and prepare for future enhancements in handling larger files through chunked uploads. * feat(qqbot): enhance media upload capabilities with chunked upload support This commit updates the media upload functionality by implementing chunked upload support for larger files. Key changes include: - Revised the `SKILL.md` documentation to clarify media file size limits and local file path requirements. - Introduced a new test suite for the chunked media upload functionality, ensuring robust error handling and upload processes. - Updated the media handling logic to enforce per-file-type upload ceilings, allowing for seamless integration of chunked uploads. - Enhanced error handling for daily upload limits, providing user-friendly messages when limits are exceeded. These improvements aim to streamline the media upload process and accommodate larger files effectively. * feat(qqbot): add C2C streaming API support for message delivery This commit introduces support for the QQ C2C official `stream_messages` API, enabling single-message typing-style updates. Key changes include: - Updated the configuration schema to include a new `c2cStreamApi` boolean option for enabling the C2C streaming API. - Enhanced the `QQBotAccountConfig` interface to accommodate the new streaming option. - Implemented a `StreamingController` to manage the lifecycle of C2C stream messages, ensuring proper handling of media tags and message boundaries. - Updated the outbound dispatch logic to utilize the new streaming capabilities, allowing for more dynamic message delivery in one-to-one chats. These enhancements aim to improve the responsiveness and interactivity of message delivery within the QQBot framework. * feat(qqbot): implement group chat support and unify adapter/DI architecture - Implement group message history tracking with pending history buffer (record on skip, render on @-mention reply) - Add mention detection and gating: explicit @bot, implicit quote-reply, ignoreOtherMentions, configurable activation mode (mention/always) - Add group activation resolution with session store persistence - Add message queue with per-peer FIFO and group message merging (batch multiple rapid messages into one merged payload) - Add deliver debounce to merge rapid outbound text bursts into single messages, with media flush and maxWait cap - Add group config resolution: per-group prompt, history limit, wildcard and specific group overrides - Enrich history attachments with local paths from processAttachments so that history context renders downloaded paths instead of ephemeral QQ CDN URLs - Merge ports/ directory into adapter/ as single entry point - Expand EngineAdapters to 5 required ports: history, mentionGate, audioConvert, outboundAudio, commands - Remove global register/get singletons in favor of constructor injection and one-time init - Add createEngineAdapters() in bridge/gateway.ts as single assembly point - Extract monolithic buildInboundContext into 11 discrete stages: access, content, quote, refidx, group-gate, envelope, assembly - Extract group chat modules: history, mention, activation, message-gating, deliver-debounce - Extract config/group.ts, utils/attachment-tags.ts * feat(qqbot): add /bot-streaming command for C2C message streaming control This commit introduces the `/bot-streaming` command, allowing users to enable or disable streaming for message delivery in C2C chats. Key changes include: - Implementation of the `isStreamingConfigEnabled` function to check the current streaming configuration. - Command handler for `/bot-streaming` that provides usage instructions and manages the streaming state. - Updates to the command's response messages to inform users of the current streaming status and how to toggle it. These enhancements aim to improve user experience by providing a straightforward way to manage streaming message delivery in private chats. * feat(qqbot): extract interaction handler and add remote config query/update support - Extract INTERACTION_CREATE handler from gateway.ts into a dedicated interaction-handler.ts module for better separation of concerns - Add config query (type=2001) and config update (type=2002) interaction branches that read/write claw_cfg via runtime.config API - Register INTERACTION intent (1<<26) in FULL_INTENTS to receive INTERACTION_CREATE events from the gateway - Add InteractionType constants (CONFIG_QUERY, CONFIG_UPDATE) - Extend GatewayPluginRuntime with optional config API (loadConfig, writeConfigFile) for interaction handler access - Add QQBotAccountConfigView interface for typed config field access - Extend acknowledgeInteraction to accept optional data payload for rich ACK responses (e.g. claw_cfg snapshot) - Export getFrameworkVersion from slash-commands-impl for version reporting in config snapshots - Remove unused eslint-disable directive in streaming-media-send.ts * feat(qqbot): enhance account management and logging capabilities - Introduced `toGatewayAccount` function to map resolved QQBot accounts to the engine's gateway account structure. - Added `persistAccountCredentialSnapshot` function to streamline credential backup during gateway events. - Updated the `qqbotPlugin` to utilize the new account mapping and credential persistence functions, improving the handling of account data. - Enhanced logging functionality by modifying the `EngineLogger` interface to support metadata in log messages. - Implemented new commands for managing logs and clearing storage, providing users with better control over their data and system resources. - Registered multiple built-in commands for improved user interaction, including `/bot-logs` for exporting logs and `/bot-clear-storage` for managing downloaded files. - Updated configuration schemas to reflect new options and improve clarity for users. * fix(qqbot): resolve oxlint errors and update raw-fetch allowlist - Replace unnecessary `else` after `return` in outbound-media-send.ts (6 occurrences) - Use `Number.parseInt` instead of global `parseInt` in outbound.ts and streaming-media-send.ts - Use `Number.isNaN` instead of global `isNaN` in register-basic.ts - Prefer `**` over `Math.pow` in media-chunked.ts - Convert interface with call signature to function type in commands.port.ts - Update api-client.ts allowlist line number (108→124) and add media-chunked.ts:552 to raw-fetch allowlist * docs(qqbot): translate streaming-c2c.ts header comments to English * feat(qqbot): add voiceMediaTypes * feat: restore dispatch changes * fix(qqbot): align test files with updated engine interfaces after rebase - inbound-attachments.test: replace removed registerAudioConvertAdapter with AudioConvertPort, pass audioConvert in ProcessContext - inbound-pipeline.self-echo.test: add required adapters field to InboundPipelineDeps mock (history, mentionGate, audioConvert, outboundAudio, commands) - outbound-dispatch.test: add required skipped field to InboundContext * fix(qqbot): update test assertions to match refactored engine interfaces - inbound-pipeline.self-echo.test: self-echo blocking was moved upstream; update test to expect non-blocked pipeline behavior - outbound-dispatch.test: TTS voice path now uses unified sendMedia instead of sendVoiceMessage; add sendMedia mock and update assertion - format-ref-entry.test: attachment format changed from [image: ...] to MEDIA: tag syntax via renderAttachmentTags; update expected output * refactor(qqbot): migrate from deprecated config API to current/replaceConfigFile Replace all usages of deprecated runtime config methods: - loadConfig() → current() - writeConfigFile(cfg) → replaceConfigFile({ nextConfig, afterWrite }) Updated files: - bridge/narrowing.ts: writeOpenClawConfigThroughRuntime - adapter/commands.port.ts: ApproveRuntimeGetter type signature - commands/builtin/register-approve.ts: loadExecConfig, writeExecConfig, reset - commands/builtin/register-streaming.ts: config read/write - gateway/interaction-handler.ts: config query/update handlers - gateway/types.ts: GatewayPluginRuntime.config interface * feat(qqbot): update package.json * fix(qqbot): replace deprecated config-runtime import with config-types subpath Bundled plugin lint requires focused plugin-sdk subpaths. - gateway.ts: openclaw/plugin-sdk/config-runtime → config-types - narrowing.ts: openclaw/plugin-sdk/config-runtime → config-types * feat(qqbot): group chat support, C2C streaming, chunked media upload, and architecture refactor (openclaw#70624) (thanks @cxyhhhhh) --------- Co-authored-by: Bobby <[email protected]> Co-authored-by: sliverp <[email protected]>
… and architecture refactor (openclaw#70624) * feat(qqbot): implement unified media upload handling and introduce chunked upload support This commit enhances the media upload functionality by introducing a unified `sendMedia` method that consolidates the previous separate methods for sending images, voice messages, videos, and files. Key changes include: - Added `uploadChunked` function for future chunked media uploads, currently marked as not implemented. - Introduced `MediaSource` abstraction to handle various media types (URLs, base64, local files, buffers) uniformly. - Updated existing media handling logic to utilize the new `sendMedia` method, ensuring consistent media processing across different types. - Enhanced error handling and validation for media uploads, including MIME type checks and file size limits. These changes aim to streamline the media upload process and prepare for future enhancements in handling larger files through chunked uploads. * feat(qqbot): enhance media upload capabilities with chunked upload support This commit updates the media upload functionality by implementing chunked upload support for larger files. Key changes include: - Revised the `SKILL.md` documentation to clarify media file size limits and local file path requirements. - Introduced a new test suite for the chunked media upload functionality, ensuring robust error handling and upload processes. - Updated the media handling logic to enforce per-file-type upload ceilings, allowing for seamless integration of chunked uploads. - Enhanced error handling for daily upload limits, providing user-friendly messages when limits are exceeded. These improvements aim to streamline the media upload process and accommodate larger files effectively. * feat(qqbot): add C2C streaming API support for message delivery This commit introduces support for the QQ C2C official `stream_messages` API, enabling single-message typing-style updates. Key changes include: - Updated the configuration schema to include a new `c2cStreamApi` boolean option for enabling the C2C streaming API. - Enhanced the `QQBotAccountConfig` interface to accommodate the new streaming option. - Implemented a `StreamingController` to manage the lifecycle of C2C stream messages, ensuring proper handling of media tags and message boundaries. - Updated the outbound dispatch logic to utilize the new streaming capabilities, allowing for more dynamic message delivery in one-to-one chats. These enhancements aim to improve the responsiveness and interactivity of message delivery within the QQBot framework. * feat(qqbot): implement group chat support and unify adapter/DI architecture - Implement group message history tracking with pending history buffer (record on skip, render on @-mention reply) - Add mention detection and gating: explicit @bot, implicit quote-reply, ignoreOtherMentions, configurable activation mode (mention/always) - Add group activation resolution with session store persistence - Add message queue with per-peer FIFO and group message merging (batch multiple rapid messages into one merged payload) - Add deliver debounce to merge rapid outbound text bursts into single messages, with media flush and maxWait cap - Add group config resolution: per-group prompt, history limit, wildcard and specific group overrides - Enrich history attachments with local paths from processAttachments so that history context renders downloaded paths instead of ephemeral QQ CDN URLs - Merge ports/ directory into adapter/ as single entry point - Expand EngineAdapters to 5 required ports: history, mentionGate, audioConvert, outboundAudio, commands - Remove global register/get singletons in favor of constructor injection and one-time init - Add createEngineAdapters() in bridge/gateway.ts as single assembly point - Extract monolithic buildInboundContext into 11 discrete stages: access, content, quote, refidx, group-gate, envelope, assembly - Extract group chat modules: history, mention, activation, message-gating, deliver-debounce - Extract config/group.ts, utils/attachment-tags.ts * feat(qqbot): add /bot-streaming command for C2C message streaming control This commit introduces the `/bot-streaming` command, allowing users to enable or disable streaming for message delivery in C2C chats. Key changes include: - Implementation of the `isStreamingConfigEnabled` function to check the current streaming configuration. - Command handler for `/bot-streaming` that provides usage instructions and manages the streaming state. - Updates to the command's response messages to inform users of the current streaming status and how to toggle it. These enhancements aim to improve user experience by providing a straightforward way to manage streaming message delivery in private chats. * feat(qqbot): extract interaction handler and add remote config query/update support - Extract INTERACTION_CREATE handler from gateway.ts into a dedicated interaction-handler.ts module for better separation of concerns - Add config query (type=2001) and config update (type=2002) interaction branches that read/write claw_cfg via runtime.config API - Register INTERACTION intent (1<<26) in FULL_INTENTS to receive INTERACTION_CREATE events from the gateway - Add InteractionType constants (CONFIG_QUERY, CONFIG_UPDATE) - Extend GatewayPluginRuntime with optional config API (loadConfig, writeConfigFile) for interaction handler access - Add QQBotAccountConfigView interface for typed config field access - Extend acknowledgeInteraction to accept optional data payload for rich ACK responses (e.g. claw_cfg snapshot) - Export getFrameworkVersion from slash-commands-impl for version reporting in config snapshots - Remove unused eslint-disable directive in streaming-media-send.ts * feat(qqbot): enhance account management and logging capabilities - Introduced `toGatewayAccount` function to map resolved QQBot accounts to the engine's gateway account structure. - Added `persistAccountCredentialSnapshot` function to streamline credential backup during gateway events. - Updated the `qqbotPlugin` to utilize the new account mapping and credential persistence functions, improving the handling of account data. - Enhanced logging functionality by modifying the `EngineLogger` interface to support metadata in log messages. - Implemented new commands for managing logs and clearing storage, providing users with better control over their data and system resources. - Registered multiple built-in commands for improved user interaction, including `/bot-logs` for exporting logs and `/bot-clear-storage` for managing downloaded files. - Updated configuration schemas to reflect new options and improve clarity for users. * fix(qqbot): resolve oxlint errors and update raw-fetch allowlist - Replace unnecessary `else` after `return` in outbound-media-send.ts (6 occurrences) - Use `Number.parseInt` instead of global `parseInt` in outbound.ts and streaming-media-send.ts - Use `Number.isNaN` instead of global `isNaN` in register-basic.ts - Prefer `**` over `Math.pow` in media-chunked.ts - Convert interface with call signature to function type in commands.port.ts - Update api-client.ts allowlist line number (108→124) and add media-chunked.ts:552 to raw-fetch allowlist * docs(qqbot): translate streaming-c2c.ts header comments to English * feat(qqbot): add voiceMediaTypes * feat: restore dispatch changes * fix(qqbot): align test files with updated engine interfaces after rebase - inbound-attachments.test: replace removed registerAudioConvertAdapter with AudioConvertPort, pass audioConvert in ProcessContext - inbound-pipeline.self-echo.test: add required adapters field to InboundPipelineDeps mock (history, mentionGate, audioConvert, outboundAudio, commands) - outbound-dispatch.test: add required skipped field to InboundContext * fix(qqbot): update test assertions to match refactored engine interfaces - inbound-pipeline.self-echo.test: self-echo blocking was moved upstream; update test to expect non-blocked pipeline behavior - outbound-dispatch.test: TTS voice path now uses unified sendMedia instead of sendVoiceMessage; add sendMedia mock and update assertion - format-ref-entry.test: attachment format changed from [image: ...] to MEDIA: tag syntax via renderAttachmentTags; update expected output * refactor(qqbot): migrate from deprecated config API to current/replaceConfigFile Replace all usages of deprecated runtime config methods: - loadConfig() → current() - writeConfigFile(cfg) → replaceConfigFile({ nextConfig, afterWrite }) Updated files: - bridge/narrowing.ts: writeOpenClawConfigThroughRuntime - adapter/commands.port.ts: ApproveRuntimeGetter type signature - commands/builtin/register-approve.ts: loadExecConfig, writeExecConfig, reset - commands/builtin/register-streaming.ts: config read/write - gateway/interaction-handler.ts: config query/update handlers - gateway/types.ts: GatewayPluginRuntime.config interface * feat(qqbot): update package.json * fix(qqbot): replace deprecated config-runtime import with config-types subpath Bundled plugin lint requires focused plugin-sdk subpaths. - gateway.ts: openclaw/plugin-sdk/config-runtime → config-types - narrowing.ts: openclaw/plugin-sdk/config-runtime → config-types * feat(qqbot): group chat support, C2C streaming, chunked media upload, and architecture refactor (openclaw#70624) (thanks @cxyhhhhh) --------- Co-authored-by: Bobby <[email protected]> Co-authored-by: sliverp <[email protected]>
… and architecture refactor (openclaw#70624) * feat(qqbot): implement unified media upload handling and introduce chunked upload support This commit enhances the media upload functionality by introducing a unified `sendMedia` method that consolidates the previous separate methods for sending images, voice messages, videos, and files. Key changes include: - Added `uploadChunked` function for future chunked media uploads, currently marked as not implemented. - Introduced `MediaSource` abstraction to handle various media types (URLs, base64, local files, buffers) uniformly. - Updated existing media handling logic to utilize the new `sendMedia` method, ensuring consistent media processing across different types. - Enhanced error handling and validation for media uploads, including MIME type checks and file size limits. These changes aim to streamline the media upload process and prepare for future enhancements in handling larger files through chunked uploads. * feat(qqbot): enhance media upload capabilities with chunked upload support This commit updates the media upload functionality by implementing chunked upload support for larger files. Key changes include: - Revised the `SKILL.md` documentation to clarify media file size limits and local file path requirements. - Introduced a new test suite for the chunked media upload functionality, ensuring robust error handling and upload processes. - Updated the media handling logic to enforce per-file-type upload ceilings, allowing for seamless integration of chunked uploads. - Enhanced error handling for daily upload limits, providing user-friendly messages when limits are exceeded. These improvements aim to streamline the media upload process and accommodate larger files effectively. * feat(qqbot): add C2C streaming API support for message delivery This commit introduces support for the QQ C2C official `stream_messages` API, enabling single-message typing-style updates. Key changes include: - Updated the configuration schema to include a new `c2cStreamApi` boolean option for enabling the C2C streaming API. - Enhanced the `QQBotAccountConfig` interface to accommodate the new streaming option. - Implemented a `StreamingController` to manage the lifecycle of C2C stream messages, ensuring proper handling of media tags and message boundaries. - Updated the outbound dispatch logic to utilize the new streaming capabilities, allowing for more dynamic message delivery in one-to-one chats. These enhancements aim to improve the responsiveness and interactivity of message delivery within the QQBot framework. * feat(qqbot): implement group chat support and unify adapter/DI architecture - Implement group message history tracking with pending history buffer (record on skip, render on @-mention reply) - Add mention detection and gating: explicit @bot, implicit quote-reply, ignoreOtherMentions, configurable activation mode (mention/always) - Add group activation resolution with session store persistence - Add message queue with per-peer FIFO and group message merging (batch multiple rapid messages into one merged payload) - Add deliver debounce to merge rapid outbound text bursts into single messages, with media flush and maxWait cap - Add group config resolution: per-group prompt, history limit, wildcard and specific group overrides - Enrich history attachments with local paths from processAttachments so that history context renders downloaded paths instead of ephemeral QQ CDN URLs - Merge ports/ directory into adapter/ as single entry point - Expand EngineAdapters to 5 required ports: history, mentionGate, audioConvert, outboundAudio, commands - Remove global register/get singletons in favor of constructor injection and one-time init - Add createEngineAdapters() in bridge/gateway.ts as single assembly point - Extract monolithic buildInboundContext into 11 discrete stages: access, content, quote, refidx, group-gate, envelope, assembly - Extract group chat modules: history, mention, activation, message-gating, deliver-debounce - Extract config/group.ts, utils/attachment-tags.ts * feat(qqbot): add /bot-streaming command for C2C message streaming control This commit introduces the `/bot-streaming` command, allowing users to enable or disable streaming for message delivery in C2C chats. Key changes include: - Implementation of the `isStreamingConfigEnabled` function to check the current streaming configuration. - Command handler for `/bot-streaming` that provides usage instructions and manages the streaming state. - Updates to the command's response messages to inform users of the current streaming status and how to toggle it. These enhancements aim to improve user experience by providing a straightforward way to manage streaming message delivery in private chats. * feat(qqbot): extract interaction handler and add remote config query/update support - Extract INTERACTION_CREATE handler from gateway.ts into a dedicated interaction-handler.ts module for better separation of concerns - Add config query (type=2001) and config update (type=2002) interaction branches that read/write claw_cfg via runtime.config API - Register INTERACTION intent (1<<26) in FULL_INTENTS to receive INTERACTION_CREATE events from the gateway - Add InteractionType constants (CONFIG_QUERY, CONFIG_UPDATE) - Extend GatewayPluginRuntime with optional config API (loadConfig, writeConfigFile) for interaction handler access - Add QQBotAccountConfigView interface for typed config field access - Extend acknowledgeInteraction to accept optional data payload for rich ACK responses (e.g. claw_cfg snapshot) - Export getFrameworkVersion from slash-commands-impl for version reporting in config snapshots - Remove unused eslint-disable directive in streaming-media-send.ts * feat(qqbot): enhance account management and logging capabilities - Introduced `toGatewayAccount` function to map resolved QQBot accounts to the engine's gateway account structure. - Added `persistAccountCredentialSnapshot` function to streamline credential backup during gateway events. - Updated the `qqbotPlugin` to utilize the new account mapping and credential persistence functions, improving the handling of account data. - Enhanced logging functionality by modifying the `EngineLogger` interface to support metadata in log messages. - Implemented new commands for managing logs and clearing storage, providing users with better control over their data and system resources. - Registered multiple built-in commands for improved user interaction, including `/bot-logs` for exporting logs and `/bot-clear-storage` for managing downloaded files. - Updated configuration schemas to reflect new options and improve clarity for users. * fix(qqbot): resolve oxlint errors and update raw-fetch allowlist - Replace unnecessary `else` after `return` in outbound-media-send.ts (6 occurrences) - Use `Number.parseInt` instead of global `parseInt` in outbound.ts and streaming-media-send.ts - Use `Number.isNaN` instead of global `isNaN` in register-basic.ts - Prefer `**` over `Math.pow` in media-chunked.ts - Convert interface with call signature to function type in commands.port.ts - Update api-client.ts allowlist line number (108→124) and add media-chunked.ts:552 to raw-fetch allowlist * docs(qqbot): translate streaming-c2c.ts header comments to English * feat(qqbot): add voiceMediaTypes * feat: restore dispatch changes * fix(qqbot): align test files with updated engine interfaces after rebase - inbound-attachments.test: replace removed registerAudioConvertAdapter with AudioConvertPort, pass audioConvert in ProcessContext - inbound-pipeline.self-echo.test: add required adapters field to InboundPipelineDeps mock (history, mentionGate, audioConvert, outboundAudio, commands) - outbound-dispatch.test: add required skipped field to InboundContext * fix(qqbot): update test assertions to match refactored engine interfaces - inbound-pipeline.self-echo.test: self-echo blocking was moved upstream; update test to expect non-blocked pipeline behavior - outbound-dispatch.test: TTS voice path now uses unified sendMedia instead of sendVoiceMessage; add sendMedia mock and update assertion - format-ref-entry.test: attachment format changed from [image: ...] to MEDIA: tag syntax via renderAttachmentTags; update expected output * refactor(qqbot): migrate from deprecated config API to current/replaceConfigFile Replace all usages of deprecated runtime config methods: - loadConfig() → current() - writeConfigFile(cfg) → replaceConfigFile({ nextConfig, afterWrite }) Updated files: - bridge/narrowing.ts: writeOpenClawConfigThroughRuntime - adapter/commands.port.ts: ApproveRuntimeGetter type signature - commands/builtin/register-approve.ts: loadExecConfig, writeExecConfig, reset - commands/builtin/register-streaming.ts: config read/write - gateway/interaction-handler.ts: config query/update handlers - gateway/types.ts: GatewayPluginRuntime.config interface * feat(qqbot): update package.json * fix(qqbot): replace deprecated config-runtime import with config-types subpath Bundled plugin lint requires focused plugin-sdk subpaths. - gateway.ts: openclaw/plugin-sdk/config-runtime → config-types - narrowing.ts: openclaw/plugin-sdk/config-runtime → config-types * feat(qqbot): group chat support, C2C streaming, chunked media upload, and architecture refactor (openclaw#70624) (thanks @cxyhhhhh) --------- Co-authored-by: Bobby <[email protected]> Co-authored-by: sliverp <[email protected]>
… and architecture refactor (openclaw#70624) * feat(qqbot): implement unified media upload handling and introduce chunked upload support This commit enhances the media upload functionality by introducing a unified `sendMedia` method that consolidates the previous separate methods for sending images, voice messages, videos, and files. Key changes include: - Added `uploadChunked` function for future chunked media uploads, currently marked as not implemented. - Introduced `MediaSource` abstraction to handle various media types (URLs, base64, local files, buffers) uniformly. - Updated existing media handling logic to utilize the new `sendMedia` method, ensuring consistent media processing across different types. - Enhanced error handling and validation for media uploads, including MIME type checks and file size limits. These changes aim to streamline the media upload process and prepare for future enhancements in handling larger files through chunked uploads. * feat(qqbot): enhance media upload capabilities with chunked upload support This commit updates the media upload functionality by implementing chunked upload support for larger files. Key changes include: - Revised the `SKILL.md` documentation to clarify media file size limits and local file path requirements. - Introduced a new test suite for the chunked media upload functionality, ensuring robust error handling and upload processes. - Updated the media handling logic to enforce per-file-type upload ceilings, allowing for seamless integration of chunked uploads. - Enhanced error handling for daily upload limits, providing user-friendly messages when limits are exceeded. These improvements aim to streamline the media upload process and accommodate larger files effectively. * feat(qqbot): add C2C streaming API support for message delivery This commit introduces support for the QQ C2C official `stream_messages` API, enabling single-message typing-style updates. Key changes include: - Updated the configuration schema to include a new `c2cStreamApi` boolean option for enabling the C2C streaming API. - Enhanced the `QQBotAccountConfig` interface to accommodate the new streaming option. - Implemented a `StreamingController` to manage the lifecycle of C2C stream messages, ensuring proper handling of media tags and message boundaries. - Updated the outbound dispatch logic to utilize the new streaming capabilities, allowing for more dynamic message delivery in one-to-one chats. These enhancements aim to improve the responsiveness and interactivity of message delivery within the QQBot framework. * feat(qqbot): implement group chat support and unify adapter/DI architecture - Implement group message history tracking with pending history buffer (record on skip, render on @-mention reply) - Add mention detection and gating: explicit @bot, implicit quote-reply, ignoreOtherMentions, configurable activation mode (mention/always) - Add group activation resolution with session store persistence - Add message queue with per-peer FIFO and group message merging (batch multiple rapid messages into one merged payload) - Add deliver debounce to merge rapid outbound text bursts into single messages, with media flush and maxWait cap - Add group config resolution: per-group prompt, history limit, wildcard and specific group overrides - Enrich history attachments with local paths from processAttachments so that history context renders downloaded paths instead of ephemeral QQ CDN URLs - Merge ports/ directory into adapter/ as single entry point - Expand EngineAdapters to 5 required ports: history, mentionGate, audioConvert, outboundAudio, commands - Remove global register/get singletons in favor of constructor injection and one-time init - Add createEngineAdapters() in bridge/gateway.ts as single assembly point - Extract monolithic buildInboundContext into 11 discrete stages: access, content, quote, refidx, group-gate, envelope, assembly - Extract group chat modules: history, mention, activation, message-gating, deliver-debounce - Extract config/group.ts, utils/attachment-tags.ts * feat(qqbot): add /bot-streaming command for C2C message streaming control This commit introduces the `/bot-streaming` command, allowing users to enable or disable streaming for message delivery in C2C chats. Key changes include: - Implementation of the `isStreamingConfigEnabled` function to check the current streaming configuration. - Command handler for `/bot-streaming` that provides usage instructions and manages the streaming state. - Updates to the command's response messages to inform users of the current streaming status and how to toggle it. These enhancements aim to improve user experience by providing a straightforward way to manage streaming message delivery in private chats. * feat(qqbot): extract interaction handler and add remote config query/update support - Extract INTERACTION_CREATE handler from gateway.ts into a dedicated interaction-handler.ts module for better separation of concerns - Add config query (type=2001) and config update (type=2002) interaction branches that read/write claw_cfg via runtime.config API - Register INTERACTION intent (1<<26) in FULL_INTENTS to receive INTERACTION_CREATE events from the gateway - Add InteractionType constants (CONFIG_QUERY, CONFIG_UPDATE) - Extend GatewayPluginRuntime with optional config API (loadConfig, writeConfigFile) for interaction handler access - Add QQBotAccountConfigView interface for typed config field access - Extend acknowledgeInteraction to accept optional data payload for rich ACK responses (e.g. claw_cfg snapshot) - Export getFrameworkVersion from slash-commands-impl for version reporting in config snapshots - Remove unused eslint-disable directive in streaming-media-send.ts * feat(qqbot): enhance account management and logging capabilities - Introduced `toGatewayAccount` function to map resolved QQBot accounts to the engine's gateway account structure. - Added `persistAccountCredentialSnapshot` function to streamline credential backup during gateway events. - Updated the `qqbotPlugin` to utilize the new account mapping and credential persistence functions, improving the handling of account data. - Enhanced logging functionality by modifying the `EngineLogger` interface to support metadata in log messages. - Implemented new commands for managing logs and clearing storage, providing users with better control over their data and system resources. - Registered multiple built-in commands for improved user interaction, including `/bot-logs` for exporting logs and `/bot-clear-storage` for managing downloaded files. - Updated configuration schemas to reflect new options and improve clarity for users. * fix(qqbot): resolve oxlint errors and update raw-fetch allowlist - Replace unnecessary `else` after `return` in outbound-media-send.ts (6 occurrences) - Use `Number.parseInt` instead of global `parseInt` in outbound.ts and streaming-media-send.ts - Use `Number.isNaN` instead of global `isNaN` in register-basic.ts - Prefer `**` over `Math.pow` in media-chunked.ts - Convert interface with call signature to function type in commands.port.ts - Update api-client.ts allowlist line number (108→124) and add media-chunked.ts:552 to raw-fetch allowlist * docs(qqbot): translate streaming-c2c.ts header comments to English * feat(qqbot): add voiceMediaTypes * feat: restore dispatch changes * fix(qqbot): align test files with updated engine interfaces after rebase - inbound-attachments.test: replace removed registerAudioConvertAdapter with AudioConvertPort, pass audioConvert in ProcessContext - inbound-pipeline.self-echo.test: add required adapters field to InboundPipelineDeps mock (history, mentionGate, audioConvert, outboundAudio, commands) - outbound-dispatch.test: add required skipped field to InboundContext * fix(qqbot): update test assertions to match refactored engine interfaces - inbound-pipeline.self-echo.test: self-echo blocking was moved upstream; update test to expect non-blocked pipeline behavior - outbound-dispatch.test: TTS voice path now uses unified sendMedia instead of sendVoiceMessage; add sendMedia mock and update assertion - format-ref-entry.test: attachment format changed from [image: ...] to MEDIA: tag syntax via renderAttachmentTags; update expected output * refactor(qqbot): migrate from deprecated config API to current/replaceConfigFile Replace all usages of deprecated runtime config methods: - loadConfig() → current() - writeConfigFile(cfg) → replaceConfigFile({ nextConfig, afterWrite }) Updated files: - bridge/narrowing.ts: writeOpenClawConfigThroughRuntime - adapter/commands.port.ts: ApproveRuntimeGetter type signature - commands/builtin/register-approve.ts: loadExecConfig, writeExecConfig, reset - commands/builtin/register-streaming.ts: config read/write - gateway/interaction-handler.ts: config query/update handlers - gateway/types.ts: GatewayPluginRuntime.config interface * feat(qqbot): update package.json * fix(qqbot): replace deprecated config-runtime import with config-types subpath Bundled plugin lint requires focused plugin-sdk subpaths. - gateway.ts: openclaw/plugin-sdk/config-runtime → config-types - narrowing.ts: openclaw/plugin-sdk/config-runtime → config-types * feat(qqbot): group chat support, C2C streaming, chunked media upload, and architecture refactor (openclaw#70624) (thanks @cxyhhhhh) --------- Co-authored-by: Bobby <[email protected]> Co-authored-by: sliverp <[email protected]>
… and architecture refactor (openclaw#70624) * feat(qqbot): implement unified media upload handling and introduce chunked upload support This commit enhances the media upload functionality by introducing a unified `sendMedia` method that consolidates the previous separate methods for sending images, voice messages, videos, and files. Key changes include: - Added `uploadChunked` function for future chunked media uploads, currently marked as not implemented. - Introduced `MediaSource` abstraction to handle various media types (URLs, base64, local files, buffers) uniformly. - Updated existing media handling logic to utilize the new `sendMedia` method, ensuring consistent media processing across different types. - Enhanced error handling and validation for media uploads, including MIME type checks and file size limits. These changes aim to streamline the media upload process and prepare for future enhancements in handling larger files through chunked uploads. * feat(qqbot): enhance media upload capabilities with chunked upload support This commit updates the media upload functionality by implementing chunked upload support for larger files. Key changes include: - Revised the `SKILL.md` documentation to clarify media file size limits and local file path requirements. - Introduced a new test suite for the chunked media upload functionality, ensuring robust error handling and upload processes. - Updated the media handling logic to enforce per-file-type upload ceilings, allowing for seamless integration of chunked uploads. - Enhanced error handling for daily upload limits, providing user-friendly messages when limits are exceeded. These improvements aim to streamline the media upload process and accommodate larger files effectively. * feat(qqbot): add C2C streaming API support for message delivery This commit introduces support for the QQ C2C official `stream_messages` API, enabling single-message typing-style updates. Key changes include: - Updated the configuration schema to include a new `c2cStreamApi` boolean option for enabling the C2C streaming API. - Enhanced the `QQBotAccountConfig` interface to accommodate the new streaming option. - Implemented a `StreamingController` to manage the lifecycle of C2C stream messages, ensuring proper handling of media tags and message boundaries. - Updated the outbound dispatch logic to utilize the new streaming capabilities, allowing for more dynamic message delivery in one-to-one chats. These enhancements aim to improve the responsiveness and interactivity of message delivery within the QQBot framework. * feat(qqbot): implement group chat support and unify adapter/DI architecture - Implement group message history tracking with pending history buffer (record on skip, render on @-mention reply) - Add mention detection and gating: explicit @bot, implicit quote-reply, ignoreOtherMentions, configurable activation mode (mention/always) - Add group activation resolution with session store persistence - Add message queue with per-peer FIFO and group message merging (batch multiple rapid messages into one merged payload) - Add deliver debounce to merge rapid outbound text bursts into single messages, with media flush and maxWait cap - Add group config resolution: per-group prompt, history limit, wildcard and specific group overrides - Enrich history attachments with local paths from processAttachments so that history context renders downloaded paths instead of ephemeral QQ CDN URLs - Merge ports/ directory into adapter/ as single entry point - Expand EngineAdapters to 5 required ports: history, mentionGate, audioConvert, outboundAudio, commands - Remove global register/get singletons in favor of constructor injection and one-time init - Add createEngineAdapters() in bridge/gateway.ts as single assembly point - Extract monolithic buildInboundContext into 11 discrete stages: access, content, quote, refidx, group-gate, envelope, assembly - Extract group chat modules: history, mention, activation, message-gating, deliver-debounce - Extract config/group.ts, utils/attachment-tags.ts * feat(qqbot): add /bot-streaming command for C2C message streaming control This commit introduces the `/bot-streaming` command, allowing users to enable or disable streaming for message delivery in C2C chats. Key changes include: - Implementation of the `isStreamingConfigEnabled` function to check the current streaming configuration. - Command handler for `/bot-streaming` that provides usage instructions and manages the streaming state. - Updates to the command's response messages to inform users of the current streaming status and how to toggle it. These enhancements aim to improve user experience by providing a straightforward way to manage streaming message delivery in private chats. * feat(qqbot): extract interaction handler and add remote config query/update support - Extract INTERACTION_CREATE handler from gateway.ts into a dedicated interaction-handler.ts module for better separation of concerns - Add config query (type=2001) and config update (type=2002) interaction branches that read/write claw_cfg via runtime.config API - Register INTERACTION intent (1<<26) in FULL_INTENTS to receive INTERACTION_CREATE events from the gateway - Add InteractionType constants (CONFIG_QUERY, CONFIG_UPDATE) - Extend GatewayPluginRuntime with optional config API (loadConfig, writeConfigFile) for interaction handler access - Add QQBotAccountConfigView interface for typed config field access - Extend acknowledgeInteraction to accept optional data payload for rich ACK responses (e.g. claw_cfg snapshot) - Export getFrameworkVersion from slash-commands-impl for version reporting in config snapshots - Remove unused eslint-disable directive in streaming-media-send.ts * feat(qqbot): enhance account management and logging capabilities - Introduced `toGatewayAccount` function to map resolved QQBot accounts to the engine's gateway account structure. - Added `persistAccountCredentialSnapshot` function to streamline credential backup during gateway events. - Updated the `qqbotPlugin` to utilize the new account mapping and credential persistence functions, improving the handling of account data. - Enhanced logging functionality by modifying the `EngineLogger` interface to support metadata in log messages. - Implemented new commands for managing logs and clearing storage, providing users with better control over their data and system resources. - Registered multiple built-in commands for improved user interaction, including `/bot-logs` for exporting logs and `/bot-clear-storage` for managing downloaded files. - Updated configuration schemas to reflect new options and improve clarity for users. * fix(qqbot): resolve oxlint errors and update raw-fetch allowlist - Replace unnecessary `else` after `return` in outbound-media-send.ts (6 occurrences) - Use `Number.parseInt` instead of global `parseInt` in outbound.ts and streaming-media-send.ts - Use `Number.isNaN` instead of global `isNaN` in register-basic.ts - Prefer `**` over `Math.pow` in media-chunked.ts - Convert interface with call signature to function type in commands.port.ts - Update api-client.ts allowlist line number (108→124) and add media-chunked.ts:552 to raw-fetch allowlist * docs(qqbot): translate streaming-c2c.ts header comments to English * feat(qqbot): add voiceMediaTypes * feat: restore dispatch changes * fix(qqbot): align test files with updated engine interfaces after rebase - inbound-attachments.test: replace removed registerAudioConvertAdapter with AudioConvertPort, pass audioConvert in ProcessContext - inbound-pipeline.self-echo.test: add required adapters field to InboundPipelineDeps mock (history, mentionGate, audioConvert, outboundAudio, commands) - outbound-dispatch.test: add required skipped field to InboundContext * fix(qqbot): update test assertions to match refactored engine interfaces - inbound-pipeline.self-echo.test: self-echo blocking was moved upstream; update test to expect non-blocked pipeline behavior - outbound-dispatch.test: TTS voice path now uses unified sendMedia instead of sendVoiceMessage; add sendMedia mock and update assertion - format-ref-entry.test: attachment format changed from [image: ...] to MEDIA: tag syntax via renderAttachmentTags; update expected output * refactor(qqbot): migrate from deprecated config API to current/replaceConfigFile Replace all usages of deprecated runtime config methods: - loadConfig() → current() - writeConfigFile(cfg) → replaceConfigFile({ nextConfig, afterWrite }) Updated files: - bridge/narrowing.ts: writeOpenClawConfigThroughRuntime - adapter/commands.port.ts: ApproveRuntimeGetter type signature - commands/builtin/register-approve.ts: loadExecConfig, writeExecConfig, reset - commands/builtin/register-streaming.ts: config read/write - gateway/interaction-handler.ts: config query/update handlers - gateway/types.ts: GatewayPluginRuntime.config interface * feat(qqbot): update package.json * fix(qqbot): replace deprecated config-runtime import with config-types subpath Bundled plugin lint requires focused plugin-sdk subpaths. - gateway.ts: openclaw/plugin-sdk/config-runtime → config-types - narrowing.ts: openclaw/plugin-sdk/config-runtime → config-types * feat(qqbot): group chat support, C2C streaming, chunked media upload, and architecture refactor (openclaw#70624) (thanks @cxyhhhhh) --------- Co-authored-by: Bobby <[email protected]> Co-authored-by: sliverp <[email protected]>
Summary
stream_messagesAPI support with aStreamingControllerlifecycle manager.sendMediamethod withMediaSourceabstraction and chunked upload support for large files.inbound-pipeline.tsinto 11 discrete pipeline stages; splitoutbound.ts(~1200 LOC) into 5 focused submodules; splitslash-commands-impl.ts(~1000 LOC) intobuiltin/command modules.ports/intoadapter/with 5 explicit DI ports; introducedcreateEngineAdapters()single assembly point.INTERACTION_CREATE.toGatewayAccount, credential snapshot persistence, and structured logging with metadata.extensions/qqbot/.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause (if applicable)
N/A — This is a feature PR, not a bug fix.
Regression Test Plan (if applicable)
media-chunked.test.ts— chunked upload retry, error handling, resume logicgroup.test.ts— per-group config resolution, wildcard overridesmessage-queue.test.ts— FIFO ordering, group merge batchingcontent-stage.test.ts,envelope-stage.test.ts— inbound pipeline stagesactivation.test.ts— group activation mode persistencedeliver-debounce.test.ts— rapid-burst merge, media flush, maxWait caphistory.test.ts— pending history buffer, render on mention replymention.test.ts— explicit @bot, implicit quote-reply, ignoreOtherMentionsmessage-gating.test.ts— gating rules for group message filteringattachment-tags.test.ts— inline attachment tag parsing and enrichmentUser-visible / Behavior Changes
c2cStreamApiconfig)./bot-streamingcommand: New slash command to toggle streaming on/off per account./bot-logscommand: Export engine logs for debugging./bot-clear-storagecommand: Manage downloaded file storage.INTERACTION_CREATE(type 2001/2002).c2cStreamApi: booleanin account configuration.Diagram (if applicable)
Security Impact (required)
NoNoYesYesNoYes, explain risk + mitigation:stream_messagesAPI and chunked media upload endpoints are new QQ Bot API calls. These use the same authenticated credential flow as existing API calls — no new auth surface./bot-streaming,/bot-logs,/bot-clear-storageare plugin-scoped slash commands that only operate on the bot's own state/config./bot-clear-storagedeletes only files in the plugin-managed download directory./bot-logsexports only engine-internal logs — no user data.Repro + Verification
Environment
c2cStreamApi: truefor streaming; group config withactivation,prompt,historyLimitfieldsSteps
@botmention./bot-streaming onand send a message.Expected
Actual
Evidence
11 new test suites (2,153 lines) all passing — covering chunked upload, group config, message queue, pipeline stages, activation, debounce, history, mention, message gating, and attachment tags.
Human Verification (required)
/bot-logsand/bot-clear-storagecommands, config query/update via interaction.Review Conversations
Compatibility / Migration
Yes— All new features are opt-in. Existing C2C-only accounts work unchanged.Yes— New optionalc2cStreamApiboolean in account config (defaults tofalse).NoRisks and Mitigations
maxWaitcap ensures messages are flushed within a bounded window; unit tests cover burst scenarios.