Commit Graph

21 Commits

Author SHA1 Message Date
Peter Steinberger
f0000ab72d refactor(plugin-sdk): split infra runtime barrel 2026-04-27 20:50:35 +01:00
Vincent Koc
dcdf97685b fix(diagnostics): trust internal trace parents (#71574)
* fix(diagnostics): trust internal trace parents

* fix(diagnostics): harden trusted trace metadata

* fix(tooling): honor explicit oxlint threads

* fix(agents): use stable nonmutating sort helpers

* chore(plugin-sdk): refresh api baseline

* fix(diagnostics): gate internal event subscriptions

* fix(diagnostics): isolate listener event copies

* chore(plugin-sdk): refresh internal diagnostics baseline

* chore(plugin-sdk): refresh diagnostics event baseline

* fix(diagnostics): keep event state module local

* fix(diagnostics): harden internal subscription capability

* fix(diagnostics): freeze listener metadata
2026-04-25 10:18:52 -07:00
Peter Steinberger
32dd1ffc5a refactor(approvals): unify structured path display 2026-04-25 02:41:24 +01:00
Peter Steinberger
4a9dd3fe49 refactor: drop provider reconnect shim 2026-04-22 06:39:48 +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
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
Vincent Koc
74e7b8d47b fix(cycles): bulk extract leaf type surfaces 2026-04-11 13:26:50 +01:00
Vincent Koc
7308e72fac fix(cycles): continue seam extraction 2026-04-11 10:43:22 +01:00
Marcus Castro
95d467398e fix(whatsapp): drain eligible pending deliveries on reconnect (#63916)
* fix(whatsapp): drain eligible pending deliveries on reconnect

* docs(changelog): note whatsapp reconnect pending drain
2026-04-09 23:41:25 -03:00
manuel-claw
e30d0cffc4 fix(whatsapp): drain reconnect queue after WhatsApp reconnects (#30806) (#46299)
Merged via squash.

Prepared head SHA: 5ce763406e
Co-authored-by: manuel-claw <268194568+manuel-claw@users.noreply.github.com>
Co-authored-by: mcaxtr <7562095+mcaxtr@users.noreply.github.com>
Reviewed-by: @mcaxtr
2026-04-09 02:33:36 -03:00
Peter Steinberger
856592cf00 fix(outbound): restore generic delivery and security seams 2026-04-03 19:09:20 +01:00
Vincent Koc
dc6e041cfe test(bluebubbles): narrow monitor normalize number parsing 2026-04-03 20:36:24 +09:00
Peter Steinberger
ddce362d34 refactor(approvals): share native delivery runtime 2026-03-31 23:11:53 +01:00
scoootscooob
9ff57ac479 refactor(exec): unify channel approvals and restore routing/auth (#57838)
* fix(exec): add shared approval runtime

* fix(exec): harden shared approval runtime

* fix(exec): guard approval expiration callbacks

* fix(exec): handle approval runtime races

* fix(exec): clean up failed approval deliveries

* fix(exec): restore channel approval routing

* fix(exec): scope telegram legacy approval fallback

* refactor(exec): centralize native approval delivery

* fix(exec): harden approval auth and account routing

* test(exec): align telegram approval auth assertions

* fix(exec): align approval rebase followups

* fix(exec): clarify plugin approval not-found errors

* fix(exec): fall back to session-bound telegram accounts

* fix(exec): detect structured telegram approval misses

* test(exec): align discord approval auth coverage

* fix(exec): ignore discord dm origin channel routes

* fix(telegram): skip self-authored message echoes

* fix(exec): keep implicit approval auth non-explicit
2026-03-30 15:49:02 -07:00
Josh Avant
6ade9c474c feat(hooks): add async requireApproval to before_tool_call (#55339)
* Plugins: add native ask dialog for before_tool_call hooks

Extend the before_tool_call plugin hook with a requireApproval return field
that pauses agent execution and waits for real user approval via channels
(Telegram, Discord, /approve command) instead of relying on the agent to
cooperate with a soft block.

- Add requireApproval field to PluginHookBeforeToolCallResult with id, title,
  description, severity, timeout, and timeoutBehavior options
- Extend runModifyingHook merge callback to receive hook registration so
  mergers can stamp pluginId; always invoke merger even for the first result
- Make ExecApprovalManager generic so it can be reused for plugin approvals
- Add plugin.approval.request/waitDecision/resolve gateway methods with
  schemas, scope guards, and broadcast events
- Handle requireApproval in pi-tools via two-phase gateway RPC with fallback
  to soft block when the gateway is unavailable
- Extend the exec approval forwarder with plugin approval message builders
  and forwarding methods
- Update /approve command to fall back to plugin.approval.resolve when exec
  approval lookup fails
- Document before_tool_call requireApproval in hooks docs and unified
  /approve behavior in exec-approvals docs

* Plugins: simplify plugin approval code

- Extract mergeParamsWithApprovalOverrides helper to deduplicate param
  merge logic in before_tool_call hook handling
- Use idiomatic conditional spread syntax in toolContext construction
- Extract callApprovalMethod helper in /approve command to eliminate
  duplicated callGateway calls
- Simplify plugin approval schema by removing unnecessary Type.Union
  with Type.Null on optional fields
- Extract normalizeTrimmedString helper for turn source field trimming

* Tests: add plugin approval wiring and /approve fallback coverage

Fix 3 broken assertions expecting old "Exec approval" message text.
Add tests for the /approve command's exec→plugin fallback path,
plugin approval method registration and scope authorization, and
handler factory key verification.

* UI: wire plugin approval events into the exec approval overlay

Handle plugin.approval.requested and plugin.approval.resolved gateway
events by extending the existing exec approval queue with a kind
discriminator. Plugin approvals reuse the same overlay, queue management,
and expiry timer, with branched rendering for plugin-specific content
(title, description, severity). The decision handler routes resolve calls
to the correct gateway method based on kind.

* fix: read plugin approval fields from nested request payload

The gateway broadcasts plugin approval payloads with title, description,
severity, pluginId, agentId, and sessionKey nested inside the request
object (PluginApprovalRequestPayload), not at the top level. Fix the
parser to read from the correct location so the overlay actually appears.

* feat: invoke plugin onResolution callback after approval decision

Adds onResolution to the requireApproval type and invokes it after
the user resolves the approval dialog, enabling plugins to react to
allow-always vs allow-once decisions.

* docs: add onResolution callback to requireApproval hook documentation

* test: fix /approve assertion for unified approval response text

* docs: regenerate plugin SDK API baseline

* docs: add changelog entry for plugin approval hooks

* fix: harden plugin approval hook reliability

- Add APPROVAL_NOT_FOUND error code so /approve fallback uses structured
  matching instead of fragile string comparison
- Check block before requireApproval so higher-priority plugin blocks
  cannot be overridden by a lower-priority approval
- Race waitDecision against abort signal so users are not stuck waiting
  for the full approval timeout after cancelling a run
- Use null consistently for missing pluginDescription instead of
  converting to undefined
- Add comments explaining the +10s timeout buffer on gateway RPCs

* docs: document block > requireApproval precedence in hooks

* fix: address Phase 1 critical correctness issues for plugin approval hooks

- Fix timeout-allow param bug: return merged hook params instead of
  original params when timeoutBehavior is "allow", preventing security
  plugins from having their parameter rewrites silently discarded.

- Host-generate approval IDs: remove plugin-provided id field from the
  requireApproval type, gateway request, and protocol schema. Server
  always generates IDs via randomUUID() to prevent forged/predictable
  ID attacks.

- Define onResolution semantics: add PluginApprovalResolutions constants
  and PluginApprovalResolution type. onResolution callback now fires on
  every exit path (allow, deny, timeout, abort, gateway error, no-ID).
  Decision branching uses constants instead of hard-coded strings.

- Fix pre-existing test infrastructure issues: bypass CJS mock cache for
  getGlobalHookRunner global singleton, reset gateway mock between tests,
  fix hook merger priority ordering in block+requireApproval test.

* fix: tighten plugin approval schema and add kind-prefixed IDs

Harden the plugin approval request schema: restrict severity to
enum (info|warning|critical), cap timeoutMs at 600s, limit title
to 80 chars and description to 256 chars. Prefix plugin approval
IDs with `plugin:` so /approve routing can distinguish them from
exec approvals deterministically instead of relying on fallback.

* fix: address remaining PR feedback (Phases 1-3 source changes)

* chore: regenerate baselines and protocol artifacts

* fix: exclude requesting connection from approval-client availability check

hasExecApprovalClients() counted the backend connection that issued
the plugin.approval.request RPC as an approval client, preventing
the no-approval-route fast path from firing in headless setups and
causing 120s stalls. Pass the caller's connId so it is skipped.
Applied to both plugin and exec approval handlers.

* Approvals: complete Discord parity and compatibility fallback

* Hooks: make plugin approval onResolution non-blocking

* Hooks: freeze params after approval owner is selected

* Gateway: harden plugin approval request/decision flow

* Discord/Telegram: fix plugin approval delivery parity

* Approvals: fix Telegram plugin approval edge cases

* Auto-reply: enforce Telegram plugin approval approvers

* Approvals: harden Telegram and plugin resolve policies

* Agents: static-import gateway approval call and fix e2e mock loading

* Auto-reply: restore /approve Telegram import boundary

* Approvals: fail closed on no-route and neutralize Discord mentions

* docs: refresh generated config and plugin API baselines

---------

Co-authored-by: Václav Belák <vaclav.belak@gendigital.com>
2026-03-27 09:06:40 -07:00
Peter Steinberger
6f6468027a refactor: dedupe test and runtime seams 2026-03-24 23:33:30 +00:00
wangchunyue
4e849ac127 fix: ensure env proxy dispatcher before MiniMax and OpenAI Codex OAuth flows (openclaw#52228)
Verified:
- pnpm install --frozen-lockfile
- NPM_CONFIG_CACHE=/tmp/openclaw-npm-cache-52228 pnpm build
- pnpm check
- pnpm test:macmini (failed on inherited pre-existing plugin contract test: src/plugins/contracts/registry.contract.test.ts missing deepseek in bundled provider contract registry outside this PR surface)

Co-authored-by: openperf <80630709+openperf@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-03-23 09:26:34 -05:00
Peter Steinberger
dc90d3b1d3 refactor(media): share local file access guards 2026-03-23 00:58:23 -07:00
Peter Steinberger
62ddc9d9e0 refactor: consolidate plugin sdk surface 2026-03-20 19:24:10 +00:00
Gustavo Madeira Santana
f62be0ddcf Matrix: guard private-network homeserver access 2026-03-19 23:24:50 -04:00
Peter Steinberger
9ebe38b6e3 refactor: untangle remaining plugin sdk boundaries 2026-03-16 21:16:32 -07:00