Skip to content

feat(qqbot): group chat support, C2C streaming, chunked media upload, and architecture refactor#70624

Merged
sliverp merged 17 commits into
openclaw:mainfrom
cxyhhhhh:feat/qqbot_dev
Apr 27, 2026
Merged

feat(qqbot): group chat support, C2C streaming, chunked media upload, and architecture refactor#70624
sliverp merged 17 commits into
openclaw:mainfrom
cxyhhhhh:feat/qqbot_dev

Conversation

@cxyhhhhh

Copy link
Copy Markdown
Contributor

Summary

  • Problem: The QQBot engine lacked group chat support, C2C streaming message delivery, large-file upload handling, and the codebase had accumulated monolithic files with tightly coupled logic that hindered maintainability.
  • Why it matters: Group chat is a fundamental QQ messaging capability; C2C streaming enables typing-style real-time delivery; chunked upload removes the file-size ceiling; the architecture refactor unblocks future development velocity.
  • What changed:
    • Implemented full group chat pipeline: history tracking, @-mention detection/gating, activation modes, per-group config, message queue with FIFO merging, and deliver debounce.
    • Added C2C stream_messages API support with a StreamingController lifecycle manager.
    • Introduced unified sendMedia method with MediaSource abstraction and chunked upload support for large files.
    • Extracted monolithic inbound-pipeline.ts into 11 discrete pipeline stages; split outbound.ts (~1200 LOC) into 5 focused submodules; split slash-commands-impl.ts (~1000 LOC) into builtin/ command modules.
    • Merged ports/ into adapter/ with 5 explicit DI ports; introduced createEngineAdapters() single assembly point.
    • Added interaction handler for remote config query/update via INTERACTION_CREATE.
    • Enhanced account management with toGatewayAccount, credential snapshot persistence, and structured logging with metadata.
  • What did NOT change (scope boundary): No changes to the core OpenClaw framework, other plugins, authentication flows, or public API contracts. All changes are scoped to extensions/qqbot/.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #
  • This PR fixes a bug or regression

Root Cause (if applicable)

N/A — This is a feature PR, not a bug fix.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: 11 new test suites (2,153 LOC) covering:
    • media-chunked.test.ts — chunked upload retry, error handling, resume logic
    • group.test.ts — per-group config resolution, wildcard overrides
    • message-queue.test.ts — FIFO ordering, group merge batching
    • content-stage.test.ts, envelope-stage.test.ts — inbound pipeline stages
    • activation.test.ts — group activation mode persistence
    • deliver-debounce.test.ts — rapid-burst merge, media flush, maxWait cap
    • history.test.ts — pending history buffer, render on mention reply
    • mention.test.ts — explicit @bot, implicit quote-reply, ignoreOtherMentions
    • message-gating.test.ts — gating rules for group message filtering
    • attachment-tags.test.ts — inline attachment tag parsing and enrichment
  • Scenario the test should lock in: Each module's happy path, edge cases (empty input, max limits, timeout), and error paths.
  • Why this is the smallest reliable guardrail: Unit tests at module boundaries verify contracts without requiring a live QQ gateway.

User-visible / Behavior Changes

  • Group chat support: Bot can now participate in QQ group conversations with @-mention activation, message history context, and per-group configurable prompts.
  • C2C streaming: Messages in private chats can now be delivered with typing-style streaming updates (opt-in via c2cStreamApi config).
  • /bot-streaming command: New slash command to toggle streaming on/off per account.
  • Large file upload: Media uploads now support chunked transfer for files exceeding the single-request size limit.
  • /bot-logs command: Export engine logs for debugging.
  • /bot-clear-storage command: Manage downloaded file storage.
  • Remote config: Interaction-based config query/update via INTERACTION_CREATE (type 2001/2002).
  • New config option: c2cStreamApi: boolean in account configuration.

Diagram (if applicable)

Before (group messages):
[QQ group msg] -> [ignored / no handler]

After (group messages):
[QQ group msg] -> [access-stage] -> [content-stage] -> [quote-stage]
    -> [group-gate-stage (mention/activation check)]
    -> [envelope-stage] -> [assembly-stage]
    -> [message-queue (FIFO + merge)] -> [deliver-debounce] -> [outbound]

Before (outbound.ts):
[outbound.ts ~1200 LOC monolith]

