openclaw - ✅(Solved) Fix ACP: gemini CLI session/load always fails - acpx session ID not recognized by gemini [1 pull requests, 2 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#52182Fetched 2026-04-08 01:14:38
View on GitHub
Comments
2
Participants
3
Timeline
29
Reactions
0
Author
Timeline (top)
referenced ×25commented ×2closed ×1cross-referenced ×1

Error Message

{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"Internal error","data":{"details":"Invalid session identifier "3403b421-...". Use --list-sessions to see available sessions"}}}

Root Cause

acpx generates its own session UUIDs and expects the agent to accept them via session/load. Gemini CLI only recognizes session IDs it created itself (stored in ~/.gemini/history/). The fallback to session/new works for a single turn but breaks session tracking:

  • OpenClaw stores the acpx session ID → identity stays pending forever
  • Gemini stores its own session ID → never matches on reload
  • Multi-turn sessions fail because the second session/load uses the acpx ID again

Fix Action

Fixed

PR fix notes

PR #52209: fix(acpx): store agent session ID when session/load fails

Description (problem / solution / changelog)

Problem

When an ACP agent (e.g. Gemini CLI) rejects the acpx-generated session ID in session/load and falls back to session/new, the agent-returned session ID was previously discarded. This caused:

  • Identity stuck at pending forever (never resolving to resolved)
  • Multi-turn sessions failing on second turn (wrong session ID sent)
  • Completion events lost in oneshot mode
  • Persistent checked=N resolved=0 failed=N reconcile warnings on every gateway restart

Codex CLI is unaffected because it accepts external session IDs. Gemini CLI only recognizes its own session IDs, triggering this bug.

Root Cause

The ACP protocol trace shows:

  1. acpx sends session/load with its generated session ID
  2. Gemini returns error: "Invalid session identifier"
  3. acpx falls back to session/new, Gemini returns its own session ID
  4. Bug: The agent-returned session ID from step 3 was never captured or stored
  5. All subsequent operations used the wrong (acpx) ID

Fix

extensions/acpx/src/runtime.ts

  • Parse the ACP JSON-RPC protocol stream during runTurn() to detect session/new responses containing an agentSessionId
  • Update the runtime handle in real-time when an agent session ID is discovered
  • Use agentSessionId (when available) instead of the acpx name for all subsequent --session commands (status, cancel, set-mode, set)

src/acp/runtime/session-identity.ts

  • Flip resolveRuntimeResumeSessionId() priority: prefer agentSessionId over acpxSessionId so persistent sessions resume with the correct agent ID
  • Add createIdentityFromHandleEvent() to create identity objects from handle-level session ID discoveries

src/acp/control-plane/manager.identity-reconcile.ts

  • Layer handle event identity before status-based identity during reconciliation
  • Sessions with a discovered agentSessionId now resolve to "resolved" state immediately, even if the runtime status probe omits them

Test fixtures (runtime-fixtures.ts)

  • Add session state persistence (JSON file) to the mock CLI script so session IDs are tracked across ensure/prompt/status/cancel calls
  • Add MOCK_ACPX_PROMPT_LOAD_INVALID and MOCK_ACPX_PROMPT_NEW_AGENT_SESSION_ID env vars to simulate the Gemini load-rejection scenario

Tests

  • runtime.test.ts: New test verifying prompt-time session ID learning and reuse across turns
  • manager.test.ts: Two new tests — restart resume prefers agentSessionId, and reconcile resolves identity from handle events when status omits agent IDs

How I tested

  • manager.test.ts: 35/35 tests pass (including 2 new regression tests)
  • runtime.test.ts: Existing tests pass; new load-fallback test passes. Note: this test file has a pre-existing upstream import error (message-tool-schema.js deleted from main) that prevents the full suite from loading — this is unrelated to this PR.

Closes #52182

