Commit Graph

3124 Commits

Author SHA1 Message Date
Josh Avant a042125170 fix(memory): preserve provenance across dreaming (#126489)
* fix(memory): preserve provenance across dreaming

* fix(build): preserve bundled hook metadata

* refactor(build): remove obsolete directory helper

* test(memory): align provenance fixtures

* test(memory): type consolidation run options

* test(memory): register write provenance siblings

* fix(memory): preserve legacy provenance registration

* fix(memory): make provenance provider-independent

* fix(memory): canonicalize provenance workspace keys

* fix(memory): keep provenance mutation host-private

* fix(build): track runtime postbuild implementations

* fix(build): verify bundled hook metadata outputs
2026-08-20 17:58:31 -07:00
Sarah Fortune 67bcea131e feat(slack): add compact commentary progress (#126480)
* feat(slack): add compact progress style

* chore(slack): protect compact progress contract

* chore(slack): clarify compact progress comment

* chore(slack): document compact task card behavior

* chore(slack): document compact draft card behavior

* chore(slack): document compact progress config contract

* fix(slack): enforce compact commentary-only progress

* chore(slack): strengthen compact style guard

* fix(slack): type compact progress config

* fix(slack): scope compact plan suppression

---------

Co-authored-by: Sarah Fortune <sarah.fortune@gmail.com>
2026-08-20 15:02:33 -07:00
Dallin Romney 2f602fd382 fix(plugin-sdk): deduplicate API diff declarations (#126725) 2026-08-20 11:31:48 -07:00
Peter Steinberger 8b448439b6 fix(plugins): retire executable plugin caches on metadata lifecycle clears (#126719)
Plugin install, replacement, and uninstall clear process memos through
registerPluginMetadataProcessMemoLifecycleClear, but four executable-
authority caches never registered, so retired plugin callbacks kept
executing after the registry moved on:

- createConfigScopedPromiseLoader (document/web-content extractor lists)
  now self-registers its clear at the factory, so no caller can leak
  resolved plugin callbacks past a lifecycle change.
- Provider policy surface maps (bundled + external, including cached
  negative entries) clear on lifecycle changes.
- Public surface loader now drops module exports, loader closures, and
  native require cache entries, not just resolved locations.
- SDK facade loader registers the same clear for facade exports and
  loader state; imported-plugin history is preserved as diagnostics.

The tracked-roots + native-require eviction pattern from provider
discovery is extracted into clearPluginModuleLoaderLifecycleCache and
reused by provider discovery, doctor contracts, the public surface
loader, and the facade loader, removing two near-copies.

Regression tests fail pre-fix: replaced or uninstalled plugin callbacks
must not run after clearPluginMetadataLifecycleCaches, proven down to
on-disk artifact replacement through the native require chain.
2026-08-20 08:58:05 -07:00
Vito Cappello 1b9d3ac57d fix(claude-cli): apply thinking and keep live sessions warm (#125528)
* fix(models): preserve CLI runtime thinking capabilities

* fix(models): preserve configured thinking overrides

* fix: keep Claude live CLI process warm across captured turns

MCP delivery capture no longer kills the warm Claude process after every
turn. Capture-key admission is fenced by grant activate/deactivate so
prompt-cache continuity can survive across messages.

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

* fix(claude-cli): apply thinking levels

* fix(claude-cli): materialize thinking capabilities

* test(claude-cli): cover warm thinking budget reuse

* test(models): restore prepared catalog contracts

* fix(agents): restore catalog test boundaries

* fix(agents): break prepared catalog import cycle

* refactor(gateway): extract model-choice runtime resolution into public-projection module

Keeps models-list-result.ts under the max-lines cap after the origin/main
merge by moving resolveModelChoiceAgentRuntime next to the projection
helpers it feeds.

Claude-Session: https://claude.ai/code/session_01QXUQuDVataA5o16kxNnmoX

* test(claude-cli): cover thinking cache reuse

* test(claude-cli): cover captured live reuse

* fix(claude-cli): rotate MCP grants across live turns

* fix(anthropic): respect mandatory adaptive thinking

* fix(claude-cli): restore warm MCP bearer

* fix(anthropic): keep Mythos adaptive thinking

* test(claude-cli): prove live MCP cache reuse

* test(claude-cli): align live cache coverage

* fix(claude-cli): reuse live sessions across MCP grant rotation

* test(claude-cli): satisfy cache lane static gates

* fix(claude-cli): preserve runtime thinking policy

* fix(thinking): honor concrete runtime policy

* fix(gateway): honor mandatory thinking in model list

* refactor(auto-reply): extract prepared catalog merge

* docs(cli-backend): document thinking execution input

* refactor(auto-reply): extract catalog lookup helper

* style(auto-reply): format catalog helper import

* fix(claude-cli): stabilize live context budget

* fix(auto-reply): type prepared context metadata

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-20 06:44:49 -07:00
Peter Steinberger 147edf47f3 fix(auth): keep a retired auth JSON from stranding a migrated store (#126562)
* fix(auth): keep a retired auth JSON from stranding a migrated store

Runtime failed closed with AUTH_PROFILE_MIGRATION_REQUIRED whenever a retired
credential file was present, even when the canonical SQLite store already held
the agent's profiles. One leftover auth.json therefore made a fully migrated
install unusable, and the gateway lifecycle preflight refused start/restart on
top of it, so every channel and provider stayed offline until Doctor ran.

A legacy file is now only fatal when the canonical store cannot serve
credentials. Doctor's importer never overwrites a usable stored credential, so
a file sitting beside a populated store is unarchived bytes, not pending
migration: runtime logs a one-time warning and keeps serving. An empty store
with a credential file still fails closed and never falls through to
environment auth. Startup degrades that owner to configured-unavailable
instead of refusing to boot, which lets the lifecycle preflight go away.

* refactor(secrets): retire the auth-profiles.json vocabulary

Auth profiles moved to SQLite, but operator-facing surfaces still named the
retired JSON file. The duplicate-agentDir error told operators to copy
auth-profiles.json to share credentials, which does nothing and lands the
second agent in a migration-required state; `openclaw migrate plan codex`
reported a target file that is never created; and the secrets picker labelled
candidates with a filename that no longer exists.

Renames the SecretTargetConfigFile discriminator to "auth-profile-store" and
corrects the operator-facing text, the migrate plan target, and the docs that
described the file as a live target. Genuine legacy-filename uses in doctor,
the security fixer, and migration fixtures are unchanged.

Also deletes resolveSecretPlanTargetByPath and ResolvedSecretPlanTarget from
the plugin SDK. They have no callers in core, plugins, or tests, and the
symbols are absent from the latest stable tag, so they carry no compatibility
obligation and are removed rather than deprecated. Their inline parameter type
was the only thing putting the retired filename on the public SDK surface.

* improve(wizard): warn about device-code phishing

The device-code prompt only warned against sharing the code, and only when an
expiry was known. Device-code phishing works the other way around: the attacker
starts the login and gets the victim to enter the attacker's code. Codes
delivered over a chat channel are the risky case and carry no expiry hint, so
the warning is now unconditional and covers received codes, matching the Codex
CLI prompt.

Also documents the Codex auth handoff: a subscription profile is installed as
in-memory external auth rather than persisted, and token refresh is inverted
so the refresh token stays in OpenClaw's store.

* fix(test): make transcript read-failure injection order-independent

server.sessions.compaction-read-errors.test.ts injected its failures with
mockRejectedValueOnce, which fails the NEXT call to loadTranscriptEvents
globally. Under --isolate=false a shard shares one worker, so any sibling
transcript read could consume the one-shot rejection before the compaction RPC
issued its own; compaction then ran against the real reader and returned ok,
failing three assertions. This shard was already red on main; a prior repair
fixed the mock's initialization order but left the call-order dependency.

Key the injection on the seeded sessionId instead, so unrelated readers cannot
consume it and the re-read case counts only its own session's reads.

Also updates two expectations invalidated by this branch: the duplicate-agentDir
remediation text, and the plugin SDK export ratchet, shrunk by the two retired
secret-plan exports.
2026-08-20 00:42:41 -07:00
Peter Steinberger 966c233dcc refactor(sessions): remove thinking selection provenance (#126561)
* refactor(sessions): remove thinking selection provenance

* test(gateway): fix shared-worker reasoning cleanup

* test(gateway): avoid shared-worker merge overlap
2026-08-20 00:38:45 -07:00
Peter Steinberger 75fcb1fbb9 fix(memory): reject unknown --agent ids and keep the hint runnable (#126570)
The memory CLI resolved --agent by returning the caller's string verbatim,
so an id that is not configured produced a confident empty result:
`memory status` rendered a panel for it, `memory index` fabricated a
workspace-<id> path, and `memory search` reported No matches. A typo read
as an empty memory rather than a nonexistent agent, while hooks, status
--usage, capability, migrate, and session targets already rejected unknown
ids.

Consolidate that duplicated check into resolveConfiguredAgentId beside the
agent roster owner, reuse it at the matching core sites, and route memory
to it through the existing memory-core host-runtime facade so no new
plugin SDK surface is added.

The canonical hint uses formatCliCommand rather than a literal: under a
profile or container the bare command is wrong, so consolidating on a
literal would have regressed the hooks and migrate hints and left the
status, capability, and session-target hints unrunnable.
2026-08-20 00:32:59 -07:00
Peter Steinberger 1b6c42d1f0 refactor(openai): unify ChatGPT auth identity derivation in plugin SDK (#126544)
The OpenAI ChatGPT auth profile identity was derived in two drifted copies:
the plugin-sdk helper (used by Codex/Hermes import migrations) fell back to
bare JWT sub and leaked the workspace accountId into the user subject, while
the openai extension copy (used by login/refresh) composed the OIDC-stable
iss|sub pair and honored the credential email fallback.

Fold the extension's chain into the canonical SDK helper (credential-email
fallback, iss|sub before bare sub, no workspace-id subject), delete the
extension copy, and move all extension call sites onto
openclaw/plugin-sdk/provider-auth. Cross-checked against Codex OSS
(codex-rs/login/src/token_data.rs): chatgpt_account_id is workspace identity,
never user identity. No doctor migration: the divergent fallback branch only
fires for tokens lacking every user-id claim and email, which real ChatGPT
tokens do not produce, so no shipped install holds divergent keys from it.
2026-08-19 23:48:43 -07:00
Peter Steinberger efc33f882e fix: preserve GPT-5.6 Max and Ultra through Codex (#126492)
* fix(agents): preserve GPT-5.6 thinking capabilities

Carry harness-owned effort metadata from the prepared catalog to the final executable model without leaking it across model or harness changes. Preserve exact GPT-5.6 registry metadata and persisted Ultra selections across route-scoped projections.

* fix(agents): resolve ambient catalog owner

* test(commands): mock thinking hydration policy

* fix(sessions): validate persisted thinking selections

* fix(commands): persist thinking selection provenance

* fix(agents): scope thinking hydration per fallback

* fix(sessions): hide fallback thinking provenance
2026-08-19 21:48:18 -07:00
Peter Steinberger 35e0bc22ea fix(memory): distinguish missing file reads (#125979)
* fix(memory): distinguish missing file reads

* test(memory): keep adapter identity assertion bound

* fix(memory): preserve statusless manager reads
2026-08-19 20:08:50 -07:00
Josh Avant 29cfd195d1 fix(memory): honor turn tool policy during automatic recall (#126482)
* fix(memory): bind prompt recall to turn tool policy

* test(plugins): update hook contract inventory

* fix(memory): bind recall to active run lifecycle

* docs(plugins): define prompt authority contract

* test(plugins): track prompt authority type guard

* fix(plugins): revalidate prompt authority per handler
2026-08-19 19:21:51 -07:00
Peter Steinberger 0961247d94 fix(discord): route polls through canonical delivery (#126250)
* fix(discord): route polls through canonical delivery

* test(discord): align canonical poll action coverage

* test(gateway): isolate canonical poll fallback coverage

* fix(gateway): align canonical poll capability
2026-08-19 18:07:21 -07:00
Peter Steinberger 8b15dc9447 refactor: share media and process runtime helpers (#126490)
* refactor(media): share video description requests

* refactor(process): expand buffered runtime options
2026-08-19 17:48:49 -07:00
Peter Steinberger 7e0b599ca4 fix: surface Codex input prompts across runtimes (#126387)
* fix: surface Codex input prompts across runtimes

Codex structured input now reaches bounded Gateway questions in native and ACP runs, with exact turn ownership, explicit unsupported outcomes, and cancellation fencing. Consume the published ACPX elicitation support.

* chore: align elicitation helpers with current guards

Use protocol-specific helper names required by current main and update the reservation regression to the generalized input owner.

* fix: formalize structured input SDK surface

Expose one documented, frozen agent-harness structured-input contract with runtime and subpath coverage, replacing the accidental function-property API.

* fix: satisfy elicitation architecture gates

Register the real-process ACPX fixture as an executable test root and move shared structured-input types into the boundary leaf to keep Knip and Madge clean.

* fix: remove structured input lint suppression

Preserve the rejected control and invisible-character ranges with an explicit code-point check so the production suppression inventory stays closed.
2026-08-19 15:25:33 -07:00
Steven ff37627804 fix(discord): resolve realtime voice API key references (#125443)
* fix(discord): resolve realtime voice SecretRefs

* fix(discord): isolate realtime voice secret owners

* fix(discord): contain realtime secret owner gate

* fix(build): align plugin SDK boundary paths

* fix(discord): normalize realtime secret owner accounts

* fix(discord): gate canonical realtime secret owners

* style(discord): format realtime voice tests

* test(codex): assign run-attempt tools shard

* fix(discord): skip unavailable realtime providers

* fix(discord): preserve realtime provider availability errors

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-19 15:23:14 -07:00
Peter Steinberger 0135046830 refactor(llama-cpp): use one provider for managed and existing servers (#126434)
* refactor(llama-cpp): unify server ownership modes

* test(llama-cpp): preserve shared discovery limits

* fix(plugin-sdk): retain provider auth removal export
2026-08-19 13:57:33 -07:00
Peter Steinberger db533799d5 fix(qa): reject incomplete evidence runs (#126407)
* fix(qa): enforce terminal evidence lifecycle

* test(qa): mark CPU fixture summary completed

* fix(qa): fence calls after flow timeout
2026-08-19 13:30:02 -07:00
Peter Steinberger 8a9e21d3bc fix(providers): prevent malformed streamed tool calls (#126391)
Co-authored-by: 曾令彪 0668001395 <zeng.lingbiao@xydigit.com>
2026-08-19 11:30:09 -07:00
Peter Steinberger 6267703b30 refactor(canvas): share eligible node selection (#126374) 2026-08-19 10:51:02 -07:00
Michael Appel 62a97ae4f4 fix: decode NAT64 embedded IPv4 prefixes [AI] (#123241)
* fix: decode NAT64 embedded IPv4 prefixes

* test: update NAT64 SSRF fixtures

* fix: check NAT64 local-use candidates

* fix: decode NAT64 local-use prefix directly

* fix: block NAT64 local-use allocation

* fix: block trusted NAT64 local-use rebinding

* docs: note NAT64 exact-origin block

* fix: block trusted local-use NAT64 labels

* docs: clarify NAT64 private-network opt-in

* fix: keep NAT64 block before proxy exemptions

* fix: explain local-use NAT64 provider opt-in

* fix: keep local-use nat64 out of gateway trust

* test: exercise nat64 configured-origin trust
2026-08-19 06:24:31 -07:00
Peter Steinberger 30337c8962 fix(qa-lab): include plural execution channels (#126140)
* fix(qa-lab): include plural execution channels

* chore(qa-lab): register browser error adapter

* fix(qa-lab): keep browser errors within boundaries

* fix(qa-lab): redact browser error credentials

* fix(sessions): drain sqlite writers during test cleanup

* fix(sessions): scope sqlite test handle cleanup

* test(codex): dedupe run attempt tools shard

* test(codex): converge run attempt tools shard
2026-08-19 01:17:22 -07:00
Peter Steinberger 3378e07d50 refactor(plugin-sdk): promote shared runtime primitives (#126193)
* refactor(plugin-sdk): promote shared runtime primitives

* test(codex): keep one attempt tools owner
2026-08-19 01:10:18 -07:00
Peter Steinberger baefd067bb fix(deps): keep package runtime dependencies single-owned (#126119)
* fix(deps): consolidate shared runtime helpers

* test(concurrency): support current test lib target

* fix(time): preserve year-scale plugin durations

* fix(agents): preserve empty subagent completions
2026-08-18 22:12:45 -07:00
Peter Steinberger 66cacbae5d test: remove strict-subset assertions (#126142) 2026-08-18 20:15:50 -07:00
Peter Steinberger feda957fc5 fix(gateway): bind channel completion dispatch (#126113)
* fix(gateway): bind channel completion dispatch

* fix(plugin-sdk): scope harness completion dispatch

* test(agents): cover scoped completion dispatch
2026-08-18 19:48:24 -07:00
Peter Steinberger c97b8ffdfc refactor: consolidate meeting and media provider families (#126053)
* refactor(plugins): consolidate provider family helpers

* fix(plugin-sdk): keep meeting script helpers private

* fix(plugins): sync meeting boundary paths
2026-08-18 19:11:13 -07:00
Samuel Judson 6ccc57b331 fix: add ssrf protection to Beam fetches (#123848)
* Add ssrf protection to Beam fetches.

* Additional robustness following initial comments.

* fix(beam): make redirect failures terminal

* chore(plugin-sdk): refresh surface budget

* docs(beam): define redirect restart behavior

* docs(beam): align redirect config help

* test(beam): cover warning before redirect block

* fix(beam): always report terminal redirect blocks

---------

Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-08-18 18:00:58 -07:00
Peter Steinberger e2643afb2a fix(codex): retain terminal facts in oversized trajectories (#126050)
* fix(codex): delegate trajectory bounding to host

* fix(trajectory): preserve compact terminal facts

* style: format release validation skill
2026-08-18 16:22:25 -07:00
Josh Lehman ffbbb64178 fix: plugin install rejects bare prerelease gateway minimums (#126020)
* fix(plugins): accept bare prerelease gateway minimums

* fix(plugins): honor prerelease host ordering
2026-08-18 16:12:10 -07:00
Peter Steinberger 1d9cda833f feat(ui): show machine CPU and RAM in the cloud picker (#125696)
The cloud machine picker described each class in prose ("Cheap smoke checks
and small repos"), which was the widest thing in the row, got ellipsized, and
did not say what the operator actually picks on. Machine options now carry the
class shape and the picker renders "32 vCPU · 64 GB" instead.

Crabbox reports per-provider class shapes from `providers --json`; the plugin
reads that catalog once per lifecycle and attaches cpu/memoryGb to each option.
A missing binary, failed command, unparseable output, absent classes, or an
unmatched provider all degrade to label-only rows, so an older Crabbox keeps
working.

`description` was never released, so it is removed rather than deprecated, and
listMachineOptions becomes async for the catalog read. Deletes the duplicate
machine-option projector in the environments server method.
2026-08-18 15:38:15 -07:00
Peter Steinberger b34eb16071 fix(copilot): restore OpenClaw guidance to agent turns (#125997)
* fix(copilot): add OpenClaw prompt guidance

Copilot append-mode system messages included credential safety, workspace bootstrap, and extra context but omitted OpenClaw delegation and reply-delivery policy.

Build guidance from the final policy-filtered tool surface so visible delegated work, Skill Workshop, and source replies follow the same behavior as Codex.

* fix(copilot): break prompt guidance import cycle

The CI architecture gate detected a cycle through attempt-config and prompt-guidance. Isolate raw-run mode detection in a leaf module.
2026-08-18 15:01:15 -07:00
Onur Solmaz 5cabd2b72e Revert "fix(providers): report request acceptance consistently (#125807)" (#126021)
This reverts commit f5e9622fc9.
2026-08-19 00:16:09 +03:00
Onur Solmaz f5e9622fc9 fix(providers): report request acceptance consistently (#125807)
* fix(providers): report request acceptance consistently

* fix(providers): retain response hook compatibility

* fix(providers): keep legacy response hook path

* fix(providers): distinguish rejected response attempts

* fix(providers): keep acceptance evidence truthful

* fix(google): preserve provider acceptance errors

* test(google): satisfy acceptance callback lint

* fix(google): exclude acceptance hooks from retry deadline

* fix(openai): report Codex websocket acceptance

* fix(openai): commit websocket state before acceptance hook

* fix(google): abort pending acceptance callbacks

* fix(providers): abort pending acceptance callbacks

* fix(mistral): report observed HTTP response

* fix(mistral): report rejected HTTP responses

* fix(providers): derive acceptance from HTTP status

* fix(providers): preserve acceptance lifecycle cleanup

* fix(anthropic): report observed HTTP response

* fix(anthropic): report rejected HTTP responses

* fix(plugin-sdk): expose provider lifecycle

* fix(providers): stop after lifecycle abort

* fix(mistral): cancel unread acceptance failures
2026-08-18 23:50:57 +03:00
Peter Steinberger 3a96fbd64d feat(canvas): present widgets on native device panels (#125818)
* feat(canvas): present widgets on native panels

* refactor(agents): inline gateway caller selection

* fix(canvas): restrict widget panels to macOS

* refactor(agents): reuse resolved spawn workspace
2026-08-18 11:05:41 -07:00
Peter Steinberger fd8326c5bf fix(codex): reap sandbox process trees before termination (#125908) 2026-08-18 10:48:10 -07:00
Peter Steinberger 0684f50136 fix(gateway): harden hook admission and shutdown (#125893)
* fix(gateway): harden hook admission and shutdown

Flush structured 413 and 408 hook responses before closing oversized or timed-out request sockets, and reject deferred wake requests that target an explicit session.

Direct Gateway close now marks startup and readiness as draining immediately and attempts every HTTP listener shutdown before reporting an incomplete close.

* test(gateway): model request destruction in fuzzing

Give the HTTP request fuzz double the IncomingMessage destroy contract exercised after 413 and 408 responses finish.

* fix(gateway): preserve response and shutdown bounds

Route installed webhook body-limit failures through the shared response-first close owner and require complete Feishu 413/408 responses before terminal connection closure.

Retain the current-main grace bound for agent-harness disposal so one stuck harness cannot block listener teardown.

* test(telegram): model response-close request cleanup

Keep the slow-body request alive through response finish, then assert cleanup when the mock response transport closes.
2026-08-18 10:39:56 -07:00
Peter Steinberger b9d0e13b5d fix(agents): share one delegation policy across agent runtimes (#125892)
The `## Delegation` guidance added in #125691 lived only in
buildAgentSystemPrompt, so Codex-runtime agents never received it: the
Codex harness builds its own developer instructions in
extensions/codex/src/app-server/thread-prompt.ts and imports nothing
from the system-prompt builders. Live A/B on gpt-5.6-luna had the native
runtime answer "spawn a visible session" while the Codex runtime
answered "spawn a hidden subagent".

Move the policy into src/agents/delegation-guidance.ts, owning both the
main-session mode resolver and the section text, and export it through
the agent-harness plugin SDK barrel that the Codex harness already uses.
The hidden-delegation vocabulary is injected by each runtime, so core
never names a plugin-owned tool: native passes `sessions_spawn`, Codex
passes native `spawn_agent`. Visible sessions stay `sessions_spawn`
with visible=true on both runtimes because Codex-native children are
never OpenClaw sessions.

Also narrows the Codex line that told the model to use `sessions_spawn`
only for OpenClaw/ACP delegation; it now scopes that to internal
legwork, so user-facing deliverables still route to a visible session.
2026-08-18 09:57:52 -07:00
Peter Steinberger e011e9db61 fix: child sessions honor inherited model pins over channel defaults (#125880)
* fix: honor inherited model pins over channel defaults

Child sessions now keep parent model pins consistently across reply, status, harness prediction, and agentCommand.

* test: align agent command model selection fixtures

Keep concurrent override and threaded parent-selection coverage aligned with canonical model normalization and runtime snapshot access.
2026-08-18 09:24:15 -07:00
Peter Steinberger 9e24399e82 fix(ci): stop the codex lane hanging on a cold real-tool graph (#125864)
* fix(ci): stop codex lane cold-graph hangs

The side-question domain-policy test loaded the complete agent-harness tool graph inside a one-second readiness race, making the serial non-isolated Codex shard fail or stay silent under cold imports. Build the test's web_search marker and real web_fetch tool from the narrow implementation, then synchronize on turn startup before issuing the tool call. Cap each Codex test process at 12 files so CI gets bounded time-to-first-output as defense in depth.\n\nRefs #125839

* fix(test): keep codex web fetch fixture on sdk boundary

Load the real web_fetch factory on demand through the existing local-only plugin test runtime. This preserves the narrow cold-graph fix without letting a bundled plugin test reach into core internals.
2026-08-18 09:15:38 -07:00
Peter Steinberger 5f65ef8138 feat: add A2UI widgets to session boards (#125803)
* feat: add A2UI board widgets

* fix: harden A2UI board widget integration

* fix: repair A2UI CI contracts

* fix(canvas): keep native A2UI pushes on v0.8

* fix(canvas): support board-only widgets without file host
2026-08-18 09:08:45 -07:00
Peter Steinberger b9fb56566b fix(browser): treat Linux zombies as exited (#125831) 2026-08-18 07:32:02 -07:00
Peter Steinberger 460b6b1e96 refactor(realtime): deduplicate voice audio handling (#125728)
Reuse the canonical realtime audio duration and OpenAI-compatible wire-format helpers while removing redundant state transitions and truncate payload construction. The production diff is net-negative.

Provider interruption policy and lifecycle ownership stay local to each provider; this does not introduce shared mutable assistant tracking or change behavior.
2026-08-18 02:00:12 -07:00
Peter Steinberger 9ad1c0c682 fix(auth): surface revoked OAuth state without masking provider failures (#125515)
* fix(auth): preserve WHAM classifications and failure recording

WHAM 401/403 state now drives accurate re-auth guidance, while inline hook failures are contained after persistence so recorded failures cannot escape or be masked.

* docs(plugin-sdk): define auth cooldown classifications

document the additive cooldown diagnostic contract and cover its canonical public-SDK projection.

* fix(auth): keep WHAM diagnostics source-compatible

keep cooldownReason canonical, persist exact WHAM diagnostics in optional cooldownClassification, and preserve operator guidance plus failure-hook containment.

* fix(auth): keep failover on canonical cooldown reasons

ensure optional WHAM diagnostics never drive scheduling and discard mismatched persisted reason/classification pairs.
2026-08-18 00:35:06 -07:00
Peter Steinberger 6cc40431d1 fix(voice): prevent choppy audio in realtime calls (#125620)
* fix(voice-call): pace realtime audio from stream clock

* fix(voice): preserve resampler state across audio chunks

* fix(voice-call): honor telephony TTS audio formats

* fix(voice-call): await acknowledged stream playback

* fix(voice): bound realtime input audio backlog

* chore(voice-call): shrink assertion baseline and localize tts format error

* test(voice-call): split playback-mark coverage into its own suite

* test(voice-call): drop helper left unused by suite split

* test(openai): scope queued audio copy assertion

* fix(openai): flush realtime resampler at response end

* fix(voice-call): reject containerized mulaw TTS
2026-08-18 00:07:01 -07:00
Hannes Rudolph 34c3d15a6b fix(macos): complete Codex onboarding and model picker (#124829)
* fix(setup): refresh Codex registry with staged install

* fix(macos): verify inference before onboarding handoff

* fix(setup): use native Codex home for subscription auth

* fix(codex): honor attempt-scoped setup config

* fix(macos): align onboarding handoff with reopen

* fix(setup): await prepared model convergence

* fix(ui): avoid false auth state for empty catalog

* fix(setup): scope catalog convergence to Codex gateway

* fix(setup): publish the committed runtime catalog

* fix(models): project configured static runtime models

* fix(codex): expose app-server model catalog

* fix(models): preserve Codex auth across reloads

* fix(ci): align Codex onboarding checks

* test(ui): stabilize dock suppression environment

* fix(codex): honor discovery config in app-server model catalog

The manifest documents discovery.enabled (bundled fallback list) and
discovery.timeoutMs (default 2500ms) for model discovery; the new catalog
path used the generic 60s request timeout and ignored the enable gate.
Also drop the test-only listModels injection seam in favor of vi.mock.

* fix(setup): refuse prepared Codex auth over an explicit remote transport

configureCodexCliPreparedAuth silently rewrote an explicitly configured
websocket/unix app-server to local stdio (keeping a dangling url), moving
the credential boundary onto this host. Fail setup with actionable
guidance instead; also surface the root cause when the prepared model
catalog refresh fails after activation.

* refactor(agents): one canonical model-catalog identity key

Three near-identical key helpers existed (models-list-result,
models-list-configured-static, harness/model-catalog). Export
resolveModelCatalogIdentityKey from the route-policy owner, collapse the
duplicate dedupe loops into dedupeByKey, make donor enrichment Map-based,
and inline the one-off harness-augment wrapper.

* fix(macos): restore custodian handoff for fresh activations

Landing every finish on the plain dashboard stranded the custodian
first-run flow (memory import, channels, permissions, hatch). Fresh
activations now hand off to custodian onboarding; live-verified
pre-existing setups reopen the normal dashboard, matching the removed
already-configured shortcut. Tests pin the destination per path.

Also isolate the post-startup Codex login test from developer machines:
ambient OPENAI_API_KEY and a real Codex login made it assert-fail.

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-17 23:31:12 -07:00
Peter Steinberger 31afd52e99 refactor(realtime): share audio duration calculation (#125612)
Fix xAI barge-in truncation that reported 3760 ms after only 3700 ms of decoded audio.

Share exact audio-duration math across OpenAI, xAI, and Google while keeping provider-specific rounding at each caller.
2026-08-17 22:25:42 -07:00
Peter Steinberger 75fcaba919 fix(voice-call): survive gateway in-process restart and stop CLI dead-ends (#125458)
* fix(voice-call): survive gateway in-process restart and stop CLI dead-ends

The gateway's in-process restart (SIGUSR1 config reload) reuses the cached
plugin registry, so service stop/start run on the same retained voice-call
registration. Generation fencing from #120289 treated that restart as a stale
actor: stop retired the generation forever, the next start silently bailed,
and every voicecall.* RPC answered UNAVAILABLE "runtime generation is
retired" while the webhook never rebound.

- Registrations now hold a replaceable generation: service start after stop
  mints a fresh generation, takes over a running slot owned by a retired
  predecessor, and reports start failures to service health instead of
  silently returning.
- The voicecall CLI classifies gateway failures with typed guards instead of
  message substrings: standalone/store fallback only when the gateway is
  genuinely absent; reachable-but-failed (request errors, auth, timeout)
  exits with actionable text; a standalone webhook port collision explains
  that a running Gateway probably owns the port instead of raw EADDRINUSE.
- Plugin SDK gateway-runtime exports structural isGatewayTransportError /
  isGatewayClientRequestError guards (+2 documented surface budget).
- Regression coverage: same-registration stop/start restart, retired-owner
  takeover, typed CLI fallback classification, and a real token-auth gateway
  server routing voicecall.status through callGatewayFromCli.

* refactor(voice-call): split CLI modules and dedupe gateway fallbacks

Collapse the four duplicated gateway-or-runtime command blocks (speak, dtmf,
end, continue fallback) into one generic runGatewayManagerCommand helper —
the continue command owns its legacy-method fallback and operation polling
via a gatewayCall closure, so the helper carries no per-command policy.
Smoke reuses the shared initiateVoiceCall path instead of a bespoke
fallback.

Split the 988-line cli.ts into concept modules (cli-gateway-call,
cli-call-log, cli-command-io) and drop its grandfathered max-lines
suppression plus the now-stale max-lines and assertion-safety baseline
entries (shrink-only ratchet maintenance).

Behavior-frozen: stdout/exit semantics unchanged; net -2 production LOC.

* fix(voice-call): redact gateway URLs in CLI operational errors

ClawSweeper P1: the operational-error formatter interpolated the raw
connectionDetails.url, so a configured gateway URL with userinfo or query
tokens would print credentials into terminal output. Redact the composed
message once with the canonical net-policy redactor (also covers
remote-controlled close-reason text), exported through the plugin SDK
gateway-runtime subpath (+1 documented surface budget). Regression test
covers a credential-bearing URL in both the URL and message fields.
2026-08-17 18:59:19 -07:00
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 eb38d5e486 fix(reply): report settled delivery outcomes once (#124773)
* refactor(reply): publish settled dispatch receipts

* refactor(reply): isolate dispatch outcome accounting

* refactor(discord): infer settled dispatch result

* test(reply): model settled dispatch receipts

* test(reply): type settled receipt fixtures

* test(telegram): declare settled final receipt

* test(telegram): adapt legacy dispatch fixtures

* fix(reply): complete settled receipt compatibility

* test(channels): keep delivery suite within lint budget

* test(channels): reuse settled count fixture

* test(channels): consolidate receipt assertions

* test(channels): extract delivery receipt fixtures

* fix(qa): recover stopped clients after config restart

* fix(reply): settle deferred delivery receipts

* test(channels): share delivery turn fixtures

* fix(channels): preserve non-visible reconciliation

* fix(reply): preserve settled receipt compatibility

* refactor(reply): make settled receipts canonical

* refactor(reply): absorb settlement at dispatcher boundary

* test(matrix): prove settled receipt precedence

* refactor(sessions): extract prompt snapshot types

* fix(reply): restore queued admission counts
2026-08-17 06:38:16 -07:00