Skip to content

feat: add --session-key support to system wake/event#34944

Closed
BrennerSpear wants to merge 1 commit into
openclaw:mainfrom
BrennerSpear:feat/session-key-wake-v4
Closed

feat: add --session-key support to system wake/event#34944
BrennerSpear wants to merge 1 commit into
openclaw:mainfrom
BrennerSpear:feat/session-key-wake-v4

Conversation

@BrennerSpear

Copy link
Copy Markdown
Contributor

Summary

  • Adds optional --session-key flag to system wake and system event CLI commands
  • Threads sessionKey through HTTP endpoints (/wake, /system-event), hook dispatch, and cron wake
  • Updates protocol schema and regenerates Swift models with explicit nil defaults for optional params
  • Adds canonicalizeWakeParams helper in session-utils for consistent wake parameter handling

Test plan

  • All 114 new/modified tests pass (vitest run on all 10 test files)
  • pnpm protocol:check passes (schema + Swift codegen in sync)
  • git diff --stat origin/main shows only expected files (22 files, no unrelated changes)
  • No .tldr/, vite.config.ts, process-respawn.test.ts, store.ts, or PRD files in diff

🤖 Generated with Claude Code

@openclaw-barnacle openclaw-barnacle Bot added app: macos App: macos app: web-ui App: web-ui gateway Gateway runtime cli CLI command changes scripts Repository scripts size: XL labels Mar 4, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: abc53e3142

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/gateway/server-methods/cron.ts Outdated
Comment on lines +63 to +65
if (p.mode === "now") {
requestHeartbeatNow({ reason: "wake", sessionKey });
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Wake targeted sessions on next-heartbeat cron requests

When sessionKey is provided, this path only calls requestHeartbeatNow for mode === "now"; in next-heartbeat mode it just enqueues into that specific session. The heartbeat runner only reads the main (or statically configured heartbeat.session) key unless a forced session key is passed, so non-main session events can sit indefinitely until another targeted wake happens. As a result, system event --session-key <non-main> --mode next-heartbeat can silently stall.

Useful? React with 👍 / 👎.

Comment thread src/gateway/server/hooks.ts Outdated
Comment on lines +47 to +51
if (value.mode === "now") {
requestHeartbeatNow({ reason: "hook:wake" });
// Only scope the heartbeat nudge when an explicit session key was
// provided. Omitting sessionKey preserves fan-out to all agents.
if (sessionKey) {
requestHeartbeatNow({ reason: "hook:wake", sessionKey });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Wake hook-targeted sessions for next-heartbeat mode

This logic also scopes heartbeat nudges to mode === "now" only. For hook wake payloads/mappings that set a non-main sessionKey with next-heartbeat, the event is queued in that session but no targeted run is ever requested, and interval heartbeats do not scan arbitrary session keys. Those hook events can therefore remain unprocessed until some later explicit wake for the same session.

Useful? React with 👍 / 👎.

@greptile-apps

greptile-apps Bot commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds an optional --session-key flag to the system event CLI command and threads the sessionKey parameter through HTTP hook endpoints (/hooks/wake), WebSocket RPC handlers (system-event, cron.wake), and the dispatchWakeHook pathway. It also adds a canonicalizeWakeSessionKey helper in session-utils.ts that mirrors the heartbeat runner's two-step resolution, adds sessionKey to the WakeParams protocol schema, and regenerates Swift models with explicit = nil defaults for optional constructor parameters.

Key observations:

  • canonicalizeWakeSessionKey is well-designed and thoroughly tested (120+ lines of test coverage), including the important regression case where scope=global must short-circuit to "global" for all keys to avoid silently misrouted events.
  • Dead code in server-http.ts (lines 413–417 and 494–501): In both the direct /hooks/wake and mapped-wake paths, the else (no-sessionKey) branches call dispatchWakeHook and then check if (!wakeResult.ok). Since dispatchWakeHook only returns { ok: false } when canonicalizeWakeSessionKey throws (which requires a sessionKey to be present), these checks in the no-key branches are unreachable dead code. Either remove them or add a comment explaining the intentional defensive check.
  • The cron.wake fan-out path response shape gains a mode field ({ ok: result.ok, mode: p.mode } vs. the previous result passthrough). context.cron.wake() only returns { ok: boolean }, so no error details are dropped, and adding mode is backwards-compatible.
  • Swift model codegen (protocol-gen-swift.ts) correctly updates the template to add = nil defaults for all optional init params, and a new regression test in test/protocol-gen-swift.test.ts verifies no optional param is missing its default.

Confidence Score: 4/5

  • Safe to merge with minor dead code cleanup recommended in server-http.ts.
  • This PR is well-scoped and thoroughly tested (114 tests across 10 files). The feature logic is sound and the canonicalization helper mirrors the existing heartbeat runner pattern. The only actionable finding is a small amount of dead code in server-http.ts (unreachable if (!wakeResult.ok) checks in the no-sessionKey branches). This does not affect functionality or security but should be cleaned up for code hygiene.
  • src/gateway/server-http.ts — the no-sessionKey dispatch branches (lines 413–417 and 494–501) have unreachable ok:false checks that should either be removed or commented as intentionally defensive.

Last reviewed commit: abc53e3

Comment on lines +413 to +417
const wakeResult = dispatchWakeHook(normalized.value);
if (!wakeResult.ok) {
sendJson(res, 400, { ok: false, error: wakeResult.error });
return true;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dead code in no-sessionKey branch.

When normalized.value.sessionKey is absent, dispatchWakeHook is called without a sessionKey argument. Inside dispatchWakeHook (in server/hooks.ts) the if (value.sessionKey) guard is skipped, so canonicalizeWakeSessionKey is never called and the function unconditionally returns { ok: true }. The if (!wakeResult.ok) check below can therefore never be true in this branch.

The same pattern repeats in the mapping path (lines 494–501). Consider removing the dead-code guard, or adding a brief comment explaining why it is intentionally defensive:

Suggested change
const wakeResult = dispatchWakeHook(normalized.value);
if (!wakeResult.ok) {
sendJson(res, 400, { ok: false, error: wakeResult.error });
return true;
}
const wakeResult = dispatchWakeHook(normalized.value);
// dispatchWakeHook only returns ok:false when a sessionKey canonicalization
// fails; without a sessionKey it always returns ok:true.
if (!wakeResult.ok) {
sendJson(res, 400, { ok: false, error: wakeResult.error });
return true;
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/gateway/server-http.ts
Line: 413-417

Comment:
Dead code in no-sessionKey branch.

When `normalized.value.sessionKey` is absent, `dispatchWakeHook` is called without a `sessionKey` argument. Inside `dispatchWakeHook` (in `server/hooks.ts`) the `if (value.sessionKey)` guard is skipped, so `canonicalizeWakeSessionKey` is never called and the function unconditionally returns `{ ok: true }`. The `if (!wakeResult.ok)` check below can therefore never be `true` in this branch.

The same pattern repeats in the mapping path (lines 494–501). Consider removing the dead-code guard, or adding a brief comment explaining why it is intentionally defensive:

```suggestion
      const wakeResult = dispatchWakeHook(normalized.value);
      // dispatchWakeHook only returns ok:false when a sessionKey canonicalization
      // fails; without a sessionKey it always returns ok:true.
      if (!wakeResult.ok) {
        sendJson(res, 400, { ok: false, error: wakeResult.error });
        return true;
      }
```

How can I resolve this? If you propose a fix, please make it concise.

@BrennerSpear BrennerSpear force-pushed the feat/session-key-wake-v4 branch from abc53e3 to 20af7fa Compare March 4, 2026 21:32
@openclaw-barnacle openclaw-barnacle Bot removed the scripts Repository scripts label Mar 4, 2026
@BrennerSpear BrennerSpear force-pushed the feat/session-key-wake-v4 branch from 20af7fa to 9953e04 Compare March 4, 2026 23:11
@BrennerSpear

Copy link
Copy Markdown
Contributor Author

Superseded by #35231

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: macos App: macos app: web-ui App: web-ui cli CLI command changes gateway Gateway runtime size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant