Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 40 additions & 24 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,35 +1,51 @@
name: CI
on:
pull_request:
branches: [main]
push:
branches: ['**']

branches: [main]
permissions:
contents: read
packages: read

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build:
node:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
node: ["20.19.0", "22.23.1", "24.18.0"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: ${{ matrix.node }}
cache: npm
- run: npm ci --ignore-scripts
- run: npm run build
- run: npm run verify:types
- run: npm run lint
- run: npm run lint:boundary
- run: npm test
- run: npm audit --audit-level=high --omit=dev
- run: npm run verify:package
- name: Pack artifact
if: matrix.node == '20.19.0'
run: |
npm pack --ignore-scripts
sha256sum quantum-l9-llm-router-*.tgz > package.sha256
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: matrix.node == '20.19.0'
with:
persist-credentials: false
- uses: actions/setup-node@v4
name: package-contract
path: |
quantum-l9-llm-router-*.tgz
package.sha256
if-no-files-found: error
artifact-roundtrip:
needs: node
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
with:
node-version: '20'
cache: 'npm'
registry-url: 'https://npm.pkg.github.com'
scope: '@quantum-l9'
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build (tsc -> dist/)
run: npm run build
- name: Typecheck
run: npm run verify:types
name: package-contract
path: artifacts/downloaded
- run: cd artifacts/downloaded && sha256sum -c package.sha256
54 changes: 10 additions & 44 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,56 +1,22 @@
name: Publish Package
name: Publish
on:
push:
branches: [main]
paths: ['package.json']
workflow_dispatch:

tags: ['v*']
permissions:
contents: read
packages: write

concurrency:
group: publish-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false

jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
registry-url: 'https://npm.pkg.github.com'
scope: '@quantum-l9'
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: npm run build

# Gate publish on a version bump: npm refuses to republish an existing
# name@version, so manual dispatch or any non-bump push to package.json
# would otherwise fail the job. Skip cleanly when this version already
# exists on the registry.
- name: Check whether this version is already published
id: published
run: |
VERSION="$(node -p "require('./package.json').version")"
if npm view "@quantum-l9/llm-router@${VERSION}" version >/dev/null 2>&1; then
echo "exists=true" >> "$GITHUB_OUTPUT"
echo "@quantum-l9/llm-router@${VERSION} is already published — skipping publish."
else
echo "exists=false" >> "$GITHUB_OUTPUT"
echo "@quantum-l9/llm-router@${VERSION} not found — will publish."
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Publish
if: steps.published.outputs.exists == 'false'
run: npm publish
node-version: 24.18.0
cache: npm
registry-url: https://npm.pkg.github.com
- run: npm ci --ignore-scripts
- run: npm run verify:all
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26 changes: 26 additions & 0 deletions .github/workflows/supply-chain.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Supply Chain
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
sbom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24.18.0
cache: npm
- run: npm ci --ignore-scripts
- run: npm sbom --sbom-format cyclonedx > sbom.cdx.json
- run: sha256sum sbom.cdx.json > sbom.sha256
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sbom
path: |
sbom.cdx.json
sbom.sha256
if-no-files-found: error
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
node_modules/
dist/
*.log
*.tgz
artifacts/
coverage/
85 changes: 85 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Architecture

`@quantum-l9/llm-router` is a reusable TypeScript routing library. `L9LLMRouter` is the supported production execution surface and the only component that composes routing, budget, resilience, and provider dispatch.

## Runtime flow

```text
validated execution task
-> effective image set merged into task
-> pure route resolution
-> request identity and timestamp
-> atomic process-local budget reservation
-> provider-family-safe downgrade
-> per-provider circuit permit
-> provider dispatch with explicit cancellation and timeout
-> aggregate execution accounting
-> budget reconciliation and audit log
```

Route resolution is pure. Request IDs and timestamps are added afterward and do not participate in routing equivalence.

## Module ownership

```text
src/types.ts public legacy contracts
src/schemas.ts runtime validation for public legacy input
src/matrices/* deterministic model and search resolution
src/pricing.ts canonical OpenRouter price table
src/budget/* process-local admission and spend accounting
src/circuit-breaker.ts process-local provider health control
src/provider-errors.ts typed failure classification and redaction
src/providers/* provider I/O and SDK transport isolation
src/vision/* vision configuration and task planning
src/index.ts composition root and supported execution API
src/control-plane/* internal Phase 1 contract kernel
```

## Provider boundary

Provider clients live under `src/providers/`. Production modules outside `src/index.ts` and `src/providers/` may not import them. ESLint and a programmatic probe enforce the rule.

Existing provider subpath exports remain available during the 1.x line for compatibility. They are deprecated because direct use bypasses budget and circuit controls. Their removal requires a major version.

## Budget state

The built-in budget tracker owns committed spend and active reservations. Admission evaluates both, so concurrent requests inside one JavaScript process cannot all pass against the same unreserved ceiling.

Critical tasks retain the documented override but still reserve and record cost. Reservation identifiers must be non-empty and unique. Client and direct tracker configuration is runtime validated.

The tracker is not a distributed ledger. Multiple processes require an external atomic persistence adapter, which is outside this repository's current scope.

## Circuit state

The circuit breaker owns independent state per provider.

- Closed calls receive ordinary permits.
- The failure threshold opens the circuit.
- The cooldown permits exactly one half-open probe.
- Retryable network, timeout, rate-limit, and server failures count.
- Client, cancellation, budget, policy, and local validation failures do not count.
- Late results from calls acquired before a circuit opened cannot overwrite newer state.

## Provider execution

The OpenAI SDK is isolated behind `OpenAIChatTransport`. SDK retries are disabled. The router controls fallback order explicitly.

OpenRouter fallbacks advance only after retryable failures. Non-retryable client failures and cancellation terminate immediately.

Perplexity consensus executes configured variations in parallel. The selected content remains one successful candidate, while budget-facing cost and token accounting aggregate all successful variations.

## Image safety

Image execution accepts public HTTPS URLs and bounded supported image data URIs. Local, private, loopback, link-local, reserved, and local-domain targets are rejected before dispatch. Option-supplied images are validated and included in route selection before budget reservation.

## Control Plane Phase 1

The Control Plane kernel owns strict runtime contracts, canonical JSON, deterministic identity, immutable builders, policy interfaces, and provider-adapter interfaces. It does not own provider clients, network access, Gate ingress, TransportPacket authority, Graphiti, Neo4j, promotion, mutable global state, or legacy cutover.

The internal barrel `src/control-plane/index.ts` is a deliberate module boundary but is absent from package exports. The one-line pass-through type module was removed because it had no independent responsibility.

Route identity excludes request-specific values and explanatory prose, including route, budget, and provider-health reasons. Complete content hashing still protects those fields.

## Runtime support

The package preserves a Node 20.19.0 compatibility floor for the 1.x line. CI validates the floor plus maintained Node 22 and Node 24 LTS lines. Publish and supply-chain jobs run on Node 24 LTS.
Loading
Loading