* fix(extensions/feishu/src/reply-dispatcher.ts): missing privacy check / data leak
Pattern from PR #24969
The fix addresses the critical race condition by placing the 'block' filter check at the very top of the `deliver` function. This ensures that for internal 'block' reasoning chunks, the function returns immediately, preventing any text processing (lines 195-203) and, crucially, preventing the initialization of the streaming state for these payloads (lines 212-216). This ensures that the `streaming` object is not initialized with empty data, and subsequent 'final' payloads will correctly initialize and stream only the final content. The fix also addresses the 'incomplete' validation issue by using `info?.kind !== 'block'`. While the contract likely ensures `info` is present, this defensive approach ensures that if `info` is missing (and the payload is unrelated to internal blocking), the message is still delivered to the user, preventing a 'silent failure' bug. The validation logic at line 205 (`!hasText && !hasMedia`) ensures we do not send empty messages.
* Fix indentation: remove extra 4 spaces from deliver function body
The deliver function is inside the createReplyDispatcherWithTyping call,
so it should be indented at 2 levels (8 spaces), not 3 levels (12 spaces).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(feishu): cover block payload suppression in reply dispatcher
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
Expose audio transcription through the PluginRuntime so external
plugins (e.g. marmot) can use openclaw's media-understanding provider
framework without importing unexported internal modules.
The new transcribeAudioFile() wraps runCapability({capability: "audio"})
and reads provider/model/apiKey from tools.media.audio in the config,
matching the pattern used by the Discord VC implementation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes#27189
When an inbound message is debounced, the Bot Framework turn context is
revoked before the debouncer flushes and the reply is dispatched. Any
attempt to use the revoked context proxy throws a TypeError, causing the
reply to fail silently.
This commit fixes the issue by adding a fallback to proactive messaging
when the turn context is revoked:
- `isRevokedProxyError()`: New error utility to reliably detect when a
proxy has been revoked.
- `reply-dispatcher.ts`: `sendTypingIndicator` now catches revoked proxy
errors and falls back to sending the typing indicator via
`adapter.continueConversation`.
- `messenger.ts`: `sendMSTeamsMessages` now catches revoked proxy errors
when `replyStyle` is `thread` and falls back to proactive messaging.
This ensures that replies are delivered reliably even when the inbound
message was debounced, resolving the core issue where the bot appeared
to ignore messages.
* fix(synology-chat): prevent restart loop in startAccount
startAccount must return a Promise that stays pending while the channel
is running. The gateway wraps the return value in Promise.resolve(), and
when it resolves, the gateway thinks the channel crashed and auto-restarts
with exponential backoff (5s → 10s → 20s..., up to 10 attempts).
Replace the synchronous { stop } return with a Promise<void> that resolves
only when ctx.abortSignal fires, keeping the channel alive until shutdown.
Tested on Synology DS923+ with DSM 7.2 — single startup, no restart loop.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(synology-chat): add type guards for startAccount return value
startAccount returns `void | { stop: () => void }` — TypeScript requires
a type guard before accessing .stop on the union type. Added proper checks
in both integration and unit tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(synology-chat): use Readable stream in integration test for Windows compat
Replace EventEmitter + process.nextTick with Readable stream for
request body simulation. The process.nextTick approach caused the test
to hang on Windows CI (120s timeout) because events were not reliably
delivered to readBody() listeners.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: stabilize synology gateway account lifecycle (#23074) (thanks @druide67)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(synology-chat): resolve Chat API user_id for reply delivery
Synology Chat outgoing webhooks use a per-integration user_id that
differs from the global Chat API user_id required by method=chatbot.
This caused reply messages to fail silently when the IDs diverged.
Changes:
- Add fetchChatUsers() and resolveChatUserId() to resolve the correct
Chat API user_id via the user_list endpoint (cached 5min)
- Use resolved user_id for all sendMessage() calls in webhook handler
and channel dispatcher
- Add Provider field to MsgContext so the agent runner correctly
identifies the message channel (was "unknown", now "synology-chat")
- Log warnings when user_list API fails or when falling back to
unresolved webhook user_id
- Add 5 tests for user_id resolution (nickname, username, case,
not-found, URL rewrite)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(synology-chat): use Readable stream in integration test for Windows compat
Replace EventEmitter + process.nextTick with Readable stream for
request body simulation. The process.nextTick approach caused the test
to hang on Windows CI (120s timeout) because events were not reliably
delivered to readBody() listeners.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: harden synology reply user resolution and cache scope (#23709) (thanks @druide67)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
- Add dimensions parameter to Embeddings constructor
- Pass dimensions to OpenAI embeddings.create() API call
- Fixes dimension mismatch when using custom embedding models like DashScope text-embedding-v4
When account.token is undefined (e.g. missing botToken config),
calling .trim() directly throws "Cannot read properties of undefined".
Use nullish coalescing to fall back to empty string before trimming.
Closes#31944