Commit Graph

5330 Commits

Author SHA1 Message Date
Peter Steinberger f02247b6c5 fix(ci): fix discord proxy websocket binding and bluebubbles timeout status 2026-02-13 19:35:55 +00:00
rodbland2021 d3b2135f86
fix(agents): wait for agent idle before flushing pending tool results (#13746)
* fix(agents): wait for agent idle before flushing pending tool results

When pi-agent-core's auto-retry mechanism handles overloaded/rate-limit
errors, it resolves waitForRetry() on assistant message receipt — before
tool execution completes in the retried agent loop. This causes the
attempt's finally block to call flushPendingToolResults() while tools
are still executing, inserting synthetic 'missing tool result' errors
and causing silent agent failures.

The fix adds a waitForIdle() call before the flush to ensure the agent's
retry loop (including tool execution) has fully completed.

Evidence from real session: tool call and synthetic error were only 53ms
apart — the tool never had a chance to execute before being flushed.

Root cause is in pi-agent-core's _resolveRetry() firing on message_end
instead of agent_end, but this workaround in OpenClaw prevents the
symptom without requiring an upstream fix.

Fixes #8643
Fixes #13351
Refs #6682, #12595

* test: add tests for tool result flush race condition

Validates that:
- Real tool results are not replaced by synthetic errors when they arrive in time
- Flush correctly inserts synthetic errors for genuinely orphaned tool calls
- Flush is a no-op after real tool results have already been received

Refs #8643, #13748

* fix(agents): add waitForIdle to all flushPendingToolResults call sites

The original fix only covered the main run finally block, but there are
two additional call sites that can trigger flushPendingToolResults while
tools are still executing:

1. The catch block in attempt.ts (session setup error handler)
2. The finally block in compact.ts (compaction teardown)

Both now await agent.waitForIdle() with a 30s timeout before flushing,
matching the pattern already applied to the main finally block.

Production testing on VPS with debug logging confirmed these additional
paths can fire during sub-agent runs, producing spurious synthetic
'missing tool result' errors.

* fix(agents): centralize idle-wait flush and clear timeout handle

---------

Co-authored-by: Renue Development <dev@renuebyscience.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-02-13 20:35:43 +01:00
Shadow 4b3c87b82d fix: finalize discord presence config (#10855) (thanks @h0tp-ftw) 2026-02-13 13:34:19 -06:00
Shadow 6acea69b20 Discord: refine presence config defaults (#10855) (thanks @h0tp-ftw) 2026-02-13 13:34:19 -06:00
h0tp 770e904c21 fix(discord): restrict activity types and statuses to valid enum values
- Removed 'offline' from valid config statuses (use 'invisible').
- Restricted activityType to 0, 1, 2, 3, 5 (excluding custom/4).
- Added logic to only send 'url' when activityType is 1 (Streaming).
- Updated Typescript definitions and Zod schemas to match.
2026-02-13 13:34:19 -06:00
h0tp 5d8c6ef91c feat(discord): add configurable presence (activity/status/type)
- Adds `activity`, `status`, `activityType`, and `activityUrl` to Discord provider config schema.
- Implements a `ReadyListener` in `DiscordProvider` to apply these settings on connection.
- Solves the issue where `@buape/carbon` ignores initial presence options in constructor.
- Validated manually and via existing test suite.
2026-02-13 13:34:19 -06:00
Peter Steinberger c801ffdf99 perf: add zero-delay gateway client connect for tests 2026-02-13 19:32:16 +00:00
Shadow 5645f227f6 Discord: add gateway proxy docs and tests (#10400) (thanks @winter-loo) 2026-02-13 13:26:51 -06:00
ludd50155 e55431bf84 fix(discord): restore gateway reconnect maxAttempts to 50 2026-02-13 13:26:51 -06:00
ludd50155 5f0debdfb2 Fix: check cleanups 2026-02-13 13:26:51 -06:00
ludd50155 0cb69b0f28 Discord: add gateway proxy support
Conflicts:
	package.json
	pnpm-lock.yaml
	src/config/schema.ts
	src/discord/monitor/provider.ts
2026-02-13 13:26:51 -06:00
Mariano 7f0489e473
Security/Browser: constrain trace and download output paths to OpenClaw temp roots (#15652)
* Browser/Security: constrain trace and download output paths to temp roots

* Changelog: remove advisory ID from pre-public security note

* Browser/Security: constrain trace and download output paths to temp roots

* Changelog: remove advisory ID from pre-public security note

* test(bluebubbles): align timeout status expectation to 408

* test(discord): remove unused race-condition counter in threading test

* test(bluebubbles): align timeout status expectation to 408
2026-02-13 19:24:33 +00:00
Peter Steinberger 08725270e2 perf: honor low timeout budgets in health telegram probes 2026-02-13 19:22:25 +00:00
Peter Steinberger 7d1be585de test: fix exec approval and pty fallback e2e flows 2026-02-13 19:19:15 +00:00
Peter Steinberger 34eb14d24f perf: trim web auto-reply test cleanup backoff 2026-02-13 19:19:11 +00:00
Peter Steinberger 1c7a099b6d test: move reasoning replay regression to unit suite 2026-02-13 19:09:41 +00:00
Peter Steinberger 4c401d336d refactor(memory): extract manager sync and embedding ops 2026-02-13 19:08:37 +00:00
Peter Steinberger b47fa9e715 refactor(exec): extract bash tool runtime internals 2026-02-13 19:08:37 +00:00
Peter Steinberger 3f5e72835e refactor(tts): extract directives and provider core 2026-02-13 19:08:37 +00:00
Peter Steinberger 83bc73f4ea refactor(exec-approvals): split allowlist evaluation module 2026-02-13 19:08:37 +00:00
Peter Steinberger 81fbfa06ee refactor(exec-approvals): extract command analysis module 2026-02-13 19:08:37 +00:00
Peter Steinberger 2a1f8b2615 refactor(media): extract runner entry execution helpers 2026-02-13 19:08:37 +00:00
Peter Steinberger 1d46d3ae4e refactor(node-host): extract invoke handlers 2026-02-13 19:08:37 +00:00
Peter Steinberger 02684b913b refactor(cli): split update command modules 2026-02-13 19:08:37 +00:00
Peter Steinberger 39af215c31 refactor(outbound): extract message action param helpers 2026-02-13 19:08:37 +00:00
Peter Steinberger 23555de5d9 refactor(security): extract channel audit checks 2026-02-13 19:08:37 +00:00
Peter Steinberger ca3a42009c refactor(memory): extract qmd scope helpers 2026-02-13 19:08:37 +00:00
Peter Steinberger c256503ea1 refactor(infra): extract session cost usage types 2026-02-13 19:08:37 +00:00
Peter Steinberger 5a431f57fc refactor(infra): split heartbeat event filters 2026-02-13 19:08:37 +00:00
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
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 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 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
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