Skip to content

refactor!: streaming API redesign - #61

Merged
camilleislasse merged 1 commit into
mainfrom
refactor/streaming-api-v2
May 7, 2026
Merged

refactor!: streaming API redesign#61
camilleislasse merged 1 commit into
mainfrom
refactor/streaming-api-v2

Conversation

@camilleislasse

Copy link
Copy Markdown
Contributor

Summary

Replaces the v1 parser with four orthogonal primitives, each doing one thing. The previous all-in-one parseSession returned the full transcript inline, forcing every consumer to load up to 80 MB of turns even for analytics-only workloads. The new shape lets callers fetch only what they need and stream the rest.

API changes

// Before
parseAllSessions(dir)              // → ParsedSession[]   (full transcripts inline)
parseSession(dir, id)              // → ParsedSession     (with turns + subagentTurns)

// After
readSessionIds(dir)                // → string[]                                  (was internal `listSessionIds`)
readSession(dir, id)               // → ParsedSession                             (aggregate metadata only)
readSessionTurns(dir, id)          // → AsyncGenerator<MessageEntry>              (main transcript, streamed)
readSubagentTurns(dir, id)         // → AsyncGenerator<{ agentId, turn }>         (subagents, streamed, tagged)

Why

  • Memory: 80 MB sessions no longer force callers to hold all turns in RAM. readSession stays light; readSessionTurns streams.
  • Footgun removed: parseAllSessions did Promise.all over every session with no concurrency cap → OOM on large histories. The new shape forces the caller to pick its strategy.
  • Subagents preserved: readSubagentTurns exposes the previously-internal <sessionId>/subagents/ walker, including nested layouts (workflows/<runId>/agent-*.jsonl).
  • Single-purpose primitives: aligns with gray-matter / marked (no orchestration baked into the lib).

Validation

  • 97 unit tests, 100 % coverage, typedoc clean
  • Smoke test against a real ~/.claude/projects/ (12 projects, 64 sessions, 80 MB peak): 0 errors, 14332 turns streamed in 659 ms with bounded heap (76 → 32 MB)

Breaking changes

  • parseAllSessions, parseSession are removed
  • ParsedSession.turns and ParsedSession.subagentTurns are removed (migrate to readSessionTurns / readSubagentTurns)
  • userMessageCount / assistantMessageCount doc clarified — the lib applies stricter filters than CC's own metric (documented in parsed-session.ts)

Released as v2.0.0.

Test plan

  • CI green (lint + typecheck + tests + typedoc)
  • Smoke test against a non-trivial ~/.claude/projects/ directory
  • Downstream migration (claude-memory-studio) reviewed in a follow-up PR

Replaces the v1 parser with four orthogonal primitives, each doing one thing.
The previous all-in-one `parseSession` returned the full transcript inline,
forcing every consumer to load up to 80 MB of turns even for analytics-only
workloads. The new shape lets callers fetch only what they need and stream
the rest.

API changes:
- Add `readSessionIds(dir)` (was internal `listSessionIds`)
- Rename `parseSession` -> `readSession` (now returns aggregate metadata only,
  no `turns` / `subagentTurns` in `ParsedSession`)
- Add `readSessionTurns(dir, id)` async generator over the main transcript
- Add `readSubagentTurns(dir, id)` async generator over `<sessionId>/subagents/`,
  yielding `{ agentId, turn }` tagged tuples
- Remove `parseAllSessions` (callers compose `readSessionIds` + their own
  concurrency strategy)

Internal:
- Add `bun run ci` script chaining check + typecheck + test --coverage + typedoc
- Cap subagent directory recursion at depth 8 (symlink loop guard)
- Document the asymmetry between `userMessageCount` (stricter than CC,
  excludes subagent / meta / compactSummary) and `assistantMessageCount`
  (includes subagent turns, dedupes on messageId+requestId)

BREAKING CHANGE: `parseSession`, `parseAllSessions`, `ParsedSession.turns`
and `ParsedSession.subagentTurns` are removed. Migrate to `readSession`
(metadata) + `readSessionTurns` / `readSubagentTurns` (streamed turns).
@camilleislasse
camilleislasse merged commit 8ae42be into main May 7, 2026
1 check passed
@guiziwebbot guiziwebbot Bot mentioned this pull request May 7, 2026
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