Skip to content

feat: forward proposedSessionId in session/new via createSession hints#249

Open
henkterharmsel wants to merge 2 commits intoopenclaw:mainfrom
henkterharmsel:fix/proposed-session-id
Open

feat: forward proposedSessionId in session/new via createSession hints#249
henkterharmsel wants to merge 2 commits intoopenclaw:mainfrom
henkterharmsel:fix/proposed-session-id

Conversation

@henkterharmsel
Copy link
Copy Markdown

@henkterharmsel henkterharmsel commented Apr 16, 2026

What

Two related fixes for reliable ACP session resume in `acpx`:

1. `createSession(cwd, hints?)` — forward `proposedSessionId`

`createSession` now accepts an optional `hints` object. When `hints.proposedSessionId` is provided, it is included in the `_meta` field of the `session/new` ACP request.

All internal `createSession` call sites in the runtime engine (`manager.ts` and `reconnect.ts`) now derive the session UUID from the ACP session key (`agent:claude:acp:` → `.split(':').pop()`) and pass it as `proposedSessionId`. This gives Claude Code sessions a stable, predictable file name — required for reliable resume.

2. Oneshot resume double-load fix

`ensureSession` (phase 1) previously started Claude, loaded the session, then shut it down via `client.close()`. This wrote a `closed` marker to the JSONL file. `connectAndLoadSession` (phase 2) then failed because the JSONL was already closed.

For oneshot sessions with a `resumeSessionId`, `ensureSession` now skips the start/load/close cycle entirely, constructs a minimal session record, and returns early. Phase 2 performs the actual resume.

Why

Without these fixes, resuming a completed oneshot session in OpenClaw always returns "Internal error". New sessions work fine; it is specifically resume that fails.

Root causes:

  1. `claude-agent-acp` used `randomUUID()` for every session, making file names unpredictable.
  2. `acpx` did not support passing `proposedSessionId` through `createSession` or its internal call sites.
  3. `ensureSession`'s two-phase design closed the JSONL before phase 2 could use it.

Backward Compatibility

Both changes are additive. Existing behavior is preserved for non-oneshot modes and sessions without a `resumeSessionId`. Passing `proposedSessionId` is opt-in.

Dependencies

This PR is part of a two-repo fix for ACP session resume. Merge order:

  1. `fix: deterministic session IDs and reliable resume for ACP sessions agentclientprotocol/claude-agent-acp#554` — support `proposedSessionId` in `_meta` and fix UUID extraction (merge first)
  2. `openclaw/acpx` — this PR (merge after Align CI/test setup with SimpleDoc and expand coverage #1)

Note: an openclaw PR is not required. OpenClaw already passes the correct `resumeSessionId` and `sessionKey` parameters to `ensureSession` — all fixes are encapsulated in `acpx`.

Each PR is backward-compatible with the previous version of its dependency.

Testing

  • New tests added for `proposedSessionId` forwarding (in `createSession` and reconnect fallback paths), oneshot resume bypass, and UUID extraction.
  • Full test suite passes: `pnpm test` (527/527)
  • Build and lint clean: `pnpm build && pnpm check`
  • End-to-end verified locally: OpenClaw oneshot sessions resume correctly with multi-turn history preserved (OpenClaw 2026.4.12 + acpx 0.5.3 + claude-agent-acp 0.27.0).

AI Assistance 🤖

Developed with AI assistance (Claude Code). Logic derived from locally-applied patches confirmed working. Author (Henk ter Harmsel) has reviewed and understands all changes.

…n hints

createSession(cwd, hints?) now accepts an optional hints object. If
hints.proposedSessionId is set, it is forwarded in the _meta field of
the session/new ACP request, allowing the agent (claude-agent-acp) to
use it as the session ID instead of generating a random UUID.

This enables ACP callers to create sessions with predictable, deterministic
file names — a prerequisite for reliable session resume.

Backward-compatible: omitting hints produces the same behavior as before.
Two related fixes for reliable ACP session resume:

1. proposedSessionId in createSession calls: all createSession call sites
   now pass the session UUID (extracted from the session key via .split(':').pop())
   as proposedSessionId. This gives Claude Code sessions a predictable, stable
   file name — required for resume to work.

2. Oneshot resume double-load fix: ensureSession previously started Claude,
   loaded the session, then closed it. This wrote a 'closed' marker to the JSONL
   file. connectAndLoadSession (phase 2) then failed because the JSONL was already
   marked closed. For oneshot sessions with a resumeSessionId, ensureSession now
   skips the start/load/close cycle entirely, saves a minimal record, and returns
   early. Phase 2 handles the actual resume.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant