Skip to content

Add message ID tracking and session registry for client deduplication#72

Merged
gricha merged 3 commits intomainfrom
feature/message-id-tracking
Jan 10, 2026
Merged

Add message ID tracking and session registry for client deduplication#72
gricha merged 3 commits intomainfrom
feature/message-id-tracking

Conversation

@gricha
Copy link
Copy Markdown
Owner

@gricha gricha commented Jan 10, 2026

Summary

  • Capture upstream message IDs from Claude (msg.message.id or msg.id) and OpenCode (part.messageID) adapters
  • Propagate messageId to all emitted ChatMessage objects (text deltas, tool calls, done messages)
  • Add session registry (src/sessions/registry.ts) with file locking for concurrent access safety
  • Sessions tracked from first message with Perry-assigned IDs, linked to agent session IDs when available
  • Auto-import external sessions discovered during listing

This enables clients to deduplicate messages on reconnection using messageId + content as a stable key.

Additional changes (review feedback)

Registry simplification:

  • Removed unused functions (touchSession, getSession, findSessionByAgentId, getAllSessions, deleteSession, sessionExists)
  • Kept only functions actually used: createSession, linkAgentSession, getSessionsForWorkspace, importExternalSession

Error handling:

  • Fixed silent error swallowing in manager.ts
  • createSession now properly awaited
  • linkAgentSession errors routed through handleAdapterError

Update checker fix:

  • Skip update check for worker commands (was breaking OpenCode session listing by polluting stdout with update messages)
  • Use console.error instead of console.log for update notifications

Web UI deduplication:

  • Added messageId-based deduplication for reconnection scenarios
  • Track seen messages via seenMessageChunksRef
  • Deduplicate user messages, tool_use, tool_result by messageId/toolId

Test plan

  • All tests pass (76 session-related tests)
  • Manual testing of OpenCode session listing
  • Web UI reconnection deduplication verified

🤖 Generated with Claude Code

gricha and others added 2 commits January 10, 2026 03:00
- Capture upstream message IDs from Claude (msg.message.id or msg.id) and
  OpenCode (part.messageID) adapters
- Propagate messageId to all emitted ChatMessages (text deltas, tool calls,
  done messages)
- Add session registry (src/sessions/registry.ts) with file locking for
  concurrent access safety
- Sessions tracked from first message with Perry-assigned IDs, linked to
  agent session IDs when available
- Auto-import external sessions discovered during listing
- Add comprehensive test coverage (96 session-related tests)

This enables clients to deduplicate messages on reconnection using
messageId + content as a stable key.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Registry changes:
- Remove unused functions (touchSession, getSession, findSessionByAgentId,
  getAllSessions, deleteSession, sessionExists)
- Keep only: createSession, linkAgentSession, getSessionsForWorkspace,
  importExternalSession

Error handling:
- Fix silent error swallowing in manager.ts
- createSession now properly awaited
- linkAgentSession errors routed to handleAdapterError

Update checker:
- Skip update check for worker commands (programmatic use)
- Use console.error instead of console.log (doesn't pollute stdout)

Web UI:
- Add messageId-based deduplication for reconnection scenarios
- Track seen messages via seenMessageChunksRef
- Deduplicate user messages, tool_use, tool_result by messageId/toolId

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Comment on lines 226 to 235
this.emitMessage({
type: 'done',
content: 'Response complete',
messageId: this.currentMessageId,
timestamp,
});
this.currentMessageId = undefined;
}
}

This comment was marked as outdated.

Fix bug where currentMessageId wasn't cleared in error or interrupt
scenarios, causing subsequent messages to reuse stale IDs and break
client-side deduplication.

- Claude adapter: clear in handleProcessExit
- OpenCode adapter: clear in catch block and interrupt method

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@gricha gricha merged commit 8e49f46 into main Jan 10, 2026
8 checks passed
@gricha gricha deleted the feature/message-id-tracking branch January 10, 2026 04:53
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