feat(booterm): structured pty_exited WS notifications. Plan-validated, impl-validated, code-reviewed green (contracts build clean, contracts test 29/29, booterm + web typecheck clean). wip: in-progress inference/provider refactor (agents.ts, provider.ts, new llama-providers.ts, removed llama-args-validator), plus arena, dispatcher, compaction, schema changes. openspec: pty-exit-notifications complete; x-agent-flags planned (not yet implemented).
62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
import { writeFileSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { buildPiProviderEntry } from '../pi-config-sync.js';
|
|
import { loadLlamaProviders } from '../llama-providers.js';
|
|
|
|
describe('buildPiProviderEntry', () => {
|
|
const fetchMock = vi.fn();
|
|
|
|
beforeEach(() => {
|
|
vi.stubGlobal('fetch', fetchMock);
|
|
fetchMock.mockResolvedValue(
|
|
new Response(JSON.stringify({ data: [{ id: 'qwen3.6-35b' }] }), {
|
|
status: 200,
|
|
headers: { 'content-type': 'application/json' },
|
|
}),
|
|
);
|
|
const file = {
|
|
defaultProvider: 'sam-desktop',
|
|
providers: [
|
|
{ id: 'sam-desktop', label: 'Sam Desktop', baseUrl: 'http://a.test:8401', kind: 'llama-swap' },
|
|
],
|
|
};
|
|
const path = join(tmpdir(), `llama-providers-pi-${Math.random().toString(36).slice(2)}.json`);
|
|
writeFileSync(path, JSON.stringify(file), 'utf8');
|
|
loadLlamaProviders(path, 'http://legacy.test:8080');
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
it('emits a Pi-routable provider with gateway baseUrl and composite model ids', async () => {
|
|
const entry = await buildPiProviderEntry('http://127.0.0.1:9502');
|
|
expect(entry.baseUrl).toBe('http://127.0.0.1:9502/v1');
|
|
expect(entry.api).toBe('openai-completions');
|
|
expect(entry.models?.map((m) => m.id)).toEqual(['sam-desktop/qwen3.6-35b']);
|
|
expect(entry.models?.[0]?.contextWindow).toBeGreaterThan(0);
|
|
expect(entry.models?.[0]?.cost).toEqual({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0 });
|
|
});
|
|
|
|
it('preserves hand-tuned per-model overrides on re-sync', async () => {
|
|
const existing = {
|
|
baseUrl: 'http://stale:1/v1',
|
|
models: [
|
|
{
|
|
id: 'sam-desktop/qwen3.6-35b',
|
|
name: 'Old Name',
|
|
contextWindow: 262_144,
|
|
maxTokens: 65_536,
|
|
},
|
|
],
|
|
};
|
|
const entry = await buildPiProviderEntry('http://127.0.0.1:9502', existing);
|
|
expect(entry.baseUrl).toBe('http://127.0.0.1:9502/v1'); // ours wins
|
|
const m = entry.models?.[0];
|
|
expect(m?.contextWindow).toBe(262_144); // hand-tuned values preserved
|
|
expect(m?.maxTokens).toBe(65_536);
|
|
});
|
|
});
|