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); }); });