Commit Graph

41112 Commits

Author SHA1 Message Date
Pavan Kumar Gondhi
18b733577f fix(gateway): gate plugin node routes on approved capabilities (#115980) 2026-07-31 00:17:15 +05:30
Vincent Koc
e92e02ad7d fix(agents): index retained subagent descendant reads (#116449) 2026-07-31 02:36:20 +08:00
keshavbotagent
4dc90937a0 fix(session): isolate memory flush lifecycle from parent recovery (#116198)
* fix(session): isolate memory flush lifecycle

* fix(session): fence newly introduced recovery cycles

* test(qa): prove memory flush preserves parent lifecycle

* test(session): align recovery fixtures with internal state
2026-07-30 11:31:23 -07:00
Josh Avant
ce67ffb70e feat(agents): add tool-free isolated completion (#114343)
* feat: add isolated pure-inference completion

* fix(google): block ambient system prompt writes

* docs: refresh generated map
2026-07-30 13:24:45 -05:00
Yuval Dinodia
3ffd3864ea fix: keep reply text in session transcript when media is attached (#116225)
Preserve assistant reply text alongside stable attachment names across the shared transcript mirror path. Add direct formatter, real SQLite persistence, outbound delivery, and gateway fallback matching coverage.
2026-07-31 02:14:57 +08:00
Peter Steinberger
7f7534253f fix(onboard): preflight TTY before reset (#116491) 2026-07-30 11:01:02 -07:00
Vincent Koc
3b355879b8 test(infra): run exec allowlist suite on Windows (#116492) 2026-07-31 01:46:19 +08:00
Peter Steinberger
1bca61b509 fix(docker): honor legacy apt package argument (#116466) 2026-07-30 10:09:56 -07:00
Vincent Koc
26f107071e test(agents): run exec preflight suite on Windows (#116469) 2026-07-31 00:57:04 +08:00
Omar Shahine
9bebf7ac43 fix(imessage): bold approval prompt labels in poll mode (#116221)
* fix(imessage): bold approval prompt labels in poll mode

#113193 added bold headers and labels to the approval reaction prompt, but
iMessage only shows that copy when tapbacks own the controls. On any
poll-capable bridge the details message is built from `manualFallbackPayload`,
the legacy unstyled builder, so every label (`Title:`, `Tool:`, `Host:`,
`CWD:`, `Full id:`, ...) reaches Messages as flat text. Native polls are the
default on a bridge-v2 host, so in practice #85954 still reproduced after it
was closed.

Add `nativeControlsPayload` to `ApprovalReactionPendingContent`: the same rich
copy as `reactionPayload` minus the tapback hint, for channels whose native
controls already own the decision surface. iMessage poll mode now renders it,
so both control paths deliver identical styled copy.

`imsg poll send --question` has no attributed-body channel, so the poll
question keeps the marker-free rendering of that same text; otherwise the
balloon would show literal asterisks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Byq7UrC7ZpMHxoFXcddsa

* refactor(plugin-sdk): carry native-controls prompt copy as text

The iMessage poll path reads exactly one thing from the native-controls
payload: its text. Replace the ReplyPayload field with nativeControlsText so
buildApprovalReactionPendingContent stops running the metadata/session-key
builder for fields no caller reads, and the '?? ""' sentinel goes away.

Relative to main the SDK change stays additive: neither field exists in any
release; nativeControlsPayload only ever existed on this branch.

* refactor(plugin-sdk): expose native-controls prompt text as a builder, not a type field

ClawSweeper flagged that requiring a new member on the shipped
ApprovalReactionPendingContent type is source-incompatible for external
producers that hand-construct it. The hint-free copy does not need to ride
the type at all: export buildApprovalNativeControlsPromptText and let the
iMessage handler call it at payload-build time.

ApprovalReactionPendingContent is now byte-identical to the shipped shape;
the SDK change is a single additive function export. Signal/WhatsApp test
fixtures revert to their original form.

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 09:23:47 -07:00
Vincent Koc
85466bd89e test(mxc): run Windows-only suites in CI (#116451) 2026-07-31 00:10:22 +08:00
Omar Shahine
6f9da38401 feat(agents): rename model- and user-facing scheduler strings to automations (#114852)
* fix(agents): teach canonical automations tool in fallback guidance and reuse the identity source

Review follow-ups: the structured-list fallback still taught models the cron
tool; the cron-scope test echoed its own stub; MCP serve allowlist and voice
confirmation hardcoded the name instead of the canonical constant.

* fix(mcp): place automations identity import outside the header comment

* feat(agents): rename model- and user-facing scheduler strings to automations

Rewrites every string the model or user sees that names the feature:
tool label and terminal presentation, display-summary preset, subagents
catalog description, heartbeat guidance, subagent prompt, session labels
(Cron: -> Automation:), default job name, unattended-run preamble, delivery
awareness text, task-ledger progress summary, failure alerts, auto-disable
notification, model preflight diagnostics, validation errors, and the
shipped workspace AGENTS.md template. Adds a system-prompt backstop rule on
the automations tool line: the feature is called automations, never cron.

Cron stays only where it names the schedule syntax ({kind:"cron"}, cron
expressions), config keys (cron.triggers.enabled), RPC method names, and
session-key namespaces. Test fixtures with legacy labels are kept as
stored-data coverage. Part of RFC openclaw/rfcs#50 Phase 1 (PR B).

* docs(templates): keep workspace template on the live docs anchor until the docs PR renames it

* fix(cron): rename remaining failure-notification producers and stale test expectations

Codex review follow-ups: the per-run failure notification (server-cron-
notifications) and the doctor legacy-notify advisory still said Cron job;
failure-alert and incomplete-turn suites still asserted the old wording.

* chore(plugin-sdk): re-emit plugin-state test runtime dts

CI's extension-boundary runner holds stale tsgo incremental state whose
cached plugin-state-test-runtime.d.ts predates the keyed-store re-exports;
the freshness stamp validates it and reruns reuse the same sticky disk.
Touching the module forces incremental emit to regenerate the declaration.
Fresh builds of this head (local exact CI command and a forced Testbox
rebuild) both emit the exports correctly.

* fix(agents): rename residual model- and operator-facing cron prose

Found in combined dev-gateway E2E: fallback tool line still told models the
scheduler tool is cron; heartbeat scratch description, cron model preflight
rejection, doctor and Claw prose still said cron jobs.

* fix(agents): finish model-facing scheduler strings flagged in review

Loop work-order prompts, subagents tool description, cron-tool write errors,
and the headless exec denial label now say automations; loop builders covered
by prompt assertions; snapshots regenerated.

* chore(agents): refresh generated baselines and live docs anchor after rebase onto main

* fix(agents): rename new main-side cron tool error expectations to automations

* fix(gateway): rename main-side cron notification test expectations to automations

* chore(agents): apply review moves - automations commands in workspace template, drop unrelated sdk comment

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
2026-07-30 08:54:55 -07:00
Vincent Koc
0090549188 fix(agents): refresh Claude live system prompts (#116292)
Co-authored-by: William Faris Chesnutt <farischesnutt@gmail.com>
2026-07-30 23:40:40 +08:00
Vincent Koc
90a22b4f50 chore(test): run browser copilot E2E in CI (#116407)
* test(browser): run copilot E2E in CI

* test(browser): stabilize copilot E2E synchronization

* test(browser): wake extension workers deterministically

* test(ci): route browser copilot command changes
2026-07-30 23:20:34 +08:00
Vincent Koc
9cfe4ebf08 fix(talk): preserve consult errors during cleanup 2026-07-30 23:17:38 +08:00
Vincent Koc
8668ac4e6a test(talk): cover talkback queue saturation 2026-07-30 23:17:38 +08:00
Vincent Koc
46d51bb3a4 fix(talk): bound pending talkback work 2026-07-30 23:17:38 +08:00
Vincent Koc
ca1328dddb Merge pull request #116285 from openclaw/fix/control-ui-session-dedupe
* origin/fix/control-ui-session-dedupe:
  chore: leave release notes to release flow
  fix(ui): deduplicate gateway-native session hosts
2026-07-30 22:53:53 +08:00
Shakker
cd60d65f0a chore: refresh ClickClack generated metadata 2026-07-30 15:42:18 +01:00
Omar Shahine
b82a59a798 feat(cli): add openclaw automations alias and reword cron display prose (#114854)
* feat(cli): add openclaw automations alias and reword cron display prose

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WhJ8EiMXue6ADLmHfb7FL6

* test(doctor): update cron doctor prose assertions for automations wording

* fix(plugins): include command aliases in plugin CLI collision detection

Codex review finding on the automations alias: plugin CLI registration
seeded existingCommands from command names only, so a plugin exposing a
top-level command matching an alias-only root name (automations, terminal,
chat) would crash Commander at startup instead of being skipped. Seed from
names plus aliases; regression test covers the alias path.

* fix(cli): rename residual cron prose in CLI and gateway RPC errors

Found in combined dev-gateway E2E: automation not found / unknown automation
id errors, add/edit prose, docs tip, skills-cli mention, and the gateway RPC
not-found message. The CLI missing-get matcher accepts both message forms so
older gateways keep resolving name lookups.

* fix(gateway): keep cron.get missing wording as a wire contract for older CLI matchers

ClawSweeper rank-up: shipped CLI matchers parse 'cron job not found: <id>'
before the name-lookup fallback; the rename stays CLI-display only. Adds a
regression pinning the exact wire form.

* fix(cli): rename doctor and task-summary cron prose flagged in review

Repair-plan advisories, session-registry task summary, and the heartbeat
migration health check now say automations; recreate hints use the
openclaw automations CLI form.

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 07:16:57 -07:00
Omar Shahine
364d8be010 feat(agents): rename scheduler agent tool cron -> automations (#114841)
* refactor(agents): route scheduler tool-name consumers through canonical identity

Introduce AUTOMATIONS_TOOL_NAME + isAutomationsToolName() in
src/agents/tools/automations-tool-name.ts as the single source of truth for
the scheduler agent tool's name, and convert every exact-name consumer:
factory descriptors, deferred-followup availability detection, add-counting,
policy deny lists, mutation classification, trusted media set, tool catalog
id, system-prompt tool order and tool-line map, sandbox deny defaults,
delegation capability map, MCP loopback probes, and local-model lean deny.

Behavior-neutral: the constant still resolves to "cron". Prepares the
rename in RFC openclaw/rfcs#50 so the flip is a one-line change with no
scattered literals.

* feat(agents): rename scheduler agent tool cron -> automations

Flip AUTOMATIONS_TOOL_NAME to "automations" and register the legacy name:

- TOOL_NAME_ALIASES gains cron -> automations, so persisted toolsAllow/
  toolsDeny lists, tool groups, and creator allowlists written before the
  rename keep matching through the same shipped mechanism as bash -> exec.
  No doctor rewrite needed.
- isAutomationsToolName() accepts legacy names so saved transcripts keep
  their mutation/replay-safety classification; MUTATING_TOOL_NAMES retains
  the legacy entry for the same reason.
- Tool label, catalog label, and tool-search keywords follow the rename
  ("cron" kept as a search synonym).
- Regression tests cover old-name policy matching (allow and deny), legacy
  transcript replay classification, and legacy creator allowlists
  normalizing to the canonical id.

Model-facing description strings still say cron; those move in the
follow-up strings PR. Part of RFC openclaw/rfcs#50 Phase 1.

* test(agents): update creator-cap expectations for canonical automations id

The creator tool surface derives from normalized live tool names, so derived
toolsAllow outputs now emit "automations". Passthrough paths without a
creator cap keep storing user input verbatim; those expectations stay on the
legacy name as stored-data coverage.

* fix(gateway): canonicalize legacy cron tool calls and restore scheduler deny protection

Review follow-ups from ClawSweeper and Codex on the rename (RFC 0026):

- MCP loopback tools/call resolves legacy "cron" names to the published
  automations tool without re-advertising the old name in tools/list.
- Gateway /tools/invoke canonicalizes legacy names before core-id checks and
  exact-name dispatch, so pre-rename integrations keep working.
- Security fix: dangerous-tools deny lists (owner-only HTTP deny and
  control-plane set) were keyed on the literal "cron", so the renamed tool
  silently lost default-deny and owner-only protection on the HTTP invoke
  surface. Lists now use the canonical constant, and the gateway.tools.allow
  un-deny filter normalizes both sides so legacy allow entries still lift it.
- Voice high-impact confirmation list and MCP serve creator allowlist follow
  the canonical name.

Existing cron-regression suite now proves the legacy path end to end:
default deny 404 for both names, legacy allow entry lifts the deny, and
non-owner protection holds.

* fix(agents): cover stdio MCP legacy calls, probe prompts, and prompt snapshots for the rename

- stdio MCP servers (openclaw-tools-serve / plugin tools handlers) resolve
  legacy "cron" callTool names to the published canonical tool, matching
  the HTTP loopback behavior; listTools stays canonical-only.
- Live probe prompts instruct harnesses to load/call the automations MCP
  tool (mcp__openclaw__automations) instead of the retired name.
- Prompt snapshot fixture filter follows the canonical name (the renamed
  tool had silently dropped out of the Codex dynamic-tools snapshots);
  snapshots regenerated as a clean rename.
- Type-cast the new mcp-http handler test payloads for check-test-types.

* test(agents): update tool-surface expectations for the automations rename

CI-surfaced fallout in shards not covered by the focused local runs: tool
availability, agent-config filtering, coding-tools construction,
model-provider lean policy, and skill dispatch all assert the scheduler
tool's surface name. Mock fixtures and expectations follow the canonical
id; legacy-name coverage stays in the dedicated policy/creator-cap/invoke
regression suites.

* test(gateway): update tool-resolution exclude expectations for automations rename

* test(security): update trust-model audit expectations for automations rename

* docs(agents): declare cron a permanent scheduler-tool alias per owner decision

Maintainer decision (Omar): cron is not being retired anywhere — config keys,
RPC methods, schedule syntax, and the CLI token all keep it, and the tool
alias follows the same permanent contract as bash -> exec. No doctor rewrite
and no removal window; comments updated to state the contract instead of a
deprecation plan.

* chore(agents): regen prompt snapshots after rebase onto main

* fix(agents): teach canonical automations tool in fallback guidance and reuse the identity source

Review follow-ups: the structured-list fallback still taught models the cron
tool; the cron-scope test echoed its own stub; MCP serve allowlist and voice
confirmation hardcoded the name instead of the canonical constant.

* fix(mcp): place automations identity import outside the header comment

---------

Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com>
2026-07-30 07:16:13 -07:00
Peter Steinberger
319fd692d1 fix(tui): preserve session state across switches and reconnects (#116399)
* fix(tui): isolate session lifecycle state

* fix(tui): preserve session incarnation identity

* fix(tui): preserve gateway disconnect fallback
2026-07-30 06:29:31 -07:00
Ayaan Zaidi
2ca340fa0a feat(agents): report CLI command outcomes in channel progress
The CLI candidate bridged tool events itself: it forwarded starts without a toolCallId and returned early on the result phase, so a Claude CLI turn produced progress lines with no identity and no terminal outcome. A failed command rendered exactly like one that succeeded.

The bridge now forwards the call id and projects results through the same buildCommandOutputFromToolResultEvent the embedded path uses. Two gaps had to close for that projection to see a CLI result: it only read structured records, where CLI backends report raw text plus is_error, and it needed a title or the terminal line would describe the output instead of the command, so the runner carries the started args onto its result event. A bare result with no content stays excluded, since runners that report an outcome send a separate command_output event.

Modeled on the sibling t3code Claude adapter, which correlates each tool_result back to its in-flight tool by tool_use_id and emits a failed/completed status. Proven live on the real Claude CLI backend: two calls, two lines updating in place, the failing one marked failed.
2026-07-30 21:31:37 +09:00
Peter Steinberger
1cbe674d6a fix(cli): preserve explicit option intent (#116389) 2026-07-30 05:22:50 -07:00
Peter Steinberger
7dd75d0716 fix(heartbeat): serialize wake lifecycle state (#116351)
* fix(heartbeat): serialize wake lifecycle state

* style(heartbeat): format wake scheduler

* refactor(heartbeat): split wake coordination

* refactor(heartbeat): extract wake contracts
2026-07-30 04:58:12 -07:00
Peter Steinberger
7fa95e2656 feat(ui): add composable skill references (#116330)
* feat(ui): add composable skill references

* fix(ui): align skill reference CI contracts

* fix(ui): scope skill references to WebChat
2026-07-30 04:07:02 -07:00
Dallin Romney
424c36a2d5 fix(qa): prevent Slack cleanup from stalling profile runs (#116361)
* fix(qa): release Slack leases after gateway stop

* fix(qa): preserve async Slack cleanup contract

* fix(qa): expose post-gateway adapter cleanup
2026-07-30 19:05:49 +08:00
Ayaan Zaidi
c4b82609b7 fix(agents): compare shell tool names case-insensitively and stop re-parsing tool labels
Progress-draft lines recovered their detail by string-slicing the label formatToolAggregate had just rendered, and three sites decided "is this a shell tool?" against lowercase spellings only. The Claude CLI sends "Bash", so those checks missed, the slice returned nothing, and every CLI tool call rendered a line with no detail: Telegram printed the icon twice and the tool-summary payload could no longer merge, leaving a second id-less line per call.

formatToolAggregateParts now returns the label with the detail it composed, so a line cannot disagree with its own text, and one predicate owns the shell question across all four sites. Proven live on the Claude CLI backend: two lines with a doubled icon became one.
2026-07-30 19:52:08 +09:00
Peter Steinberger
cb54749df2 fix(gateway): repair node terminal and rename state (#116355) 2026-07-30 03:52:05 -07:00
Jesse Merhi
f1ee2a3098 fix(diagnostics-otel): agent turns split into one-span traces instead of a trace tree (#116246)
* fix(diagnostics-otel): keep parent span links across long turns

Retained trusted span contexts translate a completed lifecycle span's
diagnostic span id to the real OTel span context. That table was evicted
5s after run.completed, so children of a longer turn missed their parent
and OTel minted a fresh trace id for each one, silently splitting a turn
into single-span traces.

Retention is now identity-based and lives for the service lifetime,
bounded by MAX_RETAINED_TRUSTED_SPAN_CONTEXTS, which removes the timing
race and the drain/timeout cleanup subsystem.

Also nests openclaw.exec under its run: the exec event now carries a
trusted trace context and the recorder resolves the ambient run scope.

* fix(diagnostics-otel): key retained span contexts by diagnostic trace id

Retained lifecycle span contexts were stored under the span's OTel trace id
but looked up with the event's diagnostic trace id. Those are different id
spaces, so every post-completion parent lookup missed and each straggler
span started a brand-new trace.

The mocked suite could not catch this: its tracer reports the same trace id
the test feeds in, collapsing both id spaces into one value. Adds a boundary
test that runs the real OTel SDK and OTLP/protobuf exporter against a local
receiver and asserts on exported span bytes.

* fix(diagnostics-otel): harden span-linking contract after review

Review findings on the parent-span linking fix:

- completeTrackedLifecycleSpan now takes the DiagnosticTraceContext instead of a
  bare trace id beside a span id. Two adjacent hex strings let a transposition
  compile clean and silently reinstate split traces; DiagnosticTraceContext is
  the only shape an OTel SpanContext cannot satisfy (traceFlags string vs number).
- internalOrTrustedTraceContext composes normalizedTrustedTraceContext rather
  than spelling the trust predicate a third time.
- Corrected comments that claimed OTel ids never equal diagnostic ids. Spans
  parented from an upstream traceparent do adopt the diagnostic trace id; the
  removed guard only ever misfired on root lifecycle spans.
- Exec comment now states the real parent: the openclaw harness opens no run
  scope, so exec nests under openclaw.harness.run.

Test gaps closed:

- The core emitter switch was untested; reverting it kept every test green.
  The pty-fallback test now asserts the emitted metadata.
- The boundary test covered only run.completed of three lifecycle owners; it now
  covers harness.run.completed and message.processed too, each with a straggler.
- Dropped the service-context cast for the typed helper, which caught a bogus
  context.assembled field, and moved teardown into afterEach so a failed
  assertion cannot leak the real NodeSDK across files.
- Scoped the one-trace assertion to this turn's spans; faked Date so a lazy
  Date.now expiry cannot pass.

Docs: exec and tool spans now listed as staying on an upstream request trace.

* fix(diagnostics-otel): keep late children on the trace on every terminator

Native review found three correctness gaps in the previous commit:

- Exec spans could be exported naming a parent span id nothing ever emits. The
  ambient lookup fell through to a remote-parent fallback built from diagnostic
  ids, which is a regression from the previous clean-root behavior and breaks
  waterfalls and parent-id-keyed backends. Exec now resolves only spans this
  process exported and stays a root on a miss; message spans keep the remote
  fallback because their context can come from an inbound traceparent.
- harness.run.error never retained its span context, so an aborted turn still
  split. For the openclaw harness that span is the only ancestor a late child
  has, and aborted turns emit no run.completed.
- completeTrackedLifecycleSpan no longer takes a redundant spanId.

The boundary test now runs through the OPENCLAW_OTEL_PRELOADED seam with an
in-memory exporter and releases the global tracer provider in teardown. A
NodeSDK cannot be unregistered, so the old version would have made any later
real-SDK test silently export nothing. That also deletes the hand-rolled OTLP
protobuf decoder. Added guards for the aborted-turn path and for exec staying
parentless; both are mutation-verified.

* fix(diagnostics-otel): age retained parent contexts out after 10 minutes

Retention had no time bound at all, so a command backgrounded by a turn could
finish hours later and still attach to a parent that ended long before. Backends
derive trace latency from the span envelope, so a 30s turn rendered as hours with
a child extending past its parent.

The horizon is checked lazily on lookup rather than on a timer: a timer firing
mid-turn is exactly what silently split traces before. Past the horizon a
straggler starts its own trace, which only loses causality for a span that would
have skewed its parent's duration anyway.

The two bounds now pin each other - shrinking the horizon to the old 5s window
fails the original regression tests, and removing it fails the new horizon test.

* fix(diagnostics-otel): retain parent contexts until capacity
2026-07-30 20:41:41 +10:00
Vincent Koc
8a3f5c862b fix(plugin-sdk): ship documented public typings (#116345)
* fix(plugin-sdk): ship documented public typings

* fix(plugin-sdk): refresh public contract artifacts
2026-07-30 18:20:07 +08:00
Peter Steinberger
a4c6efc998 fix(cli): preserve installed plugins in agent exec (#116336) 2026-07-30 03:00:17 -07:00
WhatsSkiLL
c63fdc631f fix(sessions): release closed SQLite entry caches (#115794)
* fix(sessions): release closed sqlite entry caches

* chore(ci): register sqlite cache lifetime proof

---------

Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com>
2026-07-30 02:06:44 -07:00
Ayaan Zaidi
21d3533460 fix(channels): ack mentions in groups that do not require them
The group-mentions ack gate returned false whenever a group did not require mentions, conflating group policy with whether this message mentioned the agent. Under the default scope, mentioning the agent in a group configured to answer everything produced no ack at all, so the user had no signal the turn was picked up until the reply arrived.

Behavior change on a default path: those groups now show the 👀 ack (and the lifecycle status reactions when messages.statusReactions.enabled is true) on mentions. Mention-required groups, group-all, unmentioned messages, and off/none are unchanged. The gate no longer reads requireMention, so the parameter is gone from the shared type and all channel call sites.

Proven live on Telegram across three configurations, including a no-mention control confirming group-mentions did not become group-all.
2026-07-30 17:58:46 +09:00
Dallin Romney
b765ada174 fix: stop WhatsApp restart loop after remote logout (#114445) 2026-07-30 16:48:32 +08:00
Vincent Koc
6e4f67f084 Merge remote-tracking branch 'origin/main' into fix/control-ui-session-dedupe
* origin/main: (25 commits)
  fix(qqbot): use Gateway timezone for reminders (#116294)
  test(openai): cover out-of-order named mark acks
  docs(openai): clarify cumulative playback marks
  test(openai): cover sustained unnamed mark acknowledgements
  fix(openai): preserve playback acknowledgement order
  test(openai): verify bounded playback acknowledgements
  fix(openai): bound realtime playback marks
  test(agents): mock incremental registry persistence (#116307)
  fix(memory-core): MEMORY.md compaction deletes user notes written under a promotion-style heading (#116180)
  feat(reply): annotate recent history images (#100866)
  chore(ios): refresh native i18n inventory
  fix(ios): isolate capability router handlers
  docs(ios): cut 2026.7.22 release notes
  docs(hooks): document validation responses
  test(qa): assert hook account rejection reasons
  fix(gateway): validate hook delivery accounts
  perf(gateway): bound prepared runtime startup work (#116261)
  fix(agents): prevent registry stalls during large fan-outs (#116286)
  fix(sqlite): preserve replaced snapshot targets on Windows (#116284)
  fix(ci): load frozen shard runner without repository fetch (#116273)
  ...
2026-07-30 16:37:47 +08:00
Vincent Koc
ec53d0eaae test(agents): mock incremental registry persistence (#116307) 2026-07-30 16:27:31 +08:00
Huang Wanjia
ef5be76394 feat(reply): annotate recent history images (#100866)
* feat(reply): annotate recent history images

* fix(reply): describe bounded history image positions

---------

Co-authored-by: martin <huangtongxuedev@outlook.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 16:24:09 +08:00
joshavant
54a6dba0d3 fix(gateway): validate hook delivery accounts 2026-07-30 02:59:06 -05:00
Jason (Json)
a67ad03eea perf(gateway): bound prepared runtime startup work (#116261) 2026-07-30 01:41:35 -06:00
Vincent Koc
d30d22d33c fix(agents): prevent registry stalls during large fan-outs (#116286)
* fix(agents): persist subagent registry mutations incrementally

* chore(agents): leave release notes to release process
2026-07-30 15:40:54 +08:00
Peter Steinberger
d5f8be355d fix(sqlite): preserve replaced snapshot targets on Windows (#116284) 2026-07-30 00:40:20 -07:00
Ayaan Zaidi
7c47e4ad0e fix(channels): collapse cumulative commentary snapshots onto one progress-draft line
Providers stream commentary as cumulative snapshots, and the draft line id was derived from the commentary text, so each snapshot minted a new id and stacked another line instead of replacing the open one. Id-less commentary now remembers its open line and reuses that id when the next snapshot continues it; a snapshot sanitized to nothing no longer clears the line, since only an explicit item id retracts.

Also fixes activation: the commentary gate guessed "partial" when streaming.mode was unset, which made progress.commentary a silent no-op on channels whose own default is progress (Telegram, Discord). It now takes the caller's resolved mode, matching resolveChannelStreamingPreviewToolProgress. Proven live on Telegram: three overlapping commentary lines collapse to one.
2026-07-30 16:36:16 +09:00
Vincent Koc
bb68389a66 fix(ui): deduplicate gateway-native session hosts 2026-07-30 15:22:37 +08:00
Dallin Romney
7df05d5fc0 refactor(qa): remove live-channel scenario registries and wrappers (#115752)
* refactor(qa): remove duplicate channel scenario registries

* refactor(qa): route live scenarios through shared runners

* fix(qa): isolate WhatsApp driver retries

* refactor(qa): add module export flow arguments

* test(qa): include scenario metadata in matrix fixture
2026-07-30 13:56:34 +08:00
Peter Steinberger
ea42a4612a fix(plugins): plugin install survives pnpm-only overrides (#116245)
* fix(plugins): preserve compatible npm overrides on retry

* fix(plugins): keep npm compatibility type internal

* fix(plugins): bound managed override retries
2026-07-29 22:43:34 -07:00
Vincent Koc
814d1fdf1a fix(test): review Codex runtime scan chunks (#116212)
* fix(test): review Codex runtime scan chunks

* fix(test): count reviewed scan findings
2026-07-30 13:02:57 +08:00
Miorbnli
5e1e70e423 fix(systemd): clear start-limit latch before gateway start (#116178)
* fix(systemd): clear start-limit latch before gateway start

systemd latches a unit into failed/start-limit-hit after a crash loop,
then refuses systemctl start until reset-failed clears the latch. The
reset-failed step only ran for the restart action, so the natural
recovery command `openclaw gateway start` failed on a crash-looped
gateway while `openclaw gateway restart` recovered it.

Run reset-failed before both start and restart (stop is unchanged),
mirroring launchd's startLaunchAgent which calls launchctl enable before
kickstart. reset-failed is idempotent and a no-op on a healthy unit.

* test(systemd): cover start-limit latch clearing on system-scope start

Mirrors the existing system-scope restart test: when startSystemdService
targets a system unit as root, it must emit reset-failed before start so
a crash-looped gateway recovers via `openclaw gateway start` too.

* test(systemd): assert healthy start tolerates reset-failed no-op

reset-failed is idempotent on a non-failed unit (systemd returns success
without changing unit state), so prepending it to start cannot regress a
healthy gateway. Covers the merge-risk concern that every start now
depends on an extra reset-failed call.

* test(systemd): cover reset failure and stop controls

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-30 12:47:56 +08:00
Vincent Koc
2899323fe3 fix(security): expose every executable call in plugin scans (#116222)
* fix(security): report every scanner line match

* fix(security): bound scanner match evidence
2026-07-30 12:45:25 +08:00
Ayaan Zaidi
c63241d3ce fix(channels): resolve tool progress against the caller's stream mode
resolveChannelStreamingPreviewToolProgress guessed a mode when streaming.mode
was unset, so it could never be right for every channel: guessing "partial"
dropped Discord and Telegram's explicit progress.toolProgress opt-out, and my
earlier switch to "progress" broke it the other way for Slack, Mattermost, and
Teams, whose real default is partial. With both keys configured and disagreeing,
the wrong one won.

The helper has no channel identity, so it stops guessing and takes the mode the
caller already resolved. All nine call sites pass theirs. Omitting it keeps the
previous configured-mode reading, so untouched callers behave exactly as before.

Reported by ClawSweeper on #116143.
2026-07-30 13:36:21 +09:00