Skip to content
Merged
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
29 changes: 22 additions & 7 deletions .github/workflows/l9-pr-pipeline.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
# Quantum-L9 org starter — Full PR validation pipeline (lint, type-check, tests, security). Calls l9-ci-core kernel; do not add logic here.
# Quantum-L9 — PR validate with GitHub Packages auth.
# l9-ci-core pr-pipeline@v1 omits registry-url/NODE_AUTH_TOKEN; private
# @quantum-l9/* deps then 401. Mirror CI job auth (ci.yml).
name: "L9 PR Pipeline"
on:
pull_request:
branches: [main, 'release/**']
push:
branches: [main]

permissions:
contents: read
packages: read

jobs:
l9_pr_pipeline:
uses: Quantum-L9/l9-ci-core/.github/workflows/pr-pipeline.yml@v1
secrets: inherit
with:
python-version: "3.12"
run-security: true
working-directory: "."
runs-on: ubuntu-latest
timeout-minutes: 30
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "20.19.0"
cache: npm
registry-url: https://npm.pkg.github.com
- run: npm ci --ignore-scripts
- run: npm run lint
- run: npm run verify:types
- run: npm test
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@quantum-l9/llm-router",
"version": "1.1.0",
"version": "1.1.1",
"type": "module",
"description": "Reusable multi-provider LLM routing module with governed l9-graphiti-memory hydration, task-to-model routing, budgets, search, vision, and provider resilience.",
"main": "dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion src/providers/openrouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { GeneralModel as GeneralModelValue } from '../types.js';
const MODEL_IDS: Record<GeneralModel, string> = {
[GeneralModelValue.GPT4O_MINI]: 'openai/gpt-4o-mini',
[GeneralModelValue.GEMINI_FLASH]: 'google/gemini-2.5-flash',
[GeneralModelValue.CLAUDE_HAIKU]: 'anthropic/claude-haiku-4',
[GeneralModelValue.CLAUDE_HAIKU]: 'anthropic/claude-haiku-4.5',
[GeneralModelValue.GPT4O]: 'openai/gpt-4o',
[GeneralModelValue.CLAUDE_SONNET]: 'anthropic/claude-sonnet-4',
[GeneralModelValue.GEMINI_PRO]: 'google/gemini-2.5-pro',
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export enum SonarModel {
export enum GeneralModel {
GPT4O_MINI = 'openai/gpt-4o-mini',
GEMINI_FLASH = 'google/gemini-2.5-flash',
CLAUDE_HAIKU = 'anthropic/claude-haiku-4',
CLAUDE_HAIKU = 'anthropic/claude-haiku-4.5',
GPT4O = 'openai/gpt-4o',
CLAUDE_SONNET = 'anthropic/claude-sonnet-4',
GEMINI_PRO = 'google/gemini-2.5-pro',
Expand Down
36 changes: 36 additions & 0 deletions tests/haiku-model-id.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { describe, expect, it } from 'vitest';
import { resolveRoute } from '../src/index.js';
import { OpenRouterClient } from '../src/providers/openrouter.js';
import type { ChatCompletionRequest, ChatCompletionResult, ChatTransport } from '../src/providers/openai-transport.js';
import { GeneralModel, Provider, TaskComplexity, TaskType, type GeneralModelConfig } from '../src/types.js';

class CapturingTransport implements ChatTransport {
requests: ChatCompletionRequest[] = [];
async create(request: ChatCompletionRequest): Promise<ChatCompletionResult> {
this.requests.push(request);
return { id: 'req', choices: [{ message: { content: 'ok' } }], usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 } };
}
}

describe('CLAUDE_HAIKU OpenRouter model id', () => {
it('uses anthropic/claude-haiku-4.5 in enum and CODE_GENERATION+LOW routing', () => {
expect(GeneralModel.CLAUDE_HAIKU).toBe('anthropic/claude-haiku-4.5');
const route = resolveRoute({ type: TaskType.CODE_GENERATION, complexity: TaskComplexity.LOW });
expect(route.model).toBe(GeneralModel.CLAUDE_HAIKU);
});

it('maps CLAUDE_HAIKU to the OpenRouter request model id', async () => {
const transport = new CapturingTransport();
const client = new OpenRouterClient('key', 'app', 1000, transport);
const config: GeneralModelConfig = {
model: GeneralModel.CLAUDE_HAIKU,
provider: Provider.OPENROUTER,
temperature: 0.1,
maxTokens: 100,
estimatedCostPerCall: 0.01,
resolutionReason: 'test',
};
await client.complete(config, 'system', 'user');
expect(transport.requests[0]?.model).toBe('anthropic/claude-haiku-4.5');
});
});
Loading