Skip to content

test(sdk): unit tests for ChatHandle (usage aggregation, permission, lifecycle)#13

Merged
shreyas-lyzr merged 1 commit into
mainfrom
test/sdk-chat-handle-unit-tests
May 31, 2026
Merged

test(sdk): unit tests for ChatHandle (usage aggregation, permission, lifecycle)#13
shreyas-lyzr merged 1 commit into
mainfrom
test/sdk-chat-handle-unit-tests

Conversation

@shreyas-lyzr
Copy link
Copy Markdown
Contributor

Backfills unit coverage for packages/sdk/src/chat-handle.ts — currently the largest untested SDK file (245 LOC) and the one with the subtlest hidden invariant (cumulative-vs-delta cost-semantic aggregation).

What's covered (19 tests)

  • Usage aggregation — tokens always SUM; cost respects costSemantic (cumulative → MAX, delta → SUM, mixed → prefer cumulative, undefined → safe default). Also covers getUsage() consistency mid-stream vs after drain.
  • Dual iterationfor await yields raw events; await handle drains to ChatResult; result() is memoized; drain() throws if the stream closes without ca_session_ended.
  • Permission callbackonPermissionRequest is called with exact event args, decision is POSTed to the harness, default decision is allow, custom deny is forwarded.
  • LifecycleonComplete fires once after end; doesn't fire on broken streams; sdk_message payloads collected in order; cancel() POSTs the right URL.

Style

Pure mocks (vi.fn, an async generator for the event stream, a fake fetchImpl). No subprocess, no network. Whole file runs in ~22ms.

Verification

$ pnpm --filter @open-gitagent/sdk test
Tests  73 passed | 8 skipped (81)

(The 8 skipped tests are the live-API substrate matrix — gated on ANTHROPIC_API_KEY. Unchanged from main.)

19 tests covering the parts of ChatHandle that are easy to get subtly
wrong without a live harness:

  Usage aggregation
    - input/output tokens always SUM across snapshots
    - cache creation + cache read tokens SUM
    - cost cumulative semantic → MAX
    - cost delta semantic → SUM
    - undefined semantic defaults to cumulative (safe)
    - mixed cumulative + delta in one turn → prefer cumulative (no double-count)
    - no cost snapshots → costUsd is undefined
    - getUsage() consistent mid-stream and after drain

  Dual iteration interface
    - for-await yields events in order
    - await handle drains to ChatResult
    - result() is memoized (no re-iteration)
    - drain() throws if stream closes without ca_session_ended

  Permission callback
    - onPermissionRequest called with exact event args; decision POSTed
    - default decision is allow when no hook provided
    - custom deny decision is forwarded

  Lifecycle
    - onComplete fires after ca_session_ended (once)
    - onComplete NOT fired when stream never ends
    - sdk_message payloads collected into result.messages in order
    - cancel() POSTs /cancel for the right session

All assertions use vi.fn mocks — no network, no harness, no subprocess.
Suite runs in <25ms. Full SDK suite: 73 passing, 8 skipped (offline),
0 failures.
@shreyas-lyzr shreyas-lyzr merged commit 3f2e0a6 into main May 31, 2026
0 of 2 checks passed
@shreyas-lyzr shreyas-lyzr deleted the test/sdk-chat-handle-unit-tests branch May 31, 2026 09:06
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