Commit Graph

1440 Commits

Author SHA1 Message Date
Peter Steinberger 7170a6231a feat(agents): unify agent status into a durable progress_card (#125125)
* feat(agents): unify agent status into a durable progress_card

Replace the write-only update_plan to-do tool and the fragmented plan
rendering with one durable status artifact per session: progress_card
({plan?, markdown?}, replace-on-write, 8 KiB markdown / 50-step caps).
Cards persist in a lazy-additive session_progress_cards table in the
per-agent DB (no schema-version bump), broadcast progressCard.changed,
and render from the store with exactly one live placement per view
(session rail when visible, else the composer-adjacent bar); transcripts
collapse to one-line receipts, and the sidebar hovercard shows other
sessions' cards inline (markdown + <progress>, DOMPurify allowlist, no
iframes). The three stream-derived plan renderers and their dedup
heuristics are deleted.

Codex runs disable the native plan tool per thread
(tools.update_plan.enabled=false) and receive progress_card via the
dynamic-tool bridge; compaction restore now reinjects the card (steps +
bounded markdown). Card writes still emit the legacy plan stream event so
native apps and channels keep working until their per-platform
migrations. Policy names map update_plan -> progress_card; the shipped
tools.updatePlan=false kill switch is honored.

Net -277 production LOC; -480 test LOC.

* test(agents): regenerate Codex prompt snapshots for update_plan thread-config disable

* chore(protocol): allowlist progressCard.changed for native apps pending card migration

* fix(ci): repair progress card integration checks

* fix(codex): canonicalize native progress cards

* test(gateway): reconcile progress card method order