Changed files

  • docs/.generated/config-baseline.json (modified, +1/-1)
  • docs/.generated/config-baseline.jsonl (modified, +1/-1)
  • extensions/acpx/src/runtime.test.ts (modified, +92/-7)
  • extensions/acpx/src/runtime.ts (modified, +123/-12)
  • extensions/acpx/src/test-utils/runtime-fixtures.ts (modified, +172/-30)
  • extensions/irc/src/inbound.behavior.test.ts (modified, +1/-1)
  • extensions/mattermost/src/mattermost/directory.test.ts (modified, +6/-12)
  • extensions/msteams/src/setup-surface.test.ts (modified, +3/-1)
  • extensions/nextcloud-talk/src/inbound.behavior.test.ts (modified, +9/-3)
  • extensions/openshell/src/remote-fs-bridge.test.ts (modified, +4/-2)
  • src/acp/control-plane/manager.core.ts (modified, +16/-2)
  • src/acp/control-plane/manager.identity-reconcile.ts (modified, +13/-2)
  • src/acp/control-plane/manager.test.ts (modified, +131/-2)
  • src/acp/runtime/session-identity.ts (modified, +21/-1)
  • src/agents/pi-embedded-runner/extensions.ts (modified, +1/-1)
  • src/agents/subagent-announce.ts (modified, +2/-0)
  • src/agents/subagent-registry.announce-loop-guard.test.ts (modified, +239/-4)
  • src/agents/subagent-registry.ts (modified, +69/-4)
  • src/agents/subagent-registry.types.ts (modified, +4/-0)
  • src/agents/subagent-spawn.ts (modified, +15/-0)
  • src/agents/tools/sessions-spawn-tool.test.ts (modified, +65/-0)
  • src/agents/tools/sessions-spawn-tool.ts (modified, +26/-0)
  • src/config/schema.base.generated.ts (modified, +6/-6)
  • src/config/schema.help.ts (modified, +2/-2)
  • src/config/zod-schema.agent-defaults.ts (modified, +1/-1)
  • src/infra/heartbeat-runner.model-override.test.ts (modified, +22/-1)
  • src/infra/heartbeat-runner.ts (modified, +5/-0)

Code Example

# Create an acpx session
acpx gemini sessions new
# Output: created session cwd (3403b421-054f-4f30-9aaa-47aaa9b4ead2)

# Send a prompt
echo '{"role":"user","content":"say hello"}' | acpx --format json --json-strict --approve-all gemini prompt --file -

---

// 1. acpx sends session/load with its own session ID
{"jsonrpc":"2.0","id":1,"method":"session/load","params":{"sessionId":"3403b421-...","cwd":"/path/to/project"}}

// 2. Gemini rejects it - does not recognize this ID
{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"Internal error","data":{"details":"Invalid session identifier \"3403b421-...\". Use --list-sessions to see available sessions"}}}

// 3. acpx falls back to session/new - gemini creates ITS OWN session ID
{"jsonrpc":"2.0","id":2,"method":"session/new","params":{"cwd":"/path/to/project"}}
{"jsonrpc":"2.0","id":2,"result":{"sessionId":"698380a6-..."}}  // Different ID!

// 4. Prompt works fine on first turn
{"jsonrpc":"2.0","id":3,"result":{"stopReason":"end_turn"}}
// But OpenClaw cannot track this session properly
RAW_BUFFERClick to expand / collapse

Bug Description

When OpenClaw spawns a Gemini CLI session via ACP (acpx), session/load always fails because Gemini CLI does not recognize acpx-generated session IDs. This causes:

  1. Oneshot mode: Gemini completes the task but OpenClaw never receives the completion event → session stuck at idle/pending
  2. Persistent mode: Second turn fails with ACP_TURN_FAILED (session ID mismatch)
  3. Identity reconcile: All gemini sessions accumulate as pending, causing checked=N resolved=0 failed=N warnings on every gateway restart

Reproduction

# Create an acpx session
acpx gemini sessions new
# Output: created session cwd (3403b421-054f-4f30-9aaa-47aaa9b4ead2)

