| 1 | // Run: pnpm exec tsx src/__tests__/interrupted-turn-provider-error.test.ts |
| 2 | import assert from "node:assert/strict"; |
| 3 | |
| 4 | import { initialState, reducer } from "../lib/useController"; |
| 5 | |
| 6 | function finish(e: Record<string, unknown>) { |
| 7 | const started = reducer(initialState, { type: "event", e: { kind: "turn_started" } }); |
| 8 | return reducer(started, { type: "event", e: { kind: "turn_done", ...e } }); |
| 9 | } |
| 10 | |
| 11 | const quota = finish({ |
| 12 | status: "recovery_required", |
| 13 | err: "relay · Chat Completions: provider balance or plan quota insufficient (HTTP 402)", |
| 14 | detail: "Connection ID: relay", |
| 15 | diagnostic: { kind: "quota", status: 402, protocol: "openai" }, |
| 16 | recovery: { state: "recovery_required", reason: "silent_interruption" }, |
| 17 | }); |
| 18 | const notices = quota.items.filter((item) => item.kind === "notice"); |
| 19 | const failure = notices.find((item) => item.kind === "notice" && item.level === "warn"); |
| 20 | assert.ok(failure?.kind === "notice" && failure.text.includes("HTTP 402"), "provider error stays visible on a recovery_required turn"); |
| 21 | assert.equal(failure?.kind === "notice" ? failure.detail : "", "Connection ID: relay"); |
| 22 | assert.ok(notices.some((item) => item.kind === "notice" && item.level === "info"), "interrupted guidance stays alongside the error"); |
| 23 | assert.equal(new Set(quota.items.map((item) => item.id)).size, quota.items.length, "notice ids stay unique"); |
| 24 | |
| 25 | const cancelled = finish({ status: "interrupted", err: "context canceled", diagnostic: { kind: "cancelled" } }); |
| 26 | assert.ok(!cancelled.items.some((item) => item.kind === "notice" && item.level === "warn"), "a user stop is not reported as a provider failure"); |
| 27 | |
| 28 | console.log("interrupted-turn-provider-error: ok"); |
| 29 |