From d5161807c8efea4213891287666941eefcf62d8a Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Sun, 4 Oct 2026 01:09:12 +0800 Subject: [PATCH] fix(llm-pi-ai): offer only catalog providers that ship a chat model pi-ai 1.0.0 adds classifier and image models to the built-in catalog and ships `typesafe` with classifier models only. The adapter dispatches chat requests only, so a catalog provider without a chat model gets no entry in the configurable-provider directory and no sign-in flow. --- packages/llm/llm-pi-ai/README.i18n.yaml | 4 ++-- packages/llm/llm-pi-ai/README.md | 2 +- packages/llm/llm-pi-ai/README.zh.md | 2 +- packages/llm/llm-pi-ai/src/catalog.ts | 9 ++++++--- packages/llm/llm-pi-ai/tests/catalog.spec.ts | 10 ++++++++++ 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/llm/llm-pi-ai/README.i18n.yaml b/packages/llm/llm-pi-ai/README.i18n.yaml index f32c029ee1..f4c6c00caf 100644 --- a/packages/llm/llm-pi-ai/README.i18n.yaml +++ b/packages/llm/llm-pi-ai/README.i18n.yaml @@ -51,8 +51,8 @@ en: 20afee7bbfb332ca zh: b080cf4e97094366 /deepseek-ai-dsh-llm-pi-ai/understand-the-implementation/registration-and-directory: - en: 4da379c9be65c18a - zh: fd305d4bd3dfa452 + en: 2788246134f1be0d + zh: 2140c47f09e6d55a /deepseek-ai-dsh-llm-pi-ai/understand-the-implementation/replay-and-vocabulary: en: 36e0c59a0f9f5980 zh: 90a62c4a9cd23429 diff --git a/packages/llm/llm-pi-ai/README.md b/packages/llm/llm-pi-ai/README.md index d46923b749..8b587f9f9e 100644 --- a/packages/llm/llm-pi-ai/README.md +++ b/packages/llm/llm-pi-ai/README.md @@ -152,7 +152,7 @@ The adapter is built on immutable snapshots and per-operation resolution. Each o ### Registration and directory -The plugin declares every installed catalog provider it can authenticate in the configurable-provider directory, joined with every route the current profiles declare, so configuration surfaces can offer the full catalog before any route exists. Each entry carries `declared` — whether pi-ai ships nothing under that key — because only the adapter can distinguish a hand-declared route from a narrowed catalog route. Route registration is atomic: a candidate set that collides with another adapter leaves the previous routes serving. A bare mount with zero routes is the dormant posture: nothing registers until the Config supplies profiles, and routes drop when it empties. +The plugin declares every installed catalog provider that ships a chat model and that it can authenticate in the configurable-provider directory, joined with every route the current profiles declare, so configuration surfaces can offer the full catalog before any route exists. A catalog provider whose models are all image-generation or classifier models is left out and gets no sign-in flow, because this adapter dispatches chat requests only. Each entry carries `declared` — whether pi-ai ships nothing under that key — because only the adapter can distinguish a hand-declared route from a narrowed catalog route. Route registration is atomic: a candidate set that collides with another adapter leaves the previous routes serving. A bare mount with zero routes is the dormant posture: nothing registers until the Config supplies profiles, and routes drop when it empties. ### Replay and vocabulary diff --git a/packages/llm/llm-pi-ai/README.zh.md b/packages/llm/llm-pi-ai/README.zh.md index 9176c27f79..15790e7744 100644 --- a/packages/llm/llm-pi-ai/README.zh.md +++ b/packages/llm/llm-pi-ai/README.zh.md @@ -152,7 +152,7 @@ Config 更新严格验证发生变化的 provider。初始加载将已存储的 ### 注册与目录 -插件会在可配置提供方目录中声明它能认证的每个已安装目录提供方,并加入当前 profile 声明的每条路由,因此配置界面可以在任何路由存在之前提供完整目录。每个条目都携带 `declared`——pi-ai 是否在该键下不提供任何内容——因为只有适配器能区分手工声明路由与收窄目录路由。路由注册具有原子性:与其他适配器冲突的候选集合会让此前路由继续服务。零路由的裸挂载即休眠姿态:settings 分节提供 profile 前不注册任何内容,分节清空时路由随之消失。 +插件会在可配置提供方目录中声明它能认证且提供聊天模型的每个已安装目录提供方,并加入当前 profile 声明的每条路由,因此配置界面可以在任何路由存在之前提供完整目录。模型全部为图片生成或分类器模型的目录提供方不进入目录,也不注册登录流程,因为本适配器只分派聊天请求。每个条目都携带 `declared`——pi-ai 是否在该键下不提供任何内容——因为只有适配器能区分手工声明路由与收窄目录路由。路由注册具有原子性:与其他适配器冲突的候选集合会让此前路由继续服务。零路由的裸挂载即休眠姿态:settings 分节提供 profile 前不注册任何内容,分节清空时路由随之消失。 ### 回放与词汇 diff --git a/packages/llm/llm-pi-ai/src/catalog.ts b/packages/llm/llm-pi-ai/src/catalog.ts index a257feedba..1e381ad614 100644 --- a/packages/llm/llm-pi-ai/src/catalog.ts +++ b/packages/llm/llm-pi-ai/src/catalog.ts @@ -186,11 +186,14 @@ export function catalogProvider(provider: string): Provider | undefined { } /** - * Every provider route the installed pi-ai catalog ships. - * @returns the catalog provider ids. + * Every provider route the installed pi-ai catalog ships with at least one + * chat model. This adapter dispatches chat requests only, so a catalog + * provider whose models are all of another type (image generation or + * classification) is not a configurable route. + * @returns the catalog provider ids that ship chat models, in catalog order. */ export function catalogProviderIds(): readonly string[] { - return getBuiltinProviders() + return getBuiltinProviders().filter(provider => getBuiltinModels(provider).length > 0) } /** diff --git a/packages/llm/llm-pi-ai/tests/catalog.spec.ts b/packages/llm/llm-pi-ai/tests/catalog.spec.ts index e6f5330e9b..93bc398745 100644 --- a/packages/llm/llm-pi-ai/tests/catalog.spec.ts +++ b/packages/llm/llm-pi-ai/tests/catalog.spec.ts @@ -1238,6 +1238,16 @@ describe('configurable-provider directory', () => { expect(offered).toContain('openai') }) + it('leaves out an installed catalog route that ships no chat model', async () => { + const ctx = await harness({}) + const offered = ctx.llm.listConfigurableProviders().map(entry => entry.provider) + + // The installed catalog ships `typesafe` with classifier models only; with + // nothing to dispatch a chat request to, the route is not offered. + expect(getBuiltinModels('typesafe')).toEqual([]) + expect(offered).not.toContain('typesafe') + }) + it('lists a route a stored profile names as a catalog route, not a declared one', async () => { // `declared` answers catalog membership, so a profile stored against a // route pi-ai ships is not mislabelled as one this deployment invented.