AI Decision System
Replayable, offline-verifiable records for AI-assisted go/no-go decisions: experiment promotions, typed model answers and human-approved actions.
OpenAI 호환 LLM 게이트웨이용 적합성 테스트 스위트로 스트리밍·사용량·비용·동시성·오류 처리 버그를 자동으로 포착합니다
A conformance test suite for OpenAI-compatible LLM gateways -- catches streaming, usage, cost, concurrency, and error-handling bugs an eyeball review won't.
개발 도구TypeScriptGitHub @jayblast-spec온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기A conformance test suite for OpenAI-compatible LLM gateways -- streaming, usage, cost, concurrency, and error-propagation checks against a deterministic mock upstream.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
A conformance test suite for OpenAI-compatible LLM gateways — catches streaming, usage, cost, concurrency, and error-handling bugs that an eyeball review of a diff won't.README 전문 보기 ↗A conformance test suite for OpenAI-compatible LLM gateways — catches streaming, usage, cost, concurrency, and error-handling bugs that an eyeball review of a diff won't.
An LLM gateway (LiteLLM and its many peers) sits between your application and whichever model provider you're actually calling — OpenAI, Anthropic, a self-hosted model, whatever. Its job is to make all of them look the same to your app: one API shape, provider-agnostic. To do that, on every single request it has to: re-stream the model's response chunk-by-chunk back to you, recompute how many tokens were used, calculate what that request cost, and correctly propagate any upstream failure. That's a surprising amount of stateful, timing-sensitive logic sitting directly in the hot path of every request your app makes — exactly the kind of code that's easy to get subtly wrong.
Why this is dangerous specifically because it's subtle. A gateway that drops the last chunk of a streamed response still looks like it worked in a quick manual test — you'd have to notice the response was one word shorter than it should be. A gateway that miscalculates cost still returns a number; you'd only notice it was wrong when your bill didn't match your usage. A gateway that swallows an upstream error and reports finish_reason: "stop" anyway looks, to your application, exactly like a successful, complete response. None of these announce themselves. They show up in production, under load, as a wrong invoice or a user complaining about a truncated answer nobody can reproduce on demand.
There was no independent, reusable way to check for this class of bug before deploying a gateway (or a change to one). Every project either trusted the gateway's own test suite or found out the hard way. gatewayproof is a standalone answer: a deterministic mock model, and a battery of checks any OpenAI-compatible gateway can be run against.
You can't point this at a random live gateway and expect a useful answer, because there's no ground truth to compare against when the actual model is involved — you don't know in advance what a real LLM "should" say. Instead:
gatewayproof starts a mock upstream that speaks the same /v1/chat/completions API a real provider would, but every response is scripted ahead of time: you (or the checks) tell it exactly what content, token usage, and timing to produce for a given request. This is the "ground truth."api.openai.com.gatewayproof sends requests through your gateway, not directly to the mock, and compares what comes back against the ground truth the mock scripted — catching anything the gateway added, dropped, or miscalculated on the way through. gatewayproof checks ──requests──> [ gateway under test ] ──requests──> mock upstream (ground truth)
<──responses── <──responses──
| Check | The bug it catches |
|---|---|
streaming-fidelity | A dropped, duplicated, or reordered chunk mid-stream — the streamed response, reassembled, doesn't match what a non-streamed call to the same request would return. |
usage-accuracy | Wrong prompt_tokens / completion_tokens / total_tokens, in either a streamed final chunk or a non-streamed response body. |
cost-accuracy | A wrong cost calculation. Reads whatever the gateway reports as cost (defaults to LiteLLM's x-litellm-response-cost header, pluggable for others) and checks it against usage × your pricing table. |
concurrent-isolation | Content from one concurrent request leaking into another's stream — a real bug class in gateways that multiplex several streams over shared internal state. |
error-propagation | The single worst failure mode: an upstream error mid-stream getting reported to the caller as a clean finish_reason: "stop", which looks exactly like success. |
Every check is independent, so a gateway can fail one without failing the others — the report tells you specifically which promise was broken.
# 1. Pick a fixed local port and configure your gateway's upstream to point at it
# (e.g. http://127.0.0.1:5055) -- then start your gateway.
# 2. Run the suite. It starts the mock upstream on that exact port, then hits your gateway.
npx gatewayproof run --target http://localhost:4000 --mock-port 5055
Mock upstream: http://127.0.0.1:5055
Target gateway: http://localhost:4000
PASS streaming-fidelity -- Streamed content matches non-streamed content, with no drops, dupes, or reordering
PASS usage-accuracy -- Reported token usage matches the upstream's actual usage
FAIL cost-accuracy -- Reported cost matches usage x the supplied pricing table
expected cost 0.00019999999999999998, got 0.000001
PASS concurrent-isolation -- Concurrent streamed requests never leak content across streams
PASS error-propagation -- A mid-stream upstream failure surfaces as an error, never a silently-truncated success
4/5 checks passed.
Exit code 0 on all-pass, 1 otherwise.
- name: Start your gateway
run: |
# your gateway, configured with upstream = http://127.0.0.1:5055
my-gateway serve --port 4000 &
sleep 2
- name: Run gatewayproof against it
uses: jayblast-spec/gatewayproof@main
with:
target: http://localhost:4000
mock-port: '5055'
For a self-contained test where you control the gateway's lifecycle directly (e.g. testing your own gateway's code in its own test suite):
import { startMockUpstream, runChecks } from "gatewayproof";
const mock = await startMockUpstream(5055); // fixed port your gateway is already configured against
const gateway = await startMyGateway({ upstreamUrl: mock.url });
const report = await runChecks({ targetBaseUrl: gateway.url, mock });
console.log(report.passed, report.results);
await gateway.stop();
await mock.stop();
npm install --save-dev gatewayproof
npm install
npm run typecheck
npm test
npm run build
npx tsx examples/demo.ts # runs the suite against a correct fixture and a deliberately buggy one
MIT
This is one of 8 independent open-source infrastructure tools, each built against a real, researched gap:
Built by ArkNet Digital.