Commit Graph

10343 Commits

Author SHA1 Message Date
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
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
Marcus Castro
58cde87436 fix: warn when proxy env var is set but agent creation fails 2026-03-02 21:37:36 +00:00
Marcus Castro
8c1e9949b3 fix: pass proxy-aware fetchFn to media understanding providers
runProviderEntry now calls resolveProxyFetchFromEnv() and passes the
result as fetchFn to transcribeAudio/describeVideo, so media provider
API calls respect HTTPS_PROXY/HTTP_PROXY behind corporate proxies.
2026-03-02 21:37:36 +00:00
Marcus Castro
ba3fa44c5b refactor: extract shared proxy-fetch utility from Telegram module
Move makeProxyFetch to src/infra/net/proxy-fetch.ts and add
resolveProxyFetchFromEnv which reads standard proxy env vars
(HTTPS_PROXY, HTTP_PROXY, and lowercase variants) and returns a
proxy-aware fetch via undici's EnvHttpProxyAgent. Telegram re-exports
from the shared location to avoid duplication.
2026-03-02 21:37:36 +00:00
Peter Steinberger
5897eed6e9 refactor(core): dedupe final pairing and sandbox media clones 2026-03-02 21:36:23 +00:00
openjay
76d6514ff5 fix: add "audio" to openai provider capabilities
The openai provider implements transcribeAudio via
transcribeOpenAiCompatibleAudio (Whisper API), but its capabilities
array only declared ["image"]. This caused the media-understanding
runner to skip the openai provider when processing inbound audio
messages, resulting in raw audio files being passed to agents
instead of transcribed text.