After (outbound modules):
[outbound.ts (re-export hub)]
  ├── outbound-types.ts
  ├── outbound-reply.ts
  ├── outbound-audio-port.ts
  ├── outbound-media-send.ts
  └── outbound-result-helpers.ts

Before (media upload):
[file > limit] -> [error: file too large]

After (chunked upload):
[file > limit] -> [MediaSource abstraction] -> [chunked upload with retry] -> [success]

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? Yes
  • Command/tool execution surface changed? Yes
  • Data access scope changed? No
  • If any Yes, explain risk + mitigation:
    • New network calls: C2C stream_messages API 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.
    • New commands: /bot-streaming, /bot-logs, /bot-clear-storage are plugin-scoped slash commands that only operate on the bot's own state/config. /bot-clear-storage deletes only files in the plugin-managed download directory. /bot-logs exports only engine-internal logs — no user data.

Repro + Verification

Environment

  • OS: macOS / Linux
  • Runtime/container: Node.js 20+
  • Model/provider: Any (plugin is model-agnostic)
  • Integration/channel: QQ Bot (C2C + Group)
  • Relevant config: c2cStreamApi: true for streaming; group config with activation, prompt, historyLimit fields

Steps

  1. Configure a QQBot account with group intents enabled.
  2. Send a message in a group chat with @bot mention.
  3. Verify bot responds with group history context and per-group prompt.
  4. In a C2C chat, enable streaming via /bot-streaming on and send a message.
  5. Verify typing-style streamed delivery.
  6. Upload a file >10MB and verify chunked upload completes.

Expected

  • Group messages are received, gated by mention/activation rules, and replied with context.
  • C2C streaming delivers message chunks progressively.
  • Large files upload successfully via chunked transfer.

Actual

  • Verified all scenarios work as expected.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

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)

  • Verified scenarios: Group @-mention reply with history, C2C streaming toggle, chunked media upload for large files, /bot-logs and /bot-clear-storage commands, config query/update via interaction.
  • Edge cases checked: Empty group history, rapid burst message merging, file size at boundary, streaming disable/re-enable, mention with quote-reply.
  • What you did not verify: Production-scale load testing, guild channel interactions (out of scope for this PR).

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes — All new features are opt-in. Existing C2C-only accounts work unchanged.
  • Config/env changes? Yes — New optional c2cStreamApi boolean in account config (defaults to false).
  • Migration needed? No

Risks and Mitigations

  • Risk: Group message queue merge logic could drop messages under extreme burst rates.
    • Mitigation: maxWait cap ensures messages are flushed within a bounded window; unit tests cover burst scenarios.
  • Risk: Chunked upload retry could cause duplicate media delivery on transient failures.
    • Mitigation: Chunked upload uses idempotent upload IDs; test suite covers retry and resume logic.
  • Risk: Large refactor (83 files, ~12k insertions) increases review surface.
    • Mitigation: Refactor is purely structural (extracting modules, no behavior changes in moved code); 11 new test suites validate contracts at module boundaries.

@greptile-apps

greptile-apps Bot commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds group chat support, C2C streaming delivery, chunked media upload, and a significant architectural refactor to extensions/qqbot/. The 83-file change is well-structured: monolithic files are split into focused modules, logic is extracted into pure functions, and 11 new test suites (2,153 LOC) provide solid coverage at module boundaries. All behavioral changes are scoped to the qqbot extension as stated.

The dispatch-from-config.ts change correctly moves TTS accumulation to post-suppression so exec-approval duplicate blocks are not spoken, and the withTokenRetry improvement adds structured ApiError detection before falling back to string heuristics.

Confidence Score: 5/5

Safe 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 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.

---

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

