* fix: route subagent announce to originating parent session instead of channel-bound peer session
When a subagent is spawned from agent:main:main while a Telegram DM is active,
the completion announce was delivered to the parallel Telegram channel session
instead of the originating parent.
Two interacting bugs:
1. The spawn tool received the sandbox/policy session key (Telegram peer key)
as the requester, instead of the real run session key. Fixed by passing
runSessionKey to createSessionsSpawnTool so the registered requester
points to the actual parent session.
2. resolveSubagentCompletionOrigin checked child session bindings before
requester bindings. When both share the same channel+accountId (common
for Telegram DMs), the child binding hijacked the delivery target.
Fixed by checking requester binding first, with child as fallback.
Fixes#80201
* fix: drop subagent_announce from mediated completion set
The subagent_announce addition to AGENT_MEDIATED_COMPLETION_TOOLS was
unrelated to the routing fix and could cause group/channel completions
to fail silently when the subagent does not use the message tool.
This should be addressed separately with proper message-tool-only
guidance (tracked in #80223).
* fix: separate sandbox policy from completion owner in sessions_spawn
PR #80242 passed runSessionKey as agentSessionKey to createSessionsSpawnTool,
which caused spawnSubagentDirect to use the run session key for sandbox policy
checks (resolveSandboxRuntimeStatus). This could make a sandboxed channel run
appear unsandboxed.
Introduce completionOwnerKey as a separate field that is only used for
registerSubagentRun routing (requesterSessionKey), keeping agentSessionKey
for sandbox enforcement, callerDepth, activeChildren, and all other policy
checks.
* fix(agents): preserve subagent ownership routing
---------
Co-authored-by: 忻役 <xinyi@mininglamp.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
The warning branch added in the previous commit was committed with an
always-false guard (`if (false && skippedCount > 0 && ...)`), so the
notification never fired — flagged by review as [P1]. Remove the
`false &&` so partial-album media loss actually notifies the user, as
the accompanying tests already expect.
Refs #55216
Telegram albums where some photos failed to download were processed
silently: the agent received only the photos that resolved, and the
user was never told images had been lost.
processMediaGroup now tracks a skippedCount (incremented on a
recoverable per-photo fetch error and on a null resolveMedia result).
When at least one photo still resolved, it emits a single anchored
warning per album (never per photo) using the same
withTelegramApiErrorLogging wrapper + swallowed-send pattern as the
existing single-attachment "Failed to download media" notice. The
all-failed-album case is intentionally left silent (out of scope).
Fixes#55216
* fix(browser): derive Chrome launch readiness from a single CDP diagnostic (#82904)
The pre-fix launch path used `isChromeReachable` (a lightweight HTTP
`/json/version` probe) to decide failure, then called the stronger
`diagnoseChromeCdp` only to format the thrown error. On macOS cold
starts where the HTTP probe transiently fails *between* the polling
loop and the diagnostic call, the runtime would throw
"Failed to start Chrome CDP on port ... { ok: true, wsUrl: ... }"
— a self-contradicting error containing a successful diagnostic
result. Per #82904 this is the actual user-visible bug.
Capture `diagnoseChromeCdp` ONCE after the polling loop and use it for
both the decision and the error text. The diagnostic helper already
includes the lightweight reachability check and adds a websocket
`Browser.getVersion` health command, so it is strictly stronger than
the HTTP probe; if `diagnoseChromeCdp` returns ok the launch
genuinely succeeded.
The existing `withMockChromeCdpServer` success test in
chrome.internal.test.ts still exercises this code path end-to-end
(real HTTP server + real websocket handshake), so the regression-safety
case is covered. The asymmetric `probe-fails-but-diagnostic-succeeds`
scenario is hard to mock without restructuring the existing test
harness; this commit ships the fix and relies on the upstream
ClawSweeper review criteria (manual managed-Chrome cold-start proof)
plus the standalone real-behavior probe in the PR body.
* fix(browser): import ChromeCdpDiagnostic type from chrome.diagnostics
The annotation `let finalDiagnostic: ChromeCdpDiagnostic | null` referenced
a type that was only re-exported (not imported) inside chrome.ts, causing
oxlint/tsc to read it as the implicit `error` type and fail check-lint,
check-prod-types, check-test-types, etc. Add the type to the existing
chrome.diagnostics.js import block.
* fix(browser): preserve Chrome launch diagnostic fallback
* test(browser): satisfy launch diagnostic lint
* fix(browser): keep Chrome launch readiness scoped
* test(browser): answer CDP launch mock probe
---------
Co-authored-by: hclsys <hclsys@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Summary:
- Split the lightweight secrets runtime state and auth-store cache from the full secrets runtime.
- Use the startup fast path whenever gateway startup has no SecretRef values, while preserving cleanup and refresh semantics.
- Add regression coverage for startup-only empty auth-store snapshots and update affected gateway/tool tests.
Verification:
- pnpm test src/secrets/runtime.fast-path.test.ts src/secrets/runtime-state.test.ts src/gateway/server-startup-config.secrets.test.ts src/gateway/server-import-boundary.test.ts src/gateway/server-aux-handlers.test.ts src/gateway/server-methods/config.shared-auth.test.ts src/agents/tools/web-tools.enabled-defaults.test.ts src/agents/tools/web-tool-runtime-context.test.ts -- --reporter=verbose
- pnpm build
- pnpm format:check -- src/agents/tools/web-tools.enabled-defaults.test.ts src/secrets/runtime-command-secrets.ts src/secrets/runtime-fast-path.ts src/secrets/runtime.fast-path.test.ts src/agents/auth-profiles/store.ts src/agents/auth-profiles/store-cache.ts src/secrets/runtime-state.ts src/secrets/runtime-state.test.ts src/gateway/server-startup-config.ts
- codex-review --mode branch
- isolated gateway token-auth smoke: openclaw gateway run + openclaw gateway health returned ok: true
- GitHub CI on PR #83031 green; newer Real behavior proof run passed on current SHA f27ed3f7ce.
Co-authored-by: samzong <samzong.lu@gmail.com>