Commit Graph

38825 Commits

Author SHA1 Message Date
David Gorelik
63b0cac9f0 fix: reply hooks can claim ordinary agent turns (#108353)
* fix: honor reply hooks for user agent turns

* fix: preserve reply hook turn context

* fix: gate CLI reply hooks by trigger

* fix(plugins): run reply hooks once per admitted turn

Co-authored-by: Clive (OpenClaw) <clive@openclaw.local>

* fix(plugins): reconcile reply hooks after rebase

* fix(auto-reply): dispatch hooks for active steers

* test: use valid channel context shape in steer hook test

---------

Co-authored-by: Clive (OpenClaw) <clive@openclaw.local>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 11:50:43 -07:00
NianJiu
42ff5ec754 feat(kimi): add Kimi K3 support (#109202)
* feat(moonshot): add Kimi K3 support

* feat(kimi): add K3 subscription models

---------

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 11:41:12 -07:00
Shakker
f084ab2240 fix: prevent external gateway restart timeouts (#109273) 2026-07-16 19:36:58 +01:00
Alix-007
6bcf071120 fix(infra): bound macOS process start probes (#109064)
* fix(infra): bound macOS process start probes

* docs(changelog): note macOS process probe deadline

Co-authored-by: Alix-007 <li.long15@xydigit.com>

* test(infra): cover process probe timeout

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 11:36:07 -07:00
Peter Steinberger
6175e6a98c refactor: remove stale internal deprecated compatibility (#109266)
* refactor(agents): remove stale deprecated internals

* refactor(channels): remove dead target compat aliases

* refactor(plugins): collapse private deprecated types

* refactor(onboarding): remove stale provider skip alias

* style(agents): format deprecated cleanup

* refactor(agents): internalize sanitizer options
2026-07-16 11:35:34 -07:00
Peter Steinberger
76870ed958 fix(agents): scope tool-terminal completion proof to post-assistant results (#109259)
The continuation guard scanned the whole session snapshot for non-error
toolResults, so a prior turn's result with a model-reused tool-call id
could prove 'completion' for a batch that never dispatched (fresh-eyes
review finding on 2848acbbaa). Scope the scan to snapshot entries after
the terminal assistant — both assistant fields are found on the snapshot
itself, so identity lookup holds; an assistant missing from the snapshot
fails closed to the existing incomplete-turn error. Adds a stale
prior-turn-result regression.
2026-07-16 11:26:34 -07:00
wings1029
c64a16196a fix(resolve-system-bin): cap binary resolution caches with eviction (#108858)
* fix(resolve-system-bin): cap binary resolution caches with eviction

The two module-level Maps grow with every distinct binary name resolved.
A 512-entry cap prevents unbounded memory growth in long-running processes
that resolve many different system binaries.

* fix(resolve-system-bin): share LRU cache pruning

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 11:17:00 -07:00
Dallin Romney
9f0e35c233 test: stabilize UI and gateway auth timing (#109257) 2026-07-16 11:13:42 -07:00
thomas.szbay
b85531c62f fix(agents): bound base64 image input before decode in tool-image sanitizer (#105086)
* fix(agents): bound base64 image input before decode in tool-image sanitizer

* fix(agents): lower input-size cap to 10MB for OOM headroom

* fix(agents): align tool-image input-cap comment with 10 MiB ceiling

* fix(agents): typecheck-safe access in tool-image input-cap test

* test(agents): exercise real tool image input cap

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 11:13:27 -07:00
Peter Steinberger
3c1a36380f fix(gateway): read pinned session-extension registry for catalog node commands (#109248)
Session-catalog dispatch read the mutable `activeRegistry`, which a later
standalone plugin load can replace with providers built from default
(unbound) plugin runtimes. Those runtimes hit the unavailable nodes stub, so
Control UI Codex/Anthropic catalogs surfaced `NODE_LIST_FAILED` ("Plugin node
runtime is only available inside the Gateway") even though the gateway binds a
real nodes runtime and CLI `nodes list` works.

Read the pinned session-extension registry instead so catalog providers keep
the gateway-bound runtime across plugin registry churn. Generic across all
session-catalog plugins.
2026-07-16 11:12:38 -07:00
Peter Steinberger
7cf486f657 fix(agents): guard optional provider models when resolving transcript route (#109252)
resolveTranscriptAssistantRoute read providerConfig.models.find without
guarding models, but the runtime config passed here is the raw user config
where a provider entry may omit models (e.g. models.providers.openai =
{ apiKey }). That threw "Cannot read properties of undefined (reading 'find')"
inside the SQLite transcript-append transaction, so every agent turn failed to
persist its transcript (the underlying error was swallowed to {} and surfaced
only as "Turn transcript persistence failed").

Guard the optional models array at the crash site, and fix two identical
raw-config hazards found in the same sweep (cron isolated-agent model api
resolution, microsoft-foundry image provider). Regression test drives
redactTranscriptMessage with a provider that has no models array.
2026-07-16 11:10:59 -07:00
Peter Steinberger
7133305bac fix(config): reject ignored audio transcription settings (#109226)
* fix(config): reject retired audio transcription config

* fix(config): align dead audio cleanup contracts

* fix(doctor): detect retired audio config
2026-07-16 11:00:28 -07:00
wings1029
d1153e4ad8 fix(git-commit): cap commit resolution cache with FIFO eviction (#108856)
* fix(git-commit): cap commit resolution cache with FIFO eviction

The module-level cachedGitCommitBySearchDir Map grows without bound.
A 256-entry FIFO cap prevents unbounded memory growth from repeated
lookups across distinct search directories.

* fix(git-commit): use shared LRU cache pruning

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 10:54:35 -07:00
Sally O'Malley
11c7360af5 fix(chat): keep internal metadata out of transcripts (#109056)
* fix(chat): keep internal metadata out of transcripts

Signed-off-by: sallyom <somalley@redhat.com>

* fix(gateway): harden control reply projection

Co-authored-by: sallyom <somalley@redhat.com>

* chore: leave changelog to release tooling

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 10:47:43 -07:00
Bill
3590f7df7e fix(agents): route opted-in embedded runs through the CLI backend on subscription-only claude-cli auth (#106840)
Embedded runs targeting a CLI runtime provider fall through to the openclaw
harness and call the provider API directly with the runtime's credentials
(cli_runtime_passthrough_openclaw). Anthropic routes direct anthropic-messages
calls on subscription OAuth tokens to metered extra-usage billing — this is
long-standing behavior, not a recent change. Without extra-usage balance,
every such run (e.g. active-memory recall) fails with a billing error; with
extra-usage enabled, the run silently draws paid metered usage instead of the
plan limits the CLI runtime was configured for. Only CLI-backed execution
runs on plan limits for those credentials.

Add an opt-in RunEmbeddedAgentParams.cliBackendDispatch: "subscription-auth"
that dispatches the run through runCliAgent as a one-shot turn when the
provider is claude-cli, a CLI backend is registered, and the ordered auth
profile selection for the passthrough resolves to a subscription (oauth/token)
credential or nothing rather than an API key; resolution stays on stored
credential metadata, with no credential materialization or refresh on the
per-turn path. The dispatch translates toolsAllow into the selectable-backend
surface (native: [], allowlisted loopback MCP tools; wildcard allowlists stay
MCP-only), runs with a fresh CLI process (no live-session reuse; session-
scoped bundle-MCP retirement on run end rather than the process-wide loopback
close), bridges CLI tool result events to onAgentToolResult with native-path
semantics (normalizeToolName + isToolResultError), and drops CLI session
bindings from the result.

The selectable-backend MCP list now also bounds the loopback MCP grant
server-side: the grant carries a per-run gateway tool allowlist enforced in
scoped tool resolution, so tools outside the run's allowlist can be neither
listed nor called even under CLI bypass permission modes where
--allowedTools is advisory.

active-memory recall opts in so recall works on claude-cli subscription-only
instances and stops drawing metered extra usage where it previously could.
Scoped to claude-cli; other CLI runtimes keep the passthrough until their
direct-API contract is verified.

The dispatch also mirrors the run into the run's session transcript through the session
accessor (user turn, tool call/result records as they stream, final assistant
snapshot at run end) so transcript consumers keep parity with embedded runs:
active-memory's persistTranscripts, timeout partial-text salvage, and the
live terminal-search watcher that polls the session file mid-run.

Post-review hardening: canonical anthropic/<model> refs whose configured
agentRuntime is claude-cli resolve through the runtime policy before the
dispatch gate (they previously stayed on the failing passthrough); restricted
dispatches serve an exclusive loopback-only MCP bundle so user/plugin MCP
servers stay outside the run's tool universe; and the transcript recorder
flushes the latest assistant snapshot the moment the run aborts, so timeout
salvage sees partial text even while the killed CLI child is still settling.

Recalls routed to the claude-cli runtime default to a 45s budget (measured
CLI-dispatched runs take 14-20s, over the plain 15s default); explicit
timeoutMs config always wins.

Transcript mirror keeps bare-array tool_result content (claude stream-json
echoes MCP results without a {content} wrapper); dropping it classified every
successful recall as no_relevant_memory.

CLI dispatch resolves inside session/global lane admission so dispatched
runs obey the same lifecycle, placement, and concurrency gates as native
embedded runs.

LOC-ratchet offsets move the loopback grant-context builders to
cli-runner/mcp-grant-context.ts and dedupe the run/prep stage-summary
emitters into attempt-stage-timing.ts; unused type exports dropped and the
now-used stream-message baseline entry removed.

The recall timeout default now consumes the runner's own dispatch
eligibility through a new plugin-runtime seam
(agent.resolveCliBackendDispatchEligibility): API-key and missing-backend
routes keep the passthrough and its plain 15s default.

Eligibility honors an explicitly pinned authProfileId (the credential the
run executes on) before ordered profile selection, in both directions.

Transcript mirror composes buildAssistantMessage + buildUsageWithNoCost
directly; main trimmed the zero-usage wrapper export (ab0ccc244b) before
this branch's usage landed.

Dispatch eligibility is provider-owned: the anthropic plugin's claude-cli
backend declares CliBackendPlugin.subscriptionAuthDispatch and core reads
the registered descriptor instead of a core provider allowlist.

Dispatch fails closed on tool policy (only non-empty named allowlists are
expressible on the CLI surface; deny-all, wildcards, absent allowlists, and
disableTools/modelRun keep the passthrough), threads the pinned
authProfileId into CLI runtime resolution, and emits onExecutionStarted at
the admitted dispatch boundary.
2026-07-16 10:37:54 -07:00
Peter Steinberger
cb84dc76fc feat(control-ui): approval attention chip + approval history page (#108776)
Adds the sidebar approval attention chip and a dedicated approval history
page backed by the new approval.history gateway RPC (30-day retention
window). Extracts buildSidebarAttentionItems into its own module so the Lit
component consumes it as a real cross-module dependency, and wires the strict
i18n catalog for the new strings (fallbacks=0).
2026-07-16 10:32:05 -07:00
Peter Steinberger
b6e90cbed4 test: raise async wait ceilings that flaked under CI load (#109222)
vi.waitFor in the ACP abort test and the shared Swift waitUntil helper
both timed out on contended runners while passing solo; polling waits
return immediately when healthy, so the higher ceilings cost nothing.
2026-07-16 10:30:50 -07:00
Peter Steinberger
2cd3ee43ee refactor: store workspace setup state in SQLite (#109147)
* refactor(state): move workspace setup state to SQLite

* test(state): track workspace cleanup temp dirs

* fix(state): satisfy workspace migration gates

* docs(state): fix migration list indentation

* fix(state): verify sibling migration claims

* fix(state): remove obsolete claim probe
2026-07-16 10:28:36 -07:00
Peter Steinberger
2db77fb3fb test(media): speed up download timeout coverage (#109238) 2026-07-16 10:24:47 -07:00
heichl_xydigit
1f3b4e86ca fix(agents): keep not_required delivery status when completion_announced_at exists (#108710)
* fix(agents): keep not_required delivery status when completion_announced_at exists for expectsCompletionMessage=false runs

createDeliveryFromTypedColumns unconditionally overrode status to
'delivered' when completion_announced_at was present, even for runs
where expects_completion_message is false. This produced a contradictory
delivery state where a run that does not require completion delivery
was marked as delivered.

Only set status to 'delivered' when expects_completion_message is true.
For not_required runs that still have completion_announced_at recorded
(for informational purposes), preserve announcedAt without overriding
the status.

* test(agents): cover tainted delivery rows

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 10:21:50 -07:00
Peter Steinberger
e71ef76e8e feat(onboarding): offer detected Claude Code/Codex/Hermes memory imports across CLI, macOS, and Linux onboarding (#108977)
* feat(migrate): add Hermes memory-only import and a shared memory-import core

* feat(onboarding): offer detected memory imports during CLI setup and guided onboarding

* feat(ui): show a first-run memory-import offer in Control UI onboarding mode

* feat(linux-app): open the first-run dashboard in onboarding mode

* feat(macos): add the onboarding memory-import page

* docs: document the onboarding memory-import page across surfaces

* chore(i18n): translate onboarding memory-import strings for control-ui and native locales

* refactor: keep memory-import internals unexported for deadcode gates

* fix(ci): resolve lint findings in onboarding memory import

* chore(i18n): refresh native inventory after lint refactor

* fix(ci): skip updater artifacts in the unsigned Linux companion PR lane

* chore(i18n): reconcile locale artifacts after rebase
2026-07-16 10:10:01 -07:00
Peter Steinberger
4432016f7f refactor: prune redundant OpenClaw env controls (#109211)
* refactor: prune redundant OpenClaw env controls

* docs: refresh environment reference map
2026-07-16 10:06:39 -07:00
NianJiu
1eda44ee36 fix(acp): show durable notice after gateway disconnect (#108827)
* fix(acp): record disconnect interruptions

* test(acp): tighten disconnect settlement coverage

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>

* fix(acp): preserve replay order under backpressure

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>

* test(acp): await accepted prompt ledger record

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>

* fix(acp): isolate ledger mutation queues

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>

---------

Co-authored-by: NianJiuZst <180004567+NianJiuZst@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 10:01:10 -07:00
Monkey-wusky
e6ac6c8506 fix(agents,skills): keep session-identity and experience-review transcript truncation UTF-16 safe (#106370)
* fix(agents,skills): keep session-identity and experience-review transcript truncation UTF-16 safe

normalizeCliContextValue (cli-output.ts) and formatSkillExperienceReviewTranscript
(experience-review-prompt.ts) both used raw .slice(0, N) / .slice(-N) to truncate
user-facing strings. When a truncation boundary falls inside a surrogate pair (emoji),
the resulting string contains a lone surrogate — encodeURIComponent throws URIError,
JSON serialisers may reject it, and downstream display surfaces can render garbage.

Replace .slice(0, 200) with truncateUtf16Safe in normalizeCliContextValue.
Replace .slice(0, 6_000) with truncateUtf16Safe and full.slice(-tailBudget) with
sliceUtf16Safe(full, tailStart) in formatSkillExperienceReviewTranscript.

Follows the pattern established by #98644, #102470, #101728 and the broader
UTF-16 safety sweep already applied across the codebase.

* chore: re-trigger CI after PR body update

* test(agents,skills): construct transcripts exceeding 60k chars, verify old slices dangle

Both experience-review fixtures now exceed EXPERIENCE_REVIEW_MAX_TRANSCRIPT_CHARS
so the truncation branch actually fires. Pre-condition assertions prove the old raw
.slice(0,6000) / .slice(tailStart) produce isolated surrogates; the production
functions (formatSkillExperienceReviewTranscript, formatCliOutputError) do not.

cli-output test also adds pre-condition check showing normalizeCliContextValue
with raw .slice(0,200) would split a surrogate pair.

* test: tighten UTF-16 truncation coverage

Co-authored-by: 毛宇豪0668001457 <mao.yuhao@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 09:53:58 -07:00
Peter Steinberger
618002c141 refactor(core): reuse keyed promise memoization (#109184) 2026-07-16 09:51:40 -07:00
Peter Steinberger
7e410bdb52 fix(auto-reply): stop minting channel source-turn ids for internal-origin turns (#109201)
PR #108283 started deriving a durable channel source-turn id for gateway
chat.send turns carrying originatingChannel/originatingTo overrides, while
the gateway's pre-created user-turn recorder keys the persisted turn by run
id. The same PR's admission guard then throws 'channel restart recovery
requires source-keyed user-turn admission' for every such turn — breaking
qa-lab suite runs, ACP-bridge flows, and relay integrations (reproduced
live on the codex harness chat-image probe; text-only fails identically).

Internal-origin turns (gateway chat.send stamps the internal channel as the
ingress provider) carry run ids, not provider message ids; gateway turns
already own restart via fingerprint admission and client-side idempotent
retries. Skip the mint for internal ingress at both derivation sites so
admission takes the source-less persist path, while real channel ingress
keeps the new source-keyed recovery. Also surface the full agent.wait
result in the codex harness live test error (how this was found).

Live proof: gateway-codex-harness.live.test.ts chat-image probe on a
Blacksmith Testbox with a real OpenAI key failed with the admission error
twice on main and passes admission with this fix.
2026-07-16 09:48:53 -07:00
wings1029
966e176e04 fix(shell-env): cap login shell env probe cache with eviction (#108862)
* fix(shell-env): cap login shell env probe cache with eviction

The loginShellEnvProbeCache Map keys include the exec function reference
and exec environment, which can vary across calls. A 64-entry eviction
cap prevents unbounded growth.

* refactor(shell-env): share bounded probe cache insertion

Co-authored-by: 陈志强0668000989 <31802073+wings1029@users.noreply.github.com>

* fix(shell-env): retain active probe cache entries

Co-authored-by: 陈志强0668000989 <31802073+wings1029@users.noreply.github.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 09:46:35 -07:00
Peter Steinberger
fa2b38c890 test: speed up stuck-session recovery coverage (#109195) 2026-07-16 09:44:46 -07:00
Peter Steinberger
05dd921016 fix: shard OpenAI transport stream tests (#109181)
* test(agents): shard OpenAI transport stream suites

* chore(lint): transfer transport test baselines
2026-07-16 09:43:07 -07:00
Peter Steinberger
f871b499b6 fix(infra): drop consumer-less gateway supervision exports
333c4f9a61 and 244f4965dc landed six exports with no production
consumers, failing the hard-zero deadcode gate on every PR: a dead
re-export block in restart-handoff (the contract module's real importer
uses it directly), three result/mode types only referenced inside their
own modules, and two supervision symbols whose only consumers were their
tests. The types and helpers stay defined for the in-flight supervisor
work to re-export alongside real consumers; the supervision test now
proves mode resolution through the public isGatewayExternallySupervised
surface.
2026-07-16 09:31:46 -07:00
Michael Appel
9359544e84 fix: tighten control ui input validation [AI] (#106545)
* fix: harden control ui input validation

* test: avoid secret-like media fixtures

* fix: preserve edge-case preview and media handling

* test: avoid control-character media fixture

* fix(tui): type searchable select search text

* fix(config): preserve merge-patch record identifiers

---------

Co-authored-by: Pavan Kumar Gondhi <pavangondhi@gmail.com>
2026-07-16 21:44:38 +05:30
Peter Steinberger
20d748a4f0 feat(agents): agent-owned gateway terminals with operator co-attach 2026-07-16 09:12:50 -07:00
Alix-007
59fa034fcb fix(doctor): bound launchctl environment probes (#109115) 2026-07-16 09:08:55 -07:00
Shakker
9b48ad5977 fix: avoid redundant Windows restart persistence (#109162) 2026-07-16 17:01:39 +01:00
Shakker
266d3c8551 refactor: focus external restart verification 2026-07-16 17:01:39 +01:00
Shakker
6013e593c7 fix: narrow unmanaged restart results 2026-07-16 17:01:39 +01:00
Shakker
332b522f90 fix: harden external restart integration 2026-07-16 17:01:39 +01:00
Shakker
333c4f9a61 feat: add restart handoff consume protocol 2026-07-16 17:01:39 +01:00
Shakker
e123606b46 feat: support externally supervised gateway restarts 2026-07-16 17:01:39 +01:00
Shakker
244f4965dc feat: add external gateway supervision policy 2026-07-16 17:01:39 +01:00
Alix-007
2d0f0d0ec0 fix(daemon): bound Node runtime probes (#109127) 2026-07-16 09:00:06 -07:00
Peter Steinberger
8fe4eeea9e fix(exec): stop isolated state dirs from moving live approvals (#108742)
* fix(exec): isolate approval state directories

* chore: drop release-owned changelog entry

* chore: refresh native i18n inventory

* fix(ci): pin XcodeGen for Periphery scans
2026-07-16 08:57:32 -07:00
Alix-007
7a18a781bc fix(doctor): bound legacy crontab inspection (#109107) 2026-07-16 08:57:28 -07:00
Peter Steinberger
5a4004dfb7 fix: state backups hang on dev-channel installs (#109090)
* fix(backup): exclude managed runtime trees

* chore: leave release notes to release automation

* fix(backup): preserve managed-root workspaces

* fix(backup): preserve configured state paths

* test(gateway): isolate runtime service env
2026-07-16 08:56:31 -07:00
Peter Steinberger
c46cc1e2d4 refactor(channels): unify inbound replay protection (#109117)
* refactor(channels): unify inbound replay-guard orchestration on shared factory

* fix(plugin-sdk): bind replay-guard settlement to claim handles

* fix(plugin-sdk): claim-handle settlement (rest)

* fix(discord): align skipped queue cleanup

* style(feishu): simplify bot menu claim settlement

* refactor(plugin-sdk): extract replay dedupe contracts
2026-07-16 08:46:34 -07:00
wings1029
eb107c105b fix(channel-selection): cap error dedupe Set with FIFO eviction (#108840)
* fix(channel-selection): cap error dedupe Set with FIFO eviction

The module-level loggedChannelSelectionErrors Set grows without bound
for the lifetime of the gateway process. A 1024-entry FIFO eviction cap
prevents unbounded memory growth from per-plugin/account error keys.

* test(channel-selection): add LRU eviction proof with 5 focused tests

Proves the 1024-entry FIFO cap prevents unbounded growth:
- Exact limit enforcement at 1024 entries
- Oldest entry eviction on overflow
- Dedup still works after eviction
- Size never exceeds the cap

* refactor(channel-selection): use shared warning dedupe cache

Co-authored-by: 陈志强0668000989 <31802073+wings1029@users.noreply.github.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 08:45:28 -07:00
wahaha1223
d1e2fbd682 fix(skills): keep blank env requirements unsatisfied (#108848)
* fix(skills): keep blank env requirements unsatisfied

* refactor(skills): reuse secret input presence check

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-16 08:37:35 -07:00
Peter Steinberger
2dd0e7b822 test(agents): harden SSH stream error timing 2026-07-16 16:31:52 +01:00
Peter Steinberger
ae547607b0 test: consolidate setup migration tests (#109110) 2026-07-16 08:25:55 -07:00
RileyJJY
352ef94d40 fix(config): cap missing-provider group-policy warning cache with shared dedupe helper (#108806) 2026-07-16 08:18:38 -07:00