Fix: Add "audio" to the capabilities array so the runner correctly
selects the openai provider for audio transcription.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-03-02 21:33:54 +00:00
Peter Steinberger
6a425d189e refactor(channels): dedupe slack telegram and web monitor tests 2026-03-02 21:32:11 +00:00
Peter Steinberger
34daed1d1e refactor(core): dedupe infra, media, pairing, and plugin helpers 2026-03-02 21:32:11 +00:00
Peter Steinberger
91dd89313a refactor(core): dedupe command, hook, and cron fixtures 2026-03-02 21:31:36 +00:00
Peter Steinberger
5f0cbd0edc refactor(gateway): dedupe auth and discord monitor suites 2026-03-02 21:31:36 +00:00
Peter Steinberger
ab8b8dae70 refactor(agents): dedupe model and tool test helpers 2026-03-02 21:31:36 +00:00
Peter Steinberger
067855e623 refactor(browser): dedupe browser and cli command wiring 2026-03-02 21:31:36 +00:00
Glucksberg
61d14e8a8a fix(plugin-sdk): add export verification tests and release guard (#27569) 2026-03-02 21:30:44 +00:00
Peter Steinberger
2438fde6d9 fix: trim repeated slack thread context payloads (#32133) (thanks @sourman) 2026-03-02 21:29:36 +00:00
Ahmed Mansour
7a99027ef6 fix(slack): reduce token bloat by skipping thread context on existing sessions
Thread history and thread starter were being fetched and included on
every message in a Slack thread, causing unnecessary token bloat. The
session transcript already contains the full conversation history, so
re-fetching and re-injecting thread history on each turn is redundant.

Now thread history is only fetched for new thread sessions
(!threadSessionPreviousTimestamp). Existing sessions rely on their
transcript for context.

Fixes #32121
2026-03-02 21:29:36 +00:00
Peter Steinberger
42e402dfba fix: clear pending tool-call state across provider modes (#32120) (thanks @jnMetaCode) 2026-03-02 21:28:02 +00:00
jiangnan
11aa18b525 fix(agents): clear pending tool call state on interruption regardless of provider
When `allowSyntheticToolResults` is false (OpenAI, OpenRouter, and most
third-party providers), the guard never cleared its pending tool call map
when a user message arrived during in-flight tool execution. This left
orphaned tool_use blocks in the transcript with no matching tool_result,
causing the provider API to reject all subsequent requests with 400 errors
and permanently breaking the session.

The fix removes the `allowSyntheticToolResults` gate around the flush
calls. `flushPendingToolResults()` already handles both cases correctly:
it only inserts synthetic results when allowed, and always clears the
pending map. The gate was preventing the map from being cleared at all
for providers that disable synthetic results.

Fixes #32098

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:28:02 +00:00
Peter Steinberger
21d6d878ce fix: harden exec allowlist regex literal handling (#32162) (thanks @stakeswky) 2026-03-02 21:26:24 +00:00
User
8da8756f76 fix(exec): escape regex literals in allowlist path matching 2026-03-02 21:26:24 +00:00
George Pickett
1f24323583 Auth: gate OpenAI OAuth TLS preflight in doctor 2026-03-02 13:24:49 -08:00
Alex Filatov
dc8a56c857 Fix TLS cert preflight classification false positive 2026-03-02 13:24:49 -08:00
Alex Filatov
f181b7dbe6 Add OpenAI OAuth TLS preflight and doctor prerequisite check 2026-03-02 13:24:49 -08:00
scoootscooob
0f1388fa15 fix(gateway): hot-reload channelHealthCheckMinutes without full restart
The health monitor was created once at startup and never touched by
applyHotReload(), so changing channelHealthCheckMinutes only took
effect after a full gateway restart.

Wire up a "restart-health-monitor" reload action so hot-reload can
stop the old monitor and (re)create one with the updated interval —
or disable it entirely when set to 0.

Closes #32105

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:23:20 +00:00
Peter Steinberger
b782ecb7eb refactor: harden plugin install flow and main DM route pinning 2026-03-02 21:22:38 +00:00
scoootscooob
73e6dc361e fix(whatsapp): propagate fromMe through inbound message pipeline
The `fromMe` flag from Baileys' WAMessage.key was only used for
access-control filtering and then discarded.  This meant agents
could not distinguish owner-sent messages from contact messages
in DM conversations (everything appeared as from the contact).

Add `fromMe` to `WebInboundMessage`, store it during message
construction, and thread it through `buildInboundLine` →
`formatInboundEnvelope` so DM transcripts prefix owner messages
with `(self):`.

Closes #32061

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 21:20:21 +00:00
Peter Steinberger
866bd91c65 refactor: harden msteams lifecycle and attachment flows 2026-03-02 21:19:23 +00:00
Peter Steinberger
d98a61a977 fix(config): move sensitive-schema hint warnings to debug 2026-03-02 21:13:58 +00:00
Peter Steinberger
d01e04bcec test(perf): reduce heavy fixture and guardrail overhead 2026-03-02 21:07:52 +00:00
Peter Steinberger
5a32a66aa8 perf(core): speed up routing, pairing, slack, and security scans 2026-03-02 21:07:52 +00:00
Peter Steinberger
3a08e69a05 refactor: unify queueing and normalize telegram slack flows 2026-03-02 20:55:15 +00:00
Peter Steinberger
ad12d1fbce fix(plugins): prefer bundled plugin ids over bare npm specs 2026-03-02 20:49:50 +00:00
scoootscooob
bfb6c6290f fix: distinguish warning message for non-OpenClaw vs missing npm package
Address Greptile review: show "not a valid OpenClaw plugin" when the
npm package was found but lacks openclaw.extensions, instead of the
misleading "npm package unavailable" message.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:49:50 +00:00
scoootscooob
da8a17d8de fix(plugins): fall back to bundled plugin when npm spec resolves to non-OpenClaw package (#32019)
When `openclaw plugins install diffs` downloads the unrelated npm
package `diffs@0.1.1` (which lacks `openclaw.extensions`), the install
fails without trying the bundled `@openclaw/diffs` plugin.

Two fixes:
1. Broaden the bundled-fallback trigger to also fire on
   "missing openclaw.extensions" errors (not just npm 404s)
2. Match bundled plugins by pluginId in addition to npmSpec so
   unscoped names like "diffs" resolve to `@openclaw/diffs`

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:49:50 +00:00
YUJIE2002
3c0ec76e8e fix(config): harden backup file permissions and clean orphan .bak files
Addresses #31699 — config .bak files persist with sensitive data.

Changes:
- Explicitly chmod 0o600 on all .bak files after creation, instead of
  relying on copyFile to preserve source permissions (not guaranteed on
  all platforms, e.g. Windows, NFS mounts).
- Clean up orphan .bak files that fall outside the managed 5-deep
  rotation ring (e.g. PID-stamped leftovers from interrupted writes,
  manual backups like .bak.before-marketing).
- Add tests for permission hardening and orphan cleanup.

The backup ring itself is preserved — it's a valuable recovery mechanism.
This PR hardens the security surface by ensuring backup files are
always owner-only and stale copies don't accumulate indefinitely.
2026-03-02 20:40:15 +00:00
bmendonca3
54eb13893f Telegram: support compact model callback fallback 2026-03-02 20:38:43 +00:00
Jason Separovic
00347bda75 fix(tools): strip xAI-unsupported JSON Schema keywords from tool definitions
xAI rejects minLength, maxLength, minItems, maxItems, minContains, and
maxContains in tool schemas with a 502 error instead of ignoring them.
This causes all requests to fail when any tool definition includes these
validation-constraint keywords (e.g. sessions_spawn uses maxLength and
maxItems on its attachment fields).

Add stripXaiUnsupportedKeywords() in schema/clean-for-xai.ts, mirroring
the existing cleanSchemaForGemini() pattern. Apply it in normalizeToolParameters()
when the provider is xai directly, or openrouter with an x-ai/* model id.

Fixes tool calls for x-ai/grok-* models both direct and via OpenRouter.
2026-03-02 20:37:07 +00:00
Kay-051
da05395c2a fix(telegram): preserve original filename from Telegram document/audio/video uploads
The downloadAndSaveTelegramFile inner function only used the server-side
file path (e.g. "documents/file_42.pdf") or the Content-Disposition
header (which Telegram doesn't send) to derive the saved filename.
The original filename provided by Telegram via msg.document.file_name,
msg.audio.file_name, msg.video.file_name, and msg.animation.file_name
was never passed through, causing all inbound files to lose their
user-provided names.

Now downloadAndSaveTelegramFile accepts an optional telegramFileName
parameter that takes priority over the fetched/server-side name.
The resolveMedia call site extracts the original name from the message
and passes it through.

Closes #31768

Made-with: Cursor
2026-03-02 20:36:39 +00:00
bmendonca3
16e7fc2563 fix(models): infer codex weekly usage labels from reset cadence 2026-03-02 20:35:45 +00:00
SidQin-cyber
479095bcfb fix(discord): use per-channel message queues to restore parallel agent dispatch
Replace the single per-account messageQueue Promise chain in
DiscordMessageListener with per-channel queues. This restores parallel
processing for channel-bound agents that regressed in 2026.3.1.

Messages within the same channel remain serialized to preserve ordering,
while messages to different channels now proceed independently. Completed
queue entries are cleaned up to prevent memory accumulation.

Closes #31530
2026-03-02 20:34:41 +00:00
SidQin-cyber
5b63417fec fix(slack): apply mrkdwn conversion in streaming and preview paths
The native streaming path (chatStream) and preview final edit path
(chat.update) send raw Markdown text without converting to Slack
mrkdwn format. This causes **bold** to appear as literal asterisks
instead of rendered bold text.

Apply markdownToSlackMrkdwn() in streaming.ts (start/append/stop) and
in dispatch.ts (preview final edit via chat.update) to match the
non-streaming delivery path behavior.

Closes #31892
2026-03-02 20:34:41 +00:00
webdevtodayjason
ab0b2c21f3 WhatsApp: guard main DM last-route to single owner 2026-03-02 20:33:59 +00:00
Mitch McAlister
f534ea9906 fix: prevent reasoning text leak through handleMessageEnd fallback
When enforceFinalTag is active (Google providers), stripBlockTags
correctly returns empty for text without <final> tags. However, the
handleMessageEnd fallback recovered raw text, bypassing this protection
and leaking internal reasoning (e.g. "**Applying single-bot mention
rule**NO_REPLY") to Discord.

Guard the fallback with enforceFinalTag check: if the provider is
supposed to use <final> tags and none were seen, the text is treated
as leaked reasoning and suppressed.

Also harden stripSilentToken regex to allow bold markdown (**) as
separator before NO_REPLY, matching the pattern Gemini Flash Lite
produces.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:32:01 +00:00
liuxiaopai-ai
bf0653846e Gateway: suppress NO_REPLY lead-fragment chat leaks 2026-03-02 20:27:49 +00:00