Conversation
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: TanStack/ai/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (12)
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughThe OpenRouter adapter now retains normalized, cost-enriched usage and includes it on terminal error events when available. It preserves zero reasoning-token counts. New unit and E2E tests cover stream outcomes, middleware observations, and reasoning-token values. ChangesOpenRouter structured usage reporting
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to No actionable issue remains in the supplied evidence; the PR is mergeable after normal checks. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The change affects how callers account for failed requests, but no new production credential, provider request, or privilege exposure was demonstrated. The new test endpoint uses synthetic responses; whether the test app is externally reachable remains unverified. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
OpenRouter drops a reported zero reasoning-token count and loses received usage when
structuredOutputStream()fails. Preserve zero and attach token usage and cost to the existing terminalRUN_ERRORevent. Successful calls still report usage once onRUN_FINISHED.🎯 Changes
Use a nullish presence check for reasoning tokens. Normalize received structured-stream usage before parsing and retain it for parse, truncation, empty-response, and SDK errors. Requests, schemas, structured results, and error codes stay unchanged.
This lets consumers account for failed requests without a provider-specific custom usage event or a downstream dependency patch. Includes regression tests, public
chat()middleware E2E coverage, documentation, and a patch changeset. Two shipped@tanstack/aiskills now clarify that failed-call usage reachesonChunk, whileonUsagereceivesRUN_FINISHEDusage. The changeset covers the adapter fix and shipped core documentation.✅ Checklist
pnpm run test:pr, or these tests do not apply to this pull request.docs/for this change, or this change is not user-facing.pnpm changeset), or this PR does not change a published package.🚀 Release Impact
Root cause
Issue. Consumers cannot distinguish zero reasoning tokens from an unknown count, or account for received usage after structured-output failure.
Cause.
buildOpenRouterUsage()checks truthiness.structuredOutputStream()emits its retained usage only after content checks and JSON parsing succeed.Fix. Check presence and retain normalized usage for either terminal outcome. No extra usage event is emitted.
Possible alternatives
openrouter.usageevent introduces another accounting source. The existingRUN_ERROR.usagecontract supports the required data.RUN_FINISHEDbefore parsing would label a failed structured response as successful.Testing
Verified on macOS arm64, Node 26.0.0, pnpm 11.9.0. Base:
62bec34bb78a2f2d0d283c8ea2e9dc39fbd12d2c; implementation:b56990643e088394bf868872e8aa5fb526e9283e; final reviewed head:d2464b56e0275f456479b02d6c498d8f7e75741a. The cleanup commit changes only shipped skill prose and release metadata; runtime reproduction and E2E results remain applicable.Commands passed:
NX_DAEMON=false NX_BASE=62bec34bb78a2f2d0d283c8ea2e9dc39fbd12d2c pnpm test:pr: 398 Nx tasks after cleanup, including affected builds, tests, types, lint, docs, and snippet checks (394 cached); React Native smoke and declaration scan passed.pnpm --filter @tanstack/ai-openrouter test:lib: 255 tests passed. Adapter typecheck and lint passed; lint retains existing warnings.E2E_PROVIDERS=openrouter pnpm test:e2e: all spec files ran, with 357 passed and 3 skipped. This includes all six new usage cases. This is the OpenRouter-filtered suite, not the full provider matrix.pnpm build:all,pnpm test:docs, andgit diff --checkpassed.The new tests cover positive, zero, null/missing reasoning counts; malformed, truncated and empty output; success accounting; SDK failures and aborts before/after usage; and provider-iterator cleanup when the consumer stops. E2E exercises the real SDK decoder, public promise API, and middleware using deterministic SSE responses, without provider credentials. It uses a model routed through
structuredOutputStream, not the separate combined tools/schema path.Six independent cleanup audits retained the implementation and tests. The skill audit found the two passages corrected in the cleanup commit. Final verification run.
GitHub workflows require maintainer approval (
action_required). Socket checks passed. CodeRabbit is pending with no substantive findings at the last read.Reproduction transcripts
The same agent-written regression file ran against detached clean main and the committed fix. Command from each checkout's
packages/ai-openrouterdirectory:Clean main:
Committed fix:
Reviewer test path
chat()success and failure accounting.The regression file, E2E route and E2E assertions are included on the branch. No UI behavior changes; event assertions demonstrate this adapter contract.
Risk / rollback
The error event now contains usage that the provider already supplied. Consumers can read it through middleware
onChunk. The coreonUsagehook still runs forRUN_FINISHEDonly; this PR does not change that hook or the combined tools/schema path. A consumer that stops iterating cannot receive later events. Revert this PR to restore the prior behavior.No released version contains this commit yet. The changeset requests an adapter patch release; the exact version remains maintainer-controlled. DrewHoo owns contribution follow-up and downstream release tracking.
Public API change
No caller signature changes. Middleware can now account for received usage on failed structured calls through the existing
RUN_ERROR.usagefield.Before —
onUsageaccounts for successful calls. Failed structured calls omit received usage.After — keep successful-call accounting and add failed-call accounting through
onChunk.Both examples use
ChatMiddlewarefrom@tanstack/aiand the caller'srecordUsagefunction. PassusageObserverinchat({ middleware: [usageObserver], ... }). The two hooks handle separate terminal outcomes, so successful calls are counted once.Summary by CodeRabbit
Bug Fixes
Documentation