Commit Graph

79973 Commits

Author SHA1 Message Date
Peter Steinberger 1d2d44c8ff perf(ci): price agents-core-models from its measured hybrid wall
`agentic-agents-core-models` carried the 36s scaled estimate while measuring
56.3s (n=6, p90 58.6s) across 260 compact jobs on 2026-08-16. Packed beside
`agentic-agents-core-runtime-hosted-1` (60.4s) it built the only bin running
>=1.25x its prediction: compact-large-19 ran 122s of work priced at 88s, which
made it the most frequent slowest job in the workflow.

Add the measured value to the hybrid hint map, which already exists for exactly
these Blacksmith-specific observations. The packer then separates the two, and
the tallest actual compact bin drops 122s -> 109s with no bin above 1.25x and
no change to row counts (48 push / 56 pull-request), so this costs no extra
runner registrations.

Two things deliberately left alone. The `agentic-gateway-core-3` 140s pin looks
like a 2x over-prediction against its 68.5s median, but run 31938297538 really
did take 138.0s (109.03s + 28.98s across its two configs) on a run whose fleet
slowdown factor was 0.98 -- a genuine tail on a healthy run, so unpinning it
would rebuild a >200s bin whenever the tail lands. Every other bin already sits
within 1.24x of its prediction.

The replaced guard pinned one bin arrangement (`runtime-hosted-1` not sharing a
job with `agents-core-tools`) with no stated failure mode, so any honest refit
broke it. It now asserts the property that comment was reaching for -- both
weight sources survive rebalancing under the body ceiling -- plus the specific
regression this fixes. Mutation-checked: dropping the hint fails the new guard.

