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
@@ -215,6 +215,41 @@ async function main() {
|
||||
if (SHOTS) await page.screenshot({ path: join(OUT, `${name}.png`), fullPage: true }).catch(() => {});
|
||||
results.push({ path, ms: Date.now() - t0, problems: [...new Set(problems)] });
|
||||
}
|
||||
// ── 交互:Agent 上游抽屉的模型选择(PI-2;只看来源行与可搜索下拉,不点「获取」,避免拿真实凭证出站)──
|
||||
{
|
||||
const label = "/console/settings#agent → 上游抽屉 · 模型选择";
|
||||
const up = await page.request.get(`${BASE}/api/v1/pi/upstreams`);
|
||||
const first = up.ok() ? (await up.json().catch(() => null))?.data?.items?.[0] : null;
|
||||
if (!first) skipped.push(`${label}(没有上游)`);
|
||||
else {
|
||||
problems = [];
|
||||
const t0 = Date.now();
|
||||
try {
|
||||
await page.goto("about:blank");
|
||||
await page.goto(`${BASE}/console/settings#agent`, { waitUntil: "networkidle", timeout: 30_000 });
|
||||
await page.getByText(first.name, { exact: true }).first().click();
|
||||
const input = page.locator("#pu-model");
|
||||
await input.waitFor({ timeout: 10_000 });
|
||||
await page
|
||||
.getByText(/^来源:/)
|
||||
.first()
|
||||
.waitFor({ timeout: 10_000 });
|
||||
const models = (await page.request.get(`${BASE}/api/v1/pi/upstreams/${first.id}/models`).then((r) => r.json()))
|
||||
?.data?.models;
|
||||
if (models?.length) {
|
||||
await input.fill("");
|
||||
await input.focus();
|
||||
await page.locator('[role="listbox"] [role="option"]').first().waitFor({ timeout: 5_000 });
|
||||
}
|
||||
await page.keyboard.press("Escape");
|
||||
} catch (err) {
|
||||
problems.push(`交互失败:${String(err?.message ?? err).split("\n")[0]}`);
|
||||
}
|
||||
if (SHOTS) await page.screenshot({ path: join(OUT, "settings_agent_upstream_models.png") }).catch(() => {});
|
||||
results.push({ path: label, ms: Date.now() - t0, problems: [...new Set(problems)] });
|
||||
}
|
||||
}
|
||||
|
||||
// ── 旧链接重定向 ──
|
||||
for (const r of REDIRECT_ROUTES) {
|
||||
let from = r.from;
|
||||
|
||||
Reference in new issue
Block a user