Comment on lines +296 to +320
*
* 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)}`);
}
};

/**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

Comment on lines +127 to +145
* 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;
}
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

Comment on lines +1 to +20
/**
* 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,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +336 to +340
for (const cmd of commands) {
log?.debug?.(
`Processing command independently for ${peerId}: ${(cmd.content ?? "").trim().slice(0, 50)}`,
);
await processOne(cmd, peerId, "Command processor");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +225 to +228
const maxConcurrent = Math.min(
prepareResp.concurrency ? prepareResp.concurrency : DEFAULT_CONCURRENT_PARTS,
MAX_CONCURRENT_PARTS,
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@openclaw-barnacle openclaw-barnacle Bot added the scripts Repository scripts label Apr 23, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +107 to +108
const commandAuthorized =
deps.allowTextCommands !== false && isSenderAllowedForCommands(event.senderId, deps);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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 👍 / 👎.

Comment on lines +120 to +121
const channels = (cfg.channels ?? {}) as Record<string, unknown>;
const qqbot = (channels.qqbot ?? {}) as Record<string, unknown>;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@vincentkoc vincentkoc added the triage: refactor-only Candidate: refactor/cleanup-only PR without maintainer context. label Apr 26, 2026
@clawsweeper

clawsweeper Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

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:

  • Bundled QQBot scope: QQ Bot is documented as a bundled plugin with C2C private chat, group @messages, guild channel messages, and rich media support, so this belongs in the in-repo QQBot plugin surface rather than being an automatic ClawHub close. Public docs: docs/channels/qqbot.md. (docs/channels/qqbot.md:8, a35ad200d1d1)
  • Current main only dispatches group @ events: Current main declares GROUP_AT_MESSAGE_CREATE but not GROUP_MESSAGE_CREATE, and event-dispatcher only converts GROUP_AT_MESSAGE_CREATE into a queued group message. The PR's non-@ group-message/history path is therefore not implemented on main. (extensions/qqbot/src/engine/gateway/event-dispatcher.ts:123, a35ad200d1d1)
  • Current main lacks official C2C streaming implementation: The current config schema supports only boolean/object block streaming mode, with no c2cStreamApi field, and the MessageApi has no sendC2CStreamMessage method or StreamingController integration despite a route helper stub existing. (extensions/qqbot/src/config-schema.ts:27, a35ad200d1d1)
  • Current main lacks chunked upload dispatch: Current MediaApi.uploadMedia accepts only url/fileData and uses the small-file /files path; local outbound media still checks the 20MB MAX_UPLOAD_SIZE before base64 upload. There is no media-chunked.ts/ChunkedMediaApi implementation in the current checkout. (extensions/qqbot/src/engine/api/media.ts:78, a35ad200d1d1)
  • PR remains distinct and active: Remote refs show this PR head at 408366c98100bcdcad6af7fe32250d940fdd1373 with a merge ref, while main has moved independently. The provided GitHub context also shows the PR is open and unmerged. (408366c98100)
  • Security review findings still need attention: The PR diff still accepts server-provided non-positive chunk concurrency before passing it to runWithConcurrency, which can hang uploads; group batching still merges mixed senders under the last senderId and processes commands before normal messages; group command bypass auth still treats an empty allowFrom as authorized; and applyRequireMentionUpdate still mutates detached cfg.channels/qqbot objects when those containers are missing. (extensions/qqbot/src/engine/api/media-chunked.ts, 408366c98100)

Remaining risk / open question:

  • The PR is very large and mixes user-facing QQBot feature work with an architecture refactor, increasing review and regression risk.
  • The diff adds security-sensitive behavior: raw PUT uploads to pre-signed URLs, config-writing interaction handlers, log export, and file deletion commands. Some guards are present, but these paths need focused maintainer review before merge.
  • Several substantive review findings appear unresolved in the latest diff, including group sender authorization/merge semantics, command ordering, chunked upload concurrency validation, and sparse-config mutation behavior.

Codex Review notes: model gpt-5.5, reasoning high; reviewed against a35ad200d1d1.

@cxyhhhhh
cxyhhhhh force-pushed the feat/qqbot_dev branch 4 times, most recently from 2f1198d to 4f1eb23 Compare April 27, 2026 14:53
@sliverp sliverp self-assigned this Apr 27, 2026
zkd8907 and others added 14 commits April 27, 2026 23:17
…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
@sliverp
sliverp merged commit 5ccf179 into openclaw:main Apr 27, 2026
3 checks passed
@sliverp

sliverp commented Apr 27, 2026

Copy link
Copy Markdown
Member

Landed via temp rebase onto main.

Thanks @cxyhhhhh!

ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
… 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]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
… 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]>
globalcaos pushed a commit to globalcaos/tinkerclaw that referenced this pull request May 13, 2026
… 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]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
… 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]>
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
… 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]>
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
… 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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: qqbot scripts Repository scripts size: XL triage: refactor-only Candidate: refactor/cleanup-only PR without maintainer context.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants