fix(ci): align model list session metadata

This commit is contained in:
Peter Steinberger
2026-04-11 02:23:57 +01:00
parent 7e7a269ad1
commit 6c574d726b
4 changed files with 45 additions and 28 deletions

View File

@@ -1,5 +1,6 @@
import type { ProviderAuthContext } from "openclaw/plugin-sdk/core";
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
import {
normalizeOptionalString,
normalizeStringifiedOptionalString,
@@ -469,31 +470,36 @@ export async function testFoundryConnection(params: {
modelNameHint: params.modelNameHint,
api: params.api,
});
const signal =
typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(15_000) : undefined;
const res = await fetch(testRequest.url, {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
const { response: res, release } = await fetchWithSsrFGuard({
url: testRequest.url,
init: {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify(testRequest.body),
},
body: JSON.stringify(testRequest.body),
...(signal ? { signal } : {}),
timeoutMs: 15_000,
});
if (res.status === 400) {
const body = await res.text().catch(() => "");
await params.ctx.prompter.note(
`Endpoint is reachable but returned 400 Bad Request - check your deployment name and API version.\n${body.slice(0, 200)}`,
"Connection Test",
);
} else if (!res.ok) {
const body = await res.text().catch(() => "");
await params.ctx.prompter.note(
`Warning: test request returned ${res.status}. ${body.slice(0, 200)}\nProceeding anyway - you can fix the endpoint later.`,
"Connection Test",
);
} else {
await params.ctx.prompter.note("Connection test successful!", "✓");
try {
if (res.status === 400) {
const body = await res.text().catch(() => "");
await params.ctx.prompter.note(
`Endpoint is reachable but returned 400 Bad Request - check your deployment name and API version.\n${body.slice(0, 200)}`,
"Connection Test",
);
} else if (!res.ok) {
const body = await res.text().catch(() => "");
await params.ctx.prompter.note(
`Warning: test request returned ${res.status}. ${body.slice(0, 200)}\nProceeding anyway - you can fix the endpoint later.`,
"Connection Test",
);
} else {
await params.ctx.prompter.note("Connection test successful!", "✓");
}
} finally {
await release();
}
} catch (err) {
await params.ctx.prompter.note(

View File

@@ -11,7 +11,7 @@ import { normalizeProviderId } from "./model-selection.js";
export function resolveModelAuthLabel(params: {
provider?: string;
cfg?: OpenClawConfig;
sessionEntry?: SessionEntry;
sessionEntry?: Partial<Pick<SessionEntry, "authProfileOverride">>;
agentDir?: string;
}): string | undefined {
const resolvedProvider = params.provider?.trim();

View File

@@ -21,6 +21,9 @@ import type { CommandHandler } from "./commands-types.js";
const PAGE_SIZE_DEFAULT = 20;
const PAGE_SIZE_MAX = 100;
type ModelsCommandSessionEntry = Partial<
Pick<SessionEntry, "authProfileOverride" | "modelProvider" | "model">
>;
export type ModelsProviderData = {
byProvider: Map<string, Set<string>>;
@@ -196,7 +199,7 @@ function resolveProviderLabel(params: {
provider: string;
cfg: OpenClawConfig;
agentDir?: string;
sessionEntry?: SessionEntry;
sessionEntry?: ModelsCommandSessionEntry;
}): string {
const authLabel = resolveModelAuthLabel({
provider: params.provider,
@@ -215,7 +218,7 @@ export function formatModelsAvailableHeader(params: {
total: number;
cfg: OpenClawConfig;
agentDir?: string;
sessionEntry?: SessionEntry;
sessionEntry?: ModelsCommandSessionEntry;
}): string {
const providerLabel = resolveProviderLabel({
provider: params.provider,
@@ -233,7 +236,7 @@ export async function resolveModelsCommandReply(params: {
currentModel?: string;
agentId?: string;
agentDir?: string;
sessionEntry?: SessionEntry;
sessionEntry?: ModelsCommandSessionEntry;
}): Promise<ReplyPayload | null> {
const body = params.commandBodyNormalized.trim();
if (!body.startsWith("/models")) {

View File

@@ -21,11 +21,11 @@ vi.mock("../../agents/auth-profiles.js", () => ({
resolveAuthStorePathForDisplay: () => "/tmp/auth-profiles.json",
}));
import { resolveAgentDir, resolveSessionAgentId } from "../../agents/agent-scope.js";
import {
clearRuntimeAuthProfileStoreSnapshots,
replaceRuntimeAuthProfileStoreSnapshots,
} from "../../agents/auth-profiles.js";
import { resolveAgentDir, resolveSessionAgentId } from "../../agents/agent-scope.js";
import type { ModelAliasIndex } from "../../agents/model-selection.js";
import type { OpenClawConfig } from "../../config/config.js";
import type { SessionEntry } from "../../config/sessions.js";
@@ -49,9 +49,17 @@ const queueMocks = vi.hoisted(() => ({
vi.mock("../../agents/agent-scope.js", () => ({
resolveAgentConfig: vi.fn(() => ({})),
resolveAgentDir: vi.fn(() => "/tmp/agent"),
resolveAgentEffectiveModelPrimary: vi.fn(() => undefined),
resolveSessionAgentId: vi.fn(() => "main"),
}));
vi.mock("../../agents/model-catalog.js", () => ({
loadModelCatalog: vi.fn(async () => [
{ provider: "anthropic", id: "claude-opus-4-6", name: "Claude Opus" },
{ provider: "localai", id: "ultra-chat", name: "Ultra Chat" },
]),
}));
vi.mock("../../agents/sandbox.js", () => ({
resolveSandboxRuntimeStatus: vi.fn(() => ({ sandboxed: false })),
}));