feat(pi): fetch and refresh upstream model lists, searchable model picker
- POST /pi/upstreams/{id}/models/refresh calls the provider's model list
endpoint (OpenAI-shaped /models, Anthropic /v1/models, Google
/v1beta/models, OpenRouter /api/v1/models; Radius via pi-ai refresh),
normalizes {id, displayName, contextWindow, supportsVision,
supportsTools, pricing} and stores it in pi_upstream.models (0044)
- GET .../models returns {source, fetchedAt, models[]}: remote merged
with the static catalog (remote first); failures (401/network/
unsupported) fall back to static with a one-line error
- POST /pi/models/probe for trying credentials before creating
- wizard and edit drawer: fetch button, searchable dropdown with
vision/tool tags, manual id, source line; default upstream needs a model
- tests: mock /models, 401, network failure; smoke step; runbook
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
e5abfa6217
commit
0765264a47
16 files changed
+1178
-52
No files matched your search
+17
-2
@@ -129,7 +129,7 @@ curl -X POST localhost:4380/api/v1/automation-grants -H "Authorization: Bearer <
|
||||
## 上游与登录(W7-A)
|
||||
|
||||
实现:`apps/server/src/modules/pi/`(上游 CRUD、能力表、测试、服务端订阅登录、刷新任务)、`packages/agent/src/pi/{catalog,upstream,fake-upstream}.ts`、
|
||||
合同 `packages/contracts/src/pi.ts`、迁移 `0027_pi_upstreams`。研究结论见 `docs/design/pi-providers.md`。
|
||||
合同 `packages/contracts/src/pi.ts`、迁移 `0027_pi_upstreams`、`0044_upstream_models`。研究结论见 `docs/design/pi-providers.md`。
|
||||
|
||||
**模型**:一个上游(`pi_upstream`)= 一个 pi provider + 一份凭据。provider 是 pi-ai 0.87.1 内置的 41 个之一,或
|
||||
`openai-compatible`(自定义兼容端点,baseUrl 与模型必填,`extra.api` 选 openai-completions / openai-responses / anthropic-messages / google-generative-ai),
|
||||
@@ -155,11 +155,26 @@ runAgent 按 `runAgent{upstreamId}` → `agent_run.upstream_id` → 默认上游
|
||||
| `GET /pi/upstreams`、`GET /pi/upstreams/{id}` | 不含密钥,只给 `hasCredential`、`credentialMask`(前 4 后 4)、`account`、`oauthExpiresAt`、`isDefault` |
|
||||
| `POST /pi/upstreams`、`PATCH /pi/upstreams/{id}`、`DELETE …` | `apiKey` 只写(PATCH 传 null 清除);provider 不可改;改 authKind 会删掉旧凭据;删除连同 secret |
|
||||
| `POST /pi/upstreams/{id}/test {mode?: auth\|completion, model?}` | 缺省 `auth`:解析凭据(OAuth 必要时刷新)+ 校验模型在目录中,**不产生费用**;`completion` 再发一次最多 16 token 的补全 |
|
||||
| `GET /pi/upstreams/{id}/models` | 静态目录(已配置凭据时按 provider 过滤,如 Copilot);Radius 先动态刷新,失败时回静态表并给 `refreshError` |
|
||||
| `GET /pi/upstreams/{id}/models` | `{source: remote\|static, fetchedAt, models[], remoteSupported, error, errorKind}`:拉过远程列表 → 远程与静态目录合并去重(同 id 远程优先,远程缺的字段用静态补,远程在前);没拉过 → 静态目录(已配置凭据时按 provider 过滤,如 Copilot) |
|
||||
| `POST /pi/upstreams/{id}/models/refresh` | 「获取模型列表」:用该上游的凭据调 provider 的模型列表接口,成功存 `pi_upstream.models` + `models_fetched_at`(迁移 0044)。失败不动已存列表,返回当前列表 + 一句话 `error`,`errorKind` = auth(401/403)/ network / unsupported / config / other。改 Base URL 或 `extra.api` 会清掉已存列表 |
|
||||
| `POST /pi/models/probe {provider, authKind, apiKey?, baseUrl?, extra?}` | 新建上游前试拉(凭据只用这一次,不落库);新建向导创建后会用已存凭据再拉一次并存库 |
|
||||
| `POST /pi/upstreams/{id}/oauth/start {mode?, enterpriseDomain?}` | 开始订阅登录,见下 |
|
||||
| `POST /pi/upstreams/{id}/oauth/complete {sessionId, pastedUrlOrCode?, waitMs?}` | 完成 / 轮询登录 |
|
||||
| `POST /pi/upstreams/{id}/oauth/logout` | 删除本地 token,状态回到 `auth_required`(不会撤销提供方侧授权) |
|
||||
|
||||
**模型列表**(PI-2,`apps/server/src/modules/pi/models.ts`):pi-ai 0.87.1 只有 Radius 自带 `refreshModels`(照旧走 pi 的动态刷新),其它按通用规则直连,出站走进程的 `HTTP(S)_PROXY`,超时 15 秒:
|
||||
|
||||
| provider | 接口 |
|
||||
|---|---|
|
||||
| OpenAI 形状(openai、deepseek、groq、xai、mistral、together、fireworks、nvidia、huggingface、moonshot、qwen/xiaomi token plan、zai、opencode、vercel-ai-gateway、baseten、cerebras、ant-ling、meta;自定义端点 `extra.api` 为 openai-*) | `GET {base}/models`(base 以 `/v1`、`/v4`、`/v1beta` 这类版本段结尾时),否则 `GET {base}/v1/models`;`Authorization: Bearer` |
|
||||
| anthropic(API Key)、自定义端点 anthropic-messages | `GET /v1/models?limit=1000`,`x-api-key` + `anthropic-version: 2023-06-01` |
|
||||
| google、自定义端点 google-generative-ai | `GET /v1beta/models?key=…&pageSize=1000`,只留支持 generateContent 的 |
|
||||
| openrouter(API Key 或登录换到的永久 Key) | `GET /api/v1/models`(带价格、上下文、`input_modalities`、`supported_parameters`) |
|
||||
| 其它订阅登录、云凭证(Bedrock / Vertex / Azure / Cloudflare)、Copilot、Kimi、MiniMax、fake | 没有公开接口 → `unsupported`,用静态目录(界面不显示获取按钮) |
|
||||
|
||||
归一化字段 `{id, displayName, contextWindow, supportsVision, supportsTools, pricing{input, output}(美元 / 百万 token)}`,拿不到为 null;去掉嵌入、语音、审核、重排类 id。
|
||||
界面:新建向导第 2 步凭据填好后「获取模型列表」(试拉),第 3 步与编辑抽屉「获取 / 更新模型列表」;下拉可搜索,显示 id、上下文、视觉 / 工具标记,也可手填 id;来源行「来源:远程 · 几分钟前更新」或「来源:静态」;失败一句话。设为默认上游时默认模型必填(界面校验)。
|
||||
|
||||
**上游状态**(服务端维护):`auth_required`(新建 oauth / 未填 key / 已登出)→ 登录或填 key → `ok`;测试失败 → `error`(凭据被拒 → `auth_required`);
|
||||
OAuth 刷新失败 → `expired` + 待处理事项「模型上游 X 登录已失效,需要重新登录」(去重键 `pi_upstream_expired:<id>`),重新登录成功后事项自动关闭。
|
||||
|
||||
|
||||
Reference in new issue
Block a user