mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 13:07:39 +00:00
follow-up: align ingress, atomic paths, and channel tests with credential semantics (#33733)
Merged via squash.
Prepared head SHA: c290c2ab6a
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
Reviewed-by: @joshavant
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
||||
formatRemainingShort,
|
||||
} from "../agents/auth-health.js";
|
||||
import {
|
||||
type AuthCredentialReasonCode,
|
||||
CLAUDE_CLI_PROFILE_ID,
|
||||
CODEX_CLI_PROFILE_ID,
|
||||
ensureAuthProfileStore,
|
||||
@@ -203,6 +204,7 @@ type AuthIssue = {
|
||||
profileId: string;
|
||||
provider: string;
|
||||
status: string;
|
||||
reasonCode?: AuthCredentialReasonCode;
|
||||
remainingMs?: number;
|
||||
};
|
||||
|
||||
@@ -222,6 +224,9 @@ export function resolveUnusableProfileHint(params: {
|
||||
}
|
||||
|
||||
function formatAuthIssueHint(issue: AuthIssue): string | null {
|
||||
if (issue.reasonCode === "invalid_expires") {
|
||||
return "Invalid token expires metadata. Set a future Unix ms timestamp or remove expires.";
|
||||
}
|
||||
if (issue.provider === "anthropic" && issue.profileId === CLAUDE_CLI_PROFILE_ID) {
|
||||
return `Deprecated profile. Use ${formatCliCommand("openclaw models auth setup-token")} or ${formatCliCommand(
|
||||
"openclaw configure",
|
||||
@@ -239,7 +244,8 @@ function formatAuthIssueLine(issue: AuthIssue): string {
|
||||
const remaining =
|
||||
issue.remainingMs !== undefined ? ` (${formatRemainingShort(issue.remainingMs)})` : "";
|
||||
const hint = formatAuthIssueHint(issue);
|
||||
return `- ${issue.profileId}: ${issue.status}${remaining}${hint ? ` — ${hint}` : ""}`;
|
||||
const reason = issue.reasonCode ? ` [${issue.reasonCode}]` : "";
|
||||
return `- ${issue.profileId}: ${issue.status}${reason}${remaining}${hint ? ` — ${hint}` : ""}`;
|
||||
}
|
||||
|
||||
export async function noteAuthProfileHealth(params: {
|
||||
@@ -340,6 +346,7 @@ export async function noteAuthProfileHealth(params: {
|
||||
profileId: issue.profileId,
|
||||
provider: issue.provider,
|
||||
status: issue.status,
|
||||
reasonCode: issue.reasonCode,
|
||||
remainingMs: issue.remainingMs,
|
||||
}),
|
||||
)
|
||||
|
||||
166
src/commands/models/list.probe.targets.test.ts
Normal file
166
src/commands/models/list.probe.targets.test.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { AuthProfileStore } from "../../agents/auth-profiles.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
|
||||
let mockStore: AuthProfileStore;
|
||||
let mockAllowedProfiles: string[];
|
||||
|
||||
const resolveAuthProfileOrderMock = vi.fn(() => mockAllowedProfiles);
|
||||
const resolveAuthProfileEligibilityMock = vi.fn(() => ({
|
||||
eligible: false,
|
||||
reasonCode: "invalid_expires" as const,
|
||||
}));
|
||||
const resolveSecretRefStringMock = vi.fn(async () => "resolved-secret");
|
||||
|
||||
vi.mock("../../agents/model-catalog.js", () => ({
|
||||
loadModelCatalog: vi.fn(async () => []),
|
||||
}));
|
||||
vi.mock("../../secrets/resolve.js", () => ({
|
||||
resolveSecretRefString: resolveSecretRefStringMock,
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/auth-profiles.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../../agents/auth-profiles.js")>();
|
||||
return {
|
||||
...actual,
|
||||
ensureAuthProfileStore: () => mockStore,
|
||||
listProfilesForProvider: (_store: AuthProfileStore, provider: string) =>
|
||||
Object.entries(mockStore.profiles)
|
||||
.filter(
|
||||
([, profile]) =>
|
||||
typeof profile.provider === "string" && profile.provider.toLowerCase() === provider,
|
||||
)
|
||||
.map(([profileId]) => profileId),
|
||||
resolveAuthProfileDisplayLabel: ({ profileId }: { profileId: string }) => profileId,
|
||||
resolveAuthProfileOrder: resolveAuthProfileOrderMock,
|
||||
resolveAuthProfileEligibility: resolveAuthProfileEligibilityMock,
|
||||
};
|
||||
});
|
||||
|
||||
const { buildProbeTargets } = await import("./list.probe.js");
|
||||
|
||||
describe("buildProbeTargets reason codes", () => {
|
||||
beforeEach(() => {
|
||||
mockStore = {
|
||||
version: 1,
|
||||
profiles: {
|
||||
"anthropic:default": {
|
||||
type: "token",
|
||||
provider: "anthropic",
|
||||
tokenRef: { source: "env", provider: "default", id: "ANTHROPIC_TOKEN" },
|
||||
expires: 0,
|
||||
},
|
||||
},
|
||||
order: {
|
||||
anthropic: ["anthropic:default"],
|
||||
},
|
||||
};
|
||||
mockAllowedProfiles = [];
|
||||
resolveAuthProfileOrderMock.mockClear();
|
||||
resolveAuthProfileEligibilityMock.mockClear();
|
||||
resolveSecretRefStringMock.mockReset();
|
||||
resolveSecretRefStringMock.mockResolvedValue("resolved-secret");
|
||||
resolveAuthProfileEligibilityMock.mockReturnValue({
|
||||
eligible: false,
|
||||
reasonCode: "invalid_expires",
|
||||
});
|
||||
});
|
||||
|
||||
it("reports invalid_expires with a legacy-compatible first error line", async () => {
|
||||
const plan = await buildProbeTargets({
|
||||
cfg: {
|
||||
auth: {
|
||||
order: {
|
||||
anthropic: ["anthropic:default"],
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
providers: ["anthropic"],
|
||||
modelCandidates: ["anthropic/claude-sonnet-4-6"],
|
||||
options: {
|
||||
timeoutMs: 5_000,
|
||||
concurrency: 1,
|
||||
maxTokens: 16,
|
||||
},
|
||||
});
|
||||
|
||||
expect(plan.targets).toHaveLength(0);
|
||||
expect(plan.results).toHaveLength(1);
|
||||
expect(plan.results[0]?.reasonCode).toBe("invalid_expires");
|
||||
expect(plan.results[0]?.error?.split("\n")[0]).toBe(
|
||||
"Auth profile credentials are missing or expired.",
|
||||
);
|
||||
expect(plan.results[0]?.error).toContain("[invalid_expires]");
|
||||
});
|
||||
|
||||
it("reports excluded_by_auth_order when profile id is not present in explicit order", async () => {
|
||||
mockStore.order = {
|
||||
anthropic: ["anthropic:work"],
|
||||
};
|
||||
const plan = await buildProbeTargets({
|
||||
cfg: {
|
||||
auth: {
|
||||
order: {
|
||||
anthropic: ["anthropic:work"],
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
providers: ["anthropic"],
|
||||
modelCandidates: ["anthropic/claude-sonnet-4-6"],
|
||||
options: {
|
||||
timeoutMs: 5_000,
|
||||
concurrency: 1,
|
||||
maxTokens: 16,
|
||||
},
|
||||
});
|
||||
|
||||
expect(plan.targets).toHaveLength(0);
|
||||
expect(plan.results).toHaveLength(1);
|
||||
expect(plan.results[0]?.reasonCode).toBe("excluded_by_auth_order");
|
||||
expect(plan.results[0]?.error).toBe("Excluded by auth.order for this provider.");
|
||||
});
|
||||
|
||||
it("reports unresolved_ref when a ref-only profile cannot resolve its SecretRef", async () => {
|
||||
mockStore = {
|
||||
version: 1,
|
||||
profiles: {
|
||||
"anthropic:default": {
|
||||
type: "token",
|
||||
provider: "anthropic",
|
||||
tokenRef: { source: "env", provider: "default", id: "MISSING_ANTHROPIC_TOKEN" },
|
||||
},
|
||||
},
|
||||
order: {
|
||||
anthropic: ["anthropic:default"],
|
||||
},
|
||||
};
|
||||
mockAllowedProfiles = ["anthropic:default"];
|
||||
resolveSecretRefStringMock.mockRejectedValueOnce(new Error("missing secret"));
|
||||
|
||||
const plan = await buildProbeTargets({
|
||||
cfg: {
|
||||
auth: {
|
||||
order: {
|
||||
anthropic: ["anthropic:default"],
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
providers: ["anthropic"],
|
||||
modelCandidates: ["anthropic/claude-sonnet-4-6"],
|
||||
options: {
|
||||
timeoutMs: 5_000,
|
||||
concurrency: 1,
|
||||
maxTokens: 16,
|
||||
},
|
||||
});
|
||||
|
||||
expect(plan.targets).toHaveLength(0);
|
||||
expect(plan.results).toHaveLength(1);
|
||||
expect(plan.results[0]?.reasonCode).toBe("unresolved_ref");
|
||||
expect(plan.results[0]?.error?.split("\n")[0]).toBe(
|
||||
"Auth profile credentials are missing or expired.",
|
||||
);
|
||||
expect(plan.results[0]?.error).toContain("[unresolved_ref]");
|
||||
expect(plan.results[0]?.error).toContain("env:default:MISSING_ANTHROPIC_TOKEN");
|
||||
});
|
||||
});
|
||||
@@ -3,9 +3,12 @@ import fs from "node:fs/promises";
|
||||
import { resolveOpenClawAgentDir } from "../../agents/agent-paths.js";
|
||||
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../../agents/agent-scope.js";
|
||||
import {
|
||||
type AuthProfileCredential,
|
||||
type AuthProfileEligibilityReasonCode,
|
||||
ensureAuthProfileStore,
|
||||
listProfilesForProvider,
|
||||
resolveAuthProfileDisplayLabel,
|
||||
resolveAuthProfileEligibility,
|
||||
resolveAuthProfileOrder,
|
||||
} from "../../agents/auth-profiles.js";
|
||||
import { describeFailoverError } from "../../agents/failover-error.js";
|
||||
@@ -23,6 +26,8 @@ import {
|
||||
resolveSessionTranscriptPath,
|
||||
resolveSessionTranscriptsDirForAgent,
|
||||
} from "../../config/sessions/paths.js";
|
||||
import { coerceSecretRef, normalizeSecretInputString } from "../../config/types.secrets.js";
|
||||
import { type SecretRefResolveCache, resolveSecretRefString } from "../../secrets/resolve.js";
|
||||
import { redactSecrets } from "../status-all/format.js";
|
||||
import { DEFAULT_PROVIDER, formatMs } from "./shared.js";
|
||||
|
||||
@@ -38,6 +43,15 @@ export type AuthProbeStatus =
|
||||
| "unknown"
|
||||
| "no_model";
|
||||
|
||||
export type AuthProbeReasonCode =
|
||||
| "excluded_by_auth_order"
|
||||
| "missing_credential"
|
||||
| "expired"
|
||||
| "invalid_expires"
|
||||
| "unresolved_ref"
|
||||
| "ineligible_profile"
|
||||
| "no_model";
|
||||
|
||||
export type AuthProbeResult = {
|
||||
provider: string;
|
||||
model?: string;
|
||||
@@ -46,6 +60,7 @@ export type AuthProbeResult = {
|
||||
source: "profile" | "env" | "models.json";
|
||||
mode?: string;
|
||||
status: AuthProbeStatus;
|
||||
reasonCode?: AuthProbeReasonCode;
|
||||
error?: string;
|
||||
latencyMs?: number;
|
||||
};
|
||||
@@ -139,7 +154,91 @@ function selectProbeModel(params: {
|
||||
return null;
|
||||
}
|
||||
|
||||
function buildProbeTargets(params: {
|
||||
function mapEligibilityReasonToProbeReasonCode(
|
||||
reasonCode: AuthProfileEligibilityReasonCode,
|
||||
): AuthProbeReasonCode {
|
||||
if (reasonCode === "missing_credential") {
|
||||
return "missing_credential";
|
||||
}
|
||||
if (reasonCode === "expired") {
|
||||
return "expired";
|
||||
}
|
||||
if (reasonCode === "invalid_expires") {
|
||||
return "invalid_expires";
|
||||
}
|
||||
if (reasonCode === "unresolved_ref") {
|
||||
return "unresolved_ref";
|
||||
}
|
||||
return "ineligible_profile";
|
||||
}
|
||||
|
||||
function formatMissingCredentialProbeError(reasonCode: AuthProbeReasonCode): string {
|
||||
const legacyLine = "Auth profile credentials are missing or expired.";
|
||||
if (reasonCode === "expired") {
|
||||
return `${legacyLine}\n↳ Auth reason [expired]: token credentials are expired.`;
|
||||
}
|
||||
if (reasonCode === "invalid_expires") {
|
||||
return `${legacyLine}\n↳ Auth reason [invalid_expires]: token expires must be a positive Unix ms timestamp.`;
|
||||
}
|
||||
if (reasonCode === "missing_credential") {
|
||||
return `${legacyLine}\n↳ Auth reason [missing_credential]: no inline credential or SecretRef is configured.`;
|
||||
}
|
||||
if (reasonCode === "unresolved_ref") {
|
||||
return `${legacyLine}\n↳ Auth reason [unresolved_ref]: configured SecretRef could not be resolved.`;
|
||||
}
|
||||
return `${legacyLine}\n↳ Auth reason [ineligible_profile]: profile is incompatible with provider config.`;
|
||||
}
|
||||
|
||||
function resolveProbeSecretRef(profile: AuthProfileCredential, cfg: OpenClawConfig) {
|
||||
const defaults = cfg.secrets?.defaults;
|
||||
if (profile.type === "api_key") {
|
||||
if (normalizeSecretInputString(profile.key) !== undefined) {
|
||||
return null;
|
||||
}
|
||||
return coerceSecretRef(profile.keyRef, defaults);
|
||||
}
|
||||
if (profile.type === "token") {
|
||||
if (normalizeSecretInputString(profile.token) !== undefined) {
|
||||
return null;
|
||||
}
|
||||
return coerceSecretRef(profile.tokenRef, defaults);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function formatUnresolvedRefProbeError(refLabel: string): string {
|
||||
const legacyLine = "Auth profile credentials are missing or expired.";
|
||||
return `${legacyLine}\n↳ Auth reason [unresolved_ref]: could not resolve SecretRef "${refLabel}".`;
|
||||
}
|
||||
|
||||
async function maybeResolveUnresolvedRefIssue(params: {
|
||||
cfg: OpenClawConfig;
|
||||
profile?: AuthProfileCredential;
|
||||
cache: SecretRefResolveCache;
|
||||
}): Promise<{ reasonCode: "unresolved_ref"; error: string } | null> {
|
||||
if (!params.profile) {
|
||||
return null;
|
||||
}
|
||||
const ref = resolveProbeSecretRef(params.profile, params.cfg);
|
||||
if (!ref) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
await resolveSecretRefString(ref, {
|
||||
config: params.cfg,
|
||||
env: process.env,
|
||||
cache: params.cache,
|
||||
});
|
||||
return null;
|
||||
} catch {
|
||||
return {
|
||||
reasonCode: "unresolved_ref",
|
||||
error: formatUnresolvedRefProbeError(`${ref.source}:${ref.provider}:${ref.id}`),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function buildProbeTargets(params: {
|
||||
cfg: OpenClawConfig;
|
||||
providers: string[];
|
||||
modelCandidates: string[];
|
||||
@@ -150,133 +249,162 @@ function buildProbeTargets(params: {
|
||||
const providerFilter = options.provider?.trim();
|
||||
const providerFilterKey = providerFilter ? normalizeProviderId(providerFilter) : null;
|
||||
const profileFilter = new Set((options.profileIds ?? []).map((id) => id.trim()).filter(Boolean));
|
||||
const refResolveCache: SecretRefResolveCache = {};
|
||||
const catalog = await loadModelCatalog({ config: cfg });
|
||||
const candidates = buildCandidateMap(modelCandidates);
|
||||
const targets: AuthProbeTarget[] = [];
|
||||
const results: AuthProbeResult[] = [];
|
||||
|
||||
return loadModelCatalog({ config: cfg }).then((catalog) => {
|
||||
const candidates = buildCandidateMap(modelCandidates);
|
||||
const targets: AuthProbeTarget[] = [];
|
||||
const results: AuthProbeResult[] = [];
|
||||
for (const provider of providers) {
|
||||
const providerKey = normalizeProviderId(provider);
|
||||
if (providerFilterKey && providerKey !== providerFilterKey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const provider of providers) {
|
||||
const providerKey = normalizeProviderId(provider);
|
||||
if (providerFilterKey && providerKey !== providerFilterKey) {
|
||||
continue;
|
||||
}
|
||||
const model = selectProbeModel({
|
||||
provider: providerKey,
|
||||
candidates,
|
||||
catalog,
|
||||
});
|
||||
|
||||
const model = selectProbeModel({
|
||||
provider: providerKey,
|
||||
candidates,
|
||||
catalog,
|
||||
});
|
||||
const profileIds = listProfilesForProvider(store, providerKey);
|
||||
const explicitOrder = (() => {
|
||||
return (
|
||||
findNormalizedProviderValue(store.order, providerKey) ??
|
||||
findNormalizedProviderValue(cfg?.auth?.order, providerKey)
|
||||
);
|
||||
})();
|
||||
const allowedProfiles =
|
||||
explicitOrder && explicitOrder.length > 0
|
||||
? new Set(resolveAuthProfileOrder({ cfg, store, provider: providerKey }))
|
||||
: null;
|
||||
const filteredProfiles = profileFilter.size
|
||||
? profileIds.filter((id) => profileFilter.has(id))
|
||||
: profileIds;
|
||||
|
||||
const profileIds = listProfilesForProvider(store, providerKey);
|
||||
const explicitOrder = (() => {
|
||||
return (
|
||||
findNormalizedProviderValue(store.order, providerKey) ??
|
||||
findNormalizedProviderValue(cfg?.auth?.order, providerKey)
|
||||
);
|
||||
})();
|
||||
const allowedProfiles =
|
||||
explicitOrder && explicitOrder.length > 0
|
||||
? new Set(resolveAuthProfileOrder({ cfg, store, provider: providerKey }))
|
||||
: null;
|
||||
const filteredProfiles = profileFilter.size
|
||||
? profileIds.filter((id) => profileFilter.has(id))
|
||||
: profileIds;
|
||||
|
||||
if (filteredProfiles.length > 0) {
|
||||
for (const profileId of filteredProfiles) {
|
||||
const profile = store.profiles[profileId];
|
||||
const mode = profile?.type;
|
||||
const label = resolveAuthProfileDisplayLabel({ cfg, store, profileId });
|
||||
if (explicitOrder && !explicitOrder.includes(profileId)) {
|
||||
results.push({
|
||||
provider: providerKey,
|
||||
model: model ? `${model.provider}/${model.model}` : undefined,
|
||||
profileId,
|
||||
label,
|
||||
source: "profile",
|
||||
mode,
|
||||
status: "unknown",
|
||||
error: "Excluded by auth.order for this provider.",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
if (allowedProfiles && !allowedProfiles.has(profileId)) {
|
||||
results.push({
|
||||
provider: providerKey,
|
||||
model: model ? `${model.provider}/${model.model}` : undefined,
|
||||
profileId,
|
||||
label,
|
||||
source: "profile",
|
||||
mode,
|
||||
status: "unknown",
|
||||
error: "Auth profile credentials are missing or expired.",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
if (!model) {
|
||||
results.push({
|
||||
provider: providerKey,
|
||||
model: undefined,
|
||||
profileId,
|
||||
label,
|
||||
source: "profile",
|
||||
mode,
|
||||
status: "no_model",
|
||||
error: "No model available for probe",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
targets.push({
|
||||
if (filteredProfiles.length > 0) {
|
||||
for (const profileId of filteredProfiles) {
|
||||
const profile = store.profiles[profileId];
|
||||
const mode = profile?.type;
|
||||
const label = resolveAuthProfileDisplayLabel({ cfg, store, profileId });
|
||||
if (explicitOrder && !explicitOrder.includes(profileId)) {
|
||||
results.push({
|
||||
provider: providerKey,
|
||||
model,
|
||||
profileId,
|
||||
model: model ? `${model.provider}/${model.model}` : undefined,
|
||||
label,
|
||||
source: "profile",
|
||||
mode,
|
||||
status: "unknown",
|
||||
reasonCode: "excluded_by_auth_order",
|
||||
error: "Excluded by auth.order for this provider.",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
if (allowedProfiles && !allowedProfiles.has(profileId)) {
|
||||
const eligibility = resolveAuthProfileEligibility({
|
||||
cfg,
|
||||
store,
|
||||
provider: providerKey,
|
||||
profileId,
|
||||
});
|
||||
const reasonCode = mapEligibilityReasonToProbeReasonCode(eligibility.reasonCode);
|
||||
results.push({
|
||||
provider: providerKey,
|
||||
model: model ? `${model.provider}/${model.model}` : undefined,
|
||||
profileId,
|
||||
label,
|
||||
source: "profile",
|
||||
mode,
|
||||
status: "unknown",
|
||||
reasonCode,
|
||||
error: formatMissingCredentialProbeError(reasonCode),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (profileFilter.size > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const envKey = resolveEnvApiKey(providerKey);
|
||||
const customKey = getCustomProviderApiKey(cfg, providerKey);
|
||||
if (!envKey && !customKey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const label = envKey ? "env" : "models.json";
|
||||
const source = envKey ? "env" : "models.json";
|
||||
const mode = envKey?.source.includes("OAUTH_TOKEN") ? "oauth" : "api_key";
|
||||
|
||||
if (!model) {
|
||||
results.push({
|
||||
provider: providerKey,
|
||||
model: undefined,
|
||||
label,
|
||||
source,
|
||||
mode,
|
||||
status: "no_model",
|
||||
error: "No model available for probe",
|
||||
const unresolvedRefIssue = await maybeResolveUnresolvedRefIssue({
|
||||
cfg,
|
||||
profile,
|
||||
cache: refResolveCache,
|
||||
});
|
||||
if (unresolvedRefIssue) {
|
||||
results.push({
|
||||
provider: providerKey,
|
||||
model: model ? `${model.provider}/${model.model}` : undefined,
|
||||
profileId,
|
||||
label,
|
||||
source: "profile",
|
||||
mode,
|
||||
status: "unknown",
|
||||
reasonCode: unresolvedRefIssue.reasonCode,
|
||||
error: unresolvedRefIssue.error,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
if (!model) {
|
||||
results.push({
|
||||
provider: providerKey,
|
||||
model: undefined,
|
||||
profileId,
|
||||
label,
|
||||
source: "profile",
|
||||
mode,
|
||||
status: "no_model",
|
||||
reasonCode: "no_model",
|
||||
error: "No model available for probe",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
targets.push({
|
||||
provider: providerKey,
|
||||
model,
|
||||
profileId,
|
||||
label,
|
||||
source: "profile",
|
||||
mode,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
targets.push({
|
||||
if (profileFilter.size > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const envKey = resolveEnvApiKey(providerKey);
|
||||
const customKey = getCustomProviderApiKey(cfg, providerKey);
|
||||
if (!envKey && !customKey) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const label = envKey ? "env" : "models.json";
|
||||
const source = envKey ? "env" : "models.json";
|
||||
const mode = envKey?.source.includes("OAUTH_TOKEN") ? "oauth" : "api_key";
|
||||
|
||||
if (!model) {
|
||||
results.push({
|
||||
provider: providerKey,
|
||||
model,
|
||||
model: undefined,
|
||||
label,
|
||||
source,
|
||||
mode,
|
||||
status: "no_model",
|
||||
reasonCode: "no_model",
|
||||
error: "No model available for probe",
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
return { targets, results };
|
||||
});
|
||||
targets.push({
|
||||
provider: providerKey,
|
||||
model,
|
||||
label,
|
||||
source,
|
||||
mode,
|
||||
});
|
||||
}
|
||||
|
||||
return { targets, results };
|
||||
}
|
||||
|
||||
async function probeTarget(params: {
|
||||
@@ -299,6 +427,7 @@ async function probeTarget(params: {
|
||||
source: target.source,
|
||||
mode: target.mode,
|
||||
status: "no_model",
|
||||
reasonCode: "no_model",
|
||||
error: "No model available for probe",
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user