# Send a prompt
echo '{"role":"user","content":"say hello"}' | acpx --format json --json-strict --approve-all gemini prompt --file -

Observed ACP Protocol Trace

// 1. acpx sends session/load with its own session ID
{"jsonrpc":"2.0","id":1,"method":"session/load","params":{"sessionId":"3403b421-...","cwd":"/path/to/project"}}

// 2. Gemini rejects it - does not recognize this ID
{"jsonrpc":"2.0","id":1,"error":{"code":-32603,"message":"Internal error","data":{"details":"Invalid session identifier \"3403b421-...\". Use --list-sessions to see available sessions"}}}

// 3. acpx falls back to session/new - gemini creates ITS OWN session ID
{"jsonrpc":"2.0","id":2,"method":"session/new","params":{"cwd":"/path/to/project"}}
{"jsonrpc":"2.0","id":2,"result":{"sessionId":"698380a6-..."}}  // Different ID!

// 4. Prompt works fine on first turn
{"jsonrpc":"2.0","id":3,"result":{"stopReason":"end_turn"}}
// But OpenClaw cannot track this session properly

Root Cause

acpx generates its own session UUIDs and expects the agent to accept them via session/load. Gemini CLI only recognizes session IDs it created itself (stored in ~/.gemini/history/). The fallback to session/new works for a single turn but breaks session tracking:

  • OpenClaw stores the acpx session ID → identity stays pending forever
  • Gemini stores its own session ID → never matches on reload
  • Multi-turn sessions fail because the second session/load uses the acpx ID again

Expected Behavior

Either:

  • Option A: acpx should use the session ID returned by session/new for subsequent operations (not its own generated ID)
  • Option B: acpx should detect that session/load failed and store the mapping (acpx ID → agent ID) for future reference
  • Option C: The identity reconcile should handle the session/load failure gracefully and mark the session as resolved using the agent-provided ID

Environment

  • OpenClaw: latest (installed via npm)
  • acpx: 0.1.16
  • Gemini CLI: 0.34.0
  • Node: 22.22.0
  • macOS arm64

Impact

This affects all users trying to use Gemini CLI via ACP. Codex ACP works fine (codex accepts acpx session IDs). The bug makes Gemini ACP effectively unusable for multi-turn sessions and causes completion events to be lost in oneshot mode.

extent analysis

Fix Plan

To resolve the issue, we will implement Option A: acpx will use the session ID returned by session/new for subsequent operations.

Here are the steps:

  • Modify the acpx code to store the session ID returned by session/new in a variable.
  • Use this stored session ID for subsequent session/load operations.

Example code changes:

# Store the session ID returned by session/new
session_id = None

# ...

def handle_session_new(response):
    global session_id
    session_id = response['result']['sessionId']

# ...

def handle_session_load():
    global session_id
    if session_id is not None:
        # Use the stored session ID for subsequent session/load operations
        params = {'sessionId': session_id, 'cwd': '/path/to/project'}
        # Send the session/load request with the stored session ID
        send_request('session/load', params)
    else:
        # Fallback to the original behavior if no session ID is stored
        params = {'sessionId': generated_session_id, 'cwd': '/path/to/project'}
        send_request('session/load', params)

Verification

To verify that the fix worked:

  1. Create a new acpx session using acpx gemini sessions new.
  2. Send a prompt using echo '{"role":"user","content":"say hello"}' | acpx --format json --json-strict --approve-all gemini prompt --file -.
  3. Check the ACP protocol trace to ensure that the session ID returned by session/new is used for subsequent session/load operations.
  4. Verify that the session is properly tracked and completion events are received.

Extra Tips

  • Make sure to update the acpx version to include the fix.
  • If you encounter any issues, check the ACP protocol trace to ensure that the session ID is being used correctly.
  • Consider implementing Option B or Option C as an alternative solution.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix ACP: gemini CLI session/load always fails - acpx session ID not recognized by gemini [1 pull requests, 2 comments, 3 participants]