Commit Graph

1722 Commits

Author SHA1 Message Date
Peter Steinberger e6ca5266af fix: code mode dead-ends on oversized tool results instead of returning bounded output (#122924)
* fix(agents): bound code mode bridge results

Return oversized bridge, guest output, and final values as bounded successful projections with actionable narrowing guidance.

* refactor(agents): absorb code mode output bounds
2026-08-12 19:24:18 -07:00
Peter Steinberger 1ca60fbc3a refactor(agents): make multi-agent ownership explicit (H2-1 core) (#114388)
* refactor(agents): make roster ownership explicit

* feat(config): materialize legacy agent roles

* fix(cron): migrate legacy owners at startup

* feat(gateway): expose agent selection contracts

* fix(gateway): enforce agent-scoped authorization

* docs(config): document explicit agent ownership

* fix(config): pin retained owner workspace

* fix(gateway): target hook wakes at effective agent

* fix(sessions): preserve fixed-store ownership

* fix: preserve retained agent ownership

* fix: preserve legacy agent ownership across runtime surfaces

* fix: fail closed on ambiguous session ownership

* fix: preserve compatibility owners across dispatch and writes

* fix: preserve retained agent projections

* fix: preserve agent ownership compatibility

* fix: preserve per-agent heartbeat guidance

* fix: preserve compatibility owners in generic paths

* fix: enforce configured ownership in session paths

* fix: defer remote roster selection

* fix: preserve ownership across session and config writes

* fix: fail closed on ambiguous restored ownership

* fix: preserve explicit ACP and legacy ownership

* fix: honor durable fixed-store ownership

* fix: enforce fixed-store owner authority

* fix: preserve ownership evidence boundaries

* fix: honor resolved session ownership

* fix: align compatibility ownership paths

* fix: persist legacy main store ownership

* fix: close ownership fallback gaps

* fix(agents): close retained owner compatibility gaps

* fix(agents): enforce session owner resolution

* fix(agents): complete session owner resolution sweep

* fix(agents): preserve durable session ownership

* fix: complete persisted session owner routing

* fix: thread prepared session owners

* fix: preserve stable session ownership

* fix: enforce session ownership boundaries

* fix: close session ownership delta gaps

* fix: reconcile session ownership after rebase

* fix: reconcile ownership with current main

* fix: align session store path imports

* fix: align session store config path import

* fix: reconcile explicit ownership CI

* fix: reconcile ownership rebase checks

* fix: align ownership ci contracts

* fix: align ownership rebase checks

* fix: preserve compatibility owner during setup

* fix(doctor): migrate ownerless heartbeat monitors

* fix(gateway): preserve explicit session ownership

* test: align ownership fixtures after rebase

* test: complete plugin manifest fixture

* test: align runtime context mocks

* fix(gateway): preserve alias routing for existing sessions

* style: format agent routing update

* fix(gateway): preserve selected owner during alias routing

* style: normalize rebased ownership files

* fix(gateway): preserve owner through global alias routing

* fix(gateway): preserve explicit ownership at HTTP boundaries

* fix(gateway): validate compatibility model ownership

* fix(agents): reconcile strict session ownership

* fix(agents): contain media yield callback failures

* fix(agents): avoid eager bare-key owner resolution

* chore: refresh rebased ownership baselines

* chore: align hosted plugin SDK baseline

* chore: refresh ownership baselines after main sync

* chore: refresh ownership baselines after main sync

* test: align routed event owner fixtures

* chore: retrigger CI after runner startup failure

* chore: refresh ownership SDK budgets after main sync

* fix(tasks): require agent identity for bare owners

* chore: align Linux plugin SDK baseline

* chore: remove release-owned changelog entry
2026-08-12 15:55:16 -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
Pavan Kumar Gondhi 92f5f07da1 fix(browser): keep guarded CDP sockets on validated endpoints [AI] (#114506)
* fix(browser): keep guarded CDP sockets on validated endpoints

* fix(browser): avoid retrying rate-limited CDP discovery

* fix(browser): close Chrome MCP CDP policy gaps

* test(browser): match Chrome MCP policy error

* test(browser): satisfy transport type and lint checks

* fix(browser): narrow guarded CDP transport changes

* fix(browser): separate upload filesystem locality

* fix(browser): keep strict remote CDP hosts untrusted
2026-08-12 16:16:12 +05:30
Peter Steinberger 5350b92dc8 fix(browser): wake extension relay through gateway (#122537)
* fix(browser): wake extension relay through gateway

* fix(browser): preserve manual extension relay pairing
2026-08-12 02:13:03 -07:00
Shakker 0e78a64df5 fix: simplify session companion grounding 2026-08-12 03:26:33 +01:00
Shakker 70fbc35da2 fix: ground session companion context 2026-08-12 01:17:17 +02:00
Peter Steinberger 53407b154d fix(agents): remove stale media completion reply mechanics (#121937)
* fix(agents): remove stale media completion reply mechanics

Make generated image, music, and video completion wakes follow the current tool-agnostic visible-reply contract, preserving every structured attachment without NO_REPLY or transport-specific instructions.

Refs #121933.

* test(agents): remove stale media helper

Delete the unused assertion helper left behind by the table-driven generated-media completion coverage.\n\nRefs #121933.

* test(tooling): wait for profiler descendant pid

Require the PID file to contain a valid positive process ID before asserting profiler descendant cleanup, closing the create-before-write CI race.\n\nRefs #121971.
2026-08-11 02:29:05 -07:00
Marvinthebored bd897a6143 fix(exec): make timeout unit explicit (#119874)
* fix: exec timeout field does not state its unit, so callers pass milliseconds

`exec.timeout` is in seconds, but its sibling `yieldMs` is in milliseconds and
the `process` tool's identically named `timeout` is also in milliseconds. Those
two tools are used together in one workflow: exec backgrounds a long command,
then process polls it.

The unit exists only in the field description, and code mode deliberately defers
descriptions - the model sees `timeout?: number` and nothing else. A caller that
guesses milliseconds passes 900000 intending 15 minutes and gets ~10 days, so
the command never times out.

Add `timeoutSeconds` as the canonical field, matching the convention already
used by the config default (`tools.exec.timeoutSeconds`) and the sibling
(`yieldMs`). Keep `timeout` as a deprecated alias; `timeoutSeconds` wins when
both are supplied. Project the new field onto `nodeExecSchema`, which
hand-picks its properties.

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

* fix(ci): satisfy test-type and dependency checks

Two CI failures from the test approach, not the change itself.

- check-test-types: TypeBox's TOptional does not surface `description` on its
  static type, so the schema assertions failed under tsgo. Read it through a
  narrow accessor instead.
- check-dependencies: knip flagged resolveExecTimeoutSeconds as an unused
  export because only the test imported it. Move it beside the schema it
  resolves, where the exec runtime imports it, so it is production-reachable.

Verified with the same commands CI runs: `run-tsgo.mjs -p
test/tsconfig/tsconfig.core.test.json` reports no errors in these files, and
knip --production reports no unused exports.

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

* fix(ci): fit the exec description budget and satisfy oxlint

- `agent-tools.schema.test.ts` enforces a 550-char budget on the exec tool's
  model-facing descriptions; the two new ones pushed it to 640. Shortened both.
  The rename is what makes this possible: the unit now lives in the field name,
  so the description no longer has to carry it. Extended that budget test to
  pin `timeoutSeconds` alongside `timeout`.
- oxlint `no-base-to-string`: the test's description accessor typed the field as
  `unknown` and stringified it. Typed as `string | undefined` instead.

Verified: budget test passes (137 tests green across both suites), and all six
behavior tests still fail against origin/main.

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

* fix: remove the unit-ambiguous exec timeout field instead of deprecating it

Owner decision on the review's "ambiguous model-visible alias" finding: drop
`timeout` entirely rather than keep it as a deprecated alias.

Keeping it visible defeated the purpose. Code mode renders property names and
types and defers descriptions, so a model would still be offered a bare
`timeout` sitting next to a millisecond-based `yieldMs` and could still pick it.
A deprecation marker in a description the model never sees changes nothing.

Backward compatibility is not required here: every tool call is constructed
fresh by the model from the current schema, and a repository search found no
internal caller passing `timeout` to the exec tool. `timeoutSeconds` is now the
only exec timeout field, on both the main and node-only surfaces.

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

* fix: migrate the internal exec callers to timeoutSeconds

Removing `timeout` from the exec schema broke three real internal callers that
the earlier survey missed, plus two test files and the runtime's own reads.
`check-test-types` caught it; my local search had filtered `timeout:` matches to
lines mentioning "exec" and discarded these.

- src/auto-reply/reply/bash-command.ts
- src/auto-reply/reply/commands-diagnostics.ts
- src/auto-reply/reply/commands-export-trajectory.ts
  all passed `timeout: timeoutSec` and now pass `timeoutSeconds: timeoutSec`.
- bash-tools.exec-run.ts reads the field through the same typeof narrowing the
  third call site already used; `params` is loosely typed, so a raw read is
  `unknown`.
- Test fixtures updated. A vitest `waitFor({ timeout })` option in
  background-abort.test.ts is NOT an exec param and was left alone.

`run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json` now reports zero errors
in changed files; the 5 remaining `rejectSymlinks` errors are pre-existing on
main. 148 tests pass across the affected suites.

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

* docs: synchronize the exec config table with timeoutSeconds

Addresses the P2 finding. The tools.exec.timeoutSeconds row still described the
per-call override as `timeout` and `timeout: 0`, which no longer exist. The
only remaining bare `timeout` reference in this page is the deliberate
contrast with the process tool's millisecond field.

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

* fix: migrate the QA lifecycle caller and the shared ExecToolArgs contract

Two findings from the re-review of 6e8c3560e7, both real.

[P1] test/e2e/qa-lab/runtime/openclaw-exec-process-lifecycle.e2e.test.ts:174
still passed `timeout: 0.05`. After the removal that field is accepted and
ignored, so the call silently used the default timeout and could not produce
the asserted 50 ms `overall-timeout` result. Migrated.

[P2] ExecToolArgs in bash-tools.exec-request-preparation.ts:33 still declared
`timeout?: number` while the runtime reads only `timeoutSeconds`, offering
request-preparation users an accepted-but-inert argument. Renamed.

Why the typecheck missed both: ExecToolArgs is
`Record<string, unknown> & {...}`, and that index signature defeats excess
property checking, so a stale member produces no error at any call site. The
e2e file also sits outside the core test tsconfig I had been running locally.

Left alone deliberately: `processTool.execute({ action: "poll", timeout })` is
milliseconds and correct, and `createBashTool` in sessions/tools/bash.ts is a
separate tool surface with its own timeout.

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

* fix(test): update the node exec tool property assertion to timeoutSeconds

src/gateway/tool-resolution.exclude.test.ts:413 asserts the exact property list
of the node-forced exec tool and still expected "timeout". Renamed to match
nodeExecSchema.

Found by checks-node-compact-large-5; my local core-test tsconfig does not cover
src/gateway, so it did not surface there.

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

* fix: accept the legacy exec timeout as an undocumented alias

Removing the field from the schema does not reject it at runtime: the exec
schema accepts unknown properties, so a call built against an older schema was
accepted and then silently ignored, taking the default deadline instead of the
one it asked for.

Route every read through resolveExecTimeoutSeconds, which prefers the canonical
timeoutSeconds and falls back to a numeric timeout. The alias stays out of
execSchema, nodeExecSchema and ExecToolArgs, so no new caller can adopt it.

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

* docs: update the background-process guide to timeoutSeconds

The exec parameter table and the inheritance note still taught `timeout` and
`timeout: 0`, which kept the retired spelling publicly discoverable and
contradicted the exec guide.

`poll`'s own millisecond `timeout` is left alone; it is a different tool and a
different unit, which is the collision this rename removes.

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

* fix(exec): reject removed timeout field

* chore: regenerate plugin SDK API baseline

---------

Co-authored-by: Marvinthebored <262704729+Marvinthebored@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-10 20:02:53 -07:00
Peter Steinberger fada067277 feat(browser): add zero-click Chrome extension bootstrap (#121586)
* feat(browser): add zero-click extension bootstrap

Pre-register deterministic path-derived extension IDs and install a strict native messaging host.

Keep the popup and options UI minimal while removing the obsolete copilot and page-share flows.

* fix(browser): satisfy native bootstrap CI guards

* test(browser): isolate native bootstrap Chrome roots

* test(browser): flush native bootstrap profile before status

* test(browser): seed Linux native bootstrap identity

* fix(browser): preserve native bootstrap upgrade safety

Allow immutable root-owned package inputs while keeping mutable state, manifests, and launchers user-owned. Preserve all retired copilot keys whenever active or unrecognized recovery custody remains.

* fix(browser): preserve pending copilot custody

Retired cleanup now removes copilot state only when the durable registry is exactly empty. Any session, archive, malformed value, future shape, or read failure preserves every retired key.

* fix(browser): guard native bootstrap upgrades

Fail closed while retired copilot custody remains and make discard durable across partial failures.

Require exact launcher-embedded origins and repair full launcher drift without accepting mismatched registrations.

* fix(browser): remove stale layout export

* chore(release): leave changelog to release flow
2026-08-10 19:31:13 -07:00
Jesse Merhi d90e47783d fix(plugins): remove local dependency denylist (#101813) 2026-08-11 12:21:29 +10:00
Vito Cappello 9320bd379e fix(ollama): enable cloud max thinking (#121074)
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
2026-08-10 19:06:54 -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 bdf202ccc8 feat(skills): reconcile learned skill collections (#121653)
Replace divergent per-skill curation with one daily isolated collection review that can consolidate, rewrite, create, and drop writable skills atomically.

Autonomous auto mode remains automatic. Adds bounded review, transactional recovery, durable cadence, shared locking, and reuse-first /learn behavior.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-11 02:06:26 +05:30
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
Ayaan Zaidi 2d627a0c25 feat(skills): repair used skills in turn (#121522)
* feat(skills): repair used skills in turn
* fix(skills): bind repair to used skill receipt
* fix(skills): preserve explicit repair review

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-10 14:42:41 +05:30
Ayaan Zaidi 7d4d02fff0 feat(skills): improve used skills autonomously
Teach the semantic reviewer to improve skills the agent actually used, keep review input provider-bound, and preserve bounded deterministic retries.

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-08-10 13:50:33 +05:30
Peter Steinberger 914f73ac99 docs: replace retired config keys with canonical schema keys (#121330) 2026-08-09 20:30:43 -07:00
Peter Steinberger f44c5e2e5e fix(plugins): surface manifest-only bundled capabilities (#121354)
Use a manifest-first inventory with independent coverage for manifest-only bundled capabilities.

Retire the undocumented thread-ownership plugin while Doctor removes stale references.

Document Talk voice and persist only provider-scoped voice selection.

Closes #121353
2026-08-09 19:43:49 -07:00
Peter Steinberger 8362f74c99 feat(browser): add all-tabs extension access (#120995)
* feat(browser): add all-tabs extension access

* fix(browser): preserve cancel revocation during startup

* test(browser): align all-tabs Chromium fixtures
2026-08-09 03:15:54 -07:00
Peter Steinberger 6f94e7b23d docs: clarify OpenAI fast mode precedence (#120682) 2026-08-08 13:14:10 -07:00
Peter Steinberger 88975f85ea fix: required background completion silently disappears (#120453)
* fix(agents): surface silent required completions

* refactor(agents): simplify completion fallback handling

* fix(agents): require visible completion delivery

* fix(agents): preserve resolved session patches

* fix(agents): bound resolved session patch output

* fix(agents): reject silent automatic completions

* fix(agents): settle committed completion side effects

* fix(agents): retain ultra thinking profile

* fix(agents): require destination-safe completion evidence

* fix(agents): block invisible completion side effects

* fix(agents): preserve outbound no-replay evidence

* fix(agents): preserve resolved session identifiers
2026-08-08 07:52:12 -07:00
wonfong 9fdc266f64 fix(subagents): wake the parent when a follow-up finishes a yielded child (#120187)
* fix(subagents): wake the parent when a follow-up finishes a yielded child

A sub-agent that calls sessions_yield on its own behalf parks its run and
correctly withholds the parent's announce. But a later follow-up to that same
child session registered a sibling registry row instead of continuing the paused
one, so the requester defaulted to the child's own main session and the original
parent — itself idle behind sessions_yield — was never woken. The paused row also
stayed an unsettled descendant, deferring the parent's settle batch forever with
nothing recorded explaining the silence.

Follow-up dispatch now adopts the paused row through the existing post-steer
replacement seam, inheriting the requester identity and carrying the settle-wake
credential forward with its frozen batch membership remapped to the new run id.
A follow-up that names its own requester keeps registering separately, since an
explicit requester is a delivery opt-in that adoption would silently drop.

Also stops frozen-result refill from targeting paused rows: a yield clears the
result on purpose, so refilling from the session would attribute a later turn's
text to the paused run.

Closes #120157

* fix(subagents): select the paused owner past a requester-bound sibling

Adoption looked up the newest run for the child session and adopted it only
when that row was itself paused. A requester-bound follow-up deliberately stays
a sibling, but it registers at a higher generation and becomes that newest row,
so any later default follow-up saw an unpaused newest row, declined adoption,
and registered yet another sibling. The original requester stayed parked behind
a paused row that can never announce -- the same silent stall this fix exists to
remove, reached through a valid mixed-delivery sequence.

The latest-run query now takes an optional predicate applied before the
generation comparison, so a caller that owns a specific row class selects the
newest row of that class. Adoption asks for the newest `sessions_yield` row
directly instead of inferring it from generation order.

Docs now state that continuation applies to default delivery, since a follow-up
carrying its own requester runs as a sibling by design.

* test(qa): prove post-yield follow-up delivery through the gateway boundary

The unit and gateway-method tests for paused-run adoption assert on registry
rows, which proves the bookkeeping but not that an operator ever sees the
result. This adds the boundary proof: a real gateway child, the QA mock channel,
and the mock provider driving a subagent that pauses itself and finishes only on
a later follow-up.

A fixture plugin owns both legs. Its `before_dispatch` hook spawns the child with
`completionDelivery: "current-requester"`, so the announce has the operator turn
as its audience. An HTTP route then dispatches the follow-up to that same paused
session using default delivery -- the path adoption is meant to catch. A
requester-bound follow-up would opt into its own audience and run as a sibling
instead, so the two legs must differ here.

The mock provider gains a child that yields on its own behalf. Both of its turns
match on the current prompt rather than the shared transcript, so the yielded
kickoff cannot make the follow-up turn yield a second time.

The scenario asserts both sides of the invariant: no outbound traffic while the
child is paused, and exactly one announce carrying the follow-up marker once it
ends.

Reverting the adoption call site fails this test in the way that matters: the
child still produces its marker and the run still ends with stopReason=stop, but
nothing reaches the requester and the wait times out. The result is computed and
then silently dropped -- which is the failure this repair exists to remove.

* fix(ci): match QA Lab fixture plugin entries as a group in knip

The all-exports pass listed one fixture entry by name, so every new QA Lab
fixture plugin lands as an unused file and turns check-dependencies red until
someone remembers this file. Nothing imports these entries by design: the
Gateway E2E loads them through plugin config paths.

* docs(subagents): scope yield continuation to plugin runtime follow-ups

Adoption is gated on plugin_subagent task tracking, which only
createGatewaySubagentRuntime().run sets, so api.runtime.subagent.run is the
sole route into it. Writing that as one example implied other follow-up paths
to a paused session continue the run too; they are not tracked as sub-agent
runs and announce nobody.

* fix(subagents): reject undurable paused-run adoption

Fail plugin follow-up admission closed when the paused-run ownership swap cannot be persisted, while retaining the existing restart-recovery return-false contract. Trim duplicate tests and keep boundary coverage for requester routing, wake-batch remapping, repeated yield, and persistence rollback.

Co-authored-by: zhou.huanfeng <woundfongv3@163.com>

* docs(subagents): clarify yielded-run steering

Co-authored-by: zhou.huanfeng <woundfongv3@163.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-08 06:46:19 -07:00
Peter Steinberger 83900e4683 feat(browser): add relay authentication v2 (#120526)
* feat(browser): add relay authentication v2

* fix(browser): cap relay test WebSocket payload

* fix(browser): keep relay E2E inside extension boundary

* fix(browser): isolate relay admission and cleanup auth

* fix(browser): finish relay auth migration hardening

* fix(browser): keep preauth transport bounded through teardown
2026-08-08 05:48:24 -07:00
Peter Steinberger 947bca5608 fix(browser): harden extension relay authorization (#120390)
* fix(browser): harden extension relay authorization

* fix(browser): validate persisted relay pairing
2026-08-07 21:56:15 -07:00
Peter Steinberger 2c5214f9e8 fix(mcp): listen on the OAuth loopback redirect during mcp login (#120433) 2026-08-07 19:29:13 -07:00
Peter Steinberger 96a75be170 fix(discord): default preview streaming to off (#120376)
Make Discord progress drafts and activity receipts explicit opt-ins while preserving configured streaming modes and legacy explicit progress migrations. Related: #87704.
2026-08-07 17:18:12 -07:00
Peter Steinberger b99c507ce6 docs(plugins): include Agent Plugins in the plugins page read-when hints (#120323) 2026-08-07 12:35:03 -07:00
Peter Steinberger 8994c7799b fix(agents): subagent hard-deny list cannot be overridden by allow config (#120025)
* fix(agents): make subagent hard-deny list non-overridable and deny message tool

The always-deny list for subagent sessions (gateway, cron, message, sessions_send,
conversations_*) could be overridden by ordinary allow/alsoAllow config entries,
letting a configured subagent profile re-enable direct user delivery outside the
announce chain. The hard-deny layer now applies unconditionally; message joins the
list so resumed/visible subagent sessions cannot send directly either (hidden
launches already disabled it at spawn time).

* chore: re-fire CI

* chore: re-fire CI against fixed main baseline

* test(agents): workspace authority reflects non-overridable subagent deny list

The delegating-worker rejection case relied on alsoAllow bypassing the
subagent hard-deny list; with the bypass closed the policy owner blocks
sessions_spawn and the worker stays confined, so the guard has nothing to
reject.
2026-08-07 03:58:02 -07:00
Peter Steinberger f4387b7a5e feat(plugins): support the Agent Plugins bundle format (#120115)
* feat(plugins): support the Agent Plugins bundle format

* docs(plugins): document the Agent Plugins bundle format

* test(agents): preserve agent bundle runtime discovery

* fix(plugins): isolate Agent Plugins data-dir failures and align MCP support reporting

* docs(plugins): list Agent Plugins in the canonical plugin-format guides

* fix(plugins): gate Agent Plugins detection on schema, pure inspection, root-relative cwd

* fix(plugins): record Agent Plugins data-dir ownership explicitly

* docs(plugins): cover Agent Plugins in the CLI install detection guide

* fix(plugins): carry Agent Plugins data-dir and transport contracts through external MCP projections
2026-08-07 02:55:08 -07:00
Vito Cappello 5621979a46 fix(models): preserve session selection across fallback turns (#119325)
* feat(models): add session-only model selection

* fix(models): use trailing session scope option

* test(models): satisfy session scope lint

* fix(models): reject duplicate model options

* fix(models): clarify default and session scope

* fix(models): require complete session option tokens

* fix(models): report configured default dispatch

* fix(models): keep directive handler within lint limit

* fix(models): parse model options in either order

* fix(models): apply session scope to aliases

* fix(models): align alias scope with reply routing

* fix(discord): surface model selection scope in picker

* fix(models): preserve mixed-text model selection

* fix(models): centralize command selection ownership

* fix(models): align session scope lifecycle

* fix(models): preserve command and auth ownership

* fixup! fix(models): preserve command and auth ownership

* fix(auth): preserve scoped CLI provider discovery

* test(models): align result and cron fixtures

* test(models): nest result timing metadata

* fix(discord): narrow silent dispatch results

* fix(transcript): preserve admitted turn identity

* fix(context-engine): fence the admitted transcript turn

* fix(context-engine): stabilize plugin compatibility contract

* chore(plugin-sdk): refresh context engine API baseline

* chore(plugin-sdk): use Linux context engine API baseline

* fix(context-engine): align fallback ownership

* fix(fallback): scope auth skip cache by profile

* fix(context-engine): settle only accepted fallback turns

* refactor(sessions): issue canonical turn admissions

* refactor(context-engine): own logical turn advancement

* fix(context-engine): settle cron fallback winners

* fix(models): align picker and fallback transactions

* fix(delivery): notify block admission after queueing

* fix(sessions): preserve canonical admission receipts

* chore(plugin-sdk): refresh API baseline hash

* fix(context-engine): commit accepted turns durably

* fix(context-engine): validate durable host transitions

* fix(context-engine): preserve fallback turn ownership

* fix(context-engine): preserve queued turn order

* fix(models): preserve fallback retry ownership

* fix(context-engine): enforce durable transcript anchors

* fix(runtime): close fallback persistence gaps

* fix(context-engine): preflight fallback harnesses

* chore(plugin-sdk): use Linux API baseline

* fix(context-engine): drain durable commits before reads

* fix(models): scope harness auth failures by profile

* fix(codex): fence legacy transcript history

* fix(commands): honor suppressed directive interpretation

* chore(runtime): remove unused branch exports

* test(context-engine): derive private outbox payload type

* fix(context-engine): apply durable drain degradation

* fix(context-engine): recover durable turn intents

* fix(context-engine): settle durable turn intents

* refactor(context-engine): satisfy branch quality gates

* fix(context-engine): close durable recovery gaps

* fix(discord): preserve dropped model command outcome

* test(copilot): keep journal fixture types local

* fix(auto-reply): preserve model alias provenance

* fix: close model scope review gaps

* fix(models): close review-found scope leaks

* fix(review): satisfy branch line budgets

* fix(agents): preserve context engine turn facts

* fix(agents): finalize silent context turns

* fix(context-engine): preserve compatibility window

* test(agents): cover both harness preparations

* fix(context-engine): retain blocked turn advancements

* fix(models): parse compact runtime options

* fix(telegram): report runtime resets accurately

* fix(models): isolate automatic auth failure skips

* fix(context-engine): project commit turn host params

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-08-07 16:19:12 +08:00
Peter Steinberger 804ae7f121 fix(security): stop recommending retired install-policy bypasses (#120011)
* fix(security): align install policy path contract

* test(security): align install policy wording

* style(security): format install policy test

* fix(security): identify failing install policy path

* test(security): track Windows ACL temp dirs
2026-08-06 18:45:18 -07:00
Peter Steinberger 01281ad9f8 refactor(browser): remove model-backed page extraction (#120101)
* refactor(browser): remove model-backed extraction

* docs(browser): remove stale extract reference
2026-08-06 18:32:14 -07:00
Ayaan Zaidi 90e39c49e4 feat(skills): reviewer patch contract, active learning bias, shallow-turn accumulation
Self-learning reviewer edits existing skills via targeted patches: it quotes the exact live text (or appends a section) and the service composes the full body inside the receipt-pinned read that hash-binds the proposal — untouched content survives by construction, and patches auto-apply through the scanner-gated pipeline. Full-body rewrites and oversized-skill edits stay pending for the operator. The review prompt shifts to active capture within the existing evidence gates, and shallow same-sender turns accumulate per session (provider-identity scoped, zero-iteration and duplicate-run contracts honored, aborted provenance carried, bounded state) so quick corrections get reviewed with their own transcripts. Replaces closed #119856.
2026-08-06 17:52:03 +05:30
Onur Solmaz 1f10ef8050 fix(agents): recover once from critical tool loops (#118647)
* feat(agents): add bounded tool-loop recovery

* feat(agents): wire loop detection into batch recovery

* test(agents): cover bounded tool-loop recovery

* fix(agents): enforce loop thresholds within tool batches

* fix(agents): retain rejected loop batch evidence

* test(agents): update embedded session recovery fixture

* fix(agents): surface terminal loop recovery failures

* fix(agents): preserve loop recovery across retries

* fix(agents): isolate rejected loop evidence

* fix(agents): terminate native critical tool loops

* fix(agents): canonicalize tool loop actions

* fix(agents): preserve tool loop recovery guidance

* fix(agents): preserve code mode tool identity

* fix(agents): preserve prebatch loop evidence

* fix(agents): order native loop termination

* fix(agents): clean up rebased tool validation

* fix(agents): interrupt codex side turns on critical tool loops

* fix(agents): tighten loop recovery batch lifecycle

* fix(agents): drop unconsumed loop detector type export

* fix(agents): drop unconsumed loop relay exports

* test(agents): add agent subscribe to embedded session doubles

* fix(agents): scope critical loop recovery to embedded runs
2026-08-06 14:09:10 +08:00
Ayaan Zaidi 874c63318b fix(skills): remove regex correction capture; self-learning is reviewer-only
Deletes the deterministic regex capture path that templated raw chat text into skill proposals (junk like a proposal whose whole procedure was one slugified user message). All autonomous learning now flows through the isolated experience reviewer: it sees a bounded workspace skill list, prefers revising pending proposals or updating the governing skill over creating new ones, and treats durable user corrections as first-class evidence. Update proposals are reviewer-only (explicit opt-in) and never auto-apply, since the reviewer drafts them without the live skill body. Removes the producerless pending-suggestion session machinery. Regression test proves the junk path is gone; real-Telegram E2E verdict in the PR body.
2026-08-06 11:01:59 +05:30
Jerry-Xin b8f6086411 fix(tts): deliver Telegram final speech without text churn
Defer Telegram final-mode text until speech settles, then deliver one captioned voice note or a proven-safe text fallback.

Co-authored-by: Jerry-Xin <jerryxin0@gmail.com>
2026-08-06 10:41:40 +05:30
Jesse Merhi 95d7d95515 feat(tools): support batched tool search queries (#118623)
* feat(tools): support batched tool search queries

* fix(tools): harden batched tool search

* fix(tools): preserve batch search contracts

* fix(tools): bound batch search processing

* fix(tools): bound batch candidate metadata

* fix(tools): preserve callable batch candidates

* docs(tools): align batch search QA proof

* refactor(tools): isolate search request parsing

* test(qa): strengthen structured search proof

* test(qa): align structured directory proof

* fix(tools): preserve scalar search compatibility

* test(qa): disable batch scenario retries

* test(qa): allow direct-only tools in structured proof

* test(qa): verify nested catalog call result

* test(qa): remove obsolete result scanner
2026-08-05 16:28:10 +10:00
Ayaan Gazali 347398311a docs: fix stale 2gb session disk budget default on chrome extension page (#110624) 2026-08-04 05:24:23 +08:00
joshavant d9393bd3cb fix: make subagent completion delivery durable 2026-08-03 02:48:34 -05:00
Peter Steinberger e04caa6aee fix(openai): support flexible GPT Image 2 dimensions (#118476)
* fix(openai): support flexible GPT Image 2 dimensions

* docs(openai): explain flexible GPT Image 2 dimensions
2026-08-02 22:40:07 -07:00
Peter Steinberger e9d88696b5 feat(cron): add webhook SSRF policy (#118237) (#118286) 2026-08-02 17:02:20 -07:00
Jason (Json) 01565bdc47 fix(agents): make requested threads sidebar-visible (#118073)
* fix(agents): make requested threads sidebar-visible

* fix(agents): preserve visible spawn authority
2026-08-02 14:26:24 -06:00
Peter Steinberger 4133fe925f docs(browser): note mcporter auto-detects the extension relay (#118066)
Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-02 09:51:06 -07:00
Vincent Koc 2844876be3 fix(google): align unsupported CLI auth paths (#118034) 2026-08-03 00:13:19 +08:00
Peter Steinberger f599ff520d feat(browser): relay CDP compat for Puppeteer clients (chrome-devtools-mcp) (#117915)
* feat(browser): relay CDP compat for Puppeteer clients

Answer Target.getBrowserContexts with the always-empty context list so
puppeteer.connect() (chrome-devtools-mcp) can drive the paired Chrome
through the extension relay without the remote-debugging prompt. Serve
DevTools-style /json/list descriptors (id + type), which also makes the
HTTP tab-list fallback see extension-profile tabs, and add
`openclaw browser extension cdp` to print the relay endpoint and auth
header for external CDP clients.

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

* fix(browser): avoid map-spread in relay target descriptors

oxc(no-map-spread): build the /json/list descriptor object explicitly
instead of spreading RelayTabInfo inside map().

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

---------

Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-02 01:59:44 -07:00
Vincent Koc fb087bf947 fix(agents): identify Tool Search counter lifetimes (#116070)
* fix(agents): scope Tool Search telemetry counters

* fix(agents): keep tool-search scopes visible

* docs(tool-search): document counter scopes

---------

Co-authored-by: Peter Steinberger <steipete@macos.shared>
2026-08-01 22:50:16 -07:00
Jesse Merhi 8b21c23cc2 feat(web-fetch): add tools.web.fetch.headers for operator request headers (#115545)
* feat(web-fetch): add tools.web.fetch.headers for operator request headers

* docs(web-fetch): update cache discriminator comment

* fix(web-fetch): reserve runtime and cookie headers

* fix(web-fetch): harden operator header normalization

* fix(web-fetch): align header safety contracts

* fix(web-fetch): close header logging gaps

* fix(web-fetch): report case-colliding headers

* fix(web-fetch): reject stale colliding headers

* fix(web-fetch): refuse credential token aliases

* fix(web-fetch): preserve empty header values

* fix(web-fetch): refuse credential-shaped headers

* chore(config): refresh web fetch header baselines

* test(web-fetch): cover header security contracts

* fix(web-fetch): narrow credential header refusal

* fix(web-fetch): preserve trace metadata headers

* fix(web-fetch): keep header validation internal

* test(web-fetch): satisfy strict test contracts

* fix(web-fetch): refuse vendor credential headers

* fix(web-fetch): refuse authentication signatures

* fix(web-fetch): detect qualified auth signatures

* fix(web-fetch): refuse auth-suffixed headers

* fix(web-fetch): refuse compact credential headers

* fix(secrets): audit authentication signatures

* fix(web-fetch): redact operator headers in captures

* fix(web-fetch): keep capture metadata internal

* fix(web-fetch): allow sensitive operator headers

* test(web-fetch): cover normalized operator headers

* docs: note web fetch request headers

* chore(config): refresh web fetch header baseline

* chore: remove release-owned changelog entry
2026-08-02 02:07:25 +10:00
Jesse Merhi d3f4530ce8 feat(google): allow operator headers on Gemini web search (#115549)
* feat(google): support Gemini web search headers

* fix(google): validate Gemini search headers

* docs(changelog): credit Gemini headers

* test(secrets): route config contracts through collector

* chore: remove release-owned changelog entry

* test(google): cover resolved search headers
2026-08-02 01:41:09 +10:00