Commit Graph

20715 Commits

Author SHA1 Message Date
Peter Steinberger
fbddef34bd perf(ci): trim provider catalog test setup 2026-04-22 05:57:22 +01:00
Peter Steinberger
dbf3eca590 test: stabilize workspace fallback assertion 2026-04-22 05:50:57 +01:00
pashpashpash
89932593bb Show typing while heartbeats are running (#69963)
* Heartbeat: show typing during runs

* Heartbeat: fix typing review issues

* Discord: preserve heartbeat typing config
2026-04-22 13:50:27 +09:00
fuller-stack-dev
276c00015c fix: add local embedded TUI mode (#66767) (thanks @fuller-stack-dev)
* feat(tui): add local embedded TUI mode with terminal/chat aliases

Adds a gateway-free local TUI path so users can run openclaw in their
terminal without needing a running gateway process.

- TuiBackend interface abstraction (tui-backend.ts) with EmbeddedTuiBackend
  implementation that drives the agent loop in-process
- openclaw tui --local flag for local embedded mode
- openclaw terminal / openclaw chat aliases that imply --local
- /auth slash command with codex CLI delegation to avoid prolite plan issue
- Default model display fallback on startup
- Local-aware status text and log suppression
- Concise auth error hints, raw HTML 403 suppression
- Onboarding hatch flow launches local TUI (no gateway required)
- Commander alias bug fix in run-main.ts (.aliases() check)
- All new and updated tests passing (145/145)

* TUI: fix alias detection, cross-platform codex lookup, and history byte-budget safeguards

* TUI: remove RuntimeEnv type annotation to fix CI oxlint error

* TUI: filter gateway-dependent tools and auto-approve plugin hooks in embedded mode

* TUI: suppress console noise and add embedded mode system prompt note

* TUI: reduce embedded-mode tool filtering from 15 to 7, add local session tools

* TUI: fix remaining PR review comments

* TUI: address latest review feedback and CI drift

* Core: align prompt helper with latest base

* Core: match prompt helper formatting with base

* Core: restore prompt helper from latest base

* fix(tui): preserve local auth fallback in source checkouts

* fix(tts): guard telephony provider invocation

* fix(tui): support Windows codex auth shim

* fix(tui): harden local auth flow

* fix: preserve embedded tool-first run events

* fix(tui): keep embedded plugin approvals gated

* fix(tui): restore embedded attempt import

* fix(tui): resolve sessions in embedded stub

* fix: add embedded TUI changelog entry (#66767) (thanks @fuller-stack-dev)

* fix: pass setup TUI local mode through relaunch (#66767) (thanks @fuller-stack-dev)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-04-22 10:08:57 +05:30
Peter Steinberger
a99490fba4 fix(plugins): support root-owned bundled runtime deps 2026-04-22 05:02:35 +01:00
Shakker
3528a17b67 fix: scope static catalog discovery fallback 2026-04-22 04:51:38 +01:00
Shakker
bbe3dc6c2f fix: sanitize models list terminal output 2026-04-22 04:51:38 +01:00
Shakker
754125947a fix: include partial provider discovery fallbacks 2026-04-22 04:51:38 +01:00
Shakker
10959aa980 fix: restrict static model catalogs to bundled providers 2026-04-22 04:51:38 +01:00
Shakker
f3da6e96b7 fix: bound static provider catalog listing 2026-04-22 04:51:38 +01:00
Shakker
d6c7b468ea fix: honor provider hook aliases in catalog filters 2026-04-22 04:51:38 +01:00
Shakker
f9bac5038c fix: harden static provider catalog path 2026-04-22 04:51:38 +01:00
Shakker
d73c31110b fix: harden static provider catalog listing 2026-04-22 04:51:38 +01:00
Shakker
04ecf284fc fix: use static provider catalogs for model listing 2026-04-22 04:51:38 +01:00
Shakker
cc78dd2044 fix: show provider catalog models in all list 2026-04-22 04:51:38 +01:00
Gustavo Madeira Santana
a197b544fe fix(doctor): route setup doctor discovery (#69919)
Merged via squash.

Prepared head SHA: 90c7067941
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-21 23:40:22 -04:00
Peter Steinberger
b0734664f8 style: format touched code 2026-04-22 04:24:45 +01:00
Peter Steinberger
23a017be7c fix: suppress Mattermost quoted reasoning replies (#69927) (thanks @lawrence3699) 2026-04-22 04:10:28 +01:00
Peter Steinberger
24c409035c perf(gateway): lazy load deferred plugin bootstrap 2026-04-22 04:06:22 +01:00
Peter Steinberger
cb4ec1265f fix(agents): align embedded built-in tool types 2026-04-22 03:42:49 +01:00
Ayaan Zaidi
2da1406b29 test(cron): trim message trace comments 2026-04-22 08:12:20 +05:30
davehappyminion
9db67e79a5 fix(cron): narrow accountId spoof guard to explicit mismatch only
Addresses codex P1 review on PR #69940: the previous guard rejected
targets that simply omitted accountId, but message-tool fills accountId
from the agent's bound account at exec time (message-tool.ts:730-733),
so account-bound cron jobs legitimately start with target.accountId
undefined. Rejecting that case lost skipMessagingToolDelivery, causing
dispatchCronDelivery to double-send.

Now we only reject when the tool explicitly names a *different*
accountId — which is the real CWE-284 spoof vector. Omission matches.

Tests updated accordingly:
- matcher unit test: flipped "omit accountId" case from false to true;
  "accountIds differ" case preserved as the real spoof guard
- integration tests: one legitimate-default case (rewrite happens),
  one explicit-mismatch case (rewrite suppressed)

658 cron tests pass.
2026-04-22 08:12:20 +05:30
davehappyminion
851bef9c25 fix(cron): rewrite generic message provider in trace + guard accountId spoof
When a cron job sends via the generic `message` tool, the delivery trace
previously recorded `messageToolSentTo[i].channel = "message"` even
though the send was resolved to a specific channel (e.g. telegram). This
made `jq` diffing intended-vs-actual awkward for the happy path.

Fix:
- `normalizeMessagingToolTarget` now rewrites `channel: "message"`
  to the resolved channel when `matchesMessagingToolDeliveryTarget`
  confirms the tool send matches the resolved cron delivery target.
  Genuinely unmatched generic sends keep the literal "message" so
  audits can still flag them.

- `matchesMessagingToolDeliveryTarget` now requires strict accountId
  equality whenever the resolved delivery carries an `accountId`. An
  omitted `target.accountId` previously short-circuited the guard and
  was treated as a wildcard, letting a generic send spoof attribution to
  any bot identity in the cron delivery trace (CWE-284). This was
  flagged by Aisle on #69771.

Tests:
- Unit: `matchesMessagingToolDeliveryTarget` rejects omitted-accountId
  against account-tied delivery; still matches same-accountId.
- Integration: cron run trace rewrites generic "message" to the
  resolved channel, preserves accountId on both sides, and leaves the
  literal "message" provider in place when the tool send omits
  accountId against an account-tied delivery.
2026-04-22 08:12:20 +05:30
Peter Steinberger
e8f18f95d5 test(docker): cover slack bundled runtime deps 2026-04-22 03:40:37 +01:00
Peter Steinberger
f9b20c7d17 fix(plugins): repair bundled runtime deps during doctor 2026-04-22 03:40:37 +01:00
Peter Steinberger
0f4dc42767 build: update pi packages to 0.68.1 2026-04-22 03:35:15 +01:00
Peter Steinberger
de6f548a7c fix: suppress disabled channel read-only presence 2026-04-22 03:21:07 +01:00
Aaron U'Ren
8d021ee7bf perf(plugins): prefer native jiti for bundled plugin dist modules (#69925)
Merged via squash.

Prepared head SHA: 1b2da10865
Co-authored-by: aauren <1392295+aauren@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-21 22:18:35 -04:00
Peter Steinberger
1801b90460 chore: bump version to 2026.4.22 2026-04-22 03:04:53 +01:00
Peter Steinberger
ef66798433 fix: preserve outbound thread sessions 2026-04-22 02:56:23 +01:00
Peter Steinberger
d87f8cc142 test: move cron validation off gateway server 2026-04-22 02:55:40 +01:00
Patrick Erichsen
529577e045 fix(memory/dreaming): surface blocked status when heartbeat is disabled for main (#69875)
* fix(memory/dreaming): surface blocked status in memory status when heartbeat disabled for main

Replace the hand-rolled heartbeat-rules logic in resolveDreamingBlockedReason
with the shared resolveHeartbeatSummaryForAgent helper, promoted from core to
the plugin-sdk via infra-runtime. Collapses the two disabled-reason branches
into a single message that points at a new Troubleshooting section in the
dreaming docs, so the silent-failure mode described in openclaw/openclaw#69843
becomes legible without the extension re-encoding heartbeat-enablement rules.

Refs openclaw/openclaw#69843, openclaw/openclaw#46046.

* refactor(memory/dreaming): share resolveDreamingBlockedReason across cli and /dreaming surfaces

- Move resolveDreamingBlockedReason from cli.runtime.ts into dreaming.ts as an exported helper and pin its heartbeat check to DEFAULT_AGENT_ID (now exported from plugin-sdk/routing) so the status-line check agrees with the cron's hardcoded sessionTarget even when the configured default agent is not main.
- Render the blocked reason from formatStatus in dreaming-command.ts directly under the enabled line, so /dreaming status, /dreaming on, /dreaming off, and bare /dreaming all flag that the cron is blocked instead of implying dreaming is healthy.
- Tighten the blocked-reason text to lead with user impact ('dreaming is enabled but will not run because heartbeat is disabled for main'), so operators immediately understand the config is toggled on but nothing is actually running.
- Tighten the dreaming Troubleshooting copy to name main explicitly and mention both surfaces.
- Add tests locking the new behavior across cli.test.ts (default-agent=ops still reports blocked for main) and dreaming-command.test.ts (/dreaming status ordering, /dreaming on surfacing, healthy-heartbeat omission).

Refs openclaw/openclaw#69843, openclaw/openclaw#46046.

* fix(memory/dreaming): check heartbeat for the resolved default agent, not the literal 'main'

sessionTarget: 'main' is a cron session-type enum variant meaning 'the default agent's main session', not an agent id (see src/cron/service/jobs.ts). buildManagedDreamingCronJob does not set agentId, and cron runtime resolves the missing agentId through resolveDefaultAgentId(cfg) before enqueuing or waking. The previous pin to DEFAULT_AGENT_ID could produce a false 'blocked' reading when a configured default agent is not 'main' and its heartbeat is fine, and could miss a real block when the default agent is not 'main' and that agent's heartbeat is actually off.

Switch resolveDreamingBlockedReason to resolveDefaultAgentId(cfg) and interpolate the resolved agent id into the message so the blocked line names the agent whose heartbeat is the blocker. Introduce a narrow local CRON_SESSION_TARGET_MAIN constant for the cron session-type enum variant (used by the sessionTarget type and value) so the remaining 'main' literal is semantically distinct from any agent id. Revert the DEFAULT_AGENT_ID export addition on plugin-sdk/routing; memory-core no longer needs it. Update the Troubleshooting doc wording and the cli test that was locking the wrong behaviour.

Refs openclaw/openclaw#69843, openclaw/openclaw#46046.

* fix(memory/dreaming): align blocked check with server-cron wake's defaults-only heartbeat

resolveDreamingBlockedReason was using resolveHeartbeatSummaryForAgent, which merges agents.defaults.heartbeat with agents.list[].heartbeat. The managed dreaming cron leaves job.agentId and job.sessionKey unset, so server-cron's wake wrapper cannot look up a per-agent entry and calls runHeartbeatOnce with agents.defaults.heartbeat only. Using the summary helper would disagree with the actual wake when the default agent overrides heartbeat.every differently from the defaults (either direction — false blocked when the override would run, or false healthy when defaults block).

Mirror the wake path explicitly: rule-1 enablement via isHeartbeatEnabledForAgent against the default agent, rule-3 interval via resolveHeartbeatIntervalMs with defaults-only heartbeat config. Comment points at server-cron so a future cleanup of that latent override-propagation gap sees the coupling.

Refs openclaw/openclaw#69843.
2026-04-21 18:51:43 -07:00
Peter Steinberger
fb9a21ae8f fix: centralize draft preview finalization 2026-04-22 02:32:55 +01:00
Peter Steinberger
e5909f3e5d ci: scope mlx helper as macos native 2026-04-22 02:19:58 +01:00
Gustavo Madeira Santana
f4478a142a Fix channel presence gating for disabled plugins (#69862)
Merged via squash.

Prepared head SHA: f76f6212b2
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-21 20:51:09 -04:00
Gustavo Madeira Santana
819d15481d fix: validate plugin source entries before runtime inference (#69868)
Merged via squash.

Prepared head SHA: b67644cdda
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-21 20:12:19 -04:00
Ron Cohen
08bc16853e WhatsApp: add group and direct system prompt support (#59553)
Merged via squash.

Prepared head SHA: 63e2b50e01
Co-authored-by: Bluetegu <1525690+Bluetegu@users.noreply.github.com>
Co-authored-by: omarshahine <10343873+omarshahine@users.noreply.github.com>
Reviewed-by: @omarshahine
2026-04-21 16:40:32 -07:00
Bek
e116b343b2 feat(slack): Annotate inbound Slack mention tokens in Slack RawBody and BodyForAgent content so the agent sees both the actionable Slack mention token and a human-readable name. (#65731)
* Annotate inbound Slack mentions in raw bodies

* Avoid shared regex state in Slack mention rendering

* Bound Slack mention lookups with concurrency

* slack: keep mention concurrency helper plugin-local

* test: stabilize node core CI assertions

* slack: cap mention lookups per inbound message

* test: reset suite gateway runtime state

* fix(slack): reuse plugin sdk concurrency helper
2026-04-21 19:03:50 -04:00
Bek
70683179a0 fix(slack): narrow first turn context seeding to remove redundant thread-starter content (#68402)
Fix Slack thread bootstrap replaying the bot's own prior turns into new sessions and duplicating the thread-starter prompt block.

Narrows first-turn context seeding to exclude only the current Slack bot's own starter/history entries, so self-authored turns no longer pollute new session prompts while preserving human and third-party bot context

Removes the redundant plain-text starter prelude in runPreparedReply() that doubled thread-starter content when no ThreadHistoryBody was present
2026-04-21 18:28:34 -04:00
Bek
dfe0e49c8a fix(qmd): Dedup in-flight manager creation so only one full QMD manager arms per agent/config at a time, eliminating the concurrent exportSessions() collisions that triggered path changed during write errors (#65226)
Fixes concurrent manager creation races that caused SafeOpenErrors during session export.

Deduplicates in-flight manager creation so only one full QMD manager arms per agent/config at a time, eliminating the concurrent exportSessions() collisions that triggered path changed during write errors
Resolves and snapshots runtime inputs before cache reuse, replacing stale managers atomically when workspace/config changes, and aborting queued export work promptly on close()
2026-04-21 18:22:21 -04:00
Bek
1acb094579 fix: wrap oversized session lines before JSONL write (#64494)
updates the real session-export path so pathological transcript messages no longer become a single toxic export line for downstream indexing.
2026-04-21 18:18:22 -04:00
Gustavo Madeira Santana
66add9fcd9 perf(cli): lazy-load doctor plugin paths (#69840)
Merged via squash.

Prepared head SHA: ebf93ad913
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-21 18:17:19 -04:00
Bek
0e1d324dd8 fix(agents): Wake active requester sessions for subagent completions while keeping dormant sessions externally deliverable (#62963)
Route subagent completion announces through embedded-run wake for active requesters, preserve external delivery for dormant ones
2026-04-21 18:13:53 -04:00
Bek
14dcbd4044 fix(prompt): align system prompt messaging and subagent routing guidance (#64059)
replace legacy `to` with `target` in prompt
2026-04-21 18:10:53 -04:00
Peter Steinberger
824c4785e4 test: speed channel contract suites 2026-04-21 23:09:22 +01:00
Peter Steinberger
74668ea8a1 fix(image-generation): log provider fallback failures 2026-04-21 22:50:09 +01:00
Peter Steinberger
d1e3789e15 test: optimize slow test hotspots 2026-04-21 22:42:08 +01:00
Bek
49b233caa1 fix(slack): preserve thread aliases in runtime outbound sends (#62947)
Slack-threaded direct sends that go through the generic runtime wrapper now stay in the intended thread when the caller supplies threadTs.
2026-04-21 17:40:47 -04:00
Peter Steinberger
e71e543350 fix: route explicit image describe models 2026-04-21 22:25:45 +01:00
scotthuang
8a7c21407a fix(agents): gate sessions_send A2A skip on requester ownership
Greptile/Codex review follow-ups on #69817:

- Narrow skipA2AFlow from target-only detection to a combined check that
  the caller is the parent of the target (new
  isRequesterParentOfBackgroundAcpSession helper). Under
  tools.sessions.visibility=all a non-parent sender can see the same
  oneshot ACP session; the previous guard would have suppressed their
  only follow-up delivery path. With requester ownership required, those
  senders continue through the normal A2A flow.
- When the A2A flow is skipped, return delivery.status="skipped" instead
  of "pending" so the parent LLM does not wait for a second result that
  will never arrive.
- Add unit tests for resolveAcpSessionInteractionMode and
  isRequesterParentOfBackgroundAcpSession covering both the new
  ownership gate and the existing target-type branches.
2026-04-21 22:17:28 +01:00