* 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>
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.
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.
* fix(auto-reply): deliver ingress-retried messages after their queued run is dropped
* fix(auto-reply): key queued dedupe release by adoption lifecycle
Overflow-summary compaction clones a queued run onto a new object, so a
release keyed by the run object missed runs completed via their clone and
the ingress retry stayed suppressed on the summarize drop policy. The
adoption lifecycle reference survives cloning and already keys admission
state, so it is the identity the release must use.
* fix(auto-reply): guard queued dedupe ownership
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix: diagnose prepared model owner config drift
* fix(gateway): bind replies to published model owner
* fix(gateway): bind durable replay to published owner
* test: preserve requested workspace in reply mock
* feat(gateway): manage audio and video attachments
* feat(gateway): preserve generated media metadata
* fix(gateway): align seeded managed media
* fix(gateway): scope pending media trust by URL
* fix(gateway): split managed media by trust
* fix(gateway): require terminal media trust unanimity
* fix(gateway): align managed media metadata types
* fix(gateway): refresh managed media contracts
* chore(ci): model managed media test seams
* test(sessions): expect canonical media kinds
* feat(agents): persist last-used session model as the agent default
* fix(agents): gate sticky model persistence on admin authority and make it best-effort
* fix(agents): keep sticky model helper internal
* fix(agents): satisfy sticky model lint rules
* style(agents): format sticky model gateway test
Track full dispatch completion separately for error handling and shutdown drain while allowing same-session follow-ups to steer active runs. Fixes#113180.
Co-authored-by: Taksh <takshkothari09@gmail.com>
The fallback exists for a user who asked and got nothing. Gate it and the
eligibility flag on positive directedness so ambient group chatter, room
events, and turns whose classification facts were lost upstream can never
surface a visible failure notice - even under silentReply: disallow. A turn
is directed when it is an explicit command, or a non-room_event direct chat
or mention/reply-to-bot; a command turn is the one directed room_event,
mirroring the room_event source-reply suppression bypass. Every other
room_event stays undirected regardless of a stray WasMentioned/direct
classification, so the exact production regression - an unmentioned
room_event group turn drawing the fallback into the channel on every ambient
message - cannot recur through any room_event path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The message_tool_only-specific didDeliverSourceReplyViaMessageTool flag
never covers automatic-mode turns, so a message-tool answer to the source
conversation followed by NO_REPLY still drew the no-visible-reply fallback
(reproduced on a live mock-Telegram gateway). Reuse the payload-dedupe
route matcher - the same route-awareness that already suppresses duplicate
finals - to attest observed delivery for visibly delivered source-routed
tool sends in every delivery mode; unrelated-target sends stay excluded.
Route-aware completed source-reply evidence now marks observed delivery
regardless of sourceReplyDeliveryMode, matching the followup-runner
contract, so an automatic-mode turn answered via the message tool plus
NO_REPLY no longer draws the no-visible-reply fallback into the source
conversation (reported live on Discord). The result eligibility flag now
requires resolved settlement and no delivered fallback, so channel-level
recovery cannot double-send while a queued payload is still unresolved.
Give settleQueued a 30s failsafe deadline alongside the abort race so a
transport that never settles cannot block finalization past the completion
barrier, and classify only cancelled/failed-before-deliver outcomes as
proven-invisible: a started-then-failed send may have shown partial chunked
content, so it keeps the no-visible-reply fallback quiet instead of stacking
a misleading fallback on top of partial output.
Race the no-visible-reply fallback's settlement against the dispatch abort
signal so a wedged transport cannot block finalization, and drain outcome
promises admitted while settlement is in progress so a late straggler
delivery cannot race the silence verdict into a double-send.