Commit Graph

16351 Commits

Author SHA1 Message Date
Peter Steinberger
f9cbcfca0d refactor: modularize slack/config/cron/daemon internals 2026-03-02 22:30:21 +00:00
Peter Steinberger
5d3032b293 fix: align gateway and zalouser typing imports 2026-03-02 22:29:18 +00:00
Peter Steinberger
11adaa15a8 test: isolate high-variance suites in parallel scheduler 2026-03-02 22:29:13 +00:00
Peter Steinberger
3cb851be90 test: micro-optimize heavy gateway/browser/telegram suites 2026-03-02 22:29:04 +00:00
Peter Steinberger
1fa2488db1 fix: wire telegram disableAudioPreflight config validation and precedence tests (#23067) (thanks @yangnim21029) 2026-03-02 22:26:52 +00:00
gemini-3-flash
d3cb85eaf5 feat(telegram): add disableAudioPreflight config for groups and topics 2026-03-02 22:26:52 +00:00
Peter Steinberger
d89c25d69e fix: support parakeet-mlx output-dir transcript parsing (#9177) (thanks @mac-110) 2026-03-02 22:22:17 +00:00
Alessandro Rodi
f257818ea5 fix(sandbox): prevent Windows PATH from poisoning docker exec (#13873)
* fix(sandbox): prevent Windows PATH from poisoning docker exec shell lookup

On Windows hosts, `buildDockerExecArgs` passes the host PATH env var
(containing Windows paths like `C:\Windows\System32`) to `docker exec -e
PATH=...`. Docker uses this PATH to resolve the executable argument
(`sh`), which fails because Windows paths don't exist in the Linux
container — producing `exec: "sh": executable file not found in $PATH`.

Two changes:
- Skip PATH in the `-e` env loop (it's already handled separately via
  OPENCLAW_PREPEND_PATH + shell export)
- Use absolute `/bin/sh` instead of bare `sh` to eliminate PATH
  dependency entirely

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: add braces around continue to satisfy linter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(test): update assertion to match /bin/sh in buildDockerExecArgs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:17:33 -06:00
magos-minor
350ac0d824 fix(daemon): default NODE_USE_SYSTEM_CA=1 on macOS 2026-03-02 22:17:14 +00:00
Peter Steinberger
19fafed11d refactor(zalouser): extract policy and message helpers 2026-03-02 22:16:47 +00:00
Peter Steinberger
7253e91300 fix: strengthen cron heartbeat multi-payload suppression (#32131) (thanks @adhishthite) 2026-03-02 22:16:18 +00:00
Adhish
2330c71b63 fix(cron): suppress delivery when multi-payload response contains HEARTBEAT_OK
When a cron agent emits multiple text payloads (narration + tool
summaries) followed by a final HEARTBEAT_OK, the delivery suppression
check `isHeartbeatOnlyResponse` fails because it uses `.every()` —
requiring ALL payloads to be heartbeat tokens. In practice, agents
narrate their work before signaling nothing needs attention.

Fix: check if ANY payload contains HEARTBEAT_OK (`.some()`) while
preserving the media delivery exception (if any payload has media,
always deliver). This matches the semantic intent: HEARTBEAT_OK is
the agent's explicit signal that nothing needs user attention.

Real-world example: heartbeat agent returns 3 payloads:
1. "It's 12:49 AM — quiet hours. Let me run the checks quickly."
2. "Emails: Just 2 calendar invites. Not urgent."
3. "HEARTBEAT_OK"

Previously: all 3 delivered to Telegram. Now: correctly suppressed.

Related: #32013 (fixed a different HEARTBEAT_OK leak path via system
events in timer.ts)
2026-03-02 22:16:18 +00:00
Maple778
477de545f9 fix(feishu): suppress reasoning/thinking block payloads from delivery (#31723)
* 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>
2026-03-02 16:15:45 -06:00
Peter Steinberger
bd4a082b73 fix: land config raw redaction collision guard (#32174) (thanks @bmendonca3) 2026-03-02 22:14:35 +00:00
Tak Hoffman
cbd2e8eea8 Config: consolidate raw redaction overlap and SecretRef safety 2026-03-02 22:14:35 +00:00
bmendonca3
807c600ad1 config: avoid raw redaction collisions on round-trip 2026-03-02 22:14:35 +00:00
Zico
a1ee605494 fix(slack): prevent duplicate DM processing from app_mention events
Fixes duplicate message processing in Slack DMs where both message.im
and app_mention events fire for the same message, causing:
- 2x token/credit usage per message
- 2x API calls
- Duplicate agent invocations with same runId

Root cause: app_mention events should only fire for channel mentions,
not DMs. Added channel_type check to skip im/mpim in app_mention handler.

Evidence of bug (from production logs):
- Same runId firing twice within 200-300ms
- Example: runId 13cd482c... at 20:32:42.699Z and 20:32:42.954Z

After fix:
- One message = one runId = one processing run
- 50% reduction in duplicate processing
2026-03-02 22:12:45 +00:00
OliYeet
923ff17ff3 fix(slack): filter inherited parent files from thread replies (#32203)
Slack's Events API includes the parent message's files array in every
thread reply event payload. This caused OpenClaw to re-download and
attach the parent's files to every text-only thread reply, creating
ghost media attachments.

The fix filters out files that belong to the thread starter by comparing
file IDs. The resolveSlackThreadStarter result is already cached, so
this adds no extra API calls.

Closes #32203
2026-03-02 22:11:07 +00:00
markfietje
49687d313c fix(plugins): allow hardlinks for bundled plugins (fixes #28175, #28404) (openclaw#32119) thanks @markfietje
Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: markfietje <4325889+markfietje@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-02 16:10:31 -06:00
Peter Steinberger
11dcf96628 fix: add changelog for session-store cache invalidation (#32191) (thanks @jalehman) 2026-03-02 22:09:36 +00:00
Josh Lehman
21a1db78b3 test: stabilize bun cache invalidation fixtures 2026-03-02 22:09:36 +00:00
Josh Lehman
175c770171 fix: address session-store cache review feedback 2026-03-02 22:09:36 +00:00
Josh Lehman
1212328c8d fix: refresh session-store cache when file size changes within same mtime tick
The session-store cache used only mtime for invalidation. In fast CI
runs (especially under bun), test writes to the session store can
complete within the same filesystem mtime granularity (~1s on HFS+/ext4),
so the cache returns stale data. This caused non-deterministic failures
in model precedence tests where a session override written to disk was
not observed by the next loadSessionStore() call.

Fix: add file size as a secondary cache invalidation signal. The cache
now checks both mtimeMs and sizeBytes — if either differs from the
cached values, it reloads from disk.

Changes:
- cache-utils.ts: add getFileSizeBytes() helper
- sessions/store.ts: extend SessionStoreCacheEntry with sizeBytes field,
  check size in cache-hit path, populate size on cache writes
- sessions.cache.test.ts: add regression test for same-mtime rewrite
2026-03-02 22:09:36 +00:00
Peter Steinberger
f9025c3f55 feat(zalouser): add reactions, group context, and receipt acks 2026-03-02 22:08:11 +00:00
bmendonca3
317075ef3d telegram: route dm sessions by sender id 2026-03-02 22:08:07 +00:00
Peter Steinberger
2c39731846 fix: keep slack off-mode top-level turns in one session (#32193) (thanks @bmendonca3) 2026-03-02 22:05:25 +00:00
bmendonca3
29342c37b5 slack: keep top-level off-mode channel turns in one session 2026-03-02 22:05:25 +00:00
Peter Steinberger
cc18e43832 docs(media): clarify audio echo defaults and proxy env 2026-03-02 22:01:24 +00:00
Peter Steinberger
6545317a2c refactor(media): split audio helpers and attachment cache 2026-03-02 22:01:24 +00:00
Peter Steinberger
9bde7f4fde perf: cache allowlist and account-id normalization 2026-03-02 21:58:35 +00:00
Peter Steinberger
3beb1b9da9 test: speed up heavy suites with shared fixtures 2026-03-02 21:58:35 +00:00
Peter Steinberger
6358aae024 refactor(infra): share windows path normalization helper 2026-03-02 21:55:12 +00:00
Peter Steinberger
55a2d12f40 refactor: split inbound and reload pipelines into staged modules 2026-03-02 21:55:01 +00:00
Peter Steinberger
99a3db6ba9 fix(zalouser): enforce group mention gating and typing 2026-03-02 21:53:54 +00:00
Peter Steinberger
e5597a8dd4 refactor(media): dedupe tiny-audio test setup and normalize guards formatting 2026-03-02 21:50:54 +00:00
Peter Steinberger
8e259b8310 fix: keep audio transcript echo off-by-default and tiny-audio-safe (#32150) 2026-03-02 21:48:08 +00:00
AytuncYildizli
8f995dfc7a fix(audio): add echoTranscript/echoFormat to Zod config schema 2026-03-02 21:47:09 +00:00
AytuncYildizli
1b61269eec feat(audio): auto-echo transcription to chat before agent processing
When echoTranscript is enabled in tools.media.audio config, the
transcription text is sent back to the originating chat immediately
after successful audio transcription — before the agent processes it.
This lets users verify what was heard from their voice note.

Changes:
- config/types.tools.ts: add echoTranscript (bool) and echoFormat
  (string template) to MediaUnderstandingConfig
- media-understanding/apply.ts: sendTranscriptEcho() helper that
  resolves channel/to from ctx, guards on isDeliverableMessageChannel,
  and calls deliverOutboundPayloads best-effort
- config/schema.help.ts: help text for both new fields
- config/schema.labels.ts: labels for both new fields
- media-understanding/apply.echo-transcript.test.ts: 10 vitest cases
  covering disabled/enabled/custom-format/no-audio/failed-transcription/
  non-deliverable-channel/missing-from/OriginatingTo/delivery-failure

Default echoFormat: '📝 "{transcript}"'

Closes #32102
2026-03-02 21:47:09 +00:00
Shawn
ef89b48785 fix(agents): normalize windows workspace path boundary checks (#30766)
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-02 15:47:02 -06:00
Peter Steinberger
a183656f8f fix: apply missed media/runtime follow-ups from merged PRs 2026-03-02 21:45:39 +00:00
Peter Steinberger
f2b37f0aa9 refactor(media): dedupe runner proxy and video test fixtures 2026-03-02 21:44:52 +00:00
benthecarman
faa4ffec03 Add runtime.stt.transcribeAudioFile for plugin STT access
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>
2026-03-02 21:43:01 +00:00
Glucksberg
f7b0378ccb fix(test): update media-understanding tests for whisper skip empty audio
Increase test audio file sizes to meet MIN_AUDIO_FILE_BYTES (1024) threshold
introduced by the skip-empty-audio feature. Fix localPathRoots in skip-tiny-audio
tests so temp files pass path validation. Remove undefined loadApply() call
in apply.test.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:41:09 +00:00
Glucksberg
5f19112217 fix(test): use strict assertion instead of optional chaining 2026-03-02 21:41:09 +00:00
Glucksberg
8039ef7dba test: add URL-only audio skip test for tiny remote attachments 2026-03-02 21:41:09 +00:00
Glucksberg
43f94e3ab8 fix: strengthen test assertions - assert array lengths before indexing 2026-03-02 21:41:09 +00:00
Glucksberg
8b70ba6ab8 fix(#8127): auto-skip tiny/empty audio files in whisper transcription
Add a minimum file size guard (MIN_AUDIO_FILE_BYTES = 1024) before
sending audio to transcription APIs. Files below this threshold are
almost certainly empty or corrupt and would cause unhelpful errors
from Whisper/Deepgram/Groq providers.

Changes:
- Add 'tooSmall' skip reason to MediaUnderstandingSkipError
- Add MIN_AUDIO_FILE_BYTES constant (1024 bytes) to defaults
- Guard both provider and CLI audio paths in runner.ts
- Add comprehensive tests for tiny, empty, and valid audio files
- Update existing test fixtures to use audio files above threshold
2026-03-02 21:41:09 +00:00
Peter Steinberger
036bd18e2a docs(changelog): fix 2026.3.1 split and dedupe entries 2026-03-02 21:40:57 +00:00
Clawrence
9c9ab891c2 fix(media-understanding): guard malformed attachments arrays 2026-03-02 21:39:57 +00:00
Peter Steinberger
f7c658efb9 fix(core): resolve post-rebase type errors 2026-03-02 21:39:43 +00:00