› cavi-ai/
GitHub ↗

Verified example · TypeScript

Streaming tests

examples/streaming-tests.ts

@cavi-ai/api-clientv0.21.007f0ee45
TypeScript · complete source
import assert from "node:assert/strict";
import { test, type TestContext } from "node:test";
import { createApiClient, createCapabilityClient, createRuntimeProviderRegistry, isApiClientError, isAuthError } from "@cavi-ai/api-client";
import { createCodexProviderModule } from "@cavi-ai/api-client/providers/codex/runtime";
import { streamText } from "./runtime-streaming.js";

function fixture(t: TestContext, frames: [string, unknown][], status = 200) {
  let requests = 0;
  const client = createApiClient("codex", {
    registry: createRuntimeProviderRegistry({ modules: [createCodexProviderModule({ apiKey: "fixture-key" })] }),
    fetchImpl: async (_url, init) => {
      requests += 1;
      assert.equal(init?.method, "POST");
      assert.equal(JSON.parse(String(init?.body)).stream, true);
      if (status !== 200) return Response.json({}, { status });
      const events: [string, unknown][] = [["response.created", { response: { id: "stream-1" } }], ...frames];
      return new Response(events.map(([event, data]) => `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`).join(""), {
        headers: { "Content-Type": "text/event-stream" },
      });
    },
  });
  t.after(() => client.dispose());
  let partial = "";
  const collect = () => streamText(client, { model: "server-model", input: "Question" },
    (delta) => { partial += delta; }, new AbortController().signal);
  return { collect, requests: () => requests, partial: () => partial };
}

test("uses the final snapshot without appending it as a duplicate delta", async (t) => {
  const app = fixture(t, [
    ["response.output_text.delta", { delta: "Partial" }],
    ["response.completed", { response: { output_text: "Final answer" } }],
  ]);
  assert.equal((await app.collect()).text, "Final answer");
  assert.equal(app.partial(), "Partial");
  assert.equal((await app.collect()).text, "Final answer", "the helper must leave its borrowed client usable");
  assert.equal(app.requests(), 2);
});

test("uses observed deltas when completion has no snapshot", async (t) => {
  const app = fixture(t, [
    ["response.output_text.delta", { delta: "An " }],
    ["response.output_text.delta", { delta: "answer" }],
    ["response.completed", { response: {} }],
  ]);
  const answer = await app.collect();
  assert.equal(answer.outcome, "completed");
  assert.equal(answer.text, "An answer");
  assert.equal(answer.runId, "stream-1");
});

test("preserves an explicitly supplied empty normalized snapshot", async (t) => {
  // The pinned Codex adapter omits empty native text. Exercise the shared
  // contract directly for adapters that supply an explicit empty snapshot.
  const client = createCapabilityClient({ providerKind: "fixture", fallbackSupports: { streaming: true }, runtime: {
    getRuntimeCapabilities: async () => ({ providerKind: "fixture", supports: { streaming: true } }),
    startRun: async () => ({ run_id: "unused", status: "completed" }),
    streamRun: async (_body, handlers) => {
      handlers.onEvent({ event: "message.delta", runId: "stream-1", delta: "Partial" });
      handlers.onEvent({ event: "run.completed", runId: "stream-1", output: "" });
    },
  } });
  t.after(() => client.dispose());
  const answer = await streamText(client, { input: "Question" }, () => {}, new AbortController().signal);
  assert.equal(answer.text, "");
});

test("rejects completion with no observed text rather than inventing an empty answer", async (t) => {
  for (const response of [{}]) {
    const app = fixture(t, [["response.completed", { response }]]);
    await assert.rejects(app.collect(), (error) => {
      assert.ok(isApiClientError(error));
      assert.equal(error.type, "run");
      assert.equal(error.code, "run_output_missing");
      assert.equal((error.cause as { runId: string }).runId, "stream-1");
      return true;
    });
  }
});

test("keeps partial output failed, cancelled, or incomplete", async (t) => {
  for (const [event, code] of [["response.failed", "run_failed"], ["response.cancelled", "run_cancelled"], [null, "run_incomplete"]] as const) {
    const frames: [string, unknown][] = [["response.output_text.delta", { delta: "Partial" }]];
    if (event) frames.push([event, { response: { error: { message: "Private execution diagnostic" } } }]);
    const app = fixture(t, frames);
    await assert.rejects(app.collect(), (error) => {
      assert.ok(isApiClientError(error));
      assert.equal(error.code, code);
      assert.equal((error.cause as { runId: string }).runId, "stream-1");
      return true;
    });
    assert.equal(app.partial(), "Partial");
    assert.equal(app.requests(), 1, "a failed stream must not be replayed automatically");
  }
});

test("retains the original availability gap in the typed error", async (t) => {
  const app = fixture(t, [], 503);
  await assert.rejects(app.collect(), (error) => {
    assert.ok(isApiClientError(error));
    assert.equal(error.code, "request_failed");
    assert.equal((error.cause as { reason: string }).reason, "backend-unavailable");
    return true;
  });
  assert.equal(app.requests(), 1);
});

test("keeps provider authentication failures as exceptions", async (t) => {
  const app = fixture(t, [], 401);
  await assert.rejects(app.collect(), isAuthError);
  assert.equal(app.requests(), 1);
});

Package imports

Referenced by

Artifact provenance
Package
@cavi-ai/api-client@0.21.0
Release
v0.21.0
Commit
07f0ee45424c267278f7b0c89a7dcea4e2492cc1
Source
examples/streaming-tests.ts
Tarball SHA-256
0924b5d3a7a40869bd44fedc47a9b8eb9844c2af1fd5c7ca77469d8b7c0b8558
Content SHA-256
24eff463c41582eaf5e70c58f42e5ae13bd12d02fa14ae2a886afa3abf5cdf48