Commit Graph

9680 Commits

Author SHA1 Message Date
Peter Steinberger
a79c2de956 refactor(gateway): extract ws auth message helpers 2026-02-13 19:08:37 +00:00
Peter Steinberger
5429f2e635 refactor(line): split flex template builders 2026-02-13 19:08:37 +00:00
Peter Steinberger
b05c41f344 perf: reduce gateway multi e2e websocket churn 2026-02-13 19:07:59 +00:00
Shadow
71939523a0 fix: normalize Discord autoThread reply target (#8302) (thanks @gavinbmoore) 2026-02-13 13:04:55 -06:00
Claw
e65b649993 fix(discord): ensure autoThread replies route to existing threads
Fixes #8278

When autoThread is enabled and a thread already exists (user continues
conversation in thread), replies were sometimes routing to the root
channel instead of the thread. This happened because the reply delivery
plan only explicitly set the thread target when a NEW thread was created
(createdThreadId), but not when the message was in an existing thread.

The fix adds a fallback case: when threadChannel is set (we're in an
existing thread) but no new thread was created, explicitly route to
the thread's channel ID. This ensures all thread replies go to the
correct destination.
2026-02-13 13:04:55 -06:00
Ramin Shirali Hossein Zade
1af0edf7ff fix: ensure exec approval is registered before returning (#2402) (#3357)
* feat(gateway): add register and awaitDecision methods to ExecApprovalManager

Separates registration (synchronous) from waiting (async) to allow callers
to confirm registration before the decision is made. Adds grace period for
resolved entries to prevent race conditions.

* feat(gateway): add two-phase response and waitDecision handler for exec approvals

Send immediate 'accepted' response after registration so callers can confirm
the approval ID is valid. Add exec.approval.waitDecision endpoint to wait for
decision on already-registered approvals.

* fix(exec): await approval registration before returning approval-pending

Ensures the approval ID is registered in the gateway before the tool returns.
Uses exec.approval.request with expectFinal:false for registration, then
fire-and-forget exec.approval.waitDecision for the decision phase.

Fixes #2402

* test(gateway): update exec-approval test for two-phase response

Add assertion for immediate 'accepted' response before final decision.

* test(exec): update approval-id test mocks for new two-phase flow

Mock both exec.approval.request (registration) and exec.approval.waitDecision
(decision) calls to match the new internal implementation.

* fix(lint): add cause to errors, use generics instead of type assertions

* fix(exec-approval): guard register() against duplicate IDs

* fix: remove unused timeoutMs param, guard register() against duplicates

* fix(exec-approval): throw on duplicate ID, capture entry in closure

* fix: return error on timeout, remove stale test mock branch

* fix: wrap register() in try/catch, make timeout handling consistent

* fix: update snapshot on timeout, make two-phase response opt-in

* fix: extend grace period to 15s, return 'expired' status

* fix: prevent double-resolve after timeout

* fix: make register() idempotent, capture snapshot before await

* fix(gateway): complete two-phase exec approval wiring

* fix: finalize exec approval race fix (openclaw#3357) thanks @ramin-shirali

* fix(protocol): regenerate exec approval request models (openclaw#3357) thanks @ramin-shirali

* fix(test): remove unused callCount in discord threading test

---------

Co-authored-by: rshirali <rshirali@rshirali-haga.local>
Co-authored-by: rshirali <rshirali@rshirali-haga-1.home>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-13 19:57:02 +01:00
Shadow
a15033876c fix: add Discord voice message changelog (#7253) (thanks @nyanjou) 2026-02-13 12:44:14 -06:00
Shadow
c87e481ec9 Discord: fix voice duration error handling 2026-02-13 12:44:14 -06:00
Shadow
1c9c01ff49 Discord: refine voice message handling 2026-02-13 12:44:14 -06:00
nyanjou
76ab377a19 style: use bit shift operators for Discord message flags 2026-02-13 12:44:14 -06:00
nyanjou
b4359c84f7 feat(discord): add silent support for voice messages
- Add silent flag to sendDiscordVoiceMessage
- Combines VOICE_MESSAGE (8192) + SUPPRESS_NOTIFICATIONS (4096) flags
- Pass silent through VoiceMessageOpts and action handlers
2026-02-13 12:44:14 -06:00
nyanjou
385eed14f6 fix(discord): pass silent flag through plugin action handler
The Discord send action was going through the plugin handler path
which wasn't passing the silent flag to sendMessageDiscord.

- Add silent param reading in handle-action.ts
- Pass silent to handleDiscordAction
- Add silent param in discord-actions-messaging.ts sendMessage case
2026-02-13 12:44:14 -06:00
nyanjou
77df8b1104 feat(discord): add silent message support (SUPPRESS_NOTIFICATIONS flag)
- Add silent option to message tool for Discord
- Passes SUPPRESS_NOTIFICATIONS flag (4096) to Discord API
- Threads silent param through entire outbound chain:
  - message-action-runner.ts
  - outbound-send-service.ts
  - message.ts
  - deliver.ts
  - discord outbound adapter
  - send.outbound.ts
  - send.shared.ts

Usage: message tool with silent=true suppresses push/desktop notifications
2026-02-13 12:44:14 -06:00
nyanjou
b9da2c4679 fix: address code review feedback
- Remove unused ffmpeg astats command from generateWaveform()
- Use crypto.randomUUID() for temp file names to prevent collision
- Wrap upload URL request in retry runner for consistency
- Add validation: reject content with asVoice, require local file path
- Add clarifying comments for CDN upload behavior
2026-02-13 12:44:14 -06:00
nyanjou
36525a974e fix(discord): use fetch with proper headers for voice message upload
The @buape/carbon RequestClient wasn't setting Content-Type: application/json
for the attachments endpoint request. Use native fetch with explicit headers
for the upload URL request.

Also pass token through to sendDiscordVoiceMessage for authorization.
2026-02-13 12:44:14 -06:00
nyanjou
a09e4fac3f feat(discord): add voice message support
Adds support for sending Discord voice messages via the message tool
with asVoice: true parameter.

Voice messages require:
- OGG/Opus format (auto-converted if needed via ffmpeg)
- Waveform data (generated from audio samples)
- Duration in seconds
- Message flag 8192 (IS_VOICE_MESSAGE)

Implementation:
- New voice-message.ts with audio processing utilities
- getAudioDuration() using ffprobe
- generateWaveform() samples audio and creates base64 waveform
- ensureOggOpus() converts audio to required format
- sendDiscordVoiceMessage() handles 3-step Discord upload process

Usage:
message(action='send', channel='discord', target='...',
        path='/path/to/audio.mp3', asVoice=true)

Note: Voice messages cannot include text content (Discord limitation)
2026-02-13 12:44:14 -06:00
Yi LIU
aec3221391 chore: revert upstream labeler.yml to unblock fork push
The fork's OAuth token lacks the workflow scope required to push
changes to .github/workflows/. Reverting the upstream labeler.yml
change so the branch can be force-pushed. The PR merge into main
will pick up the correct upstream version automatically.
2026-02-13 19:43:20 +01:00
Yi LIU
a5ccfa57a8 refactor(process): use dedicated CommandLaneClearedError in clearCommandLane
Replace bare `new Error("Command lane cleared")` with a dedicated
`CommandLaneClearedError` class so callers that fire-and-forget
enqueued tasks can catch this specific type and avoid surfacing
unhandled rejection warnings.
2026-02-13 19:43:20 +01:00
Yi LIU
a49dd83b14 fix(process): reject pending promises when clearing command lane
clearCommandLane() was truncating the queue array without calling
resolve/reject on pending entries, causing never-settling promises
and memory leaks when upstream callers await enqueueCommandInLane().

Splice entries and reject each before clearing so callers can handle
the cancellation gracefully.
2026-02-13 19:43:20 +01:00
Hunter
f7e2b8ff5f fix(discord): autoThread race condition when multiple agents mentioned
When multiple agents with autoThread:true are @mentioned in the same
message, only the first agent successfully creates a thread. Subsequent
agents fail because Discord only allows one thread per message.

Previously, the failure was silently caught and the agent would fall
back to replying in the parent channel.

Now, when thread creation fails, the code re-fetches the message and
checks for an existing thread (created by another agent). If found,
the agent replies in that thread instead of falling back.

Fixes #7508
2026-02-13 12:39:11 -06:00
Clawdbot
42bfcd9c30 fix(discord): handle missing guild/channel data in link resolution
Add null checks for guild.id and guild.name when resolving Discord
entities. This prevents TypeError when processing invite links for
servers/channels the bot doesn't have cached.

Fixes #6606
2026-02-13 12:35:18 -06:00
Peter Steinberger
3c00a9e330 perf: remove redundant cli health checks from gateway multi e2e 2026-02-13 18:35:09 +00:00
Artale
ab0d8ef8c1 fix(daemon): preserve backslashes in parseCommandLine on Windows (#15642)
* fix(daemon): preserve backslashes in parseCommandLine on Windows

Only treat backslash as escape when followed by a quote or another
backslash. Bare backslashes are kept as-is so Windows paths survive.

Fixes #15587

* fix(daemon): preserve UNC backslashes in schtasks parsing (#15642) (thanks @arosstale)

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-13 19:27:06 +01:00
Peter Steinberger
39e6e4cd2c perf: reduce test/runtime overhead in plugin runtime and e2e harness 2026-02-13 18:24:19 +00:00
Peter Steinberger
3cbcba10cf fix(security): enforce bounded webhook body handling 2026-02-13 19:14:54 +01:00
Shadow
2f9c523bbe CI: run auto-response on label events (#15657) 2026-02-13 12:14:49 -06:00
Tseka Luk
5cd9e210fa fix(tui): preserve streamed text when final payload regresses (#15452) (#15573)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: e4a5e3c8a6
Co-authored-by: TsekaLuk <79151285+TsekaLuk@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
2026-02-13 19:12:59 +01:00
Shadow
be18f5f0f0 Process: fix Windows exec env overrides 2026-02-13 12:06:47 -06:00
Ross Morsali
6bc6cdad94 fix(nodes-tool): add exec approval flow for agent tool run action (#4726)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: b8ed4f1b6e
Co-authored-by: rmorse <853547+rmorse@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
2026-02-13 19:04:24 +01:00
Peter Steinberger
e84318e4bc fix: replace control-char regex with explicit sanitizer 2026-02-13 17:57:47 +00:00
Peter Steinberger
201ac2b72a perf: replace proper-lockfile with lightweight file locks 2026-02-13 17:57:30 +00:00
Tseka Luk
c544811559 fix(whatsapp): preserve outbound document filenames (#15594)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 8e0d765d1d
Co-authored-by: TsekaLuk <79151285+TsekaLuk@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
2026-02-13 18:54:10 +01:00
Shadow
f59df95896 Config: preserve env var references on write (#15600)
* Config: preserve env var references on write

* Config: handle env refs in arrays
2026-02-13 11:52:23 -06:00
Marcus Castro
eed8cd383f fix(agent): search all agent stores when resolving --session-id (#13579)
* fix(agent): search all agent stores when resolving --session-id

When `--session-id` was provided without `--to` or `--agent`, the reverse
lookup only searched the default agent's session store. Sessions created
under a specific agent (e.g. `--agent mybot`) live in that agent's store
file, so the lookup silently failed and the session was not reused.

Now `resolveSessionKeyForRequest` iterates all configured agent stores
when the primary store doesn't contain the requested sessionId.

Fixes #12881

* fix: search other agent stores when --to key does not match --session-id

When --to derives a session key whose stored sessionId doesn't match the
requested --session-id, the cross-store search now also runs. This handles
the case where a user provides both --to and --session-id targeting a
session in a different agent's store.
2026-02-13 18:46:54 +01:00
AI-Reviewer-QS
649826e435 fix(security): block private/loopback/metadata IPs in link-understanding URL detection (#15604)
* fix(security): block private/loopback/metadata IPs in link-understanding URL detection

isAllowedUrl() only blocked 127.0.0.1, leaving localhost, ::1, 0.0.0.0,
private RFC1918 ranges, link-local (169.254.x.x including cloud metadata),
and CGNAT (100.64.0.0/10) accessible for SSRF via link-understanding.

Add comprehensive hostname/IP blocking consistent with the SSRF guard
already used by media/fetch.ts.

* fix(security): harden link-understanding SSRF host checks

* fix: note link-understanding SSRF hardening in changelog (#15604) (thanks @AI-Reviewer-QS)

---------

Co-authored-by: Yi LIU <yi@quantstamp.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-13 18:38:40 +01:00
Peter Steinberger
fdfc34fa1f perf(test): stabilize e2e harness and reduce flaky gateway coverage 2026-02-13 17:32:14 +00:00
Peter Steinberger
2ab7715d16 docs: clarify auto-install deps recovery workflow 2026-02-13 18:28:56 +01:00
Marcus Castro
d91e995e46 fix(inbound): preserve literal backslash-n sequences in Windows paths (#11547)
* fix(inbound): preserve literal backslash-n sequences in Windows paths

The normalizeInboundTextNewlines function was converting literal backslash-n
sequences (\n) to actual newlines, corrupting Windows paths like
C:\Work\nxxx\README.md when sent through WebUI.

This fix removes the .replaceAll("\\n", "\n") operation, preserving
literal backslash-n sequences while still normalizing actual CRLF/CR to LF.

Fixes #7968

* fix(test): set RawBody to Windows path so BodyForAgent fallback chain tests correctly

* fix: tighten Windows path newline regression coverage (#11547) (thanks @mcaxtr)

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-13 18:24:01 +01:00
Shadow
684578ecf6 CI: drop trusted label for experienced contributors (#15605) 2026-02-13 11:23:05 -06:00
Marcus Castro
3d921b6157 fix(slack): apply limit parameter to emoji-list action (#13421)
Merged via /review-pr -> /prepare-pr -> /merge-pr.

Prepared head SHA: 67e9b64858
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
2026-02-13 18:20:41 +01:00
Mariano Belinky
86e4fe0a7a Auth: land codex oauth onboarding flow (#15406) 2026-02-13 17:18:49 +00:00
Marcus Castro
7ec60d6449 fix: use relayAbort helper for addEventListener to preserve AbortError reason 2026-02-13 18:13:18 +01:00
Marcus Castro
5ac8d1d2bb test: add abort .bind() behavioral tests (#7174) 2026-02-13 18:13:18 +01:00
Marcus Castro
d9c582627c perf: use .abort.bind() instead of arrow closures to prevent memory leaks (#7174) 2026-02-13 18:13:18 +01:00
Shadow
d637a26350 Gateway: sanitize WebSocket log headers (#15592) 2026-02-13 11:11:54 -06:00
Marcus Castro
b3b49bed80 fix(slack): override video/* MIME to audio/* for voice messages (#14941)
* fix(slack): override video/* MIME to audio/* for voice messages

* fix(slack): preserve overridden MIME in return value

* test(slack): fix media monitor MIME mock wiring

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-13 18:09:04 +01:00
Shadow
1f4943af3d fix: note Discord guild allowlist resolution (#12326) (thanks @headswim) 2026-02-13 11:03:10 -06:00
headswim
f4e295a63b Discord: fix bare guild ID misrouted as channel ID in parser
The channel allowlist parser matches bare numeric strings as channel IDs
before checking for guild IDs, causing guild snowflakes to hit Discord's
/channels/ endpoint (404). Prefix guild-only entries with 'guild:' so the
parser routes them to the correct guild resolution path.

Fixes both the monitor provider and onboarding wizard call sites.
Adds regression tests.
2026-02-13 11:03:10 -06:00
Shadow
5325d2ca51 Discord: gate guild prefix to numeric keys 2026-02-13 10:57:29 -06:00
Lilo
397011bd78 fix: increase image tool maxTokens from 512 to 4096 (#11770)
* increase image tool maxTokens from 512 to 4096

* fix: cap image tool tokens by model capability (#11770) (thanks @detecti1)

* docs: fix changelog attribution for #11770

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-13 17:52:27 +01:00