Skip to content

refactor(backend): extract shared session helpers β€” Kilo + OpenCode - #173

Merged
claudiusthebot merged 1 commit into
mainfrom
feat/shared-session-helpers
May 16, 2026
Merged

refactor(backend): extract shared session helpers β€” Kilo + OpenCode#173
claudiusthebot merged 1 commit into
mainfrom
feat/shared-session-helpers

Conversation

@claudiusthebot

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #172. The previous PR unified MCP / sessions-lifecycle /
delivery / SSE between the two remote-server backends. This one
extracts the remaining big duplication: their sessions.ts
modules.

kilo/sessions.ts (593 LOC) and opencode/sessions.ts (492 LOC) had
~95% byte-for-byte duplication. Both contained the same:

  • extractPartsSummary (parts β†’ text + tool count + synthetic flag)
  • extractAssistantUsage (token / cost from info blob)
  • summarizeXAssistantMessages (batch β†’ usage totals)
  • getXTurnSummary / getXSessionSnapshot (high-level wrappers)
  • rejectPendingQuestions (auto-handle question.list)
  • Internal helpers: summarizeQuestionHeaders, isToolApprovalQuestion,
    parseAssistantMessage, listSessionMessages, etc.

The only meaningful difference was that Kilo's extractPartsSummary
peeled synthetic: true parts into a separate syntheticErrorText
channel; OpenCode's didn't.

What changed

New backend/remote-server/session-helpers.ts (541 LOC, mostly
docstrings) containing:

  • RemoteAssistantInfo, RemoteSessionSnapshot, ParsedAssistantMessage, RemoteUsageSummary β€” shapes shared across backends.
  • RemoteSessionClient β€” extends RemoteAgentClient with the session.messages + question.{list,reply,reject} methods these helpers need. Both KiloClient and OpencodeClient structurally satisfy it.
  • REMOTE_SESSION_MESSAGE_LIMIT (5000).
  • extractPartsSummary β€” now with synthetic-error detection. Both backends gain it.
  • extractAssistantUsage
  • summarizeAssistantMessages
  • listSessionMessages
  • getTurnSummary
  • getSessionSnapshot (takes client as parameter so the shared helper doesn't bake in either backend's ensureServer)
  • rejectPendingQuestions β€” with injected backendLabel for log prefixes (Auto-approved Kilo tool question vs Auto-approved OpenCode tool question).

kilo/sessions.ts and opencode/sessions.ts reduced to thin shims:

  • Re-export shared helpers under backend-prefixed names for back-compat (KiloAssistantInfo / OpenCodeAssistantInfo are type aliases, getKiloTurnSummary / getOpenCodeTurnSummary wrap the shared getTurnSummary with backend-typed clients).
  • getKiloSessionSnapshot / getOpenCodeSessionSnapshot thread their respective ensureServer() into the shared getSessionSnapshot.
  • rejectPendingQuestions injects the backend label.

Behavioural change

OpenCode now ALSO recognises synthetic: true markers. Previously
documented as an asymmetry in the conformance test β€” synthetic is the
upstream's convention (Kilo + OpenCode emit it identically), so
symmetric handling is the right default. The conformance test for this
case has been updated to assert symmetric behaviour.

Dead-code removal