Measurement note for the next refit: sum a shard's per-config Duration lines
before taking a median. Pooling them reads as a large over-prediction that is
not there.
2026-08-16 16:34:12 -07:00
Peter Steinberger fecb377da6 fix(doctor): partition retired session stores (#124846)
Recover owner-qualified rows from the retired top-level session store into each configured agent database without guessing ambiguous ownership. Relocate stale transcript paths, tolerate historical Unicode IDs when an explicit transcript exists, and avoid double-counting physical SQLite databases in migration totals.


Amp-Thread-ID: https://ampcode.com/threads/T-01a00a6a-b64e-74a5-8b15-2d3b966a468d

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Josh Lehman <josh@martian.engineering>
2026-08-16 16:33:28 -07:00
Peter Steinberger 22ab8e3c2c fix(gateway): stop a plugin dangerous flag from revoking desktop computer.act (#124863)
* fix(gateway): stop a plugin dangerous flag from revoking desktop computer.act

`resolveNodeCommandAllowlistInternal` subtracted every plugin-declared
dangerous command from the composed allowlist, including core's own
`PLATFORM_DEFAULTS` entries and including the pairing allowlist, where core's
dangerous defaults are exempted. `computer.act` is both a desktop platform
default (grant = node-local enablement + pairing approval) and a command that
`registerComputerUseProvider` marks dangerous. Since `cua-computer` became
enabled-by-default on darwin, every macOS-hosted Gateway stripped `computer.act`
from both allowlists, so `normalizeDeclaredNodeCommands` dropped it from the
node's declaration with no pairing upgrade, no prompt, and no record. The
`computer` capability survived because caps were never allowlist-filtered, and
the `computerUse` descriptor was then dropped for the missing command.

Scope the plugin-dangerous subtraction to commands outside the platform-default
base: the flag still keeps a plugin's own surface behind an explicit allow and
still forces a registered invoke policy, but it no longer revokes a command core
declares itself.

Also make cap-without-command unrepresentable. `retainFulfilledNodeCapabilities`
drops a capability when policy withheld commands from its family and admitted
none, and the reconciler records the withheld commands so a refused declaration
is never silent.

* test(gateway): type the computer-use fixture against its contract
2026-08-16 16:27:45 -07:00
Peter Steinberger 4f92cab8b4 fix(ui): keep message presentation stable when expanded (#124898) 2026-08-16 16:27:40 -07:00
Peter Steinberger 0e280f2d33 feat(agents): record agent creation provenance and add roster tree listing (#124828)
Adds an additive agent_provenance table (shared state DB, schema v8) owned
by src/state/agent-provenance.ts. createAgent() records operator/agent
provenance after commit, the system-agent create-agent operation passes its
own id as creator, and Claw installs record created-via claw at their roster
commit point. Agent deletion removes the agent's own row inside the deletion
journal transaction; children keep dangling creator ids as historical fact.
openclaw agents list gains --tree (provenance hierarchy) and JSON provenance
fields.
2026-08-16 16:25:44 -07:00
Peter Steinberger edd9234e54 fix(sessions): report self-archive before stopping the turn (#124896) 2026-08-16 16:25:27 -07:00
Peter Steinberger ed339f9ba3 fix: remove delivery markers from historical sessions (#124888)
* fix(sessions): migrate historical transcript directives

* fix(infra): complete directive migration on pre-archives-schema databases

session_transcript_archives is a lazy additive v17 surface; valid databases
may omit it. The archives phase now treats the missing table as empty and
completes the cursor instead of warning-skipping the whole database forever.
Verified against a real long-lived agent DB: previously stuck cursor
completes with zero warnings in ~100ms.

* chore(ci): allow directive migration SQLite access
2026-08-16 16:24:46 -07:00
Peter Steinberger 5bf9fbe387 fix(tui): report the first last-session write failure (#124886)
* fix(tui): report the first last-session write failure

rememberCurrentSessionKey swallowed writeTuiLastSessionKey failures
with catch(() => undefined). A corrupt or locked state DB silently
disabled session restore: the operator only discovers it on next
launch, landing in the wrong session with no clue why.

Root cause: fire-and-forget with no recorded failure. The write wrapper
moved to its owner (tui-last-session.ts) as
createRememberSessionKeyWriter, which surfaces the first failure via
the chat log ('session memory write failed: ...') and stays silent on
repeats — one line per TUI run, not one per session switch. Empty and
'unknown' keys still skip without touching the writer.

Regression: colocated tests prove first-failure-once reporting and the
skip path — fail pre-fix (factory did not exist; failure was
swallowed at the call site).

* chore(tui): make the last-session write dependency explicit

deadcode:exports rejects writeTuiLastSessionKey as unused when only the
factory default referenced it; tui.ts now passes it explicitly.
2026-08-16 16:23:01 -07:00
Peter Steinberger 5dc4cf602b fix(sandbox): surface list probe failures instead of empty results (#124881)
sandboxListCommand and fetchAndFilterContainers swallowed backend and
registry probe failures with catch(() => []). A broken Docker daemon or
corrupt registry rendered as 'No sandbox runtimes found.' — and in
recreate, filtered an entire fleet down to nothing — indistinguishable
from a clean empty state. --json emitted a success envelope for a
failed probe.

Root cause: failure collapsed into the empty success shape at the
consumer. The listers now propagate; the sandbox CLI runner already
owns the error path (message + exit 1), and the new --json failure
contract (6c66f48a7c) emits the JSON error envelope.

Regression: replaced the test that enshrined the masking ('handle
errors gracefully' asserting the empty-state message) with the
propagation contract — fails pre-fix.
2026-08-16 16:18:18 -07:00
Peter Steinberger b8a95e082b fix(ui): make terminal open failures retryable (#124890) 2026-08-16 16:15:24 -07:00
Peter Steinberger 00990506c0 fix(tui): close selection overlays and report rejected handlers (#124876)
openSelector's onSelect fired the async handler with void and only
closed the overlay after a successful await. A rejecting handler (e.g.
setAgent -> setSession against a failing gateway) left the selector
stranded open with an unhandled rejection: the TUI froze on the picker
with no visible cause — a silent dead-end.

Root cause: failure path missing from the overlay lifecycle. The
handler now catches, surfaces the cause via chatLog, and always closes
the overlay.

Regression: /agent selection with a rejecting setSession asserts the
overlay closes and the cause reaches the chat log — fails pre-fix.
2026-08-16 16:14:28 -07:00
ClawSweeper a4efa7c22b fix(ui): replace the broken terminal tab underline (#124875)
* fix(ui): redesign dock panel tabs

* fix(ui): remove stale terminal tab overrides

---------

Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-16 16:11:30 -07:00
Peter Steinberger 572e9f907a fix(skills): expand explicit references on agent turns (#124784)
* fix(skills): expand explicit references on agent turns

Route generic Gateway, CLI, webhook, and local agent turns through the same explicit skill-reference renderer as channel auto-replies. Keep original transcript text, preserve unknown slash behavior, and fail visibly for allowlist-hidden skills.

Maintainer review: scoped Option 1 — generic agent turns expand both $skill-name and leading /skill-name args through shared skill rendering; they do not run the channel command dispatcher, and all other slash commands retain their existing behavior.

* fix(skills): bound explicit reference prompts

* fix(skills): prefer allowed reference collisions

* fix(skills): preserve command invocation boundaries

* fix(skills): reject hidden channel slash commands

* perf(skills): skip literal dollar discovery
2026-08-16 16:09:21 -07:00
Peter Steinberger 9cbf998c72 fix(cli): keep internal error causes out of operator output (#124887) 2026-08-16 16:08:56 -07:00
Peter Steinberger 06fa48099e fix(ui): reveal clipped session history (#124866)
* fix(ui): reveal clipped session history

Show a persistent earlier-history action for paginated sessions and reveal loaded content without chaining observer fetches.

Related: #110771

* refactor(ui): split chat history support
2026-08-16 16:04:30 -07:00
ClawSweeper 6bddfed530 fix: prevent clipped session selections and Code Mode timer crashes (#124879)
* fix(agents): support timers in code mode

* fix(ui): keep selected sessions clear of scrollbars

* fix(agents): propagate timer cancellation after resume

---------

Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-16 16:03:54 -07:00
Josh Avant ffc94d0ff0 fix: stop forked commands after Gateway timeouts (#124081)
* fix: stop service child trees before timeout completion

* fix: preserve service child root results during cleanup

* test: isolate relay selection from linux spawn wrapping

* refactor: keep service anchor payload internal

* test: validate lifecycle probe pid output

* fix: close service child adversarial races

* fix: preserve service startup failures

* fix(process): flush service output before root result

* fix(process): bound cleanup on held output

* chore(process): satisfy promise executor lint

* fix(process): finish cleanup after lineage loss

* fix(process): retain relay output before subscription

* fix(ci): register service child runtime entries

* fix(ci): expose relay safety invariants

* fix(process): preserve service cancellation grace

* test(process): prove service grace on macOS
2026-08-16 16:02:34 -07:00
Peter Steinberger 1f1aa88f14 perf(ci): split Windows CI two ways instead of one serial lane
`checks-windows-node-test` ran the whole 222-266s Windows body in a single
Blacksmith lane, so every run that scheduled it finished at 287-334s against a
~180s plateau. Measured across 45 canonical main runs it was the wall in all
seven runs that triggered it (324-519s vs a 210s median elsewhere).

Blacksmith's Windows class admits exactly 2 concurrent jobs (run 31865243804),
which is why the earlier 3-part split failed: its tail queued 211s behind a
finished part. Pin the split width to that measured capacity instead. The two
parts are balanced by measured per-project wall time -- part 1 keeps the old
list 1 plus list 2's non-infra projects (~108s), part 2 takes list 2's infra
project plus the old list 3 (~112s) -- so both land near 113s and the lane
stops setting the wall.

One canonical partition now serves every backend; the github-mode/dispatch
3-part variant and its separate file inventory are gone, along with the
single-lane `task: test` case and the per-row `matrix.runner` the collapsed
lane needed. The complete 65-file Windows inventory is preserved exactly, and
the guards pin the width on both sides (mutation-checked: restoring 3 parts
fails the matrix guard).
2026-08-16 16:02:24 -07:00
Shakker efc243823f docs: note length-aware Workboard errors (#118888) 2026-08-16 23:54:27 +01:00
Shakker 02d8b46b24 test: cover Workboard length errors at gateway boundary 2026-08-16 23:54:27 +01:00
Kailigithub 8f174ceca2 test(workboard): align matrix with real normalizeBoundedString consumers
ClawSweeper flagged that the prior matrix at line 31-48 tested
labels/title/notes by manually invoking normalizeBoundedString, even
though those fields use the independent normalizeTitle, normalizeNotes,
and normalizeLabels functions (each with its own generic message).
A regression that drops the (got N) suffix from normalizeBoundedString
would not be caught for those three surfaces — operators would still
see the old opaque error.

This commit narrows the matrix to only the consumers of the shared
helper (comment body, link title, link target, link URL, card id) and
restores the exact labels gateway assertion that should match the
unchanged normalizeLabels error.

Verification: 9/9 inline Node 18 AST harness (node /tmp/verify-pr-118888-v77.mjs);
parent-commit proof-gate (pre-PR helper without the got suffix) fails
4/9 of the post-fix expected messages.

Closes ClawSweeper review on PR #118888 (P2 + P3).
2026-08-16 23:54:27 +01:00
Kailigithub f990fb777a fix(workboard): include actual length in bounded-string error
The shared normalizeBoundedString helper in extensions/workboard/src
threw an opaque error like 'comment body must be 2000 characters or
fewer.' whenever an oversize string hit any bounded field. Agents that
posted a long run summary or oversized link URL had no way to tell
how far over the limit they were, so they could not retry with a
trimmed payload.

Include the actual length in the error so the message tells the agent
exactly what to do next:

  comment body must be 2000 characters or fewer (got 3502).

The format applies uniformly to every bounded field routed through
this helper (labels, link URL, link title, link target, comment
body, title, notes, worker log message, session key, run id,
protocol violation detail, etc.) since the helper is the single
canonical owner of the message.

Cover the new format with a focused unit test that pins the regex
for the comment-body repro from #118845 and exercises the six other
bounded fields listed in the issue. Update the existing
gateway.test.ts assertion to allow both the old and new format so
the format change is a forward-compatible improvement.
2026-08-16 23:54:27 +01:00
Peter Steinberger 57b1a69167 fix(state): report v9 registry migration row decisions (#124862)
* fix(state): report v9 registry migration row decisions in doctor and logs

* fix(state): consume registry migration summary type

* fix(state): avoid registry path observer import cycle
2026-08-16 15:52:42 -07:00
Peter Steinberger 800a0bb52a perf(webui): render cached model catalog while the chat pane refreshes (#124868)
* perf(webui): render cached model catalog while the chat pane refreshes

* test(webui): fix seed-test types and shrink assertion baseline
2026-08-16 15:52:26 -07:00
Peter Steinberger 7344ce4341 fix(browser): cancel node discovery with tool runs (#124880)
Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89

Co-authored-by: Amp <amp@ampcode.com>
2026-08-16 15:52:00 -07:00
Peter Steinberger 8aef31b903 fix(ui): align update status card spacing (#124878) 2026-08-16 15:48:55 -07:00
Vyctor H. Brzezowski 03f4ff5cc2 fix(ui): restore task count badge (#124840) 2026-08-16 19:48:19 -03:00
Peter Steinberger 72ddf22b93 fix(qa): recover repeated gateway restarts through channel ingress (#124746)
* fix(qa): repair repeated gateway restart recovery

* test(qa): satisfy restart recovery checks

* fix(audit): rekey repeated recovery identity

* fix(plugin-sdk): expose authored context cap

* test(android): synchronize process tree readiness
2026-08-16 15:47:31 -07:00
Peter Steinberger eadde4a9d0 fix(ui): show recovery when Control UI does not render (#124861)
* fix(ui): retire bootstrap fallback after render

* test(ui): avoid returning from Promise executor
2026-08-16 15:46:15 -07:00
Peter Steinberger 358c06ec95 fix(gateway): persist agent turns before acknowledgement (#124857)
* fix(gateway): persist agent turns before acknowledgement

* fix(gateway): revalidate exec approval handoffs

* docs(gateway): clarify durable session ownership

* fix(gateway): reject stale transcript admission targets
2026-08-16 15:42:49 -07:00
Peter Steinberger add30d455d refactor(security): consolidate path containment onto canonical fs-safe guard (#124870)
* refactor(security): expose canonical path containment modes

* refactor(agents): use canonical path containment guard

* refactor(security): consolidate core path containment sites

* refactor(plugins): consolidate path containment sites

* test(security): cover canonical path containment behavior
2026-08-16 15:37:02 -07:00
Peter Steinberger 9b468ccaa2 test: replace assertion chains with typed fixture builders — wave 2 (#124865) 2026-08-16 15:36:45 -07:00
Peter Steinberger 03cf9851d8 fix(protocol): model cron run delivery trace (#124856)
* fix(protocol): model cron run delivery trace

* chore(protocol): refresh generated cron run model
2026-08-16 15:34:56 -07:00
Peter Steinberger 36b0971772 perf(test): reuse postpublish file-cap fixture (#124871) 2026-08-16 15:31:46 -07:00
Peter Steinberger 1ce67d541f docs(ci): record artifact checkout experiment 2026-08-16 15:30:04 -07:00
Peter Steinberger 2d3612da6b fix(gateway): preserve prepared plugin metadata under load (#124844)
* fix(gateway): preserve prepared plugin metadata under load

* fix(gateway): project metadata before catalog preparation

* test(agents): assert projected startup metadata

* test(gateway): bind load probes to each finalization wave
2026-08-16 15:14:39 -07:00
Peter Steinberger 6c66f48a7c fix(cli): emit one JSON failure contract for --json invocations (#124849)
* fix(cli): unify JSON failure output

* test(cli): update skills verify failure envelope
2026-08-16 15:09:58 -07:00
Peter Steinberger 0b5bb09510 fix(test): propagate parent heavy-check ownership (#124859)
Amp-Thread-ID: https://ampcode.com/threads/T-01a00b7c-b9f0-73d5-8fb7-e619e8e458e1

Co-authored-by: Amp <amp@ampcode.com>
2026-08-16 15:09:30 -07:00
Peter Steinberger efdfb69adc fix(agents): keep queued followups from missing post-compaction context (#124850)
* fix(auto-reply): order post-compaction context before followups

Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89

* test(auto-reply): clean compaction workspace fixture

Amp-Thread-ID: https://ampcode.com/threads/T-01a00b6b-e4e9-74af-bb31-30363fae6c89

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-08-16 15:06:39 -07:00
Peter Steinberger 2d887acba3 fix(slack): drop the tool-call receipt from finished progress cards (#123851)
The Block Kit session card terminalized into a '🛠️ N tool calls · ⏱️ Ns'
footer, leaving a per-turn receipt in the Slack transcript on the default
progress path. PR #122976 deleted the same receipt from the native progress
surface but left this sibling rendering it.

Finished cards now keep only the durable diff stat and the session link;
tool-call and elapsed counters stay live working state. Also corrects the
documented channels.slack.streaming.mode default, stale since #122552.
2026-08-16 14:58:23 -07:00
Peter Steinberger 8754be900a feat(ui): add steer-now composer shortcut (#124826) 2026-08-16 14:57:58 -07:00
Peter Steinberger eab2b8fdca refactor(slack): mark approval headers with typed block ids (#124841) 2026-08-16 14:53:26 -07:00
Peter Steinberger 080887df92 refactor(types): discriminated unions for internal contracts — pilot lane A (#124845) 2026-08-16 14:49:28 -07:00
Peter Steinberger fb841993b1 perf(test): remove Gmail watcher shutdown wait (#124851) 2026-08-16 14:41:28 -07:00
Peter Steinberger 06101b1037 refactor(validation): consolidate boundary guards into schemas (#124820)
* refactor(validation): consolidate boundary guards into schemas — pilot lane B

* fix(meetings): reject non-object browser status
2026-08-16 14:41:14 -07:00
Peter Steinberger d23246770a fix(memory): report indexed SQLite sessions (#124834)
* fix(memory): report indexed SQLite sessions

* refactor(memory): remove unused state path export
2026-08-16 14:38:15 -07:00
Peter Steinberger eec67fd67b fix(ui): keep sent images visible through history handoff (#124839) 2026-08-16 14:35:21 -07:00
Peter Steinberger 9b17b93414 refactor(ui): derive cron types from gateway protocol (#124827)
* refactor(ui): derive cron types from gateway protocol

* fix(protocol): preserve cron session target type
2026-08-16 14:34:26 -07:00
Peter Steinberger 33f3b72a19 refactor(plugin-sdk): extract stream and SecretRef primitives (#124835) 2026-08-16 14:30:11 -07:00
Peter Steinberger 68762ad22c fix(ui): give queued-outbox badges their own outbox icon (#124842)
The sidebar queued-message badge and the composer queue reused the clock
glyph that also marks attached automations, so a session with both showed
two identical clocks distinguishable only by tooltip. Add an outbox tray
icon (Lucide inbox with the roof swapped for a rising arrow) and use it
for queued-to-send surfaces; the clock stays automation/cron-only. The
mock dev fixture now flags one session with hasAutomation so the badge
renders in mocked-dashboard proofs.
2026-08-16 14:29:41 -07:00