Commit Graph

33214 Commits

Author SHA1 Message Date
scotthuang
8a7c21407a fix(agents): gate sessions_send A2A skip on requester ownership
Greptile/Codex review follow-ups on #69817:

- Narrow skipA2AFlow from target-only detection to a combined check that
  the caller is the parent of the target (new
  isRequesterParentOfBackgroundAcpSession helper). Under
  tools.sessions.visibility=all a non-parent sender can see the same
  oneshot ACP session; the previous guard would have suppressed their
  only follow-up delivery path. With requester ownership required, those
  senders continue through the normal A2A flow.
- When the A2A flow is skipped, return delivery.status="skipped" instead
  of "pending" so the parent LLM does not wait for a second result that
  will never arrive.
- Add unit tests for resolveAcpSessionInteractionMode and
  isRequesterParentOfBackgroundAcpSession covering both the new
  ownership gate and the existing target-type branches.
2026-04-21 22:17:28 +01:00
scotthuang
1c3fbbd72a fix(agents): skip sessions_send A2A flow for parent-owned ACP children
The A2A ping-pong + announce flow in runSessionsSendA2AFlow treats the
send target as a peer agent and echoes replies back and forth between
requester and target. When the target is an ACP child spawned by the
requester, this creates an infinite loop: the parent is woken with the
child's reply, generates a user-facing response, and has that response
forwarded back to the child as a new user message — effectively granting
the child an implicit sessions_send capability back to the parent.

ACP children already report their results through the
[Internal task completion event] announcement path, so no A2A flow is
needed when the send target is a parent-owned background ACP session.