* test(codex): stabilize native approval fixture
2026-08-17 09:44:04 -07:00
Peter Steinberger 98d7b38d48 docs: document three-layer session ownership (#125334)
* docs: document three-layer session ownership

User documentation for the session-ownership feature landed in #125057:
the immutable creator / assignable owner / participant-history model, the
Assign-to-me and Assign-to session menu actions, the sessions tool
assign_owner action, the sidebar Owners facet with Involving-me, the
pair-stack owner avatar, and agent-spawned session receipts (sessionUrl +
owner acknowledgement). Adds the sessions.assignOwner method and ownership
row projections to the protocol reference and a zh-CN glossary entry for
the new link label.

* docs: drop nonexistent header facepile overflow count

The chat header receives the already 4-capped participant projection and no
total count, so its overflow branch cannot render. Describe up to four
avatars instead (ClawSweeper P2).
2026-08-17 09:35:07 -07:00
Peter Steinberger 185b1ab726 fix(discord): retain progress drafts after error finals (#125140)
* fix(discord): retain error progress drafts

* test(discord): parse REST probe request URLs

* test(qa): force Discord error-final path

* test(qa): match Discord overload final
2026-08-17 02:22:02 -07:00
Peter Steinberger a3578c7790 test(qa): cover Discord progress draft lifecycle (#125089)
* test(qa): cover Discord progress draft lifecycle

* test(qa): allow live Discord draft proof

* ci(qa): select Discord provider mode
2026-08-16 23:17:53 -07:00
Peter Steinberger 04fd260b4c refactor(channels): rename progress work counter (#125011) 2026-08-16 22:11:21 -07:00
Peter Steinberger 7349177ce3 feat: main-session agent-wide visibility + session.groupScope routing (#124965)
* feat: add main session group routing

* docs: explain main session routing scopes

* fix: align memory session visibility

* test(qa): cover main-scoped group bindings

* fix(sessions): preserve binding-scoped outbound routes

* fix(routing): preserve explicit outbound owners

* fix(sessions): recognize global main visibility

* chore(ci): prune assertion safety baseline
2026-08-16 19:57:18 -07:00
Peter Steinberger 13872f4338 fix: plugin tools disappear from Codex and restricted profiles (#124947)
* fix(memory): make standing intents reachable

* fix(agents): dedupe macOS read path variants

* docs(plugins): document profile tool metadata

* test(codex): complete prepared runtime fixtures

* fix(agents): preserve prepared tool boundaries
2026-08-16 19:38:07 -07:00
Peter Steinberger 462fe4d0e0 feat(agents): preserve create request provenance (#124963) 2026-08-16 19:18:28 -07:00
ClawSweeper e448c6b0ef docs: clarify model switching guidance (#124889)
* docs: clarify model switching guidance

* docs: warn that reasoning changes invalidate cache reuse

---------

Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-16 19:02:59 -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 715c379fd9 refactor(config): consolidate context budget to one per-model knob (#124665)
* refactor(config): consolidate context budget settings

* test(config): type legacy context fixtures

* test(config): align context budget fixtures

* fix(status): honor runtime context discovery

* docs(config): clarify context budget fallbacks

* fix(ci): resolve context budget lint failures

* test(ci): align context budget shard fixtures

* fix(models): preserve catalog context metadata

* fix(config): surface context migration diagnostics

* test(plugin-sdk): keep live catalog coverage focused
2026-08-16 10:05:01 -07:00
Peter Steinberger 9873b0f6ad feat(ui): named glyphs and custom emoji entry for session icons (#124629)
* feat(protocol): add named session icon glyphs

* feat(ui): add session glyph and custom emoji picker

* docs: describe named and custom session icons

* fix(ui): give the custom emoji input an accessible name

ClawSweeper P2: the input had no label relationship; assistive tech announced an unnamed edit control.

* fix(protocol): guard the v-flag icon regex for browser module loads

ClawSweeper P1: the picker's static import evaluates this module in the browser; pre-Unicode-Sets engines threw at module scope and took down the session menu. Lazy capability-guarded construction; such engines fall back to the grapheme heuristic as client pre-validation while the Gateway keeps exact RGI validation.
2026-08-16 07:55:31 -07:00
Nehorai Hadad 7d05f7c5b9 fix(auto-reply): suppress fallback notices in rooms (#107209)
Hide model fallback and recovery notices in group and channel conversations while preserving direct-chat notices, persisted state, and lifecycle events.

Co-authored-by: NehoraiHadad <nehorai.hadad.projects@gmail.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-16 12:14:25 +05:30
Vito Cappello 7f93011562 fix: preserve Claude CLI prompt cache reuse across turns (#124300)
* fix: keep claude-cli prompt-cache prefix stable across turns

Claude CLI has no cache_control breakpoint, so mashed per-turn system
prompts rewrote the native prefix and burned cache hits on follow-ups.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli): scope Claude prompt cache suffix

* docs: scope Claude CLI cache guidance

* test(cli): cover Claude cache prompt modes

* fix: gate Claude CLI prompt cache flag

* docs: clarify Claude CLI cache flag gate

* fix: preserve Claude CLI system prompt roles

* fix(claude-cli): close cache flag compatibility gaps

* fix(claude-cli): reject prerelease cache flag versions

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-15 18:17:17 -07:00
ClawSweeper 4c55629238 feat(sessions): preserve recent session history (#123987)
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-15 16:25:31 -06:00
Pavan Kumar Gondhi 8668aeb969 fix(discord): bind transcript capture to source account [AI] (#118579)
* fix(discord): bind transcript capture to source account

* style(agents): keep transcript tool wiring compact

* fix(transcripts): declare account binding channels

* fix(transcripts): report effective capture account

* fix(transcripts): enforce account lifecycle ownership

* fix(transcripts): preserve cross-surface control

* fix(copilot): preserve transcript channel context

* fix(transcripts): fail closed for legacy channel owners

* fix(transcripts): add trusted legacy recovery

* fix(transcripts): preserve auto-start cleanup ownership

* fix(transcripts): reject untrusted account starts

* fix(transcripts): keep persisted ownership authoritative

* fix(transcripts): harden legacy recovery

* fix(transcripts): preserve agent ownership boundary

* fix(transcripts): scope account binding to source channel

* fix(transcripts): preserve unattributed owner isolation

* fix(transcripts): own configured captures by account

* docs(plugins): clarify transcript auto-start ownership

* test(transcripts): cover account-less recovery

* docs(transcripts): scope legacy recovery by provider

* fix(discord): reuse eligible account ordering for transcripts

* test(discord): use neutral transcript account fixtures

* fix(transcripts): keep accountless recovery local

* fix(discord): resolve transcript accounts by voice capability

* fix(transcripts): bound account resolution failures

* fix(transcripts): bound account tool output

* fix(transcripts): honor unresolved provider accounts

* fix(transcripts): preserve binding when providers are missing

* fix(transcripts): fail closed on unknown binding provenance

* fix(transcripts): qualify account lifecycle capability

* fix(transcripts): normalize provable legacy owners

* fix(transcripts): bind scheduled capture to caller authority

* fix(transcripts): preserve scheduled caller identity tuple

* fix(transcripts): preserve channel-less scheduled authority

* fix(plugin-sdk): publish transcript provider types

* fix(transcripts): use exact lifecycle ownership tokens

* fix(transcripts): preserve local ownerless lifecycle access

* fix(transcripts): allow local configured capture control

* fix(transcripts): preserve scheduled caller channel

* fix(transcripts): retain named-agent legacy recovery

* fix(transcripts): deny unrelated remote channels

* fix(doctor): validate transcript owner inference

* fix(transcripts): restrict legacy remote recovery

* fix(ci): align transcript Doctor checks

* fix(transcripts): require Doctor-owned legacy metadata

* fix(transcripts): reject unowned remote capture starts

* fix(transcripts): reject unbound Discord lifecycle calls

* fix(transcripts): distinguish legacy owner rows

* test(discord): keep unavailable account fixture typed

* fix(transcripts): mark current imports for Doctor

* fix(transcripts): complete account ownership validation

* fix(discord): restore transcript package boundary

* fix(discord): preserve bundled transcript entry boundary

* docs(transcripts): clarify Discord auto-start account

* fix(transcripts): bind account-owned imports

* fix: preserve transcript and cron policy state

* fix(cron): preserve scheduled transcript authority

* fix(discord): keep legacy transcript rows local

* fix(transcripts): narrow account ownership boundary

* fix(transcripts): preserve trusted caller ownership

* fix(discord): enforce transcript source authorization

* fix(ci): bound Control UI gzip build variance

* test(qa): align transcript scenario contracts

* fix(agents): repair rebased caller context

* fix(discord): restore rebased account ownership

* test(discord): restore voice account fixtures

---------

Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-08-15 12:10:43 -07:00
Peter Steinberger d2be00e171 feat(ui): persistent emoji session icons in the sidebar (#124034)
* feat(gateway): persist emoji session icons

* feat(ui): add persistent session icon menu

* docs: explain persistent session icons

* docs: list Set icon in the session context menu enumeration

* test(gateway): canonicalize group defaults workspace path

* fix(ci): sync session icon protocol coverage

* fix(sessions): enforce RGI emoji sequences for session icons

ClawSweeper P2: single non-emoji graphemes like 漢 passed the segmenter-based predicate. Anchored \p{RGI_Emoji} admits exactly one interchange emoji sequence and deletes the length cap and ASCII carve-out.

* fix(sessions): compile RGI emoji validation
2026-08-15 00:15:55 -07:00
Dallin Romney a01d40bfb9 fix(sessions): honor total entry cap with protected history (#123081)
* fix(sessions): count protected rows toward entry cap

* perf(sessions): defer maintenance snapshot loading

* test(sessions): assert total maintenance cap

* fix(sessions): align warning preservation

* fix(sessions): guard malformed maintenance rows
2026-08-15 08:03:57 +08:00
Jesse Merhi bf40269cb7 feat(security): require acknowledgement for policy warnings (#116489) 2026-08-15 03:58:45 +10:00
Josh Avant 97a53a9b35 feat: audit admitted channel participant identity (#122863)
* feat: audit admitted channel participant identity

* fix: preserve Telegram identity through thread recovery

* fix: signal held gateway process groups

* fix: keep audit evidence passive in collect routing

* fix: validate copied channel participant evidence

* fix: bind channel participant evidence to host ingress

* fix: honor Telegram proof credential roles

* fix: restart held Telegram proof through gateway

* fix: repair channel identity CI regressions

* test(matrix): bind thread routing owner

* fix: preserve direct DM SDK compatibility

* fix: bind channel provenance at host runtime

* test(feishu): provide channel context builder

* fix: defer record-bound channel runtime resolution

* fix: keep channel admission evidence core-private

* fix(audit): bind channel admission to plugin lifecycle

* fix(audit): bind ingress provenance to final context

* refactor(audit): split admission scope keys

* test(queue): cover combined metadata carriers

* refactor(audit): keep lifecycle helpers private

* fix(queue): preserve combined turn authority

* test(channels): provide ingress context builders

* test(channels): align integrated CI fixtures

* test(clickclack): resolve model-loop ingress

* docs: preserve channel participant evidence invariant
2026-08-14 08:57:01 -05:00
Peter Steinberger 7cadfb0bd6 fix: speed up local node launches and isolate scratch state (#123503)
* perf(node-host): reuse advertised worker build identity

* fix(agents): keep default workspaces inside state dir

* fix(plugins): package llama.cpp private SSRF runtime

* fix(node-host): silence missing skills directory
2026-08-13 23:24:54 -07:00
Peter Steinberger 1348387076 refactor(plugins): replace node-llama-cpp with managed llama-server (#123105)
Move llama.cpp chat and local embeddings onto a verified externally managed llama-server runtime. Remove the in-process native runtime, forked embedding workers, and node-llama-cpp dependency while preserving guided setup, local GGUF models, tool-capable agent runs, diagnostics, and operator docs.
2026-08-13 16:58:20 -07:00
joshavant d83f7b815d fix(models): defer live catalog discovery 2026-08-13 18:57:50 -05:00
Peter Steinberger 11b3bf374c feat(slack): unify the native progress turn into one streamed message (#122976)
* feat(slack): unify the native progress turn into one streamed message

Native progress mode now streams the whole turn into a single Slack message:
narration flows as markdown_text chunks interleaved with plan/task chunks,
task rows carry file-path details and +N/-N output, the terminal task links
the session via url_source, and the final answer lands through stopStream in
the same message. Media/oversized/error finals keep their normal-delivery
fallbacks.

Deletes the finished-card receipt collapse (the '\u{1F6E0} N tool calls · ⏱ Ns' edit)
outright: the card now stays as its finished self.

Live-verified on a real workspace: exactly one bot message per turn.

* fix(slack): serialize native stream updates and keep append-only rendered text monotonic

Overlapping progress updates (compositor render, narration payload, final)
computed their narration delta before awaiting the network and committed
state only afterwards, so concurrent updates re-appended identical
narration into the streamed message (each status line landed 3x live).
A single ordering chain now makes each update's compute -> append -> commit
atomic.

applyAppendOnlyStreamUpdate also replaced the accumulated rendered text
with the incoming cumulative partial once an appended chunk had diverged
rendered from source, dropping content the sink already displayed; rendered
now only ever extends.

* fix(slack): stop refreshing thread status once a turn has visible output

Slack clears the assistant thread status as soon as the app puts anything
in the thread, and renders its own rotating agent-working row ("Generating
response...", "Finding answers...") for every status write after that -- it
ignores the app-supplied string. The typing keepalive re-set the status
every 3s for up to 60s, so each turn painted a duplicate status row under
the streamed card or progress message.

The status write is now gated on the turn having visible output, which the
dispatcher already tracks (delivered reply, committed preview, or posted
draft message). The first status still fires before any output, so slow
turns keep their indicator, and the typing reaction is tracked separately
so a suppressed status write still cleans up its reaction.

* fix(slack): let the plan card own the status line instead of echoing it

The status headline and plan explanation fed both the streamed narration
markdown and the plan card title, so every headline rendered twice: once as
static text and once in the card that keeps updating it in place. Narration
now carries only authored commentary and reasoning, and a preamble payload
whose text the card title already shows is not streamed again.

* feat(slack): make the native agent card the default progress surface

Slack's native plan/task card was opt-in behind streaming.progress
.nativeTaskCards while the Block Kit session card shipped as the default.
The native surface is the better product on every axis we can measure --
one streamed message instead of three artifacts, live task rows with file
paths and diff counts, and Slack's own agent chrome -- so it becomes the
default and an explicit false selects the Block Kit card instead.

The session link is now emitted only when it can actually work: the
operator set gateway.publicOrigin and left the Control UI enabled.
Installations with no externally reachable Gateway get no link rather than
a dead one.

The progress card still only appears for turns that do real work; the
existing compositor start gate keeps plain question-and-answer turns
card-free.

* fix(slack): finish the final inside a buffered native stream

A short narration leaves the SDK session un-flushed, so `delivered` stays
false until `stop` makes its first network call. Requiring delivery before
finishing in-stream sent the final through normal delivery and then
finalized the stream anyway, producing exactly the second message this path
exists to prevent. Stop-time rejection already falls back via
SlackStreamNotDeliveredError, so a live session is enough.

Addresses the ClawSweeper P1/P2 finding on this PR.

* refactor(slack): collapse duplicate streaming surfaces and drop dead code

Cleanup pass over the progress/streaming neighborhood, all verified unused
by exhaustive reference search:

- Deleted buildSlackProgressStreamStartChunks/UpdateChunks: byte-identical
  pass-throughs to the same builder, plus the render-module branch that
  chose between them. One exported builder now.
- Collapsed slackStreaming.draftMode, a lossless restatement of the mode it
  was derived from, and its outbound mapper; nine comparisons now read the
  mode directly. Inbound legacy parsing stays for doctor migration.
- Dropped stopSlackStream's text parameter, the draft stream's stop() member
  and onMessageSent hook, a redundant nativeStreaming argument, four dead
  members on the progress runtime, and two single-expression wrappers.
- Deduped the native card title, which was computed twice per render.

Production LOC for the whole PR drops from +216 to +114.

* chore(config): regenerate bundled channel metadata for the Slack card default

The generated metadata still carried the old opt-in help text and
default-false description for streaming.progress.nativeTaskCards, so
config UI and diagnostics would publish stale guidance.

* fix(slack): un-export the now-internal legacy draft-mode type

Collapsing draftMode removed the type's only external consumer, so knip
flagged it as an unused export. Doctor migration still parses these legacy
values inbound, so the type stays module-local.
2026-08-13 11:19:32 -07:00
Dallin Romney 4afccbdaa4 fix(sessions): exclude protected sessions from entry cap (#123014) 2026-08-13 15:42:55 +08:00
Peter Steinberger e45a9460ce docs: repair spellcheck and anchor drift (#122960)
* docs: repair spellcheck and anchor drift

* docs: satisfy markdown anchor lint
2026-08-12 20:50:56 -07:00
Peter Steinberger 4d54c3f1a1 refactor(config): retire dead streaming.progress.render key (#122927)
* refactor(config): retire dead streaming.progress.render key

The key had zero runtime consumers after #122552. Core doctor now strips it via stripRetiredTuningKnobs, and production LOC is net -13.

* fix(tooling): pin plugin SDK surface counts to the reduced export set

The retired progress-draft render reader counted twice via channel-outbound and channel-message's wildcard re-export.
2026-08-12 20:36:40 -07:00
joshavant 8eb9739724 fix: isolate compaction structure audit 2026-08-12 20:46:55 -05:00
joshavant 4cb21b22c0 fix: preserve compaction history when final audit fails 2026-08-12 20:46:55 -05:00
Peter Steinberger 08b134324f feat: continue web sessions in the terminal (#122870)
* feat: continue sessions in terminal

Add a credential-free Control UI continuation command and allow openclaw resume to reuse current-profile authentication only for byte-exact configured Gateway targets.

* fix(gateway): separate public origin TLS ownership

Allow exact public-origin resume targets to reuse local authentication without inheriting the direct local listener certificate fingerprint.

* fix(gateway): scope exact targets to gateway mode

Prevent remote profiles from reusing dormant local Gateway authentication for explicit loopback or public-origin targets.

* fix(cli): encode terminal resume handoffs

Replace shell-specific quoting with a strict credential-free base64url handoff, gate configured auth reuse to validated handoffs, and skip unused session discovery.

* fix(gateway): isolate handoff auth identity

Suppress ambient Gateway auth fallback for validated handoffs while preserving explicit credentials, configured SecretRefs, stored device auth, and exact-target TLS ownership.

* fix(cli): harden terminal resume handoffs

* fix(cli): parse terminal handoff outcomes

* fix(cli): bind handoffs to resolved agent

* test(ui): align terminal continuation proof

* docs(plan): track terminal continuation

* refactor(ui): keep terminal handoff result local
2026-08-12 17:07:48 -07:00
Peter Steinberger 508dd471b0 feat(slack): live session cards as the default progress mode (#122552)
* feat(slack): render live session cards as the default Slack progress mode

Slack streaming.mode default flips partial->progress.
Progress mode renders one live Block Kit session card with a status header, narration, plan, activity, diff stat, and elapsed time; it is edited in place and finalized to success or error with an Open in OpenClaw button when gateway.publicOrigin is set.
Final assistant text always delivers separately.
The shared progress compositor gains a success-only additive per-turn diffStat mirroring the task ledger fold.
resolveGatewayPublicOrigin is exported through the plugin SDK.
The diffs viewer URL falls back to publicOrigin.
The old rich/text progress render fork is deleted.
Native task cards remain unchanged and opt-in.

* chore(config): regenerate bundled channel config metadata

* refactor(slack): keep session card state type internal

* refactor(slack): split session-card and diff-stat owners under lint ceilings

* refactor(channels): reuse diff-stat type from its owner module

Import ChannelProgressDraftDiffStat from progress-draft-diffstat instead of
redeclaring it in the compositor, resolving the all-exports deadcode scan.

* chore(plugin-sdk): regenerate api baselines for channel barrels

Baselines drifted after the rebase reconciled them against main; regenerate to
match the branch's actual channel-message/channel-outbound surface.

* fix(slack): drop a session card that cannot terminalize after final delivery

If the final reply is delivered but the terminal card edit fails, the caller
now clears the stale card instead of leaving it stuck in its Working state
(mirrors the pre-card preview cleanup). Adds a transport-failure regression and
corrects three tests that asserted the prior ignore-the-result behavior.

Documents resolveGatewayPublicOrigin as a dependency-light runtime helper on the
config-contracts SDK subpath, which previously described a type-only surface.

Addresses ClawSweeper P2 (unfinalized card) and P1 (runtime SDK contract).

* fix(slack): suppress default tool messages under the default progress card

resolveChannelStreamingSuppressDefaultToolProgressMessages re-derived the stream
mode from config with an "off" default, unlike its sibling resolvers which take
a caller-resolved mode override. After this branch made progress the Slack
default, a default-config channel turn saw mode "off" and left a stray
"Using tool: X" plain message posting alongside the session card. Thread the
caller-resolved mode through (compositor passes params.mode; Slack dispatch passes
slackStreaming.mode), matching resolveChannelStreamingPreviewToolProgress.

Retarget the progress-session-card delivery-trace golden at an EMPTY Slack config
so it proves the real default path; the regenerated golden is byte-identical,
confirming defaults now yield the clean card sequence (one card post, separate
final text, one terminal update with the Open in OpenClaw button, no stray tool
message). Switch the dispatch delivery-mode mock to the real resolver so the card
tests exercise the true channel default (automatic), not a hand-rolled one.

* chore(plugin-sdk): regenerate api baselines for the streaming mode param

resolveChannelStreamingSuppressDefaultToolProgressMessages gained an optional
mode override; the changed signature reflows the surface hash of every barrel
that re-exports it, so regenerate the affected baselines.

* chore(config): regenerate config baselines
2026-08-12 10:38:31 -07:00
Peter Steinberger 0c8c8d95c7 fix(ai): restore cached OpenAI continuation (#122483) 2026-08-11 23:24:57 -07:00
Vito Cappello 77d89b2fa8 fix(agents): scope quota failures to auth profiles (#121278)
* fix(agents): scope quota failures to auth profiles

* test: repair provider suspension CI coverage

* test: keep suspension reset fixture internal

* fix(agents): spend cooldown probe only on transient candidates

Consume the one-run cooldown probe only when the candidate’s own unavailable reason is transient, so a billing-disabled pin cannot block a recoverable backup.\n\nFinding from the ClawSweeper review on openclaw/openclaw#121278.

* refactor(sessions): deprecate QuotaSuspension.laneId instead of removing

The shipped plugin-SDK surface deprecation policy requires keeping the inert field until the next surface window.

* fix(agents): extend transient probe policy to plugin-harness auth path

* fix(agents): keep provider overload from cooling auth profiles

* fix(agents): exhaust rotation candidates without cooldown records

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* test(agents): align auth rotation mocks with current main

* docs: regenerate plugin SDK API baseline

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* style(agents): format session-suspension test after rename resolution

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-11 23:07:04 -07:00
Peter Steinberger 7ecad45a7d refactor(context-engine): retire legacy host param default (#122434) 2026-08-11 21:57:46 -07:00
Peter Steinberger 38a5390e2e fix(agents): never restore a retired worktree via a generated name (#122393)
sessions.create reset-in-place persists the retired worktree's removedAt
before the RPC resolves, but a successor worktree create that rolled the
same random crustacean slug (1/420) hit nameIsUnavailable's owner-match
bypass and silently restored the retired registry record, clearing
removedAt and reviving the old branch (flaked
server.sessions.create.test.ts reset-in-place).

Generated names (title slugs and random slugs) now treat the caller's
removed records as collisions and take a numeric suffix; explicit
worktree names keep their documented reuse/restore semantics.
2026-08-11 20:02:26 -07:00
Peter Steinberger cd0a1235a3 feat: sync new-session preferences and recents by identity (#121816)
* feat(gateway): add identity preferences and project recents

* feat(ui): sync new-session identity state

* docs: explain identity-scoped session state

* test: track preference temp directories

* fix(gateway): preserve identity preference boundaries

* chore(protocol): refresh identity preference bindings

* test: refresh historical schema hashes

* style(gateway): format method order assertion

* fix(protocol): emit project recent Swift models

* test(gateway): track preference RPC release train

* fix(gateway): harden identity preference state

* fix(state): keep preference errors internal

* chore: refresh split plugin SDK baseline

* fix(gateway): use core session store loader

* refactor(state): fold additive migration checks

* chore: regenerate plugin SDK baseline

* chore: regenerate plugin SDK baseline

* chore: regenerate plugin SDK baseline

* chore: regenerate plugin SDK baseline

* chore: regenerate plugin SDK baseline

* chore: regenerate plugin SDK baseline

* chore: regenerate plugin SDK baseline

* test(ui): relocate identity recents e2e

* chore: regenerate plugin SDK baseline

* chore: regenerate plugin SDK baseline

* chore: regenerate plugin SDK baseline

* chore: regenerate plugin SDK baseline

* chore: regenerate plugin SDK baseline
2026-08-11 16:52:59 -07:00
Peter Steinberger db9bdb4a11 fix(gateway): preserve session identity through archive transitions (#121169)
* fix(sessions): fence lifecycle mutations by identity

* fix(sessions): finalize lifecycle identity fences
2026-08-11 16:43:10 -07:00
Peter Steinberger 8c567306ba fix(openai): remove duplicate GPT-5.6 picker entry (#122178)
* fix(openai): remove duplicate GPT-5.6 picker entry

* test(gateway): split OpenAI model picker coverage

* test(openai): align canonical model fixtures

* chore(plugin-sdk): refresh agent harness API baseline
2026-08-11 12:29:36 -07:00
Josh Lehman 2f4dff7428 fix(context-engine): long sessions continue past 20k events (#122149)
* oc-5b3: canonicalize durable commitTurn

* oc-deb: remove stale commitTurn test fields
2026-08-11 11:53:11 -07:00
SunnyShu d758ec48d4 fix(context-engine): durable state stalls in long sessions (#121647)
* [AI] fix(context-engine): bound accepted-turn cap to the current turn range

The accepted-turn transcript read applied the 8 MiB / 20k-event cap to
the entire active prefix instead of the admitted turn range, so durable
context engines permanently blocked every later small turn once session
history exceeded the cap. Restrict the cap check to rows at or after the
admission message position while preserving the full messages +
prePromptMessageCount payload contract.

Fixes #121623

Co-Authored-By: Claude <noreply@anthropic.com>

* [AI] test(context-engine): clean up large-prefix regression temp dirs

ClawSweeper P3: the two new accepted-turn regression cases created
multi-megabyte SQLite fixture directories that were never removed.
Track them and delete them in afterEach.

Related to #121623

Co-Authored-By: Claude <noreply@anthropic.com>

* oc-136: make durable turn commits turn-local

* oc-514: use canonical temp-dir cleanup helper

* oc-514.7: version turn-local durable commits

* oc-514.9: preserve legacy durable rows

* oc-514.8: refresh plugin SDK API baseline

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Josh Lehman <550978+jalehman@users.noreply.github.com>
2026-08-11 02:52:49 -07:00
Peter Steinberger f788af0238 docs(memory): explain automatic QMD migration (#121911) 2026-08-10 23:57:34 -07:00
Josh Avant 73a9eed95b refactor(audit): add canonical admitted-run context (#120534)
* feat(audit): carry canonical admitted execution context

* fix(agents): preserve admitted context across retries

* fix(worker): fence legacy launch dialect

* test(gateway): track approval temp dirs

* fix(plugin-sdk): preserve harness attempt compatibility

* fix: close delegated run authority at owner boundaries

* fix: internalize delegated authority validators

* refactor: split delegated authority proof surfaces

* refactor: centralize command admission identity

* test: claim runtime tool authority

* fix(gateway): keep lifecycle cleanup within static budgets

* fix(agents): revalidate harness policy authority

* fix(agents): fence awaited approval capability results

* test(copilot): supply required harness capability fixtures

* fix(agent): preserve scoped embedded run admission

* fix(agent): preserve keyless and worker authority

* test(agent): bind incomplete-turn authority

* docs: preserve execution authority invariants

* chore(plugin-sdk): regenerate API baseline

* fix(gateway): notify pending claim closure

* fix(gateway): revalidate delegated tool authority

* fix(plugin-sdk): keep source guard internal

* fix: close delegated authority races

* fix: revalidate delegated side effects

* fix: close harness authority projection gaps

* fix: align authority integration types

* fix: isolate settled harness finalization

* fix: fence recovery identity finalization

* fix: preserve committed session worktrees

* fix: preserve worker placement agent identity

* fix: fence active harness tool work

* fix(plugins): restore embedded run admission owner

* chore(plugin-sdk): compose integrated surface budgets

* fix(copilot): keep finalization attempt type internal

* fix(plugins): complete admission owner type imports

* test(harness): use settled finalization attempt shape

* fix(security): retain exact side-run and approval authority

* fix(security): preserve protected authority through terminal sweep

* fix(agents): follow moved recovery store owner

* fix(ci): align integrated authority owners with gates

* fix(plugins): distinguish embedded agent adapter export

* chore(plugin-sdk): regenerate API baseline after rolling integration

* refactor(gateway): keep session authority within owner budgets

* fix(gateway): keep session helpers private

* docs(plugin-sdk): name the V2 parameter subpath

* chore(integration): reconcile worker and SDK surfaces

* docs(plugin-sdk): require the V2 host API floor

* chore(plugin-sdk): regenerate after proxy-auth integration
2026-08-10 23:15:20 -05:00
Peter Steinberger 76b6496f34 perf(gateway): defer non-startup runtime imports (#121780)
Amp-Thread-ID: https://ampcode.com/threads/T-019fec00-3abd-710b-b9de-8925c23ad779

Co-authored-by: Amp <amp@ampcode.com>
2026-08-10 19:17:40 -07:00
Peter Steinberger 32894a3ba5 feat: start sessions from registered projects (#121465)
* feat(gateway): add project registry sessions

* fix(gateway): authorize project branch discovery

* test(gateway): reuse worktree test imports

* fix(protocol): register projects schema owner

* fix(gateway): gate project paths by write scope

* feat(control-ui): register projects from folder browser

* refactor(gateway): extract session diff baseline preparation

* fix(gateway): honor admin scope in project listings
2026-08-10 17:56:12 -07:00
Peter Steinberger 59492c51a5 feat(agents): rename spawn_task tool to suggest_task (#121694)
* feat(agents): rename spawn_task tool to suggest_task

Models across vendors read the name spawn_task as 'starts background
work' and refuse to call it when the user has not asked to start
anything (Claude Sonnet 5, verbatim: 'spawn_task (which actively starts
background work)... Since you didn't ask me to start work, I'm flagging
this as a follow-up instead'). The tool only records a suggestion card,
so the name defeated the feature.

Rename the model-facing tool to suggest_task everywhere (catalog,
descriptors, presets, display config, OpenClawKit tool-display, docs)
and migrate persisted operator state via doctor: config tool policies
and cron SQLite toolsAllow entries that reference spawn_task are
rewritten to suggest_task. No runtime alias remains; runtime exposes
only the canonical name.

Live clean-room matrix on a dev gateway (virgin session per cell):
suggested-task-card phrasing now yields exactly one card on
anthropic/claude-sonnet-5, claude-haiku-4-5, openai/gpt-5.6-sol,
gpt-5.6-luna, and google/gemini-3.1-pro; pre-rename the same bait
produced prose-only follow-ups.

* chore(doctor): keep legacy tool-name predicate module-local

isLegacyTaskSuggestionToolName has no external consumers; the exported
form tripped the knip unused-export gate (deadcode:exports).

* fix(doctor): keep tool-name migration out of plugin-owned config

The rename migration traversed the whole raw config, so any object
carrying a toolsAllow key was rewritten - including opaque
plugins.entries.*.config, which core must not mutate. Scope the apply
pass to the typed core roots (tools, agents, channels, gateway) and pin
plugin config preservation in the test. Plugin-owned tool lists migrate
via the owning plugin's doctor contract instead.

* fix(ci): heal main deadcode and stale Swift protocol mirror

Unrelated main breakage blocking this PR's merge gate, healed here per
landing policy:

- #121653 left dead exports in src/skills/workshop: make
  removeSkillCollectionDirectory and SkillCollectionRestoreResult
  module-local; register collection-review.ts under the documented knip
  ignoreIssues test-only-export convention (production runs it via the
  scheduled maintenance loop).
- #121673 added ApprovalResolveParams.reviewer without regenerating the
  Swift mirror; regenerate GatewayModels.swift (additive only).

* fix(ci): satisfy generic approval-runtime request signature in resolver test

Third main-heal carried by this PR: #121673 (9935ca3b30) left the
scoped-request mock's concrete inferred type unassignable to the generic
GatewayNativeApprovalRuntime request signature, breaking check-test-types
on main. Cast the mock at the runtime literal; assertions keep the Mock.

* chore(ci): drop approval-test cast superseded by main's typed mock rewrite

* chore(ci): drop duplicate knip entry superseded by main's heal
2026-08-10 16:41:39 -07:00
Ayaan Zaidi 4c951398ef fix(messages): keep runtime details out of chat alerts (#121600)
Keep raw commands, paths, and provider errors out of ordinary chat while preserving explicit raw diagnostics and structured admin history.

Default command progress is status-only; `/verbose full` and `commandText: "raw"` retain diagnostic detail.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-10 21:37:48 +05:30
Peter Steinberger a0ad38e71a feat(docs-ci): validate docs config examples against the schema (#121336)
* feat(docs-ci): validate config examples against schema

* docs: teach canonical agent roster configuration

* docs: nest inline environment variables under vars

* docs: update canonical media model keys

* docs: remove retired config keys from examples

* fix(docs-ci): keep audit internals private

* feat(docs-ci): validate plugin-owned config examples

* fix(docs-ci): validate indented config fences

* fix(ci): route manifest changes through docs audit

* chore(docs): refresh generated config baselines
2026-08-10 07:57:56 -07:00
Peter Steinberger f4bac99a81 feat(secrets): add SQLite-backed secret store (#121559) 2026-08-10 07:08:40 -07:00
Peter Steinberger f286928210 refactor(agents): type the reply failover seam and carry structured attempts (#121551)
* refactor(agents): carry structured fallback attempts

* refactor(agents): preserve typed failover delivery metadata

* refactor(auto-reply): consume canonical failover classification

* fix(auto-reply): preserve typed failure copy

* fix(auto-reply): keep failover facets internal

* fix(agents): remove stale failover exports

* chore(plugin-sdk): refresh API baseline

* fix(delivery): repair queue and pending-final settlement

* fix(lint): keep delivery queue within line budget

* fix(ci): refresh baselines after main rebase

* test(outbound): assert ambiguous send payload directly

* refactor(reply): follow upstream custody revert
2026-08-10 06:16:46 -07:00
Ayaan Zaidi 4b0151682e refactor(commitments): remove inferred follow-up subsystem
Remove hidden follow-up extraction, heartbeat delivery, CLI, docs, and supporting tests/tooling. Existing commitment records remain inert pending separately approved cleanup.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-10 13:48:32 +05:30