waitForPromptWithQuestionGuard and waitForAssistantReply deleted
from both backends. They were sync-prompt wrappers from the pre-SSE
era; both backends now use promptAsync + SSE (PR #172). Also dropped
from kilo/index.ts barrel re-exports.

Stats

File Before After Delta
kilo/sessions.ts 593 100 βˆ’493
opencode/sessions.ts 492 102 βˆ’390
remote-server/session-helpers.ts (new) β€” 541 +541
remote-server-session-helpers.test.ts (new) β€” 396 +396

Net: 883 LOC of duplicated logic collapsed into one tested module +
thin shims.

Tests

  • 24 new unit tests in remote-server-session-helpers.test.ts covering:
    • extractPartsSummary text joining, synthetic detection, reasoning filtering, edge cases
    • extractAssistantUsage zero defaults + full extraction
    • summarizeAssistantMessages aggregation, minCreatedAt filter, non-assistant skip, meaningful-message filter
    • listSessionMessages dedup, default limit, override limit
    • getTurnSummary end-to-end
    • getSessionSnapshot undefined-id, full snapshot construction, no-assistant case
    • rejectPendingQuestions tool-approval auto-allow, non-tool rejection, cross-session filter, idempotency, upstream-failure tolerance
  • Updated synthetic-error case in backend-conformance.test.ts to assert symmetric behaviour
  • Full suite: 2285 passing (+24 new), 12 skipped (live-tier), 0 failing

Test plan

  • npx tsc --noEmit clean
  • npm test β€” 2285 passing, 12 skipped, 0 failing
  • npm run lint β€” 0 errors, 15 pre-existing warnings unchanged
  • npm run format:check clean
  • CI matrix on push
  • Verify getKiloSessionSnapshot / getOpenCodeSessionSnapshot still return the right shape for /status (covered by existing kilo-summary tests via the shared summarizeAssistantMessages)

πŸ€– Generated with Claude Code

@claudiusthebot
claudiusthebot force-pushed the feat/shared-session-helpers branch from 8384ec9 to 1da15fc Compare May 15, 2026 23:52
@claudiusthebot
claudiusthebot enabled auto-merge (squash) May 15, 2026 23:52
@claudiusthebot
claudiusthebot force-pushed the feat/shared-session-helpers branch 2 times, most recently from 44cc42d to e3d4d69 Compare May 16, 2026 00:14
Both `kilo/sessions.ts` (593 LOC) and `opencode/sessions.ts` (492 LOC)
had ~95% byte-for-byte duplication of the message-parsing, usage
summary, snapshot construction, and pending-question rejection logic.
Move into `backend/remote-server/session-helpers.ts` so both backends
share one tested implementation.

Extracted to shared:

  - `RemoteAssistantInfo` β€” narrow `Message.info` shape (used by both).
  - `RemoteSessionSnapshot` β€” shape returned by getSessionSnapshot.
  - `REMOTE_SESSION_MESSAGE_LIMIT` (5000) β€” page cap for session.messages.
  - `extractPartsSummary` β€” parts walk, joins text with `\n\n`, peels
    `synthetic: true` parts into `syntheticErrorText`.
  - `extractAssistantUsage` β€” token + cost from message info.
  - `summarizeAssistantMessages` β€” aggregate a batch into usage totals.
  - `listSessionMessages` β€” fetch + dedupe by `info.id`.
  - `getTurnSummary` β€” list-then-summarise wrapper.
  - `getSessionSnapshot` β€” session.get + listSessionMessages β†’
    RemoteSessionSnapshot. Now takes the client as a parameter so the
    shared helper isn't coupled to either backend's `ensureServer`.
  - `rejectPendingQuestions` β€” auto-handle upstream questions with an
    injected `backendLabel` for log prefixes.

Backend-side modules become thin shims:

  - `kilo/sessions.ts`: 593 β†’ 100 LOC. Re-exports under Kilo-prefixed
    names (`KiloAssistantInfo`, `getKiloTurnSummary`, etc) for
    back-compat with handler + index imports.
  - `opencode/sessions.ts`: 492 β†’ 102 LOC. Same shape under
    OpenCode-prefixed names.

Behavioural change: OpenCode now ALSO recognises `synthetic: true`
markers. Previously documented as an asymmetry in the conformance test
β€” `synthetic` is the upstream's convention (Kilo + OpenCode emit it
the same way), so symmetric handling is the right default. The
conformance test for this case has been updated to assert symmetric
behaviour.

Dead code removal: `waitForPromptWithQuestionGuard` +
`waitForAssistantReply` deleted from both backends. Both backends now
use `promptAsync` + SSE; the sync `session.prompt` wrappers were left
over from the pre-SSE era. Also dropped them from `kilo/index.ts`
barrel re-exports.

Tests:
  - New `remote-server-session-helpers.test.ts`: 24 tests covering all
    public helpers + edge cases (dedup, minCreatedAt filter, non-tool
    questions, idempotency via seenQuestionIds, upstream-failure
    tolerance).
  - Updated `backend-conformance.test.ts` synthetic-error test to
    assert symmetric behaviour.

Stats:
  - `kilo/sessions.ts`: 593 β†’ 100 (βˆ’493 LOC)
  - `opencode/sessions.ts`: 492 β†’ 102 (βˆ’390 LOC)
  - New `remote-server/session-helpers.ts`: 541 LOC (mostly comments)
  - New `remote-server-session-helpers.test.ts`: 396 LOC
  - Net: 883 LOC of duplicated logic collapsed into one tested module
    + thin shims.

Full suite: 2285 passing (+24 new), 12 skipped (live-tier), 0 failing.
@claudiusthebot
claudiusthebot force-pushed the feat/shared-session-helpers branch from e3d4d69 to d4c1a96 Compare May 16, 2026 00:23
@claudiusthebot
claudiusthebot merged commit 5168d59 into main May 16, 2026
31 checks passed
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