Commit Graph

14781 Commits

Author SHA1 Message Date
Dallin Romney
9d68f877ac test(qa): run gateway and MCP scenarios over real transports (#99735) 2026-07-03 20:26:16 -07:00
Dallin Romney
3b4092dbaa test: add executable runtime fixture canaries (#99737)
* test(qa): add runtime fixture canaries

* test(voice-call): track fixture temp directories
2026-07-03 20:22:40 -07:00
Dallin Romney
19035bdca1 fix(qa): avoid startup prewarm contention (#99368) 2026-07-03 20:14:58 -07:00
Dallin Romney
80d129212c refactor: consolidate deferred promise construction (#99755) 2026-07-03 19:55:00 -07:00
Dallin Romney
febc70036f refactor: consolidate exact boolean coercion (#99750)
* refactor: consolidate exact boolean parsing

* test: fix normalization subpath resolution

* fix: resolve normalization boolean subpath
2026-07-03 19:42:06 -07:00
Eva
faa4f4782e fix: keep OpenClaw control tools available when tool_search misroutes (#99561)
* fix(codex): keep OpenClaw control tools direct

* test(codex): refresh direct-tool prompt snapshots

* fix(codex): keep heartbeat direct only when available

* fix(codex): keep heartbeat tool schema stable

---------

Co-authored-by: Eva <eva@100yen.org>
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-07-03 21:34:32 -05:00
Peter Steinberger
8250b8d02e fix(providers): resolve ClawRouter auth-profile models (#99759) 2026-07-03 19:27:46 -07:00
Peter Steinberger
4a354f76c1 feat(providers): add ClawRouter routing and quotas (#99658)
* feat(providers): add ClawRouter routing and quotas

* docs(plugins): refresh Ollama inventory

* test(plugins): register ClawRouter boundary coverage

* docs(i18n): add ClawRouter glossary terms

* docs(providers): expand ClawRouter setup guide
2026-07-03 18:29:14 -07:00
Dallin Romney
24f654e065 fix(qa): isolate script scenarios from flow gateways (#99736) 2026-07-03 18:25:44 -07:00
Dallin Romney
ab9e233d02 improve(qa): execute runtime scenarios through Docker (#99705)
* test(qa): run Docker runtime scenarios end to end

* test(qa): keep plugin lifecycle probe runtime-only
2026-07-03 18:13:28 -07:00
Vincent Koc
bc802ceee1 test(qa): loosen mac script timeout harness 2026-07-04 03:06:25 +02:00
Dallin Romney
c7aca4f029 refactor: consolidate async timing helpers (#99721) 2026-07-03 17:58:15 -07:00
2loch-ness6
8d3b459792 fix(file-transfer): don't inline zero-byte files as image content blocks (#99370)
* fix(file-transfer): don't inline zero-byte files as image content blocks

file_fetch's remote mime detection falls back to the extension-derived
MIME type when content sniffing finds nothing to sniff (a zero-byte
buffer), so fetching an empty .png/.jpg/.webp/.gif produces
{type: "image", data: "", mimeType: "image/png"}. That payload-less
image block reached the model as an unrecoverable placeholder instead
of the existing "saved at <path>" text fallback used for every other
non-inlined file. Require a non-empty payload before treating a fetch
as an inline image. Refs #98673.

* test(file-transfer): prove empty image fetch fallback

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-03 17:30:33 -07:00
Dallin Romney
e6dec69403 refactor: consolidate image data URL formatting (#99715) 2026-07-03 17:09:30 -07:00
Vincent Koc
f53fdb688d fix(qa): restore package docker gates 2026-07-04 01:56:21 +02:00
Dallin Romney
1ab021fba9 fix(qa): consume Crabline events without recorder polling (#99679)
* fix(qa): consume Crabline events in process

* chore(qa): use Crabline 0.1.9
2026-07-03 16:15:03 -07:00
mushuiyu886
6207a4e75b fix(google): bound OAuth token error response reads (#99605)
* fix(google): bound OAuth token error response reads

* test(google): consolidate OAuth error cases

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-03 16:00:01 -07:00
Dallin Romney
04601ae81a refactor(qa): simplify transport adapter contracts (#99632)
* feat(qa): add transport capability contracts

* fix(qa): scope sequence support by channel

* refactor(qa): simplify transport adapter contracts

* fix(qa): clarify unsupported transport method errors
2026-07-03 15:54:27 -07:00
Dallin Romney
677c8ff846 improve: enforce canonical QA scenario ownership (#99628)
* improve: enforce canonical QA scenario ownership

* docs: refresh QA documentation map

* docs: condense QA ownership guidance

* docs: remove QA migration guidance

* refactor: simplify QA scenario ownership checks

* docs: align QA coverage authoring guidance
2026-07-03 15:51:18 -07:00
Peter Steinberger
fbdfd19622 Fix Slack retry for session init conflicts (#99647)
* Fix Slack retry for session init conflicts

* fix(slack): separate native and relay retries

* style(slack): make completion exits explicit

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-03 15:45:36 -07:00
Dallin Romney
1cab479f78 fix(qa): defer partial Crabline recorder rows (#99649) 2026-07-03 15:20:47 -07:00
Ted Li
d259496425 fix(google): rotate Gemini API keys for LLM requests (#97328)
* fix(google): rotate Gemini API keys for LLM requests

* fix(google): scope Gemini key rotation to official endpoint

* fix(google): require HTTPS for Gemini key rotation

* fix(google): preserve explicit stream auth headers

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-03 14:28:55 -07:00
Dallin Romney
5361e5a0b4 test(qa): share script evidence writer (#99374) 2026-07-03 12:59:23 -07:00
zhang-guiping
0ad58848b3 fix(telegram): stop duplicate fallback when dispatch fails after final reply
Telegram no longer sends a generic "Something went wrong" fallback after a
final answer was already delivered and a later dispatch/cleanup step failed.
Failures with only partial or no visible output still send the error fallback
and stay retryable.

Related: #87299
Closes #90152
2026-07-03 09:37:48 -07:00
Matthew Delprado
235a5c4d74 fix(imessage): recognize bare hex group chat identifiers as chat targets (#99525)
* fix(imessage): recognize bare hex group chat identifiers as chat targets

A 32-char hex iMessage group chat identifier (as returned by `imsg` for
group chats) with no explicit `chat_identifier:` prefix fell through to
E.164 phone-number normalization. normalizeE164 strips non-digit
characters and prepends `+`, turning
`7d5297154d5f436d83dbbdf03fcc8fdd` into `+75297154543683038` -- a
bogus phone number. Cron/announce delivery then reported
`delivered: true` while silently sending to a nonexistent recipient.

Detect bare 32-char hex strings in both the send-path target parser
(extensions/imessage/src/targets.ts) and the outbound delivery-target
normalizer (extensions/imessage/src/normalize.ts) and route them as
chat_identifier targets, consistent with how an explicit
`chat_identifier:<id>` prefix already resolves.

Fixes #89235.

* refactor(imessage): centralize bare chat identifiers

* refactor(imessage): centralize bare chat identifiers

---------

Co-authored-by: Peter Steinberger <peter@steipete.me>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-03 08:19:02 -07:00
Chen Chia Yang
5342effebc fix(google-meet): force English Meet UI via hl=en so automation works on any locale (#89671)
Summary:
- The branch adds `forceMeetEnglishUi()` for Google Meet URLs, applies it to join/create browser opens, canonicalizes browser-created meeting links, and updates focused Google Meet tests.
- PR surface: Source +18, Tests +19. Total +37 across 6 files.
- Reproducibility: yes. Current main opens raw Meet URLs while the browser automation matches English-only lab ... R body provides after-fix CDP output showing non-English pages render expected English labels with `hl=en`.

Automerge notes:
- PR branch already contained follow-up commit before automerge: chore(tooling): add unused agent-cache-store files to knip optional a…
- PR branch already contained follow-up commit before automerge: fix(google-meet): repair non-Latin mic regex matching boundary
- PR branch already contained follow-up commit before automerge: revert(tooling): preserve current main deadcode allowlist guard
- PR branch already contained follow-up commit before automerge: revert(tooling): perfectly match origin/main deadcode list
- PR branch already contained follow-up commit before automerge: revert: match origin/main deadcode list exactly

Validation:
- ClawSweeper review passed for head 880a41b6f0.
- Required merge gates passed before the squash merge.

Prepared head SHA: 880a41b6f0
Review: https://github.com/openclaw/openclaw/pull/89671#issuecomment-4608725456

Co-authored-by: Chen Chia Yang <unayung@gmail.com>
Approved-by: hxy91819
2026-07-03 15:00:34 +00:00
LZY3538
e272da5c55 fix: keep always-on group fallback messages in dispatch (#99506)
* fix(auto-reply): honor always-on plugin fallback groups

* fix(channels): preserve mention policy across bindings

* test(discord): type mention policy dispatch context

* test(discord): type mention policy dispatch context

* fix(whatsapp): preserve effective mention policy

* fix(whatsapp): preserve effective mention policy

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-03 07:26:45 -07:00
Jesse Merhi
8c915f0685 feat(signal): add target aliases (#95738)
* feat(signal): add target aliases

* fix(signal): canonicalize alias delivery targets

* fix(signal): harden alias target resolution

* test(signal): cover formatted media aliases

* test(signal): align approval alias proof with request shape

* Reuse Signal alias map for directory listing
2026-07-03 23:40:10 +10:00
Eva
414ecd2b96 Preserve Codex output after missing turn completion (#99217)
* Preserve Codex output after missing turn completion

* fix: narrow Codex completion-timeout output recovery

* test(codex): narrow binding path guard

* fix: narrow Codex completion-timeout output recovery

* test(codex): narrow binding path guard

* fix(codex): preserve id-less post-tool replies

---------

Co-authored-by: Sedrak-Hovhannisyan <264150421+Sedrak-Hovhannisyan@users.noreply.github.com>
Co-authored-by: Eva <eva@100yen.org>
Co-authored-by: Jason (Json) <263060202+fuller-stack-dev@users.noreply.github.com>
2026-07-03 05:07:54 -07:00
Jesse Merhi
8abc633cf8 Add Signal status reaction lifecycle (#98791) 2026-07-03 21:42:39 +10:00
lwy-2
33c1e6224c fix(feishu): catch unhandled promise rejection in streaming card flush timer (#99301)
* fix(feishu): catch unhandled promise rejection in streaming card flush timer

## What Problem This Solves

The scheduled flush update in FeishuStreamingSession called
`this.update(pending)` without catching potential rejections, which
could cause unhandled promise rejections when card content updates
fail due to transient network errors.

## Why This Change Was Made

Add a `.catch()` with diagnostic logging to the scheduled flush
timer's `update()` call so transient card update failures are visible
without causing unhandled promise rejections.

## User Impact

Scheduled streaming-card updates that fail transiently will log a
diagnostic instead of producing an unhandled promise rejection.

## Evidence

node scripts/run-vitest.mjs extensions/feishu/src/media.test.ts

  Test Files  1 passed (1)
  Tests       44 passed (44)

pnpm exec oxfmt --check ...

  All matched files use the correct format.

node scripts/run-oxlint.mjs ...

  oxlint_exit=0

git diff --check

  exit=0

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

* test(feishu): cover rejected scheduled card flush

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-03 02:20:43 -07:00
Peter Steinberger
1fef99962e feat(nodes): add auto-discovered Ollama inference (#99234)
* feat(nodes): add local Ollama inference

* fix(gateway): preserve plugin node runtime for agent turns

* feat(ollama): add node inference opt-out

* test(security): preserve plugin runtime exports

* test(security): preserve plugin runtime exports

* test(security): preserve plugin runtime exports

* fix(ci): raise artifact build heap
2026-07-03 01:14:30 -07:00
xingzhou
cd6b67533d fix(qqbot): allow scoped sandbox media sends (#92872)
* fix(qqbot): allow scoped sandbox media sends

* fix(qqbot): thread scoped media access through all outbound paths

Cover the seven QQBot outbound media paths that dropped core scoped
sandbox media access: gateway block/tool/streaming deliver, direct
text qqmedia tags, structured QQBOT_PAYLOAD, and the scoped workspace
relative/missing-voice path resolution. The low-level sendPhoto /
sendVideoMsg / sendDocument now consume core mediaAccess.readFile via
the shared outbound loader with explicit localRoots guard, so
host-mediated workspace media can be sent without widening QQBot FS
access. Voice stays on the existing SILK transcode path to avoid
bypassing QQ-required format conversion.

* fix(qqbot): thread workspaceDir into gateway reply media context

Gateway dispatchOutbound previously built gatewayMediaContext with only
mediaLocalRoots, so a sandboxed block reply that carried a relative
media tag (e.g. <qqmedia>report.docx</qqmedia>) reached the downstream
sender without mediaAccess.workspaceDir and was rejected by containment
checks before the file could be resolved against the agent workspace.

Resolve the agent workspace dir via the public plugin-sdk agent-runtime
helper and pass it through mediaAccess.workspaceDir alongside the
existing mediaLocalRoots so the gateway block reply, tool forwarding,
QQBOT_PAYLOAD, and official C2C streaming paths all share the same
scoped workspace resolution as direct outbound sends. No public plugin
SDK boundary is widened; the helper is an existing export.

Add a regression test that exercises a relative <qqmedia> tag in a
gateway block reply and confirms it resolves against the configured
agent workspace.

* fix(qqbot): wrap host-read media sends with structured error handling

* fix(qqbot): preserve host-read media quota errors

* fix(qqbot): preserve host-read quota fallback path

* fix(qqbot): resolve host-read quota fallback path

* test(qqbot): satisfy host-read media lint

* fix(qqbot): cover host-read voice media

* fix(qqbot): satisfy host-read voice lint

* Drop incidental formatting from PR merge

Keep the conflict-resolution update scoped to the QQBot media send files.

* fix(qqbot): map sandbox workspace media paths

* fix(qqbot): preserve host-read media roots

* fix(qqbot): scope sandbox media delivery roots

* fix(qqbot): map virtual media roots before host read

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

* fix(qqbot): scope structured payload media roots

* fix(qqbot): keep auto media helper internal

* docs(changelog): note QQBot scoped sandbox media fix (#92872) (thanks @zhangguiping-xydt)

---------

Co-authored-by: sliverp <870080352@qq.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-03 15:02:58 +08:00
Ayaan Zaidi
0bf66ab7bd fix(sessions): scope ambient transcript watermark to session id
Ambient transcript watermarks now carry the transcript session id, resolve only for the current session entry, and skip stale room-event hooks that no longer match the prepared transcript session.

This protects Telegram group prompt windows after reset by backfilling rows that are no longer present in the new session transcript, while preserving steady-state watermark filtering within one session.

Fixes #99373

Release-note: fixes Telegram group context loss after session reset when ambient transcript watermarks outlived the transcript they referenced.
2026-07-02 22:57:01 -07:00
NianJiuZst
4d5d9dda92 fix: avoid DeepSeek-native thinking on OpenRouter V4 2026-07-02 22:50:58 -07:00
Dallin Romney
de34dfdbe8 refactor(plugins): consolidate record guards (#99361) 2026-07-02 22:12:53 -07:00
Dallin Romney
8604dbdc93 test(qa): migrate channel streaming evidence to transport flow (#99310)
* test(qa): migrate channel streaming evidence to transport flow

* test(qa): enable Telegram previews for streaming smoke

* test(qa): stabilize streaming preview evidence

* fix(qa): sanitize channel dispatch logs
2026-07-02 21:48:29 -07:00
Dallin Romney
e7384d5f02 fix(ci): restore Telegram and SDK guard checks (#99355) 2026-07-02 21:18:25 -07:00
Dallin Romney
8c5f45fc36 refactor(shared): consolidate provider and utility lazy loaders (#98749)
* refactor(shared): consolidate provider lazy loaders

* refactor(shared): leave enforcement to follow-up
2026-07-02 21:16:26 -07:00
Dallin Romney
8d535fb039 test(qa): cover Crabline Zalo transport (#99303) 2026-07-02 19:09:22 -07:00
Dallin Romney
59b08b4693 refactor(shared): consolidate remaining channel lazy loaders (#99302) 2026-07-02 19:08:11 -07:00
Ayaan Zaidi
3ad465d32b fix(telegram): persist ambient transcript rows
Persist room-event observations as durable bare user transcript rows and carry an ambient transcript watermark through session state so Telegram chat windows only include the unpersisted gap.

Fixes #99257
2026-07-02 19:01:22 -07:00
Dallin Romney
b47fe7a4b3 fix(memory-wiki): avoid implicit error coercion (#99307) 2026-07-02 18:56:46 -07:00
Dallin Romney
792060bb63 refactor(shared): consolidate Discord Slack and Telegram lazy loaders (#99298) 2026-07-02 18:45:48 -07:00
Dallin Romney
84c9f05513 Allow alternate Zalo Bot API roots (#98768)
* Allow alternate Zalo Bot API roots

* Normalize Zalo provider timestamps
2026-07-02 18:44:15 -07:00
Ayaan Zaidi
8ca6a6f8ef fix(memory-wiki): fail closed on source page read errors 2026-07-02 18:42:00 -07:00
Dallin Romney
aae57adc80 fix(qa): stagger isolated worker startup (#99294) 2026-07-02 18:39:02 -07:00
Peter Lindsey
dae86e6bec fix(telegram): guard the normal collapse-bar fallback send too
ClawSweeper review finding: F3 only wrapped the cleanup-fallback bar send.
The normal path applyProgressCollapseSummary awaited an unguarded durable
send when finalizeToPreview could not edit in place, and sendPayload throws
durable.error on delivery failure — so a cosmetic summary-bar flood-wait
could propagate and fail an otherwise-complete turn (merge-risk:
message-delivery).

Route BOTH cosmetic-bar sends through one shared guarded helper
postCosmeticSummaryBar (swallow + logVerbose), so neither the cleanup path
nor the finalizeToPreview-miss path can fail turn delivery. Add the missing
regression: no-live-message fallback bar send throwing keeps the turn alive
and the final answer delivered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 18:38:39 -07:00
Peter Lindsey
b43687d0b5 fix(telegram): align progress-window tests with rebased core types
Post-rebase onto main, check-test-types/lint failed on our touched test
files (runtime unaffected):
- core's onVerboseProgressVisibility now takes a thunk (isActive: () =>
  boolean); the dispatch test passed a bare boolean. Pass () => true.
- our TelegramDraftStream additions (finalizeToPreview,
  rotateToNewMessageDeferringDelete) are required members; the QA-e2e
  mock streams omitted them. Add both to every mock stream.
- drop a redundant 'as string' cast (oxlint no-unnecessary-type-assertion).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 18:38:39 -07:00
Peter Lindsey
9dfa7dc87a fix(telegram): red-team hardening for the progress collapse bar
Addresses five codex red-team findings on the streamed progress-window
collapse bar. Channel-side only; no core src/** changes.

F1 (transcript pollution): the collapse bar went through
sendPayload({durable:true}), which unconditionally passed the transcript
mirror to the deliverReplies fallback, writing the cosmetic digest
("💬 1 note · 🛠️ 1 tool call · ⏱️ 4s") into the session transcript so the
model read it back as its own prior turn. Added a mirrorTranscript option to
sendPayload; the bar now sends durably with mirrorTranscript:false. Discord
parity: its summary bar (monitor/reply-delivery.ts deliverDiscordReply →
sendDurableMessageBatch) has no transcript-mirror seam at all. Real finals
keep mirroring.

F4 (tool overcount): progressSummary.noteToolCall() fired for ANY start-phase
tool, but the compositor renders a line only for work tools
(isChannelProgressDraftWorkToolName) and only when toolProgress is on, so
codex/message_tool_only turns showed "🛠️ 1 tool call" with no tool line. The
count is now gated by the same public work-tool-name check plus
streamToolProgressEnabled; non-counting tool starts still close the
reasoning/commentary bursts as a boundary.

F2 (silent collapse drop): finalizeToPreview ignored a false return from the
in-place edit (flood-wait 429 / terminal error), so applyProgressCollapseSummary
assumed "edited", cleared state, posted no bar, and left the tall window.
finalizeToPreview now returns undefined when the edit did not apply, so the
dispatch falls back to the existing durable-post path.

F3 (cosmetic send fails the turn): the cleanup-time deliverProgressCollapseSummary
could throw (429/network) and propagate out of dispatch after the real final
already delivered. The bar send is now wrapped: failures log via logVerbose and
never fail the turn; the once-guard is preserved.

F5 (ghost-preview race): rotateToNewMessageDeferringDelete rewound while a FIRST
send was still in flight; the late send landed as superseded {retain:true}, which
the dispatch handler kept as an orphaned stale bubble. A reposition now records
the in-flight generation and deletes its late-landing message (deferred), while
forceNewMessage's retain-as-durable-chunk contract is unchanged.

Tests: added unit tests for each invariant (bar delivered but absent from the
transcript mirror; message-tool start → no 🛠️ count and toolProgress-off → no
count; failed edit → undefined; bar send throw → turn still succeeds; reposition
race → superseded send deleted not retained). Telegram suites green
(bot-message-dispatch 165, draft-stream 58, progress-summary 16); extensions
tsgo clean for telegram.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-02 18:38:39 -07:00