mirror of https://github.com/openclaw/openclaw.git
183 lines
5.2 KiB
TypeScript
183 lines
5.2 KiB
TypeScript
import type { Api, Model } from "@mariozechner/pi-ai";
|
|
import type { ModelRegistry } from "@mariozechner/pi-coding-agent";
|
|
import type { AuthProfileStore } from "../../agents/auth-profiles.js";
|
|
import { loadModelCatalog } from "../../agents/model-catalog.js";
|
|
import { shouldSuppressBuiltInModel } from "../../agents/model-suppression.js";
|
|
import { resolveModelWithRegistry } from "../../agents/pi-embedded-runner/model.js";
|
|
import type { OpenClawConfig } from "../../config/config.js";
|
|
import { loadModelRegistry, toModelRow } from "./list.registry.js";
|
|
import type { ConfiguredEntry, ModelRow } from "./list.types.js";
|
|
import { isLocalBaseUrl, modelKey } from "./shared.js";
|
|
|
|
type ConfiguredByKey = Map<string, ConfiguredEntry>;
|
|
|
|
type RowFilter = {
|
|
provider?: string;
|
|
local?: boolean;
|
|
};
|
|
|
|
type RowBuilderContext = {
|
|
cfg: OpenClawConfig;
|
|
authStore: AuthProfileStore;
|
|
availableKeys?: Set<string>;
|
|
configuredByKey: ConfiguredByKey;
|
|
discoveredKeys: Set<string>;
|
|
filter: RowFilter;
|
|
};
|
|
|
|
function matchesRowFilter(filter: RowFilter, model: { provider: string; baseUrl?: string }) {
|
|
if (filter.provider && model.provider.toLowerCase() !== filter.provider) {
|
|
return false;
|
|
}
|
|
if (filter.local && !isLocalBaseUrl(model.baseUrl ?? "")) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function buildRow(params: {
|
|
model: Model<Api>;
|
|
key: string;
|
|
context: RowBuilderContext;
|
|
allowProviderAvailabilityFallback?: boolean;
|
|
}): ModelRow {
|
|
const configured = params.context.configuredByKey.get(params.key);
|
|
return toModelRow({
|
|
model: params.model,
|
|
key: params.key,
|
|
tags: configured ? Array.from(configured.tags) : [],
|
|
aliases: configured?.aliases ?? [],
|
|
availableKeys: params.context.availableKeys,
|
|
cfg: params.context.cfg,
|
|
authStore: params.context.authStore,
|
|
allowProviderAvailabilityFallback: params.allowProviderAvailabilityFallback ?? false,
|
|
});
|
|
}
|
|
|
|
export async function loadListModelRegistry(
|
|
cfg: OpenClawConfig,
|
|
opts?: { sourceConfig?: OpenClawConfig },
|
|
) {
|
|
const loaded = await loadModelRegistry(cfg, opts);
|
|
return {
|
|
...loaded,
|
|
discoveredKeys: new Set(loaded.models.map((model) => modelKey(model.provider, model.id))),
|
|
};
|
|
}
|
|
|
|
export function appendDiscoveredRows(params: {
|
|
rows: ModelRow[];
|
|
models: Model<Api>[];
|
|
context: RowBuilderContext;
|
|
}): Set<string> {
|
|
const seenKeys = new Set<string>();
|
|
const sorted = [...params.models].toSorted((a, b) => {
|
|
const providerCompare = a.provider.localeCompare(b.provider);
|
|
if (providerCompare !== 0) {
|
|
return providerCompare;
|
|
}
|
|
return a.id.localeCompare(b.id);
|
|
});
|
|
|
|
for (const model of sorted) {
|
|
if (shouldSuppressBuiltInModel({ provider: model.provider, id: model.id })) {
|
|
continue;
|
|
}
|
|
if (!matchesRowFilter(params.context.filter, model)) {
|
|
continue;
|
|
}
|
|
const key = modelKey(model.provider, model.id);
|
|
params.rows.push(
|
|
buildRow({
|
|
model,
|
|
key,
|
|
context: params.context,
|
|
}),
|
|
);
|
|
seenKeys.add(key);
|
|
}
|
|
|
|
return seenKeys;
|
|
}
|
|
|
|
export async function appendCatalogSupplementRows(params: {
|
|
rows: ModelRow[];
|
|
modelRegistry: ModelRegistry;
|
|
context: RowBuilderContext;
|
|
seenKeys: Set<string>;
|
|
}): Promise<void> {
|
|
const catalog = await loadModelCatalog({ config: params.context.cfg });
|
|
for (const entry of catalog) {
|
|
if (
|
|
params.context.filter.provider &&
|
|
entry.provider.toLowerCase() !== params.context.filter.provider
|
|
) {
|
|
continue;
|
|
}
|
|
const key = modelKey(entry.provider, entry.id);
|
|
if (params.seenKeys.has(key)) {
|
|
continue;
|
|
}
|
|
const model = resolveModelWithRegistry({
|
|
provider: entry.provider,
|
|
modelId: entry.id,
|
|
modelRegistry: params.modelRegistry,
|
|
cfg: params.context.cfg,
|
|
});
|
|
if (!model || !matchesRowFilter(params.context.filter, model)) {
|
|
continue;
|
|
}
|
|
params.rows.push(
|
|
buildRow({
|
|
model,
|
|
key,
|
|
context: params.context,
|
|
allowProviderAvailabilityFallback: !params.context.discoveredKeys.has(key),
|
|
}),
|
|
);
|
|
params.seenKeys.add(key);
|
|
}
|
|
}
|
|
|
|
export function appendConfiguredRows(params: {
|
|
rows: ModelRow[];
|
|
entries: ConfiguredEntry[];
|
|
modelRegistry: ModelRegistry;
|
|
context: RowBuilderContext;
|
|
}) {
|
|
for (const entry of params.entries) {
|
|
if (
|
|
params.context.filter.provider &&
|
|
entry.ref.provider.toLowerCase() !== params.context.filter.provider
|
|
) {
|
|
continue;
|
|
}
|
|
const model = resolveModelWithRegistry({
|
|
provider: entry.ref.provider,
|
|
modelId: entry.ref.model,
|
|
modelRegistry: params.modelRegistry,
|
|
cfg: params.context.cfg,
|
|
});
|
|
if (params.context.filter.local && model && !isLocalBaseUrl(model.baseUrl ?? "")) {
|
|
continue;
|
|
}
|
|
if (params.context.filter.local && !model) {
|
|
continue;
|
|
}
|
|
params.rows.push(
|
|
toModelRow({
|
|
model,
|
|
key: entry.key,
|
|
tags: Array.from(entry.tags),
|
|
aliases: entry.aliases,
|
|
availableKeys: params.context.availableKeys,
|
|
cfg: params.context.cfg,
|
|
authStore: params.context.authStore,
|
|
allowProviderAvailabilityFallback: model
|
|
? !params.context.discoveredKeys.has(modelKey(model.provider, model.id))
|
|
: false,
|
|
}),
|
|
);
|
|
}
|
|
}
|