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:
rootandClaude Opus 5.5 committed 2026-09-29 01:26:07 +08:00
1 parent e5abfa6217
commit 0765264a47
16 files changed
+1178 -52

No files matched your search

+18
View File
@@ -1,5 +1,6 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type {
PiModelsProbeRequest,
PiOAuthCompleteRequest,
PiOAuthCompleteResult,
PiOAuthStartRequest,
@@ -54,6 +55,23 @@ export function usePiUpstreamModels(id: string | null) {
});
}
/** 获取模型列表:用该上游的凭证调 provider 的模型列表接口;失败时响应里仍是当前列表(静态表)并带 error */
export function useRefreshPiModels() {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: string) =>
apiData<PiUpstreamModels>("/pi/upstreams/{id}/models/refresh", { method: "POST", pathParams: { id }, body: {} }),
onSuccess: (data, id) => qc.setQueryData(piKeys.models(id), data),
});
}
/** 新建上游前试拉模型列表(凭证只用这一次,不落库) */
export function useProbePiModels() {
return useMutation({
mutationFn: (body: PiModelsProbeRequest) => apiData<PiUpstreamModels>("/pi/models/probe", { method: "POST", body }),
});
}
function useInvalidatePi() {
const qc = useQueryClient();
return () => {