fix(agents): resolve agentId unconditionally in message tool for cron/hook sessions#36236
fix(agents): resolve agentId unconditionally in message tool for cron/hook sessions#36236RealKai42 wants to merge 10 commits into
Conversation
Greptile SummaryThis PR fixes a bug where cron/hook agent sessions used default media roots instead of agent-scoped roots by unconditionally resolving Key findings:
Confidence Score: 3/5
Last reviewed commit: 87da294 |
| if (!json) { | ||
| defaultRuntime.log(`Gateway restart signal sent. Waiting for health...`); | ||
| } | ||
| return true; |
There was a problem hiding this comment.
Log message misleads — health check is never performed
After sending SIGUSR1, the code logs "Gateway restart signal sent. Waiting for health...", which implies health polling will follow. However, when onNotLoaded returns true, runServiceRestart in lifecycle-core.ts returns early (return true) immediately — entirely bypassing the postRestartCheck callback that contains waitForGatewayHealthyRestart. No health waiting actually occurs in this path.
Either:
- Perform a health check inside
onNotLoadedbefore returningtrue(or return the port so the caller can check), or - Change the log message to accurately describe what happened, e.g.
"Gateway restart signal (SIGUSR1) sent."without implying a wait.
| if (!json) { | |
| defaultRuntime.log(`Gateway restart signal sent. Waiting for health...`); | |
| } | |
| return true; | |
| if (!json) { | |
| defaultRuntime.log(`Gateway restart signal sent.`); | |
| } | |
| return true; |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cli/daemon-cli/lifecycle.ts
Line: 155-158
Comment:
**Log message misleads — health check is never performed**
After sending SIGUSR1, the code logs `"Gateway restart signal sent. Waiting for health..."`, which implies health polling will follow. However, when `onNotLoaded` returns `true`, `runServiceRestart` in `lifecycle-core.ts` returns early (`return true`) immediately — entirely bypassing the `postRestartCheck` callback that contains `waitForGatewayHealthyRestart`. No health waiting actually occurs in this path.
Either:
1. Perform a health check inside `onNotLoaded` before returning `true` (or return the port so the caller can check), or
2. Change the log message to accurately describe what happened, e.g. `"Gateway restart signal (SIGUSR1) sent."` without implying a wait.
```suggestion
if (!json) {
defaultRuntime.log(`Gateway restart signal sent.`);
}
return true;
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 87da29434d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| .filter((l) => { | ||
| const kind = classifyPortListener(l, port); | ||
| // Target listeners that look like the gateway or unknown (container pid may not show full path). | ||
| return kind === "gateway" || kind === "unknown"; |
There was a problem hiding this comment.
Restrict fallback signals to confirmed gateway listeners
The fallback PID selector includes listeners classified as unknown, and classifyPortListener marks any non-OpenClaw/non-SSH process as unknown; this means openclaw gateway stop/restart in no-service-manager environments can send SIGTERM/SIGUSR1 to unrelated processes that happen to own the configured port. This is a production safety issue when the port is reused by another app (or listener metadata is incomplete), because we can terminate or signal the wrong process.
Useful? React with 👍 / 👎.
| const handled = await params.onNotLoaded().catch(() => false); | ||
| if (handled) { | ||
| return true; |
There was a problem hiding this comment.
Run post-restart verification after handled fallback restart
When onNotLoaded returns true, runServiceRestart exits immediately, so postRestartCheck is skipped even though the new fallback path logs "Waiting for health...". In container/no-manager flows this can report restart success without ever checking gateway health; if SIGUSR1 is ignored or restart fails, the command still returns success.
Useful? React with 👍 / 👎.
| if (!target || typeof target !== "object" || Array.isArray(target)) { | ||
| target = null; | ||
| break; |
There was a problem hiding this comment.
Allow array traversal when stripping unknown config keys
The unknown-key stripping loop aborts whenever the current target is an array, so issues whose path includes an index (for example agents.list[0]) are never stripped. As a result, stale keys inside array entries still fail validation instead of being auto-ignored, which defeats the intended compatibility behavior for configs with removed keys.
Useful? React with 👍 / 👎.
💡 Codex Reviewopenclaw/src/cli/daemon-cli/lifecycle.ts Lines 80 to 82 in 2bb8a4a
openclaw/src/cli/daemon-cli/lifecycle-core.ts Lines 223 to 225 in 2bb8a4a When ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Summary
Fixes #36185 — message tool uses default media roots instead of agent-scoped roots for cron/hook sessions.
Root cause: In
createMessageTool, theagentIdpassed torunMessageActionwas only resolved whenagentSessionKeywas present:Cron and hook sessions often have no explicit
agentSessionKey, soagentIdwas leftundefined. This causedgetAgentScopedMediaLocalRoots(cfg, undefined)to return only the default roots, rejecting workspace files withLocalMediaAccessError: path-not-allowed.Fix: Always call
resolveSessionAgentId— it falls back to the default agent ID when no session key is provided — and pass the result unconditionally.Changes
src/agents/tools/message-tool.ts: extractresolvedAgentIdunconditionally usingresolveSessionAgentId({ sessionKey: options?.agentSessionKey, config: cfg })so cron/hook sessions still receive the correct agent-scoped media roots.src/agents/tools/message-tool.test.ts: add test verifyingagentIdis a non-empty string even when no session key is present.CHANGELOG.md: add fix entry for message tool uses default media roots instead of agent-scoped roots #36185.Test plan
pnpm test src/agents/tools/message-tool.test.ts— all 15 tests pass (including new "falls back to default agentId when no session key is present" test).pnpm check— 0 warnings, 0 errors.