mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 10:20:42 +00:00
fix: avoid broad runtime catalog supplements
This commit is contained in:
@@ -51,6 +51,10 @@ Notes:
|
||||
rows from plugin manifests or bundled provider catalog metadata even when you
|
||||
have not authenticated with that provider yet. Those rows still show as
|
||||
unavailable until matching auth is configured.
|
||||
- Broad `models list --all` merges manifest catalog rows over registry rows
|
||||
without loading provider runtime supplement hooks. Provider-filtered manifest
|
||||
fast paths only use providers marked `static`, so partial `refreshable`
|
||||
manifest rows do not hide registry-backed provider lists.
|
||||
- `models list` keeps native model metadata and runtime caps distinct. In table
|
||||
output, `Ctx` shows `contextTokens/contextWindow` when an effective runtime
|
||||
cap differs from the native context window; JSON rows include `contextTokens`
|
||||
|
||||
@@ -49,7 +49,7 @@ const mocks = vi.hoisted(() => {
|
||||
loadModelRegistry: vi.fn(),
|
||||
loadModelCatalog: vi.fn(),
|
||||
loadProviderCatalogModelsForList: vi.fn(),
|
||||
loadStaticManifestCatalogRowsForList: vi.fn(),
|
||||
loadManifestCatalogRowsForList: vi.fn(),
|
||||
loadProviderIndexCatalogRowsForList: vi.fn(),
|
||||
hasProviderStaticCatalogForFilter: vi.fn(),
|
||||
resolveConfiguredEntries: vi.fn(),
|
||||
@@ -78,7 +78,7 @@ function resetMocks() {
|
||||
});
|
||||
mocks.loadModelCatalog.mockResolvedValue([]);
|
||||
mocks.loadProviderCatalogModelsForList.mockResolvedValue([]);
|
||||
mocks.loadStaticManifestCatalogRowsForList.mockReturnValue([]);
|
||||
mocks.loadManifestCatalogRowsForList.mockReturnValue([]);
|
||||
mocks.loadProviderIndexCatalogRowsForList.mockReturnValue([]);
|
||||
mocks.hasProviderStaticCatalogForFilter.mockResolvedValue(false);
|
||||
mocks.resolveConfiguredEntries.mockReturnValue({
|
||||
@@ -143,7 +143,7 @@ function installModelsListCommandForwardCompatMocks() {
|
||||
}));
|
||||
|
||||
vi.doMock("./list.manifest-catalog.js", () => ({
|
||||
loadStaticManifestCatalogRowsForList: mocks.loadStaticManifestCatalogRowsForList,
|
||||
loadManifestCatalogRowsForList: mocks.loadManifestCatalogRowsForList,
|
||||
}));
|
||||
|
||||
vi.doMock("./list.provider-index-catalog.js", () => ({
|
||||
@@ -525,7 +525,7 @@ describe("modelsListCommand forward-compat", () => {
|
||||
|
||||
it("uses manifest catalog rows before provider runtime catalog rows", async () => {
|
||||
mocks.resolveConfiguredEntries.mockReturnValueOnce({ entries: [] });
|
||||
mocks.loadStaticManifestCatalogRowsForList.mockReturnValueOnce([
|
||||
mocks.loadManifestCatalogRowsForList.mockReturnValueOnce([
|
||||
{
|
||||
provider: "moonshot",
|
||||
id: "kimi-k2.6",
|
||||
@@ -596,7 +596,7 @@ describe("modelsListCommand forward-compat", () => {
|
||||
getAll: () => [{ ...OPENAI_CODEX_MODEL }],
|
||||
},
|
||||
});
|
||||
mocks.loadStaticManifestCatalogRowsForList.mockReturnValueOnce([
|
||||
mocks.loadManifestCatalogRowsForList.mockReturnValueOnce([
|
||||
{
|
||||
provider: "moonshot",
|
||||
id: "kimi-k2.6",
|
||||
@@ -622,6 +622,7 @@ describe("modelsListCommand forward-compat", () => {
|
||||
});
|
||||
expect(mocks.loadProviderCatalogModelsForList).not.toHaveBeenCalled();
|
||||
expect(mocks.resolveModelWithRegistry).not.toHaveBeenCalled();
|
||||
expect(mocks.loadModelCatalog).not.toHaveBeenCalled();
|
||||
expect(lastPrintedRows<{ key: string }>()).toEqual([
|
||||
expect.objectContaining({
|
||||
key: "openai-codex/gpt-5.4",
|
||||
|
||||
@@ -8,7 +8,10 @@ import {
|
||||
resolveAwsSdkEnvVarName,
|
||||
resolveEnvApiKey,
|
||||
} from "../../agents/model-auth.js";
|
||||
import { shouldSuppressBuiltInModel } from "../../agents/model-suppression.js";
|
||||
import {
|
||||
shouldSuppressBuiltInModel,
|
||||
shouldSuppressBuiltInModelFromManifest,
|
||||
} from "../../agents/model-suppression.js";
|
||||
import { discoverAuthStorage, discoverModels } from "../../agents/pi-model-discovery.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { resolveRuntimeSyntheticAuthProviderRefs } from "../../plugins/synthetic-auth.runtime.js";
|
||||
@@ -85,7 +88,11 @@ function validateAvailableModels(availableModels: unknown): Model<Api>[] {
|
||||
return availableModels as Model<Api>[];
|
||||
}
|
||||
|
||||
function loadAvailableModels(registry: ModelRegistry, cfg: OpenClawConfig): Model<Api>[] {
|
||||
function loadAvailableModels(
|
||||
registry: ModelRegistry,
|
||||
cfg: OpenClawConfig,
|
||||
opts?: { runtimeSuppression?: boolean },
|
||||
): Model<Api>[] {
|
||||
let availableModels: unknown;
|
||||
try {
|
||||
availableModels = registry.getAvailable();
|
||||
@@ -93,14 +100,19 @@ function loadAvailableModels(registry: ModelRegistry, cfg: OpenClawConfig): Mode
|
||||
throw normalizeAvailabilityError(err);
|
||||
}
|
||||
try {
|
||||
return validateAvailableModels(availableModels).filter(
|
||||
(model) =>
|
||||
!shouldSuppressBuiltInModel({
|
||||
provider: model.provider,
|
||||
id: model.id,
|
||||
baseUrl: model.baseUrl,
|
||||
config: cfg,
|
||||
}),
|
||||
return validateAvailableModels(availableModels).filter((model) =>
|
||||
opts?.runtimeSuppression === false
|
||||
? !shouldSuppressBuiltInModelFromManifest({
|
||||
provider: model.provider,
|
||||
id: model.id,
|
||||
config: cfg,
|
||||
})
|
||||
: !shouldSuppressBuiltInModel({
|
||||
provider: model.provider,
|
||||
id: model.id,
|
||||
baseUrl: model.baseUrl,
|
||||
config: cfg,
|
||||
}),
|
||||
);
|
||||
} catch (err) {
|
||||
throw normalizeAvailabilityError(err);
|
||||
@@ -111,26 +123,32 @@ export async function loadModelRegistry(
|
||||
cfg: OpenClawConfig,
|
||||
opts?: { providerFilter?: string; normalizeModels?: boolean },
|
||||
) {
|
||||
const runtimeSuppression = opts?.normalizeModels !== false;
|
||||
const agentDir = resolveOpenClawAgentDir();
|
||||
const authStorage = discoverAuthStorage(agentDir, { readOnly: true });
|
||||
const registry = discoverModels(authStorage, agentDir, {
|
||||
providerFilter: opts?.providerFilter,
|
||||
normalizeModels: opts?.normalizeModels,
|
||||
});
|
||||
const models = registry.getAll().filter(
|
||||
(model) =>
|
||||
!shouldSuppressBuiltInModel({
|
||||
provider: model.provider,
|
||||
id: model.id,
|
||||
baseUrl: model.baseUrl,
|
||||
config: cfg,
|
||||
}),
|
||||
const models = registry.getAll().filter((model) =>
|
||||
runtimeSuppression
|
||||
? !shouldSuppressBuiltInModel({
|
||||
provider: model.provider,
|
||||
id: model.id,
|
||||
baseUrl: model.baseUrl,
|
||||
config: cfg,
|
||||
})
|
||||
: !shouldSuppressBuiltInModelFromManifest({
|
||||
provider: model.provider,
|
||||
id: model.id,
|
||||
config: cfg,
|
||||
}),
|
||||
);
|
||||
let availableKeys: Set<string> | undefined;
|
||||
let availabilityErrorMessage: string | undefined;
|
||||
|
||||
try {
|
||||
const availableModels = loadAvailableModels(registry, cfg);
|
||||
const availableModels = loadAvailableModels(registry, cfg, { runtimeSuppression });
|
||||
availableKeys = new Set(availableModels.map((model) => modelKey(model.provider, model.id)));
|
||||
} catch (err) {
|
||||
if (!shouldFallbackToAuthHeuristics(err)) {
|
||||
|
||||
@@ -109,13 +109,15 @@ export async function appendAllModelRowSources(
|
||||
});
|
||||
}
|
||||
|
||||
if (params.modelRegistry) {
|
||||
if (params.modelRegistry && params.context.filter.provider) {
|
||||
await appendCatalogSupplementRows({
|
||||
rows: params.rows,
|
||||
modelRegistry: params.modelRegistry,
|
||||
context: params.context,
|
||||
seenKeys,
|
||||
});
|
||||
}
|
||||
if (params.modelRegistry) {
|
||||
return { requiresRegistryFallback: false };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user