refactor(backend): extract shared session helpers β Kilo + OpenCode - #173
Merged
Conversation
claudiusthebot
force-pushed
the
feat/shared-session-helpers
branch
from
May 15, 2026 23:52
8384ec9 to
1da15fc
Compare
claudiusthebot
enabled auto-merge (squash)
May 15, 2026 23:52
claudiusthebot
force-pushed
the
feat/shared-session-helpers
branch
2 times, most recently
from
May 16, 2026 00:14
44cc42d to
e3d4d69
Compare
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
force-pushed
the
feat/shared-session-helpers
branch
from
May 16, 2026 00:23
e3d4d69 to
d4c1a96
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.tsmodules.
kilo/sessions.ts(593 LOC) andopencode/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)summarizeQuestionHeaders,isToolApprovalQuestion,parseAssistantMessage,listSessionMessages, etc.The only meaningful difference was that Kilo's
extractPartsSummarypeeled
synthetic: trueparts into a separatesyntheticErrorTextchannel; OpenCode's didn't.
What changed
New
backend/remote-server/session-helpers.ts(541 LOC, mostlydocstrings) containing:
RemoteAssistantInfo,RemoteSessionSnapshot,ParsedAssistantMessage,RemoteUsageSummaryβ shapes shared across backends.RemoteSessionClientβ extendsRemoteAgentClientwith thesession.messages+question.{list,reply,reject}methods these helpers need. BothKiloClientandOpencodeClientstructurally satisfy it.REMOTE_SESSION_MESSAGE_LIMIT(5000).extractPartsSummaryβ now with synthetic-error detection. Both backends gain it.extractAssistantUsagesummarizeAssistantMessageslistSessionMessagesgetTurnSummarygetSessionSnapshot(takes client as parameter so the shared helper doesn't bake in either backend'sensureServer)rejectPendingQuestionsβ with injectedbackendLabelfor log prefixes (Auto-approved Kilo tool questionvsAuto-approved OpenCode tool question).kilo/sessions.tsandopencode/sessions.tsreduced to thin shims:KiloAssistantInfo/OpenCodeAssistantInfoare type aliases,getKiloTurnSummary/getOpenCodeTurnSummarywrap the sharedgetTurnSummarywith backend-typed clients).getKiloSessionSnapshot/getOpenCodeSessionSnapshotthread their respectiveensureServer()into the sharedgetSessionSnapshot.rejectPendingQuestionsinjects the backend label.Behavioural change
OpenCode now ALSO recognises
synthetic: truemarkers. Previouslydocumented as an asymmetry in the conformance test β
syntheticis theupstream'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
waitForPromptWithQuestionGuardandwaitForAssistantReplydeletedfrom both backends. They were sync-prompt wrappers from the pre-SSE
era; both backends now use
promptAsync+ SSE (PR #172). Also droppedfrom
kilo/index.tsbarrel re-exports.Stats
kilo/sessions.tsopencode/sessions.tsremote-server/session-helpers.ts(new)remote-server-session-helpers.test.ts(new)Net: 883 LOC of duplicated logic collapsed into one tested module +
thin shims.
Tests
remote-server-session-helpers.test.tscovering:extractPartsSummarytext joining, synthetic detection, reasoning filtering, edge casesextractAssistantUsagezero defaults + full extractionsummarizeAssistantMessagesaggregation, minCreatedAt filter, non-assistant skip, meaningful-message filterlistSessionMessagesdedup, default limit, override limitgetTurnSummaryend-to-endgetSessionSnapshotundefined-id, full snapshot construction, no-assistant caserejectPendingQuestionstool-approval auto-allow, non-tool rejection, cross-session filter, idempotency, upstream-failure tolerancebackend-conformance.test.tsto assert symmetric behaviourTest plan
npx tsc --noEmitcleannpm testβ 2285 passing, 12 skipped, 0 failingnpm run lintβ 0 errors, 15 pre-existing warnings unchangednpm run format:checkcleangetKiloSessionSnapshot/getOpenCodeSessionSnapshotstill return the right shape for/status(covered by existing kilo-summary tests via the sharedsummarizeAssistantMessages)π€ Generated with Claude Code