Detect this case via isParentOwnedBackgroundAcpSession and short-circuit
startA2AFlow before runSessionsSendA2AFlow is invoked.
2026-04-21 22:17:28 +01:00
Vincent Koc
ff67a890af docs(channels): clean troubleshooting link labels, generic imessage path placeholder, drop msteams stamped date 2026-04-21 13:59:12 -07:00
Peter Steinberger
8d1b3d4578 ci: speed up release metadata pre-commit checks 2026-04-21 21:56:06 +01:00
Peter Steinberger
aa94501f5f feat(openai): default images to gpt-image-2 2026-04-21 21:49:16 +01:00
Peter Steinberger
0b1a35363e chore: start 2026.4.21 development 2026-04-21 21:42:15 +01:00
Vincent Koc
8f1a87ea47 docs: note Kimi K2.6 thinking-disabled on Fireworks and Ollama cloud onboard live-tag fetch 2026-04-21 13:41:10 -07:00
Vincent Koc
9702f0bf21 docs: tool-progress preview streaming, Control UI avatar auth, exec heredoc and external-content token sanitization 2026-04-21 13:39:55 -07:00
Devin Robison
3cb1a56bfc fix(gateway): derive loopback owner context from token (#69796)
* fix(gateway): derive loopback owner context from token

* docs(changelog): note loopback owner token hardening

* refactor(gateway): clarify loopback runtime cleanup

* fix(gateway): compare both loopback bearer classes
2026-04-21 14:39:48 -06:00
Peter Steinberger
674feda214 docs(plugins): document message presentation cards 2026-04-21 21:29:44 +01:00
Peter Steinberger
c742a706bf feat(plugins): add experimental skill workshop 2026-04-21 21:29:44 +01:00
Peter Steinberger
fd0970c077 refactor(channels): decouple presentation rendering 2026-04-21 21:29:44 +01:00
Peter Steinberger
d7a173e60e feat(plugin-sdk): add presentation and skills runtime contracts 2026-04-21 21:29:44 +01:00
Vincent Koc
78030d0d52 docs: plugin manifest precedence, QQBot engine/bot-approve/QR onboarding, web-search plugin-scoped SecretRefs 2026-04-21 13:26:25 -07:00
Vincent Koc
b4a59be9b6 docs: document stdio env filter, enforceOwnerForCommands, OPENCLAW_* .env blocking 2026-04-21 13:21:34 -07:00
Vincent Koc
32ccf27e60 docs: document WS broadcast scope gating and Control UI img-src CSP 2026-04-21 13:14:15 -07:00
Vincent Koc
7d7c0b1dfe docs: cover BB tapback fallback, iMessage/SMS routing, Mattermost streaming, Matrix mention-prefixed slash 2026-04-21 13:09:09 -07:00
Peter Steinberger
e5af4e3b5c ci(deps): gate extension-owned root dependencies 2026-04-21 21:08:08 +01:00
Devin Robison
b2e8b7d4bb fix(exec): block heredoc parameter expansion (#69795)
* fix(exec): block heredoc parameter expansion

* chore(changelog): note heredoc parameter expansion fix

* fix(exec): tighten heredoc expansion guardrails

* fix(exec): reject continued heredoc expansions

* fix(exec): buffer heredoc continuation chunks

* fix(exec): harden heredoc continuation parsing

* fix(exec): cap heredoc continuation chunks

* fix(exec): reject continued heredoc param expansion across delimiter

Bash splices `$VAR\\<newline>REST` into `$VARREST` inside an
unquoted heredoc body even when the continued physical line matches the
heredoc delimiter; the heredoc only terminates at EOF with a warning.
The analyzer previously shifted the pending heredoc the moment a line
equaled the delimiter, so a payload like `cat <<KEY\n$OPENAI_API_\\\nKEY`
passed allowlist review while the runtime would expand and print
$OPENAI_API_KEY.

Mirror bash's splicing: only treat a delimiter-matching line as the
terminator when no continuation chunks are pending, otherwise append it
to the logical line and evaluate it through the expansion check. The
tail handler does the same splice + expansion check before falling back
to "unterminated heredoc".
2026-04-21 14:01:35 -06:00
Peter Steinberger
ccfef0f13f chore: update appcast for 2026.4.20 2026-04-21 21:01:19 +01:00
Peter Steinberger
8d289306de ci: support release branch mac validation 2026-04-21 21:01:05 +01:00
Devin Robison
2ce16e558e fix(gateway): require auth for control UI avatar route (#69775)
* fix(gateway): require auth for control UI avatar route

* chore: add changelog for control UI avatar auth

* fix(control-ui): honor device auth for avatar urls

* fix(control-ui): avoid query tokens for avatar auth

* fix(control-ui): render authenticated avatar blob URLs in chat views

* fix(control-ui): restore normalizeOptionalString import in render helpers
2026-04-21 13:51:03 -06:00
Gustavo Madeira Santana
6b185e2849 perf: speed up discord channel registration (#69791)
Merged via squash.

Prepared head SHA: 231d8763b4
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-21 15:48:08 -04:00
Peter Steinberger
895ac965da test: cover Telegram session recreation 2026-04-21 20:36:32 +01:00
Peter Steinberger
0a6ce260ed fix(deps): keep qqbot connector plugin-local 2026-04-21 20:33:16 +01:00
Peter Steinberger
6f004ed4d4 feat(fireworks): add Kimi K2.6 model 2026-04-21 20:31:33 +01:00
Peter Steinberger
2514746b32 fix: sanitize LLM special tokens in external content 2026-04-21 20:29:02 +01:00
Shakker
fb7bfb411c docs: add Copilot Opus changelog (#69818) (thanks @shakkernerd) 2026-04-21 20:00:06 +01:00
Shakker
2161ed8259 fix: update Copilot Opus default to 4.7 2026-04-21 20:00:06 +01:00
Peter Steinberger
11efbf5a2e fix: prevent stale subagent failure announces 2026-04-21 19:59:12 +01:00
Tak Hoffman
dcf131e54c docs: restore general multi-gateway guidance (#69810) 2026-04-21 13:34:18 -05:00
Peter Steinberger
47cfdd2df1 test: cover active provider thinking registry 2026-04-21 19:24:26 +01:00
Peter Steinberger
61564147f3 fix: break provider thinking import cycle 2026-04-21 19:19:03 +01:00
Peter Steinberger
b2b43085bc ci: use larger Blacksmith macOS runners 2026-04-21 19:03:50 +01:00
Tak Hoffman
5218c1a01f docs: front-load rescue bot quickstart (#69803)
* docs: front-load rescue bot quickstart

* docs: recommend rescue port 19789

* docs: show rescue port in quickstart command
2026-04-21 13:01:23 -05:00
Agustin Rivera
38356c658a fix(synology): validate webhook file urls (#69784)
* fix(synology): validate webhook file urls

* fix(synology): restore file send throttle

* docs(changelog): note synology webhook file_url SSRF guard (#69784)

---------

Co-authored-by: Devin Robison <drobison@nvidia.com>
2026-04-21 12:00:28 -06:00
Peter Steinberger
bcfa781a1b fix: remap thinking levels on model switch 2026-04-21 18:53:49 +01:00
Gustavo Madeira Santana
24db09a19b fix(cli): keep channel status checks off plugin runtimes (#69479)
Merged via squash.

Prepared head SHA: 63f6e416a9
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-21 13:53:08 -04:00
Tak Hoffman
09c5669299 docs: clarify rescue bot gateway setup (#69788)
* docs: clarify rescue bot gateway setup

* docs: make rescue bot guide more prescriptive
2026-04-21 12:29:40 -05:00
Gustavo Madeira Santana
ddc1d9aa54 perf: speed up telegram channel registration (#69786)
Merged via squash.

Prepared head SHA: ac03f96e0d
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-21 13:24:28 -04:00
cxy
5e72e39c18 feat(qqbot): extract self-contained engine/ architecture with QR-code onboarding, approval handling (#67960)
* feat(qqbot): add core architecture modules

* feat(qqbot): extract engine modules with DI adapters

* refactor(qqbot): remove plugin-level TTS, delegate to framework

Remove qqbot's internal TTS implementation and unify voice synthesis
through the framework's global TTS provider registry.

- Delete engine/gateway/tts-config.ts (plugin-specific TTS config)
- Simplify TTSProvider interface to textToSpeech + audioFileToSilkBase64
- Remove dual-strategy TTS in handleAudioPayload (plugin + global fallback)
- Strip QQBotTtsSchema from config-schema, plugin.json, and tests
- Remove TTS diagnostics logging and hasTTS system prompt from gateway
- Delete ~260 lines of TTS code from utils/audio-convert.ts

Made-with: Cursor

* feat(qqbot): extract shared engine modules for config, tools, and audio

Add engine-layer modules that are self-contained and portable across
both the built-in and standalone qqbot packages:

- engine/config: account resolution helpers, field readers
- engine/tools: channel API proxy, remind scheduling logic
- engine/utils: audio format conversion, duration/error formatting,
  debug logging

Consolidate duplicate utility functions across the codebase:

- Merge debug-log.ts into log.ts
- Merge error-format.ts into format.ts with full .cause chain support
- Unify normalizeLowercase/readNumber/readBoolean/readStringMap into
  string-normalize.ts, removing private copies in resolve.ts,
  remind-logic.ts, and audio-convert.ts
- Remove dead formatDuration export from audio-convert.ts
- Delete unused config/schema.ts and config/helpers.ts

Made-with: Cursor

* refactor(qqbot): streamline account configuration and credential management

Refactor the QQBot account configuration logic by consolidating credential management into dedicated engine modules. Key changes include:

- Migrate credential clearing and validation logic to engine/config/credentials.ts.
- Simplify setup input validation and application in engine/config/setup-logic.ts.
- Enhance account resolution and configuration application in engine/config/resolve.ts.
- Update channel and messaging logic to utilize the new credential management functions.

This refactor improves code maintainability and clarity by separating concerns and reducing duplication across the codebase.

* feat(qqbot): simplify api architecture

* feat: 支持扫码绑定QQ机器人

* feat(qqbot): refactor gateway into inbound pipeline + outbound dispatch

- Extract handleMessage (620 lines) into three modules:
  - inbound-context.ts: InboundContext type definition
  - inbound-pipeline.ts: buildInboundContext()
  - outbound-dispatch.ts: dispatchOutbound()
- gateway.ts handleMessage reduced to ~35 line shell
- Unify parseRefIndices: support both ext prefix formats + MSG_TYPE_QUOTE
- Add ref/format-message-ref.ts for cache-miss quote formatting
- Remove [QQBot] to= from agentBody, use GroupSystemPrompt instead
- QueuedMessage: add msgType/msgElements for quote messages

* fix(qqbot): fix markdownSupport loss + dynamic User-Agent

Root cause: setOpenClawVersion() called _ensureInitialized(true) which
cleared _appRegistry, destroying the MessageApi instance created by
initApiConfig() with markdownSupport=true. Subsequent block deliver
calls created a default markdownSupport=false instance, causing:
1. Markdown messages sent as plain text (msg_type=0 instead of 2)
2. message_reference incorrectly added (only suppressed in MD mode)

Fix: ApiClient and TokenManager now accept userAgent as string | (() => string).
sender.ts passes the buildUserAgent function reference, so UA changes
propagate automatically on next request without rebuilding any objects.

- ApiClient: userAgent -> resolveUserAgent getter, called per-request
- TokenManager: same pattern
- types.ts: ApiClientConfig.userAgent supports string | (() => string)
- sender.ts: remove force re-init + _rebuildAppRegistry hack
  - initSender/setOpenClawVersion only update version variables
  - _ensureInitialized creates singletons once, never destroys them
  - _appRegistry is never cleared -> markdownSupport always preserved
- runtime.ts: inject framework version via setOpenClawVersion(runtime.version)
- gateway.ts: pass openclawVersion to initSender + registerPluginVersion
- slash-commands-impl.ts: remove fragile require("../package.json")

* feat(qqbot): implement native approval handling and configuration

Add a new approval handling system for QQBot that integrates with the existing framework. Key features include:

- Introduce `approval-handler.runtime.ts` for managing approval requests via QQ messages with inline keyboard support.
- Create `approval-native.ts` as the entry point for QQBot's approval capability, allowing for simplified approval processes without explicit approver lists.
- Implement configuration schema for exec approvals, enabling fine-grained control over who can approve requests.
- Enhance messaging and interaction handling to support approval decisions through button interactions.

This implementation streamlines the approval process, making it more user-friendly and efficient for QQBot users.

* refactor(qqbot): enhance error handling across API and messaging modules

This update introduces a centralized error formatting utility, `formatErrorMessage`, to improve consistency in error logging throughout the QQBot codebase. Key changes include:

- Integration of `formatErrorMessage` in various API client, messaging, and gateway modules to standardize error messages.
- Replacement of direct error message handling with the new utility to enhance readability and maintainability.

These improvements streamline error reporting and provide clearer insights into issues encountered during operation.

* refactor(qqbot): enhance API and messaging structure with type improvements

This update refines the API and messaging modules by introducing type enhancements and restructuring function signatures for better clarity and maintainability. Key changes include:

- Updated import statements to streamline type usage in  and .
- Refactored message sending functions to accept options objects, improving readability and flexibility.
- Introduced a new  method in  to facilitate external message-sent notifications.
- Enhanced error handling in the retry mechanism to ensure more robust behavior.

These modifications aim to improve the overall code quality and developer experience within the QQBot framework.

* feat: 优化文案

* refactor(qqbot): unify Logger interfaces + eliminate P0 code smells

Logger unification (17 files):
- Introduce single EngineLogger interface in engine/types.ts
  { info, error, warn?, debug? }
- Delete 5 fragmented Logger interfaces:
  GatewayLogger, ReconnectLogger, MessageRefLogger, PathLogger, SenderLogger
- Replace all references across engine/ to use EngineLogger directly

P0 code smell fixes (sender.ts + messages.ts + outbound-dispatch.ts):
- messages.ts: add public notifyMessageSent() method on MessageApi,
  replacing 8x 'as unknown as { messageSentHook }' private field hack
- sender.ts: extract notifyMediaHook() helper, deduplicate 4 media
  send functions (sendImage/sendVoice/sendVideo/sendFile)
- sender.ts: replace magic numbers 1/2/3/4 with MediaFileType enum
- sender.ts: remove 4 redundant 'as MessageResponse' type assertions
- outbound-dispatch.ts: remove 5 unnecessary 'as never' casts

* feat(qqbot): add /bot-clear-storage command + consolidate utils/types into engine/

/bot-clear-storage (slash-commands-impl.ts):
- Migrate from standalone version, aligned with its two-step flow:
  1. No args: scan ~/.openclaw/media/qqbot/downloads/{appId}/ and
     display file list with confirmation button
  2. --force: delete files + removeEmptyDirs cleanup
- C2C only (group chat returns hint)
- bot-help: exclude bot-upgrade and bot-clear-storage in group listings

Consolidate into engine/:
- Delete src/utils/audio-convert.ts (pure re-export shell, zero consumers)
- Move 5 test files from src/utils/ to src/engine/utils/ (fix import paths)
- Move src/types/silk-wasm.d.ts to src/engine/types/
- Remove empty src/utils/ and src/types/ directories

* refactor(qqbot): restructure API and bridge components for improved modularity

This update enhances the QQBot framework by reorganizing the API and bridge components, promoting better modularity and maintainability. Key changes include:

- Refactored import paths to streamline access to bridge tools and configurations.
- Introduced new bridge files for channel entry, runtime, and approval capabilities, centralizing related functionalities.
- Updated existing functions to utilize the new bridge structure, ensuring consistency across the codebase.
- Removed deprecated functions and types, simplifying the overall architecture.

These modifications aim to improve code clarity and facilitate future development within the QQBot ecosystem.

* refactor(qqbot): standardize engine log levels and unify log tag prefix

- Rename client.ts to api-client.ts to match ApiClient class name
- Downgrade ~60 non-critical info logs to debug level across 12 files
  (token request/response, HTTP request/response, session restore,
  media tag detection, image classification, quote detection,
  attachment download/transcode, retry attempts, etc.)
- Unify log tag prefix to [qqbot:xxx] format across all engine modules
  ([core-api] -> [qqbot:api], [token:x] -> [qqbot:token:x],
  [retry] -> [qqbot:retry], [messages] -> [qqbot:messages],
  [sender:x] -> [qqbot:x])
- Remove unnecessary reqTs timestamp from api-client.ts log output
- Add dispatch event debug log in gateway-connection.ts
- Merge sendProactiveMessage into sendText, remove dead code
  (sendProactiveText import, getRefIdx, QQMessageResult type)
- Narrow allow-from.ts type from unknown[] to Array<string | number>

* refactor(qqbot): move interaction handler from bridge to engine

- Move onInteraction approval handler into engine/gateway.ts as
  createApprovalInteractionHandler(), eliminating the callback
  indirection through CoreGatewayContext
- Remove onInteraction from CoreGatewayContext interface and its
  unused InteractionEvent import from gateway/types.ts
- Remove getPlatformAdapter, parseApprovalButtonData and
  InteractionEvent imports from bridge/gateway.ts

* refactor(qqbot): route bridge and sender logs through framework logger

- Add bridge/logger.ts as a shared logger holder for bridge-layer
  modules, injected with ctx.log during gateway startup
- Replace all console.log/console.error in bridge/ with
  getBridgeLogger() calls (approval, bootstrap, tools)
- Restore framework logger support in sender.ts via initSender()
  so API-layer logs flow through OpenClaw log system
- Remove all direct debugLog/debugError imports from bridge/

* feat(qqbot): per-account isolated resource stack + multi-account logger

- sender.ts: global singletons (ApiClient/TokenManager/MediaApi) -> per-account AccountContext
  - Add _accountRegistry: Map<appId, AccountContext>
  - Each account owns independent client/tokenMgr/mediaApi/messageApi/logger
  - registerAccount() atomically sets up all resources
  - resolveAccount() routes to correct resource stack by appId
  - Remove _sharedLogger/_loggerRegistry/_appRegistry and old structures

- bridge/gateway.ts: createAccountLogger() with auto [accountId] prefix
  - registerAccount() merges logger + markdownSupport + full API resources

- engine-wide: remove ~60 manual [qqbot:${accountId}] log prefixes
  - Prefixes now auto-injected by per-account logger
  - Remove prefix/logPrefix parameter chains (outbound/outbound-deliver/typing-keepalive etc)

* feat(qqbot): completes fallback path for approval with multi-account isolation

When the execApprovals are not configured, multiple QQBot accounts' handlers will attempt to deliver the same approval message. The openid is account-level, and cross-account delivery will trigger a QQ Bot API 500 error.

- Add account ownership verification in the fallback shouldHandle: Only match the account's handler when the request includes turnSourceAccountId; if unbound, delivery is only permitted when the number of enabled+secret accounts is ≤1.

- Consolidate account ownership determination into the unified export `matchesQQBotApprovalAccount` in `exec-approvals.ts`, with both capability and native runtime paths sharing the same logic to eliminate redundancy.

* feat(qqbot): optimize permission validation strategy

* feat(qqbot): show plugin version in /bot-version and /bot-help

Align /bot-version output with the standalone openclaw-qqbot build so users see both the QQBot plugin version and the OpenClaw framework version. Append the plugin version as a footer in /bot-help as well, matching the standalone UX.

Also fix the plugin version lookup that previously rendered as 'vunknown': the old code used a hardcoded '../../package.json' relative path which resolved to 'src/package.json' (non-existent) when executed from raw sources, so the require threw and the default 'unknown' value was retained. The same broken value also leaked into the QQ Bot API User-Agent header.

Replace the hardcoded path with a dedicated helper (bridge/plugin-version.ts) that walks up the directory tree from import.meta.url and validates the manifest's name field (@openclaw/qqbot) to avoid misreading the monorepo root package.json. Covered by 6 unit tests.

* feat(qqbot): trust shared ~/.openclaw/media root for payload files

Add getOpenClawMediaDir() and include it alongside getQQBotMediaDir() in the allowed roots of resolveQQBotPayloadLocalFilePath, so framework-produced attachments under sibling directories (e.g. media/outbound/ written by saveMediaBuffer) are trusted by auto-routed sends without triggering the path-outside-storage guard.

Covered by a new test case that verifies files under ~/.openclaw/media/outbound/ resolve successfully.

* fix(qqbot): ensure PlatformAdapter is registered before approval delivery

After the framework centralized approval handler bootstrap (#62135), the native approval handler is spawned by the framework layer outside the qqbot gateway startAccount context. This means channel.ts's side-effect `import "./bridge/bootstrap.js"` may not have run, leaving PlatformAdapter unregistered when deliverPending calls resolveQQBotAccount -> getPlatformAdapter().

Extract ensurePlatformAdapter() from bootstrap.ts as an idempotent, re-entrant helper and call it in both capability.ts (load callback) and handler-runtime.ts (deliverPending entry) to guarantee the adapter is available regardless of initialization order.

* fix(qqbot): add lazy factory for PlatformAdapter to eliminate import-order dependency

The bundler splits qqbot code into multiple chunks where the adapter singleton and its consumers may live in different modules. When a consumer chunk evaluates before the bootstrap side-effect chunk, getPlatformAdapter() throws because the singleton is still null.

Introduce registerPlatformAdapterFactory() in adapter/index.ts so getPlatformAdapter() can auto-initialize the adapter on first access. bootstrap.ts registers the factory at module evaluation time alongside the existing eager registration path. Also add error logging in downloadFile's catch block to surface fetch failures.

* feat(qqbot): add /bot-approve slash command for exec approval config management

Add /bot-approve command to the built-in QQBot plugin, ported from the
standalone openclaw-qqbot implementation. This command allows users to
manage tools.exec.security and tools.exec.ask settings directly from QQ.

Supported sub-commands:
  /bot-approve on      - allowlist + on-miss (recommended)
  /bot-approve off     - full + off (no approval)
  /bot-approve always  - allowlist + always (strict mode)
  /bot-approve reset   - remove overrides, restore framework defaults
  /bot-approve status  - show current security/ask values

The runtime config API is injected via registerApproveRuntimeGetter()
following the existing dependency injection pattern used by
registerVersionResolver() and registerPluginVersion().

* fix(qqbot): ACK INTERACTION_CREATE events before processing approval buttons

Send PUT /interactions/{id} immediately upon receiving any
INTERACTION_CREATE event to prevent QQ from showing a timeout
error to the user. The ACK is fire-and-forget and does not block
subsequent approval button resolution.

Also resolve merge conflict in pnpm-lock.yaml (keep
@tencent-connect/qqbot-connector@1.1.0 and newer
@thi.ng/bitstream@2.4.46).

* feat(qqbot): enhance reminder functionality with delivery context and credential backup

This update improves the QQBot reminder system by introducing a delivery context for reminders, allowing for more flexible target resolution. Key changes include:

- Updated reminder logic to utilize a delivery envelope, ensuring that reminders are sent with the correct context.
- Implemented credential backup and recovery mechanisms to prevent loss of appId and clientSecret during hot upgrades.
- Added tests for credential backup functionality and admin resolver to ensure reliability.
- Enhanced the remind tool to automatically resolve the target from the current conversation context when not explicitly provided.

These enhancements aim to improve the user experience and reliability of the reminder feature within the QQBot framework.

* fix(qqbot): ensure PlatformAdapter is registered before gateway message processing

Call ensurePlatformAdapter() at the start of bridge/gateway.ts's
startGateway() to guarantee the adapter is available when engine
code (e.g. downloadFile in file-utils.ts) calls getPlatformAdapter().

When the bundler splits code into separate chunks, bootstrap.ts's
module-level side-effect registration may not have executed yet by
the time the gateway processes its first inbound attachment download.

Also fix the TS2339 error in registerApproveRuntimeGetter by using
getQQBotRuntime() (full PluginRuntime with config) instead of
getQQBotRuntimeForEngine() (GatewayPluginRuntime subset without config).

* fix(qqbot): make isAudioFile safe when OutboundAudioAdapter is not registered

sendMedia() calls isAudioFile() as part of its media-type dispatch logic
before any actual audio processing. When the audio adapter is not yet
registered (e.g. framework tool calls sendMedia before gateway startup),
isAudioFile() would throw 'OutboundAudioAdapter not registered' even
for non-audio files like images.

Wrap the getAudio() call in isAudioFile() with try/catch to return false
when the adapter is unavailable, allowing non-audio media sends to
proceed normally.

* refactor(qqbot): remove plugin startup/upgrade greeting pipeline

Drop the startup / upgrade greeting feature that was folded into the
previous reminder + credential-backup commit. The pipeline has proven
unnecessary for the fused build and its supporting admin-resolver
scaffolding has no other consumers, so both are removed wholesale.

- Delete engine/session/startup-greeting.ts and its tests: the
  first-launch "soul online" / "updated to vX.Y.Z" messages, the
  per-(accountId, appId) startup marker, the failure cooldown, and the
  legacy startup-marker.json migration path are all gone.
- Delete engine/session/admin-resolver.ts and its tests: admin openid
  persistence/resolution, upgrade-greeting-target load/clear and the
  sendStartupGreetings dispatcher only ever served the greeting flow
  and were not referenced elsewhere.
- channel.ts: drop the sendStartupGreetings import and the READY /
  RESUMED hooks that triggered greetings; credential-backup snapshots
  stay untouched.
- engine/utils/data-paths.ts: remove getAdminMarkerFile /
  getLegacyAdminMarkerFile / getUpgradeGreetingTargetFile /
  getStartupMarkerFile / getLegacyStartupMarkerFile along with the
  now-stale module docblock sections. Credential-backup helpers and
  safeName are preserved.

Net -655 LOC across 6 files. tsc --noEmit passes on
extensions/qqbot/tsconfig.json and no references to the removed
symbols remain in the workspace.

* fix(qqbot): resolve test failures in extension batch, contracts and bundled runtime deps

- bootstrap: replace sync require() with static imports for secret-input
  and temp-path so vitest resolve.alias works correctly (require bypasses
  vitest aliases causing Cannot find module errors)
- format: handle null/undefined in formatErrorMessage before JSON.stringify
  since JSON.stringify(undefined) returns JS undefined, not a string
- gateway/types: reword comment to avoid triggering the channel-import
  guardrail regex that forbids quoted openclaw/plugin-sdk references
- package.json: mirror @tencent-connect/qqbot-connector ^1.1.0 in root
  dependencies as required by bundled plugin runtime dependency checks

* chore: revert non-qqbot changes to align with upstream main

Revert modifications to src/agents/system-prompt, src/auto-reply/reply/dispatch-from-config, and src/canvas-host/a2ui build artifacts that were inadvertently included in the qqbot feature branch. Also fix .gitignore Core/ pattern to match subdirectories.

* fix(qqbot): remove unused logUnsupportedStructuredMediaTarget after API simplification

* fix(qqbot): restore channel-plugin-api.ts for bundled plugin surface convention

* fix(qqbot): update CI lint allowlists for restructured engine paths

- Update raw fetch() allowlist in check-no-raw-channel-fetch.mjs to
  reflect engine/ directory restructure (src/api.ts → src/engine/api/api-client.ts, etc.)
- Remove stale qqbot allowlist entry for deleted src/utils/audio-convert.ts

* fix(qqbot): eliminate os.tmpdir() in engine layer via adapter injection

- Make hasPlatformAdapter() also check for registered factory, so adapter
  is always discoverable once bootstrap has run
- Remove os.tmpdir() fallbacks in platform.ts getHomeDir()/getTempDir(),
  delegate entirely to PlatformAdapter.getTempDir() which calls
  resolvePreferredOpenClawTmpDir() under the hood
- Keeps engine/ layer free of openclaw/plugin-sdk imports

* chore(qqbot): update CHANGELOG for engine architecture refactor (#67960) (thanks @cxyhhhhh)

---------

Co-authored-by: Bobby <zkd8907@live.com>
Co-authored-by: neilhwang <neilhwang@tencent.com>
Co-authored-by: sliverp <870080352@qq.com>
2026-04-22 01:05:12 +08:00
Shadow
38aaa23e63 feat(channels): stream tool progress into preview edits (#69611) (thanks @thewilloftheshadow) 2026-04-21 11:51:16 -05:00
Gustavo Madeira Santana
13636c4521 perf(matrix): narrow register-time runtime surface (#69782)
Merged via squash.

Prepared head SHA: ec32828b52
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-21 12:50:53 -04:00
Patrick Erichsen
acb27bac3a fix(dev): release run-node build lock on SIGINT/SIGTERM/exit (#69785) 2026-04-21 09:33:19 -07:00
Devin Robison
e6e83e6ccf fix(control-ui): block remote image loads (#69773)
* fix(control-ui): block remote image loads

* fix(control-ui): reject protocol-relative avatar URLs

* docs(changelog): note control-ui image CSP tightening (#69773)
2026-04-21 10:30:32 -06:00
Devin Robison
2aa93d44a1 fix: require owner identity for owner-enforced commands (#69774)
* fix: require owner identity for owner-enforced commands

Stop wildcard channel allowlists from authorizing non-owner senders when a plugin requires owner-only commands.

Add a regression test for the owner-enforced wildcard allowFrom path.

* docs(changelog): note owner identity requirement for owner-enforced commands (#69774)
2026-04-21 10:16:33 -06:00
Patrick Erichsen
4fdd005b88 onboard: plain-prose security disclaimer, searchable pickers for search/plugins/model-provider (#69760) 2026-04-21 08:54:00 -07:00
Bruce MacDonald
1be94b7a37 onboard (ollama): populate cloud-only model list from ollama.com/api/tags (#68463)
Merged via squash.

Prepared head SHA: fb12af3d63
Co-authored-by: BruceMacD <5853428+BruceMacD@users.noreply.github.com>
Co-authored-by: BruceMacD <5853428+BruceMacD@users.noreply.github.com>
Reviewed-by: @BruceMacD
2026-04-21 08:51:54 -07:00
Peter Steinberger
06b4e3885e test: stabilize stale-pid ancestor override
(cherry picked from commit 4e25479cb2)
2026-04-21 16:45:22 +01:00
Peter Steinberger
34a52ea777 fix: lazy-load discord carbon runtime for npm install
Forward-port release branch fix without beta version file changes.

(cherry picked from commit 3243c14547)
2026-04-21 16:40:18 +01:00