This commit is contained in:
seb
2026-10-05 22:27:20 +02:00
parent 7d55b9774a
commit 4b4b03172a
5 changed files with 229 additions and 18 deletions

View File

@@ -87,3 +87,124 @@ test('chatCompletions sends session_id in JSON body and x-session-id in HTTP hea
globalThis.fetch = originalFetch;
}
});
test('OpenRouterProvider resolves apiUrl from constructor option, OPENROUTER_API_URL env, or default', () => {
const originalEnv = process.env.OPENROUTER_API_URL;
try {
delete process.env.OPENROUTER_API_URL;
const defaultProvider = new OpenRouterProvider({ apiKey: 'test-key' });
assert.equal(defaultProvider.apiUrl, 'https://openrouter.ai/api/v1/chat/completions');
process.env.OPENROUTER_API_URL = 'http://127.0.0.1:8787/api/v1/chat/completions';
const envProvider = new OpenRouterProvider({ apiKey: 'test-key' });
assert.equal(envProvider.apiUrl, 'http://127.0.0.1:8787/api/v1/chat/completions');
const explicitProvider = new OpenRouterProvider({
apiKey: 'test-key',
apiUrl: 'http://127.0.0.1:9999/custom',
});
assert.equal(explicitProvider.apiUrl, 'http://127.0.0.1:9999/custom');
} finally {
if (originalEnv !== undefined) {
process.env.OPENROUTER_API_URL = originalEnv;
} else {
delete process.env.OPENROUTER_API_URL;
}
}
});
test('OpenRouterProvider emits connected, firstevent, reasoning, and content status in order', async () => {
const originalFetch = globalThis.fetch;
const statuses = [];
const chunks = [
': OPENROUTER PROCESSING\n\n',
'data: {"choices":[{"delta":{"content":"","role":"assistant","reasoning":"Thinking..."}}]}\n\n',
'data: {"choices":[{"delta":{"content":"","role":"assistant","reasoning":" more"}}]}\n\n',
'data: {"choices":[{"delta":{"content":"Hello","role":"assistant"}}]}\n\n',
'data: {"choices":[{"delta":{"content":" world","role":"assistant"}}]}\n\n',
'data: [DONE]\n\n',
];
globalThis.fetch = async () => {
return {
ok: true,
status: 200,
body: {
getReader() {
let idx = 0;
return {
async read() {
if (idx >= chunks.length) return { done: true, value: undefined };
const encoder = new TextEncoder();
const val = encoder.encode(chunks[idx++]);
return { done: false, value: val };
},
};
},
},
};
};
try {
const provider = new OpenRouterProvider({ apiKey: 'sk-test' });
const res = await provider.chatCompletions({
model: 'test/model',
messages: [{ role: 'user', content: 'hello' }],
onStatus: (s) => statuses.push(s),
});
assert.equal(res.content, 'Hello world');
assert.equal(res.reasoning, 'Thinking... more');
assert.deepEqual(statuses, ['connected', 'firstevent', 'reasoning', 'content']);
} finally {
globalThis.fetch = originalFetch;
}
});
test('OpenRouterProvider emits working status on first tool call delta', async () => {
const originalFetch = globalThis.fetch;
const statuses = [];
const chunks = [
': OPENROUTER PROCESSING\n\n',
'data: {"choices":[{"delta":{"role":"assistant","tool_calls":[{"index":0,"id":"call_1","type":"function","function":{"name":"foo","arguments":""}}]}}]}\n\n',
'data: {"choices":[{"delta":{"role":"assistant","tool_calls":[{"index":0,"function":{"arguments":"{}"}}]}}]}\n\n',
'data: [DONE]\n\n',
];
globalThis.fetch = async () => {
return {
ok: true,
status: 200,
body: {
getReader() {
let idx = 0;
return {
async read() {
if (idx >= chunks.length) return { done: true, value: undefined };
const encoder = new TextEncoder();
const val = encoder.encode(chunks[idx++]);
return { done: false, value: val };
},
};
},
},
};
};
try {
const provider = new OpenRouterProvider({ apiKey: 'sk-test' });
const res = await provider.chatCompletions({
model: 'test/model',
messages: [{ role: 'user', content: 'hello' }],
onStatus: (s) => statuses.push(s),
});
assert.equal(res.tool_calls?.length, 1);
assert.equal(res.tool_calls[0].function.name, 'foo');
assert.deepEqual(statuses, ['connected', 'firstevent', 'working']);
} finally {
globalThis.fetch = originalFetch;
}
});