feat(llm): declare pi-ai providers instead of looking them up
A pi-ai route had to name an installed catalog provider, served that catalog's models verbatim, and could override only the endpoint. An OpenAI-compatible gateway, a self-hosted server, or a model newer than the pinned pi-ai release was therefore unreachable, and a stale context window could not be corrected without upgrading the package. A route is now a declaration whose defaults come from the installed catalog. `catalog.ts` merges that catalog under the profile's own model entries, `provider.ts` builds the pi-ai Provider (reusing the catalog provider when the route keeps its protocol, so implementations this package cannot reconstruct keep working), and the adapter serves every operation from one `createModels()` collection. That also retires the `@earendil-works/pi-ai/compat` import, which pi-ai documents as a temporary entry point it deletes with its ModelManager migration. Credentials stay on the harness seam: the resolved key rides the request as pi-ai's highest-priority auth override, so `Models` holds no credential store and a named-but-missing reference still fails loud instead of falling back to an unrelated ambient key. A model's configured maxTokens now reaches the seam as defaultMaxTokens.
This commit is contained in:
@@ -400,12 +400,14 @@ describe('provider profile lifecycle', () => {
|
||||
expect(server.requests).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('validates empty, unknown, legacy-shaped, and explicitly blank profiles', () => {
|
||||
it('validates empty, underspecified, legacy-shaped, and explicitly blank profiles', () => {
|
||||
// Empty and omitted dicts are the dormant zero-route posture, not errors.
|
||||
expect(resolveProfiles({}).size).toBe(0)
|
||||
expect(resolveProfiles(undefined).size).toBe(0)
|
||||
expect(() => resolveProfiles({ '': {} })).toThrow(/non-empty/)
|
||||
expect(() => resolveProfiles({ 'not-real': {} })).toThrow(/unknown/)
|
||||
// A route the installed catalog does not ship is allowed, but it has no
|
||||
// defaults to fall back on: it must describe its own models.
|
||||
expect(() => resolveProfiles({ 'not-real': {} })).toThrow(/resolves no models/)
|
||||
// The pre-release array shape and its per-profile provider field fail
|
||||
// loud with migration directions instead of half-working.
|
||||
expect(() => resolveProfiles([{ provider: 'openai' }] as never)).toThrow(/dict keyed by provider/)
|
||||
|
||||
Reference in New Issue
Block a user