mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
refactor: extract model catalog core package
* refactor: extract model catalog core package * refactor: route model catalog imports through package boundary * build: include model catalog in plugin sdk package dts * fix: preserve static fallback model metadata
This commit is contained in:
committed by
GitHub
parent
ec15f90a55
commit
30e1556cda
@@ -601,7 +601,7 @@ jobs:
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: .artifacts/build-all-cache
|
||||
key: ${{ runner.os }}-build-all-v3-${{ hashFiles('package.json', 'pnpm-lock.yaml', 'npm-shrinkwrap.json', 'packages/plugin-sdk/package.json', 'packages/llm-core/package.json', 'packages/memory-host-sdk/package.json', 'scripts/build-all.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entries.mjs', 'tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'src/plugin-sdk/**', 'packages/llm-core/src/**', 'packages/memory-host-sdk/src/**', 'src/types/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'scripts/copy-export-html-templates.ts', 'scripts/lib/copy-assets.ts', 'src/auto-reply/reply/export-html/**') }}
|
||||
key: ${{ runner.os }}-build-all-v3-${{ hashFiles('package.json', 'pnpm-lock.yaml', 'npm-shrinkwrap.json', 'packages/plugin-sdk/package.json', 'packages/llm-core/package.json', 'packages/model-catalog-core/package.json', 'packages/memory-host-sdk/package.json', 'scripts/build-all.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entries.mjs', 'tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'src/plugin-sdk/**', 'packages/llm-core/src/**', 'packages/model-catalog-core/src/**', 'packages/memory-host-sdk/src/**', 'src/types/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'scripts/copy-export-html-templates.ts', 'scripts/lib/copy-assets.ts', 'src/auto-reply/reply/export-html/**') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-all-v3-
|
||||
|
||||
@@ -1403,7 +1403,7 @@ jobs:
|
||||
packages/plugin-sdk/dist
|
||||
extensions/*/dist/.boundary-tsc.tsbuildinfo
|
||||
extensions/*/dist/.boundary-tsc.stamp
|
||||
key: ${{ runner.os }}-extension-package-boundary-v1-${{ hashFiles('tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'packages/plugin-sdk/tsconfig.json', 'packages/llm-core/package.json', 'scripts/check-extension-package-tsc-boundary.mjs', 'scripts/prepare-extension-package-boundary-artifacts.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entrypoints.json', 'scripts/lib/plugin-sdk-entries.mjs', 'src/plugin-sdk/**', 'src/auto-reply/**', 'packages/llm-core/src/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'src/types/**', 'extensions/**', 'extensions/tsconfig.package-boundary*.json', 'package.json', 'pnpm-lock.yaml') }}
|
||||
key: ${{ runner.os }}-extension-package-boundary-v1-${{ hashFiles('tsconfig.json', 'tsconfig.plugin-sdk.dts.json', 'packages/plugin-sdk/tsconfig.json', 'packages/llm-core/package.json', 'packages/model-catalog-core/package.json', 'scripts/check-extension-package-tsc-boundary.mjs', 'scripts/prepare-extension-package-boundary-artifacts.mjs', 'scripts/write-plugin-sdk-entry-dts.ts', 'scripts/lib/plugin-sdk-entrypoints.json', 'scripts/lib/plugin-sdk-entries.mjs', 'src/plugin-sdk/**', 'src/auto-reply/**', 'packages/llm-core/src/**', 'packages/model-catalog-core/src/**', 'src/video-generation/dashscope-compatible.ts', 'src/video-generation/types.ts', 'src/types/**', 'extensions/**', 'extensions/tsconfig.package-boundary*.json', 'package.json', 'pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-extension-package-boundary-v1-
|
||||
|
||||
@@ -1425,11 +1425,17 @@ jobs:
|
||||
-type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.mts' -o -name '*.cts' -o -name '*.js' -o -name '*.mjs' -o -name '*.json' \) \
|
||||
-exec touch -t 200001010000 {} +
|
||||
fi
|
||||
if [ -d packages/model-catalog-core/src ]; then
|
||||
find packages/model-catalog-core/src \
|
||||
-type f \( -name '*.ts' -o -name '*.tsx' -o -name '*.mts' -o -name '*.cts' -o -name '*.js' -o -name '*.mjs' -o -name '*.json' \) \
|
||||
-exec touch -t 200001010000 {} +
|
||||
fi
|
||||
cache_inputs=(
|
||||
tsconfig.json \
|
||||
tsconfig.plugin-sdk.dts.json \
|
||||
packages/plugin-sdk/tsconfig.json \
|
||||
packages/llm-core/package.json \
|
||||
packages/model-catalog-core/package.json \
|
||||
scripts/check-extension-package-tsc-boundary.mjs \
|
||||
scripts/prepare-extension-package-boundary-artifacts.mjs \
|
||||
scripts/write-plugin-sdk-entry-dts.ts \
|
||||
|
||||
@@ -342,7 +342,7 @@ export function renderMattermostModelsPickerView(params: {
|
||||
|
||||
const page = paginateItems(models, params.page);
|
||||
const rows: MattermostInteractiveButtonInput[][] = page.items.map((model) => {
|
||||
const isCurrent = current?.provider === provider && current.model === model;
|
||||
const isCurrent = current?.provider === provider && current?.model === model;
|
||||
return [
|
||||
buildButton({
|
||||
action: "select",
|
||||
|
||||
@@ -102,6 +102,24 @@
|
||||
"../dist/plugin-sdk/packages/llm-core/src/validation.d.ts"
|
||||
],
|
||||
"@openclaw/llm-core/*": ["../dist/plugin-sdk/packages/llm-core/src/*.d.ts"],
|
||||
"@openclaw/model-catalog-core": [
|
||||
"../dist/plugin-sdk/packages/model-catalog-core/src/index.d.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/configured-model-refs": [
|
||||
"../dist/plugin-sdk/packages/model-catalog-core/src/configured-model-refs.d.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-id": [
|
||||
"../dist/plugin-sdk/packages/model-catalog-core/src/provider-id.d.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-model-id-normalization": [
|
||||
"../dist/plugin-sdk/packages/model-catalog-core/src/provider-model-id-normalization.d.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-model-id-normalize": [
|
||||
"../dist/plugin-sdk/packages/model-catalog-core/src/provider-model-id-normalize.d.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/*": [
|
||||
"../dist/plugin-sdk/packages/model-catalog-core/src/*.d.ts"
|
||||
],
|
||||
"@openclaw/markdown-core": [
|
||||
"../dist/plugin-sdk/packages/markdown-core/src/index.d.ts"
|
||||
],
|
||||
|
||||
@@ -111,6 +111,24 @@
|
||||
"@openclaw/llm-core/*": [
|
||||
"../../dist/plugin-sdk/packages/llm-core/src/*.d.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core": [
|
||||
"../../dist/plugin-sdk/packages/model-catalog-core/src/index.d.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/configured-model-refs": [
|
||||
"../../dist/plugin-sdk/packages/model-catalog-core/src/configured-model-refs.d.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-id": [
|
||||
"../../dist/plugin-sdk/packages/model-catalog-core/src/provider-id.d.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-model-id-normalization": [
|
||||
"../../dist/plugin-sdk/packages/model-catalog-core/src/provider-model-id-normalization.d.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-model-id-normalize": [
|
||||
"../../dist/plugin-sdk/packages/model-catalog-core/src/provider-model-id-normalize.d.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/*": [
|
||||
"../../dist/plugin-sdk/packages/model-catalog-core/src/*.d.ts"
|
||||
],
|
||||
"@openclaw/markdown-core": [
|
||||
"../../dist/plugin-sdk/packages/markdown-core/src/index.d.ts"
|
||||
],
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "@openclaw/model-catalog-core",
|
||||
"version": "0.0.0-private",
|
||||
"private": true,
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"type": "module",
|
||||
"main": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.mts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.mts",
|
||||
"import": "./dist/index.mjs",
|
||||
"default": "./dist/index.mjs"
|
||||
},
|
||||
"./configured-model-refs": {
|
||||
"types": "./dist/configured-model-refs.d.mts",
|
||||
"import": "./dist/configured-model-refs.mjs",
|
||||
"default": "./dist/configured-model-refs.mjs"
|
||||
},
|
||||
"./provider-id": {
|
||||
"types": "./dist/provider-id.d.mts",
|
||||
"import": "./dist/provider-id.mjs",
|
||||
"default": "./dist/provider-id.mjs"
|
||||
},
|
||||
"./provider-model-id-normalization": {
|
||||
"types": "./dist/provider-model-id-normalization.d.mts",
|
||||
"import": "./dist/provider-model-id-normalization.mjs",
|
||||
"default": "./dist/provider-model-id-normalization.mjs"
|
||||
},
|
||||
"./provider-model-id-normalize": {
|
||||
"types": "./dist/provider-model-id-normalize.d.mts",
|
||||
"import": "./dist/provider-model-id-normalize.mjs",
|
||||
"default": "./dist/provider-model-id-normalize.mjs"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
collectConfiguredModelRefs,
|
||||
collectConfiguredModelRefValues,
|
||||
extractProviderFromModelRef,
|
||||
} from "./configured-model-refs.js";
|
||||
|
||||
describe("configured model refs", () => {
|
||||
it("collects agent, hook, message, and channel model refs with config paths", () => {
|
||||
expect(
|
||||
collectConfiguredModelRefs({
|
||||
agents: {
|
||||
defaults: {
|
||||
model: { primary: "openai/gpt-5.5", fallbacks: ["anthropic/claude-sonnet-4-6"] },
|
||||
compaction: { memoryFlush: { model: "openai/gpt-5.5-mini" } },
|
||||
},
|
||||
list: [{ id: "custom", model: "xai/grok-4-fast" }],
|
||||
},
|
||||
hooks: {
|
||||
mappings: [{ model: "openai/gpt-5.5-nano" }],
|
||||
},
|
||||
messages: {
|
||||
tts: { summaryModel: "openai/gpt-5.5-mini" },
|
||||
},
|
||||
channels: {
|
||||
modelByChannel: {
|
||||
discord: {
|
||||
guild: "anthropic/claude-opus-4-8",
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
).toEqual([
|
||||
{ path: "agents.defaults.model.primary", value: "openai/gpt-5.5" },
|
||||
{ path: "agents.defaults.model.fallbacks.0", value: "anthropic/claude-sonnet-4-6" },
|
||||
{ path: "agents.defaults.compaction.memoryFlush.model", value: "openai/gpt-5.5-mini" },
|
||||
{ path: "agents.list.0.model", value: "xai/grok-4-fast" },
|
||||
{ path: "channels.modelByChannel.discord.guild", value: "anthropic/claude-opus-4-8" },
|
||||
{ path: "hooks.mappings.0.model", value: "openai/gpt-5.5-nano" },
|
||||
{ path: "messages.tts.summaryModel", value: "openai/gpt-5.5-mini" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("can exclude channel model overrides from configured refs", () => {
|
||||
expect(
|
||||
collectConfiguredModelRefValues(
|
||||
{
|
||||
agents: { defaults: { model: "openai/gpt-5.5" } },
|
||||
channels: { modelByChannel: { discord: { guild: "anthropic/claude-sonnet-4-6" } } },
|
||||
},
|
||||
{ includeChannelModelOverrides: false },
|
||||
),
|
||||
).toEqual(["openai/gpt-5.5"]);
|
||||
});
|
||||
|
||||
it("ignores array-shaped malformed records", () => {
|
||||
expect(
|
||||
collectConfiguredModelRefs({
|
||||
agents: {
|
||||
defaults: {
|
||||
models: ["openai/gpt-5.5"],
|
||||
},
|
||||
},
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("extracts normalized providers from provider-prefixed refs", () => {
|
||||
expect(extractProviderFromModelRef(" OpenAI/gpt-5.5 ")).toBe("openai");
|
||||
expect(extractProviderFromModelRef("gpt-5.5")).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,134 @@
|
||||
import { normalizeProviderId } from "./provider-id.js";
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
export type ConfiguredModelRef = {
|
||||
path: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export const AGENT_MODEL_CONFIG_KEYS = [
|
||||
"model",
|
||||
"imageModel",
|
||||
"imageGenerationModel",
|
||||
"videoGenerationModel",
|
||||
"musicGenerationModel",
|
||||
"voiceModel",
|
||||
"pdfModel",
|
||||
] as const;
|
||||
|
||||
export function collectConfiguredModelRefs(
|
||||
config: unknown,
|
||||
options: { includeChannelModelOverrides?: boolean } = {},
|
||||
): ConfiguredModelRef[] {
|
||||
const refs: ConfiguredModelRef[] = [];
|
||||
const pushModelRef = (path: string, value: unknown) => {
|
||||
if (typeof value === "string" && value.trim()) {
|
||||
refs.push({ path, value: value.trim() });
|
||||
}
|
||||
};
|
||||
const collectModelConfig = (path: string, value: unknown) => {
|
||||
if (typeof value === "string") {
|
||||
pushModelRef(path, value);
|
||||
return;
|
||||
}
|
||||
if (!isRecord(value)) {
|
||||
return;
|
||||
}
|
||||
pushModelRef(`${path}.primary`, value.primary);
|
||||
if (Array.isArray(value.fallbacks)) {
|
||||
for (const [index, entry] of value.fallbacks.entries()) {
|
||||
pushModelRef(`${path}.fallbacks.${index}`, entry);
|
||||
}
|
||||
}
|
||||
};
|
||||
const collectFromAgent = (path: string, agent: unknown) => {
|
||||
if (!isRecord(agent)) {
|
||||
return;
|
||||
}
|
||||
for (const key of AGENT_MODEL_CONFIG_KEYS) {
|
||||
collectModelConfig(`${path}.${key}`, agent[key]);
|
||||
}
|
||||
pushModelRef(
|
||||
`${path}.heartbeat.model`,
|
||||
isRecord(agent.heartbeat) ? agent.heartbeat.model : undefined,
|
||||
);
|
||||
collectModelConfig(
|
||||
`${path}.subagents.model`,
|
||||
isRecord(agent.subagents) ? agent.subagents.model : undefined,
|
||||
);
|
||||
if (isRecord(agent.compaction)) {
|
||||
pushModelRef(`${path}.compaction.model`, agent.compaction.model);
|
||||
pushModelRef(
|
||||
`${path}.compaction.memoryFlush.model`,
|
||||
isRecord(agent.compaction.memoryFlush) ? agent.compaction.memoryFlush.model : undefined,
|
||||
);
|
||||
}
|
||||
if (isRecord(agent.models)) {
|
||||
for (const modelRef of Object.keys(agent.models)) {
|
||||
pushModelRef(`${path}.models.${modelRef}`, modelRef);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const root = isRecord(config) ? config : {};
|
||||
const agents = isRecord(root.agents) ? root.agents : {};
|
||||
collectFromAgent("agents.defaults", agents.defaults);
|
||||
if (Array.isArray(agents.list)) {
|
||||
for (const [index, entry] of agents.list.entries()) {
|
||||
collectFromAgent(`agents.list.${index}`, entry);
|
||||
}
|
||||
}
|
||||
if (options.includeChannelModelOverrides !== false) {
|
||||
const channels = isRecord(root.channels) ? root.channels : {};
|
||||
const modelByChannel = isRecord(channels.modelByChannel) ? channels.modelByChannel : {};
|
||||
for (const [channelId, channelMap] of Object.entries(modelByChannel)) {
|
||||
if (!isRecord(channelMap)) {
|
||||
continue;
|
||||
}
|
||||
for (const [targetId, modelRef] of Object.entries(channelMap)) {
|
||||
pushModelRef(`channels.modelByChannel.${channelId}.${targetId}`, modelRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
const hooks = isRecord(root.hooks) ? root.hooks : {};
|
||||
if (Array.isArray(hooks.mappings)) {
|
||||
for (const [index, mapping] of hooks.mappings.entries()) {
|
||||
pushModelRef(`hooks.mappings.${index}.model`, isRecord(mapping) ? mapping.model : undefined);
|
||||
}
|
||||
}
|
||||
pushModelRef("hooks.gmail.model", isRecord(hooks.gmail) ? hooks.gmail.model : undefined);
|
||||
pushModelRef(
|
||||
"messages.tts.summaryModel",
|
||||
isRecord(root.messages) && isRecord(root.messages.tts)
|
||||
? root.messages.tts.summaryModel
|
||||
: undefined,
|
||||
);
|
||||
pushModelRef(
|
||||
"channels.discord.voice.model",
|
||||
isRecord(root.channels) &&
|
||||
isRecord(root.channels.discord) &&
|
||||
isRecord(root.channels.discord.voice)
|
||||
? root.channels.discord.voice.model
|
||||
: undefined,
|
||||
);
|
||||
return refs;
|
||||
}
|
||||
|
||||
export function collectConfiguredModelRefValues(
|
||||
config: unknown,
|
||||
options?: { includeChannelModelOverrides?: boolean },
|
||||
): string[] {
|
||||
return collectConfiguredModelRefs(config, options).map((ref) => ref.value);
|
||||
}
|
||||
|
||||
export function extractProviderFromModelRef(value: string): string | null {
|
||||
const trimmed = value.trim();
|
||||
const slash = trimmed.indexOf("/");
|
||||
if (slash <= 0) {
|
||||
return null;
|
||||
}
|
||||
return normalizeProviderId(trimmed.slice(0, slash));
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./configured-model-refs.js";
|
||||
export * from "./provider-id.js";
|
||||
export * from "./provider-model-id-normalization.js";
|
||||
export * from "./provider-model-id-normalize.js";
|
||||
@@ -0,0 +1,39 @@
|
||||
export function normalizeLowercaseStringOrEmpty(value: unknown): string {
|
||||
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
||||
}
|
||||
|
||||
export function normalizeProviderId(provider: string): string {
|
||||
return normalizeLowercaseStringOrEmpty(provider);
|
||||
}
|
||||
|
||||
/** Normalize provider ID before manifest-owned auth alias lookup. */
|
||||
export function normalizeProviderIdForAuth(provider: string): string {
|
||||
return normalizeProviderId(provider);
|
||||
}
|
||||
|
||||
export function findNormalizedProviderValue<T>(
|
||||
entries: Record<string, T> | undefined,
|
||||
provider: string,
|
||||
): T | undefined {
|
||||
if (!entries) {
|
||||
return undefined;
|
||||
}
|
||||
const providerKey = normalizeProviderId(provider);
|
||||
for (const [key, value] of Object.entries(entries)) {
|
||||
if (normalizeProviderId(key) === providerKey) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function findNormalizedProviderKey(
|
||||
entries: Record<string, unknown> | undefined,
|
||||
provider: string,
|
||||
): string | undefined {
|
||||
if (!entries) {
|
||||
return undefined;
|
||||
}
|
||||
const providerKey = normalizeProviderId(provider);
|
||||
return Object.keys(entries).find((key) => normalizeProviderId(key) === providerKey);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
collectManifestModelIdNormalizationPolicies,
|
||||
normalizeConfiguredProviderCatalogModelId,
|
||||
normalizeStaticProviderModelIdWithPolicies,
|
||||
} from "./provider-model-id-normalization.js";
|
||||
|
||||
describe("provider model id policy normalization", () => {
|
||||
it("applies manifest policies before built-in provider normalization", () => {
|
||||
const policies = collectManifestModelIdNormalizationPolicies([
|
||||
{
|
||||
modelIdNormalization: {
|
||||
providers: {
|
||||
"Google-Vertex": {
|
||||
aliases: {
|
||||
pro: "gemini-3-pro",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
expect(normalizeStaticProviderModelIdWithPolicies("google-vertex", "pro", policies)).toBe(
|
||||
"gemini-3.1-pro-preview",
|
||||
);
|
||||
});
|
||||
|
||||
it("normalizes provider-prefixed Google catalog refs behind gateway prefixes", () => {
|
||||
expect(
|
||||
normalizeConfiguredProviderCatalogModelId(
|
||||
"openrouter",
|
||||
"openrouter/google/gemini-3-pro-preview",
|
||||
),
|
||||
).toBe("openrouter/google/gemini-3.1-pro-preview");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,206 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "./provider-id.js";
|
||||
import {
|
||||
normalizeGooglePreviewModelId,
|
||||
normalizeTogetherModelId,
|
||||
} from "./provider-model-id-normalize.js";
|
||||
|
||||
export type ManifestModelIdNormalizationProvider = {
|
||||
aliases?: Record<string, string>;
|
||||
stripPrefixes?: string[];
|
||||
prefixWhenBare?: string;
|
||||
prefixWhenBareAfterAliasStartsWith?: {
|
||||
modelPrefix: string;
|
||||
prefix: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type ManifestModelIdNormalizationRecord = {
|
||||
modelIdNormalization?: {
|
||||
providers?: Record<string, ManifestModelIdNormalizationProvider>;
|
||||
};
|
||||
};
|
||||
|
||||
let currentManifestModelIdNormalizationPolicies:
|
||||
| ReadonlyMap<string, ManifestModelIdNormalizationProvider>
|
||||
| undefined;
|
||||
|
||||
export function collectManifestModelIdNormalizationPolicies(
|
||||
plugins: readonly ManifestModelIdNormalizationRecord[],
|
||||
): Map<string, ManifestModelIdNormalizationProvider> {
|
||||
const policies = new Map<string, ManifestModelIdNormalizationProvider>();
|
||||
for (const plugin of plugins) {
|
||||
for (const [provider, policy] of Object.entries(plugin.modelIdNormalization?.providers ?? {})) {
|
||||
policies.set(normalizeLowercaseStringOrEmpty(provider), policy);
|
||||
}
|
||||
}
|
||||
return policies;
|
||||
}
|
||||
|
||||
export function setCurrentManifestModelIdNormalizationRecords(
|
||||
plugins: readonly ManifestModelIdNormalizationRecord[] | undefined,
|
||||
): void {
|
||||
currentManifestModelIdNormalizationPolicies = plugins
|
||||
? collectManifestModelIdNormalizationPolicies(plugins)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
export function getCurrentManifestModelIdNormalizationPolicies():
|
||||
| ReadonlyMap<string, ManifestModelIdNormalizationProvider>
|
||||
| undefined {
|
||||
return currentManifestModelIdNormalizationPolicies;
|
||||
}
|
||||
|
||||
function hasProviderPrefix(modelId: string): boolean {
|
||||
return modelId.includes("/");
|
||||
}
|
||||
|
||||
function formatPrefixedModelId(prefix: string, modelId: string): string {
|
||||
return `${prefix.replace(/\/+$/u, "")}/${modelId.replace(/^\/+/u, "")}`;
|
||||
}
|
||||
|
||||
export function normalizeProviderModelIdWithPolicies(params: {
|
||||
provider: string;
|
||||
policies: ReadonlyMap<string, ManifestModelIdNormalizationProvider>;
|
||||
context: {
|
||||
modelId: string;
|
||||
};
|
||||
}): string | undefined {
|
||||
const policy = params.policies.get(normalizeLowercaseStringOrEmpty(params.provider));
|
||||
if (!policy) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let modelId = params.context.modelId.trim();
|
||||
if (!modelId) {
|
||||
return modelId;
|
||||
}
|
||||
|
||||
for (const prefix of policy.stripPrefixes ?? []) {
|
||||
const normalizedPrefix = normalizeLowercaseStringOrEmpty(prefix);
|
||||
if (normalizedPrefix && normalizeLowercaseStringOrEmpty(modelId).startsWith(normalizedPrefix)) {
|
||||
modelId = modelId.slice(prefix.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
modelId = policy.aliases?.[normalizeLowercaseStringOrEmpty(modelId)] ?? modelId;
|
||||
|
||||
if (!hasProviderPrefix(modelId)) {
|
||||
for (const rule of policy.prefixWhenBareAfterAliasStartsWith ?? []) {
|
||||
if (normalizeLowercaseStringOrEmpty(modelId).startsWith(rule.modelPrefix.toLowerCase())) {
|
||||
return formatPrefixedModelId(rule.prefix, modelId);
|
||||
}
|
||||
}
|
||||
if (policy.prefixWhenBare) {
|
||||
return formatPrefixedModelId(policy.prefixWhenBare, modelId);
|
||||
}
|
||||
}
|
||||
|
||||
return modelId;
|
||||
}
|
||||
|
||||
export function normalizeBuiltInProviderModelId(provider: string, model: string): string {
|
||||
const normalizedProvider = normalizeLowercaseStringOrEmpty(provider);
|
||||
if (
|
||||
normalizedProvider === "google" ||
|
||||
normalizedProvider === "google-gemini-cli" ||
|
||||
normalizedProvider === "google-vertex"
|
||||
) {
|
||||
return normalizeGooglePreviewModelId(model);
|
||||
}
|
||||
if (normalizedProvider === "openrouter") {
|
||||
const trimmed = model.trim();
|
||||
return trimmed && !trimmed.includes("/") ? `openrouter/${trimmed}` : model;
|
||||
}
|
||||
if (normalizedProvider === "anthropic") {
|
||||
const anthropicAliases: Record<string, string> = {
|
||||
"opus-4.8": "claude-opus-4-8",
|
||||
opus: "claude-opus-4-8",
|
||||
"opus-4.6": "claude-opus-4-6",
|
||||
"sonnet-4.6": "claude-sonnet-4-6",
|
||||
};
|
||||
return anthropicAliases[normalizeLowercaseStringOrEmpty(model)] ?? model;
|
||||
}
|
||||
if (normalizedProvider === "vercel-ai-gateway") {
|
||||
const vercelAliases: Record<string, string> = {
|
||||
"opus-4.6": "claude-opus-4-6",
|
||||
"sonnet-4.6": "claude-sonnet-4-6",
|
||||
};
|
||||
const aliased = vercelAliases[normalizeLowercaseStringOrEmpty(model)] ?? model;
|
||||
return normalizeLowercaseStringOrEmpty(aliased).startsWith("claude-")
|
||||
? `anthropic/${aliased}`
|
||||
: aliased;
|
||||
}
|
||||
if (normalizedProvider === "huggingface") {
|
||||
const prefix = "huggingface/";
|
||||
return normalizeLowercaseStringOrEmpty(model).startsWith(prefix)
|
||||
? model.slice(prefix.length)
|
||||
: model;
|
||||
}
|
||||
if (normalizedProvider === "nvidia") {
|
||||
const trimmed = model.trim();
|
||||
return trimmed && !trimmed.includes("/") ? `nvidia/${trimmed}` : model;
|
||||
}
|
||||
if (normalizedProvider === "xai") {
|
||||
const xaiAliases: Record<string, string> = {
|
||||
"grok-4-fast-reasoning": "grok-4-fast",
|
||||
"grok-4-1-fast-reasoning": "grok-4-1-fast",
|
||||
"grok-4.20-experimental-beta-0304-reasoning": "grok-4.20-beta-latest-reasoning",
|
||||
"grok-4.20-experimental-beta-0304-non-reasoning": "grok-4.20-beta-latest-non-reasoning",
|
||||
"grok-4.20-reasoning": "grok-4.20-beta-latest-reasoning",
|
||||
"grok-4.20-non-reasoning": "grok-4.20-beta-latest-non-reasoning",
|
||||
};
|
||||
return xaiAliases[normalizeLowercaseStringOrEmpty(model)] ?? model;
|
||||
}
|
||||
if (normalizedProvider === "together") {
|
||||
return normalizeTogetherModelId(model);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
export function normalizeStaticProviderModelIdWithPolicies(
|
||||
provider: string,
|
||||
model: string,
|
||||
policies?: ReadonlyMap<string, ManifestModelIdNormalizationProvider>,
|
||||
): string {
|
||||
const normalizedProvider = normalizeLowercaseStringOrEmpty(provider);
|
||||
const manifestModelId = policies
|
||||
? (normalizeProviderModelIdWithPolicies({
|
||||
provider: normalizedProvider,
|
||||
policies,
|
||||
context: {
|
||||
modelId: model,
|
||||
},
|
||||
}) ?? model)
|
||||
: model;
|
||||
return normalizeBuiltInProviderModelId(normalizedProvider, manifestModelId);
|
||||
}
|
||||
|
||||
export function normalizeConfiguredProviderCatalogModelId(
|
||||
provider: string,
|
||||
model: string,
|
||||
policies = getCurrentManifestModelIdNormalizationPolicies(),
|
||||
): string {
|
||||
const providerModel = normalizeStaticProviderModelIdWithPolicies(provider, model, policies);
|
||||
return normalizeConfiguredProviderCatalogModelRef(providerModel);
|
||||
}
|
||||
|
||||
export function normalizeConfiguredProviderCatalogModelRef(providerModel: string): string {
|
||||
const googlePrefix = "google/";
|
||||
if (!providerModel.startsWith(googlePrefix)) {
|
||||
const slash = providerModel.indexOf("/");
|
||||
if (slash <= 0 || slash >= providerModel.length - 1) {
|
||||
return providerModel;
|
||||
}
|
||||
const prefix = providerModel.slice(0, slash + 1);
|
||||
const suffix = providerModel.slice(slash + 1);
|
||||
if (!suffix.startsWith(googlePrefix)) {
|
||||
return providerModel;
|
||||
}
|
||||
const normalizedSuffix = normalizeGooglePreviewModelId(suffix);
|
||||
return normalizedSuffix === suffix ? providerModel : `${prefix}${normalizedSuffix}`;
|
||||
}
|
||||
const modelId = providerModel.slice(googlePrefix.length);
|
||||
const normalizedModelId = normalizeGooglePreviewModelId(modelId);
|
||||
return normalizedModelId === modelId ? providerModel : `${googlePrefix}${normalizedModelId}`;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
const ANTIGRAVITY_BARE_PRO_IDS = new Set(["gemini-3-pro", "gemini-3.1-pro", "gemini-3-1-pro"]);
|
||||
const GOOGLE_PROVIDER_PREFIX = "google/";
|
||||
|
||||
export function normalizeGooglePreviewModelId(id: string): string {
|
||||
if (id.startsWith(GOOGLE_PROVIDER_PREFIX)) {
|
||||
const modelId = id.slice(GOOGLE_PROVIDER_PREFIX.length);
|
||||
const normalizedModelId = normalizeGooglePreviewModelId(modelId);
|
||||
return normalizedModelId === modelId ? id : `${GOOGLE_PROVIDER_PREFIX}${normalizedModelId}`;
|
||||
}
|
||||
if (id === "gemini-3-pro" || id === "gemini-3-pro-preview") {
|
||||
return "gemini-3.1-pro-preview";
|
||||
}
|
||||
if (id === "gemini-3-flash") {
|
||||
return "gemini-3-flash-preview";
|
||||
}
|
||||
if (id === "gemini-3.1-pro") {
|
||||
return "gemini-3.1-pro-preview";
|
||||
}
|
||||
// Gemini 3.1 Flash Lite graduated to GA on 2026-05-07; the -preview
|
||||
// endpoint is deprecated (shutdown 2026-05-25). Map old preview name
|
||||
// to the stable GA id.
|
||||
if (id === "gemini-3.1-flash-lite-preview") {
|
||||
return "gemini-3.1-flash-lite";
|
||||
}
|
||||
if (id === "gemini-3.1-flash" || id === "gemini-3.1-flash-preview") {
|
||||
return "gemini-3-flash-preview";
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
export function normalizeTogetherModelId(id: string): string {
|
||||
if (id === "moonshotai/Kimi-K2.5") {
|
||||
return "moonshotai/Kimi-K2.6";
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
export function normalizeAntigravityPreviewModelId(id: string): string {
|
||||
if (ANTIGRAVITY_BARE_PRO_IDS.has(id)) {
|
||||
return `${id}-low`;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
"include": [
|
||||
"../../packages/markdown-core/src/**/*.ts",
|
||||
"../../packages/media-generation-core/src/**/*.ts",
|
||||
"../../packages/model-catalog-core/src/**/*.ts",
|
||||
"../../packages/terminal-core/src/**/*.ts",
|
||||
"../../src/plugin-sdk/**/*.ts",
|
||||
"../../src/video-generation/dashscope-compatible.ts",
|
||||
|
||||
Generated
+2
@@ -1830,6 +1830,8 @@ importers:
|
||||
|
||||
packages/memory-host-sdk: {}
|
||||
|
||||
packages/model-catalog-core: {}
|
||||
|
||||
packages/net-policy:
|
||||
dependencies:
|
||||
ipaddr.js:
|
||||
|
||||
@@ -50,12 +50,14 @@ export const BUILD_ALL_STEPS = [
|
||||
"packages/markdown-core/package.json",
|
||||
"packages/media-understanding-common/package.json",
|
||||
"packages/terminal-core/package.json",
|
||||
"packages/model-catalog-core/package.json",
|
||||
"packages/memory-host-sdk/package.json",
|
||||
"tsconfig.json",
|
||||
"tsconfig.plugin-sdk.dts.json",
|
||||
"src/plugin-sdk",
|
||||
"packages/llm-core/src",
|
||||
"packages/markdown-core/src",
|
||||
"packages/model-catalog-core/src",
|
||||
"packages/memory-host-sdk/src",
|
||||
"packages/media-generation-core/src",
|
||||
"packages/media-understanding-common/src",
|
||||
|
||||
@@ -59,6 +59,20 @@ export const EXTENSION_PACKAGE_BOUNDARY_BASE_PATHS = {
|
||||
"@openclaw/llm-core/types": ["../dist/plugin-sdk/packages/llm-core/src/types.d.ts"],
|
||||
"@openclaw/llm-core/validation": ["../dist/plugin-sdk/packages/llm-core/src/validation.d.ts"],
|
||||
"@openclaw/llm-core/*": ["../dist/plugin-sdk/packages/llm-core/src/*.d.ts"],
|
||||
"@openclaw/model-catalog-core": ["../dist/plugin-sdk/packages/model-catalog-core/src/index.d.ts"],
|
||||
"@openclaw/model-catalog-core/configured-model-refs": [
|
||||
"../dist/plugin-sdk/packages/model-catalog-core/src/configured-model-refs.d.ts",
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-id": [
|
||||
"../dist/plugin-sdk/packages/model-catalog-core/src/provider-id.d.ts",
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-model-id-normalization": [
|
||||
"../dist/plugin-sdk/packages/model-catalog-core/src/provider-model-id-normalization.d.ts",
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-model-id-normalize": [
|
||||
"../dist/plugin-sdk/packages/model-catalog-core/src/provider-model-id-normalize.d.ts",
|
||||
],
|
||||
"@openclaw/model-catalog-core/*": ["../dist/plugin-sdk/packages/model-catalog-core/src/*.d.ts"],
|
||||
"@openclaw/markdown-core": ["../dist/plugin-sdk/packages/markdown-core/src/index.d.ts"],
|
||||
"@openclaw/markdown-core/code-spans": [
|
||||
"../dist/plugin-sdk/packages/markdown-core/src/code-spans.d.ts",
|
||||
|
||||
@@ -17,6 +17,7 @@ const PLUGIN_SDK_TYPE_INPUTS = [
|
||||
"src/auto-reply",
|
||||
"packages/llm-core/src",
|
||||
"packages/markdown-core/src",
|
||||
"packages/model-catalog-core/src",
|
||||
"packages/memory-host-sdk/src",
|
||||
"packages/media-generation-core/src",
|
||||
"packages/media-understanding-common/src",
|
||||
@@ -68,6 +69,10 @@ const ROOT_DTS_REQUIRED_OUTPUTS = [
|
||||
"dist/plugin-sdk/packages/terminal-core/src/table.d.ts",
|
||||
"dist/plugin-sdk/packages/terminal-core/src/terminal-link.d.ts",
|
||||
"dist/plugin-sdk/packages/terminal-core/src/theme.d.ts",
|
||||
"dist/plugin-sdk/packages/model-catalog-core/src/configured-model-refs.d.ts",
|
||||
"dist/plugin-sdk/packages/model-catalog-core/src/provider-id.d.ts",
|
||||
"dist/plugin-sdk/packages/model-catalog-core/src/provider-model-id-normalization.d.ts",
|
||||
"dist/plugin-sdk/packages/model-catalog-core/src/provider-model-id-normalize.d.ts",
|
||||
"dist/plugin-sdk/error-runtime.d.ts",
|
||||
"dist/plugin-sdk/plugin-entry.d.ts",
|
||||
"dist/plugin-sdk/provider-auth.d.ts",
|
||||
@@ -90,6 +95,10 @@ const PACKAGE_DTS_REQUIRED_OUTPUTS = [
|
||||
"packages/plugin-sdk/dist/packages/media-generation-core/src/index.d.ts",
|
||||
"packages/plugin-sdk/dist/packages/media-generation-core/src/model-ref.d.ts",
|
||||
"packages/plugin-sdk/dist/packages/media-generation-core/src/normalization.d.ts",
|
||||
"packages/plugin-sdk/dist/packages/model-catalog-core/src/configured-model-refs.d.ts",
|
||||
"packages/plugin-sdk/dist/packages/model-catalog-core/src/provider-id.d.ts",
|
||||
"packages/plugin-sdk/dist/packages/model-catalog-core/src/provider-model-id-normalization.d.ts",
|
||||
"packages/plugin-sdk/dist/packages/model-catalog-core/src/provider-model-id-normalize.d.ts",
|
||||
"packages/plugin-sdk/dist/packages/terminal-core/src/ansi.d.ts",
|
||||
"packages/plugin-sdk/dist/packages/terminal-core/src/decorative-emoji.d.ts",
|
||||
"packages/plugin-sdk/dist/packages/terminal-core/src/health-style.d.ts",
|
||||
|
||||
@@ -74,6 +74,12 @@ type ProviderRuntimeHooks = {
|
||||
normalizeProviderTransportWithPlugin: typeof normalizeProviderTransportWithPlugin;
|
||||
};
|
||||
|
||||
type StaticCatalogFallbackModel = Model & {
|
||||
compat?: ModelCompatConfig;
|
||||
contextTokens?: number;
|
||||
mediaInput?: ModelMediaInputConfig;
|
||||
};
|
||||
|
||||
const TARGET_PROVIDER_RUNTIME_HOOKS: ProviderRuntimeHooks = {
|
||||
buildProviderUnknownModelHintWithPlugin,
|
||||
prepareProviderDynamicModel,
|
||||
@@ -989,14 +995,16 @@ function resolveConfiguredFallbackModel(params: {
|
||||
}
|
||||
const staticCatalogModel = configuredModel
|
||||
? undefined
|
||||
: resolveBundledStaticCatalogModel({
|
||||
: (resolveBundledStaticCatalogModel({
|
||||
provider,
|
||||
modelId,
|
||||
cfg,
|
||||
workspaceDir,
|
||||
includeRuntimeDiscovery: true,
|
||||
});
|
||||
}) as StaticCatalogFallbackModel | undefined);
|
||||
const metadataModel = configuredModel ?? staticCatalogModel;
|
||||
const fallbackCompat = configuredModel?.compat ?? staticCatalogModel?.compat;
|
||||
const fallbackMediaInput = configuredModel?.mediaInput ?? staticCatalogModel?.mediaInput;
|
||||
const providerHeaders = sanitizeModelHeaders(providerConfig?.headers, {
|
||||
stripSecretRefMarkers: true,
|
||||
});
|
||||
@@ -1009,7 +1017,7 @@ function resolveConfiguredFallbackModel(params: {
|
||||
provider,
|
||||
modelId,
|
||||
providerParams: providerConfig?.params,
|
||||
configuredParams: metadataModel?.params,
|
||||
configuredParams: configuredModel?.params,
|
||||
});
|
||||
const fallbackTransport = resolveProviderTransport({
|
||||
provider,
|
||||
@@ -1036,7 +1044,7 @@ function resolveConfiguredFallbackModel(params: {
|
||||
});
|
||||
const fallbackReasoning = resolveConfiguredFallbackReasoning({
|
||||
provider,
|
||||
compat: metadataModel?.compat,
|
||||
compat: fallbackCompat,
|
||||
reasoning: metadataModel?.reasoning,
|
||||
});
|
||||
return normalizeResolvedModel({
|
||||
@@ -1080,8 +1088,8 @@ function resolveConfiguredFallbackModel(params: {
|
||||
...(resolvedParams ? { params: resolvedParams } : {}),
|
||||
...(requestTimeoutMs !== undefined ? { requestTimeoutMs } : {}),
|
||||
headers: requestConfig.headers,
|
||||
compat: metadataModel?.compat,
|
||||
mediaInput: metadataModel?.mediaInput,
|
||||
compat: fallbackCompat,
|
||||
mediaInput: fallbackMediaInput,
|
||||
} as Model,
|
||||
providerRequest,
|
||||
),
|
||||
|
||||
@@ -1,37 +1,6 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
|
||||
export function normalizeProviderId(provider: string): string {
|
||||
return normalizeLowercaseStringOrEmpty(provider);
|
||||
}
|
||||
|
||||
/** Normalize provider ID before manifest-owned auth alias lookup. */
|
||||
export function normalizeProviderIdForAuth(provider: string): string {
|
||||
return normalizeProviderId(provider);
|
||||
}
|
||||
|
||||
export function findNormalizedProviderValue<T>(
|
||||
entries: Record<string, T> | undefined,
|
||||
provider: string,
|
||||
): T | undefined {
|
||||
if (!entries) {
|
||||
return undefined;
|
||||
}
|
||||
const providerKey = normalizeProviderId(provider);
|
||||
for (const [key, value] of Object.entries(entries)) {
|
||||
if (normalizeProviderId(key) === providerKey) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function findNormalizedProviderKey(
|
||||
entries: Record<string, unknown> | undefined,
|
||||
provider: string,
|
||||
): string | undefined {
|
||||
if (!entries) {
|
||||
return undefined;
|
||||
}
|
||||
const providerKey = normalizeProviderId(provider);
|
||||
return Object.keys(entries).find((key) => normalizeProviderId(key) === providerKey);
|
||||
}
|
||||
export {
|
||||
findNormalizedProviderKey,
|
||||
findNormalizedProviderValue,
|
||||
normalizeProviderId,
|
||||
normalizeProviderIdForAuth,
|
||||
} from "../../packages/model-catalog-core/src/provider-id.js";
|
||||
|
||||
@@ -43,7 +43,7 @@ function resolveConfiguredTextModelFromConfig(params: {
|
||||
const providerCfg = findNormalizedProviderValue(providers, params.providerId);
|
||||
const modelId = providerCfg?.models
|
||||
?.find(
|
||||
(model) =>
|
||||
(model: { id?: string; input?: readonly string[] }) =>
|
||||
Boolean(model?.id?.trim()) && Array.isArray(model?.input) && model.input.includes("text"),
|
||||
)
|
||||
?.id?.trim();
|
||||
|
||||
+7
-131
@@ -1,131 +1,7 @@
|
||||
import { normalizeProviderId } from "../agents/provider-id.js";
|
||||
import { isRecord } from "../utils.js";
|
||||
|
||||
export type ConfiguredModelRef = {
|
||||
path: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export const AGENT_MODEL_CONFIG_KEYS = [
|
||||
"model",
|
||||
"imageModel",
|
||||
"imageGenerationModel",
|
||||
"videoGenerationModel",
|
||||
"musicGenerationModel",
|
||||
"voiceModel",
|
||||
"pdfModel",
|
||||
] as const;
|
||||
|
||||
export function collectConfiguredModelRefs(
|
||||
config: unknown,
|
||||
options: { includeChannelModelOverrides?: boolean } = {},
|
||||
): ConfiguredModelRef[] {
|
||||
const refs: ConfiguredModelRef[] = [];
|
||||
const pushModelRef = (path: string, value: unknown) => {
|
||||
if (typeof value === "string" && value.trim()) {
|
||||
refs.push({ path, value: value.trim() });
|
||||
}
|
||||
};
|
||||
const collectModelConfig = (path: string, value: unknown) => {
|
||||
if (typeof value === "string") {
|
||||
pushModelRef(path, value);
|
||||
return;
|
||||
}
|
||||
if (!isRecord(value)) {
|
||||
return;
|
||||
}
|
||||
pushModelRef(`${path}.primary`, value.primary);
|
||||
if (Array.isArray(value.fallbacks)) {
|
||||
for (const [index, entry] of value.fallbacks.entries()) {
|
||||
pushModelRef(`${path}.fallbacks.${index}`, entry);
|
||||
}
|
||||
}
|
||||
};
|
||||
const collectFromAgent = (path: string, agent: unknown) => {
|
||||
if (!isRecord(agent)) {
|
||||
return;
|
||||
}
|
||||
for (const key of AGENT_MODEL_CONFIG_KEYS) {
|
||||
collectModelConfig(`${path}.${key}`, agent[key]);
|
||||
}
|
||||
pushModelRef(
|
||||
`${path}.heartbeat.model`,
|
||||
isRecord(agent.heartbeat) ? agent.heartbeat.model : undefined,
|
||||
);
|
||||
collectModelConfig(
|
||||
`${path}.subagents.model`,
|
||||
isRecord(agent.subagents) ? agent.subagents.model : undefined,
|
||||
);
|
||||
if (isRecord(agent.compaction)) {
|
||||
pushModelRef(`${path}.compaction.model`, agent.compaction.model);
|
||||
pushModelRef(
|
||||
`${path}.compaction.memoryFlush.model`,
|
||||
isRecord(agent.compaction.memoryFlush) ? agent.compaction.memoryFlush.model : undefined,
|
||||
);
|
||||
}
|
||||
if (isRecord(agent.models)) {
|
||||
for (const modelRef of Object.keys(agent.models)) {
|
||||
pushModelRef(`${path}.models.${modelRef}`, modelRef);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const root = isRecord(config) ? config : {};
|
||||
const agents = isRecord(root.agents) ? root.agents : {};
|
||||
collectFromAgent("agents.defaults", agents.defaults);
|
||||
if (Array.isArray(agents.list)) {
|
||||
for (const [index, entry] of agents.list.entries()) {
|
||||
collectFromAgent(`agents.list.${index}`, entry);
|
||||
}
|
||||
}
|
||||
if (options.includeChannelModelOverrides !== false) {
|
||||
const channels = isRecord(root.channels) ? root.channels : {};
|
||||
const modelByChannel = isRecord(channels.modelByChannel) ? channels.modelByChannel : {};
|
||||
for (const [channelId, channelMap] of Object.entries(modelByChannel)) {
|
||||
if (!isRecord(channelMap)) {
|
||||
continue;
|
||||
}
|
||||
for (const [targetId, modelRef] of Object.entries(channelMap)) {
|
||||
pushModelRef(`channels.modelByChannel.${channelId}.${targetId}`, modelRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
const hooks = isRecord(root.hooks) ? root.hooks : {};
|
||||
if (Array.isArray(hooks.mappings)) {
|
||||
for (const [index, mapping] of hooks.mappings.entries()) {
|
||||
pushModelRef(`hooks.mappings.${index}.model`, isRecord(mapping) ? mapping.model : undefined);
|
||||
}
|
||||
}
|
||||
pushModelRef("hooks.gmail.model", isRecord(hooks.gmail) ? hooks.gmail.model : undefined);
|
||||
pushModelRef(
|
||||
"messages.tts.summaryModel",
|
||||
isRecord(root.messages) && isRecord(root.messages.tts)
|
||||
? root.messages.tts.summaryModel
|
||||
: undefined,
|
||||
);
|
||||
pushModelRef(
|
||||
"channels.discord.voice.model",
|
||||
isRecord(root.channels) &&
|
||||
isRecord(root.channels.discord) &&
|
||||
isRecord(root.channels.discord.voice)
|
||||
? root.channels.discord.voice.model
|
||||
: undefined,
|
||||
);
|
||||
return refs;
|
||||
}
|
||||
|
||||
export function collectConfiguredModelRefValues(
|
||||
config: unknown,
|
||||
options?: { includeChannelModelOverrides?: boolean },
|
||||
): string[] {
|
||||
return collectConfiguredModelRefs(config, options).map((ref) => ref.value);
|
||||
}
|
||||
|
||||
export function extractProviderFromModelRef(value: string): string | null {
|
||||
const trimmed = value.trim();
|
||||
const slash = trimmed.indexOf("/");
|
||||
if (slash <= 0) {
|
||||
return null;
|
||||
}
|
||||
return normalizeProviderId(trimmed.slice(0, slash));
|
||||
}
|
||||
export {
|
||||
AGENT_MODEL_CONFIG_KEYS,
|
||||
collectConfiguredModelRefs,
|
||||
collectConfiguredModelRefValues,
|
||||
extractProviderFromModelRef,
|
||||
type ConfiguredModelRef,
|
||||
} from "../../packages/model-catalog-core/src/configured-model-refs.js";
|
||||
|
||||
@@ -1,43 +1,5 @@
|
||||
const ANTIGRAVITY_BARE_PRO_IDS = new Set(["gemini-3-pro", "gemini-3.1-pro", "gemini-3-1-pro"]);
|
||||
const GOOGLE_PROVIDER_PREFIX = "google/";
|
||||
|
||||
export function normalizeGooglePreviewModelId(id: string): string {
|
||||
if (id.startsWith(GOOGLE_PROVIDER_PREFIX)) {
|
||||
const modelId = id.slice(GOOGLE_PROVIDER_PREFIX.length);
|
||||
const normalizedModelId = normalizeGooglePreviewModelId(modelId);
|
||||
return normalizedModelId === modelId ? id : `${GOOGLE_PROVIDER_PREFIX}${normalizedModelId}`;
|
||||
}
|
||||
if (id === "gemini-3-pro" || id === "gemini-3-pro-preview") {
|
||||
return "gemini-3.1-pro-preview";
|
||||
}
|
||||
if (id === "gemini-3-flash") {
|
||||
return "gemini-3-flash-preview";
|
||||
}
|
||||
if (id === "gemini-3.1-pro") {
|
||||
return "gemini-3.1-pro-preview";
|
||||
}
|
||||
// Gemini 3.1 Flash Lite graduated to GA on 2026-05-07; the -preview
|
||||
// endpoint is deprecated (shutdown 2026-05-25). Map old preview name
|
||||
// to the stable GA id.
|
||||
if (id === "gemini-3.1-flash-lite-preview") {
|
||||
return "gemini-3.1-flash-lite";
|
||||
}
|
||||
if (id === "gemini-3.1-flash" || id === "gemini-3.1-flash-preview") {
|
||||
return "gemini-3-flash-preview";
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
export function normalizeTogetherModelId(id: string): string {
|
||||
if (id === "moonshotai/Kimi-K2.5") {
|
||||
return "moonshotai/Kimi-K2.6";
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
export function normalizeAntigravityPreviewModelId(id: string): string {
|
||||
if (ANTIGRAVITY_BARE_PRO_IDS.has(id)) {
|
||||
return `${id}-low`;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
export {
|
||||
normalizeAntigravityPreviewModelId,
|
||||
normalizeGooglePreviewModelId,
|
||||
normalizeTogetherModelId,
|
||||
} from "../../packages/model-catalog-core/src/provider-model-id-normalize.js";
|
||||
|
||||
@@ -196,6 +196,7 @@ describe("opt-in extension package boundaries", () => {
|
||||
expect(tsconfig.include).toEqual([
|
||||
"../../packages/markdown-core/src/**/*.ts",
|
||||
"../../packages/media-generation-core/src/**/*.ts",
|
||||
"../../packages/model-catalog-core/src/**/*.ts",
|
||||
"../../packages/terminal-core/src/**/*.ts",
|
||||
"../../src/plugin-sdk/**/*.ts",
|
||||
"../../src/video-generation/dashscope-compatible.ts",
|
||||
|
||||
@@ -1420,6 +1420,12 @@ describe("plugin sdk alias helpers", () => {
|
||||
srcFile: "ip.ts",
|
||||
distFile: "ip.mjs",
|
||||
});
|
||||
const modelCatalogProviderId = writeWorkspacePackageEntry({
|
||||
root: fixture.root,
|
||||
packageDir: "model-catalog-core",
|
||||
srcFile: "provider-id.ts",
|
||||
distFile: "provider-id.mjs",
|
||||
});
|
||||
fs.rmSync(gatewayClient.distFile);
|
||||
fs.rmSync(gatewayClientTimeouts.distFile);
|
||||
fs.rmSync(gatewayProtocol.distFile);
|
||||
@@ -1432,6 +1438,7 @@ describe("plugin sdk alias helpers", () => {
|
||||
fs.rmSync(terminalCoreTheme.distFile);
|
||||
fs.rmSync(netPolicy.distFile);
|
||||
fs.rmSync(netPolicyIp.distFile);
|
||||
fs.rmSync(modelCatalogProviderId.distFile);
|
||||
const sourcePluginEntry = writePluginEntry(
|
||||
fixture.root,
|
||||
bundledPluginFile("demo", "src/index.ts"),
|
||||
@@ -1477,6 +1484,9 @@ describe("plugin sdk alias helpers", () => {
|
||||
expect(fs.realpathSync(aliases["@openclaw/net-policy/ip"] ?? "")).toBe(
|
||||
fs.realpathSync(netPolicyIp.srcFile),
|
||||
);
|
||||
expect(fs.realpathSync(aliases["@openclaw/model-catalog-core/provider-id"] ?? "")).toBe(
|
||||
fs.realpathSync(modelCatalogProviderId.srcFile),
|
||||
);
|
||||
});
|
||||
|
||||
it("aliases workspace package subpaths to dist when available", () => {
|
||||
@@ -1520,6 +1530,12 @@ describe("plugin sdk alias helpers", () => {
|
||||
srcFile: "redact-sensitive-url.ts",
|
||||
distFile: "redact-sensitive-url.mjs",
|
||||
});
|
||||
const modelCatalogCore = writeWorkspacePackageEntry({
|
||||
root: fixture.root,
|
||||
packageDir: "model-catalog-core",
|
||||
srcFile: "provider-model-id-normalize.ts",
|
||||
distFile: "provider-model-id-normalize.mjs",
|
||||
});
|
||||
const sourcePluginEntry = writePluginEntry(
|
||||
fixture.root,
|
||||
bundledPluginFile("demo", "src/index.ts"),
|
||||
@@ -1547,6 +1563,9 @@ describe("plugin sdk alias helpers", () => {
|
||||
expect(fs.realpathSync(aliases["@openclaw/net-policy/redact-sensitive-url"] ?? "")).toBe(
|
||||
fs.realpathSync(netPolicy.distFile),
|
||||
);
|
||||
expect(
|
||||
fs.realpathSync(aliases["@openclaw/model-catalog-core/provider-model-id-normalize"] ?? ""),
|
||||
).toBe(fs.realpathSync(modelCatalogCore.distFile));
|
||||
});
|
||||
|
||||
it("aliases bundled plugin package public surfaces for source plugin transforms", () => {
|
||||
|
||||
@@ -819,6 +819,41 @@ const WORKSPACE_PACKAGE_ALIAS_ENTRIES = [
|
||||
srcFile: "url-userinfo.ts",
|
||||
distFile: "url-userinfo.mjs",
|
||||
},
|
||||
{
|
||||
packageName: "@openclaw/model-catalog-core",
|
||||
packageDir: "model-catalog-core",
|
||||
subpath: "",
|
||||
srcFile: "index.ts",
|
||||
distFile: "index.mjs",
|
||||
},
|
||||
{
|
||||
packageName: "@openclaw/model-catalog-core",
|
||||
packageDir: "model-catalog-core",
|
||||
subpath: "configured-model-refs",
|
||||
srcFile: "configured-model-refs.ts",
|
||||
distFile: "configured-model-refs.mjs",
|
||||
},
|
||||
{
|
||||
packageName: "@openclaw/model-catalog-core",
|
||||
packageDir: "model-catalog-core",
|
||||
subpath: "provider-id",
|
||||
srcFile: "provider-id.ts",
|
||||
distFile: "provider-id.mjs",
|
||||
},
|
||||
{
|
||||
packageName: "@openclaw/model-catalog-core",
|
||||
packageDir: "model-catalog-core",
|
||||
subpath: "provider-model-id-normalization",
|
||||
srcFile: "provider-model-id-normalization.ts",
|
||||
distFile: "provider-model-id-normalization.mjs",
|
||||
},
|
||||
{
|
||||
packageName: "@openclaw/model-catalog-core",
|
||||
packageDir: "model-catalog-core",
|
||||
subpath: "provider-model-id-normalize",
|
||||
srcFile: "provider-model-id-normalize.ts",
|
||||
distFile: "provider-model-id-normalize.mjs",
|
||||
},
|
||||
] as const;
|
||||
|
||||
function isUsableDistPluginSdkArtifact(candidate: string): boolean {
|
||||
|
||||
@@ -1,206 +1,12 @@
|
||||
import {
|
||||
normalizeGooglePreviewModelId,
|
||||
normalizeTogetherModelId,
|
||||
} from "../plugin-sdk/provider-model-id-normalize.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "./string-coerce.js";
|
||||
|
||||
export type ManifestModelIdNormalizationProvider = {
|
||||
aliases?: Record<string, string>;
|
||||
stripPrefixes?: string[];
|
||||
prefixWhenBare?: string;
|
||||
prefixWhenBareAfterAliasStartsWith?: {
|
||||
modelPrefix: string;
|
||||
prefix: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
export type ManifestModelIdNormalizationRecord = {
|
||||
modelIdNormalization?: {
|
||||
providers?: Record<string, ManifestModelIdNormalizationProvider>;
|
||||
};
|
||||
};
|
||||
|
||||
let currentManifestModelIdNormalizationPolicies:
|
||||
| ReadonlyMap<string, ManifestModelIdNormalizationProvider>
|
||||
| undefined;
|
||||
|
||||
export function collectManifestModelIdNormalizationPolicies(
|
||||
plugins: readonly ManifestModelIdNormalizationRecord[],
|
||||
): Map<string, ManifestModelIdNormalizationProvider> {
|
||||
const policies = new Map<string, ManifestModelIdNormalizationProvider>();
|
||||
for (const plugin of plugins) {
|
||||
for (const [provider, policy] of Object.entries(plugin.modelIdNormalization?.providers ?? {})) {
|
||||
policies.set(normalizeLowercaseStringOrEmpty(provider), policy);
|
||||
}
|
||||
}
|
||||
return policies;
|
||||
}
|
||||
|
||||
export function setCurrentManifestModelIdNormalizationRecords(
|
||||
plugins: readonly ManifestModelIdNormalizationRecord[] | undefined,
|
||||
): void {
|
||||
currentManifestModelIdNormalizationPolicies = plugins
|
||||
? collectManifestModelIdNormalizationPolicies(plugins)
|
||||
: undefined;
|
||||
}
|
||||
|
||||
export function getCurrentManifestModelIdNormalizationPolicies():
|
||||
| ReadonlyMap<string, ManifestModelIdNormalizationProvider>
|
||||
| undefined {
|
||||
return currentManifestModelIdNormalizationPolicies;
|
||||
}
|
||||
|
||||
function hasProviderPrefix(modelId: string): boolean {
|
||||
return modelId.includes("/");
|
||||
}
|
||||
|
||||
function formatPrefixedModelId(prefix: string, modelId: string): string {
|
||||
return `${prefix.replace(/\/+$/u, "")}/${modelId.replace(/^\/+/u, "")}`;
|
||||
}
|
||||
|
||||
export function normalizeProviderModelIdWithPolicies(params: {
|
||||
provider: string;
|
||||
policies: ReadonlyMap<string, ManifestModelIdNormalizationProvider>;
|
||||
context: {
|
||||
modelId: string;
|
||||
};
|
||||
}): string | undefined {
|
||||
const policy = params.policies.get(normalizeLowercaseStringOrEmpty(params.provider));
|
||||
if (!policy) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let modelId = params.context.modelId.trim();
|
||||
if (!modelId) {
|
||||
return modelId;
|
||||
}
|
||||
|
||||
for (const prefix of policy.stripPrefixes ?? []) {
|
||||
const normalizedPrefix = normalizeLowercaseStringOrEmpty(prefix);
|
||||
if (normalizedPrefix && normalizeLowercaseStringOrEmpty(modelId).startsWith(normalizedPrefix)) {
|
||||
modelId = modelId.slice(prefix.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
modelId = policy.aliases?.[normalizeLowercaseStringOrEmpty(modelId)] ?? modelId;
|
||||
|
||||
if (!hasProviderPrefix(modelId)) {
|
||||
for (const rule of policy.prefixWhenBareAfterAliasStartsWith ?? []) {
|
||||
if (normalizeLowercaseStringOrEmpty(modelId).startsWith(rule.modelPrefix.toLowerCase())) {
|
||||
return formatPrefixedModelId(rule.prefix, modelId);
|
||||
}
|
||||
}
|
||||
if (policy.prefixWhenBare) {
|
||||
return formatPrefixedModelId(policy.prefixWhenBare, modelId);
|
||||
}
|
||||
}
|
||||
|
||||
return modelId;
|
||||
}
|
||||
|
||||
export function normalizeBuiltInProviderModelId(provider: string, model: string): string {
|
||||
const normalizedProvider = normalizeLowercaseStringOrEmpty(provider);
|
||||
if (
|
||||
normalizedProvider === "google" ||
|
||||
normalizedProvider === "google-gemini-cli" ||
|
||||
normalizedProvider === "google-vertex"
|
||||
) {
|
||||
return normalizeGooglePreviewModelId(model);
|
||||
}
|
||||
if (normalizedProvider === "openrouter") {
|
||||
const trimmed = model.trim();
|
||||
return trimmed && !trimmed.includes("/") ? `openrouter/${trimmed}` : model;
|
||||
}
|
||||
if (normalizedProvider === "anthropic") {
|
||||
const anthropicAliases: Record<string, string> = {
|
||||
"opus-4.8": "claude-opus-4-8",
|
||||
opus: "claude-opus-4-8",
|
||||
"opus-4.6": "claude-opus-4-6",
|
||||
"sonnet-4.6": "claude-sonnet-4-6",
|
||||
};
|
||||
return anthropicAliases[normalizeLowercaseStringOrEmpty(model)] ?? model;
|
||||
}
|
||||
if (normalizedProvider === "vercel-ai-gateway") {
|
||||
const vercelAliases: Record<string, string> = {
|
||||
"opus-4.6": "claude-opus-4-6",
|
||||
"sonnet-4.6": "claude-sonnet-4-6",
|
||||
};
|
||||
const aliased = vercelAliases[normalizeLowercaseStringOrEmpty(model)] ?? model;
|
||||
return normalizeLowercaseStringOrEmpty(aliased).startsWith("claude-")
|
||||
? `anthropic/${aliased}`
|
||||
: aliased;
|
||||
}
|
||||
if (normalizedProvider === "huggingface") {
|
||||
const prefix = "huggingface/";
|
||||
return normalizeLowercaseStringOrEmpty(model).startsWith(prefix)
|
||||
? model.slice(prefix.length)
|
||||
: model;
|
||||
}
|
||||
if (normalizedProvider === "nvidia") {
|
||||
const trimmed = model.trim();
|
||||
return trimmed && !trimmed.includes("/") ? `nvidia/${trimmed}` : model;
|
||||
}
|
||||
if (normalizedProvider === "xai") {
|
||||
const xaiAliases: Record<string, string> = {
|
||||
"grok-4-fast-reasoning": "grok-4-fast",
|
||||
"grok-4-1-fast-reasoning": "grok-4-1-fast",
|
||||
"grok-4.20-experimental-beta-0304-reasoning": "grok-4.20-beta-latest-reasoning",
|
||||
"grok-4.20-experimental-beta-0304-non-reasoning": "grok-4.20-beta-latest-non-reasoning",
|
||||
"grok-4.20-reasoning": "grok-4.20-beta-latest-reasoning",
|
||||
"grok-4.20-non-reasoning": "grok-4.20-beta-latest-non-reasoning",
|
||||
};
|
||||
return xaiAliases[normalizeLowercaseStringOrEmpty(model)] ?? model;
|
||||
}
|
||||
if (normalizedProvider === "together") {
|
||||
return normalizeTogetherModelId(model);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
export function normalizeStaticProviderModelIdWithPolicies(
|
||||
provider: string,
|
||||
model: string,
|
||||
policies?: ReadonlyMap<string, ManifestModelIdNormalizationProvider>,
|
||||
): string {
|
||||
const normalizedProvider = normalizeLowercaseStringOrEmpty(provider);
|
||||
const manifestModelId = policies
|
||||
? (normalizeProviderModelIdWithPolicies({
|
||||
provider: normalizedProvider,
|
||||
policies,
|
||||
context: {
|
||||
modelId: model,
|
||||
},
|
||||
}) ?? model)
|
||||
: model;
|
||||
return normalizeBuiltInProviderModelId(normalizedProvider, manifestModelId);
|
||||
}
|
||||
|
||||
export function normalizeConfiguredProviderCatalogModelId(
|
||||
provider: string,
|
||||
model: string,
|
||||
policies = getCurrentManifestModelIdNormalizationPolicies(),
|
||||
): string {
|
||||
const providerModel = normalizeStaticProviderModelIdWithPolicies(provider, model, policies);
|
||||
return normalizeConfiguredProviderCatalogModelRef(providerModel);
|
||||
}
|
||||
|
||||
export function normalizeConfiguredProviderCatalogModelRef(providerModel: string): string {
|
||||
const googlePrefix = "google/";
|
||||
if (!providerModel.startsWith(googlePrefix)) {
|
||||
const slash = providerModel.indexOf("/");
|
||||
if (slash <= 0 || slash >= providerModel.length - 1) {
|
||||
return providerModel;
|
||||
}
|
||||
const prefix = providerModel.slice(0, slash + 1);
|
||||
const suffix = providerModel.slice(slash + 1);
|
||||
if (!suffix.startsWith(googlePrefix)) {
|
||||
return providerModel;
|
||||
}
|
||||
const normalizedSuffix = normalizeGooglePreviewModelId(suffix);
|
||||
return normalizedSuffix === suffix ? providerModel : `${prefix}${normalizedSuffix}`;
|
||||
}
|
||||
const modelId = providerModel.slice(googlePrefix.length);
|
||||
const normalizedModelId = normalizeGooglePreviewModelId(modelId);
|
||||
return normalizedModelId === modelId ? providerModel : `${googlePrefix}${normalizedModelId}`;
|
||||
}
|
||||
export {
|
||||
collectManifestModelIdNormalizationPolicies,
|
||||
getCurrentManifestModelIdNormalizationPolicies,
|
||||
normalizeBuiltInProviderModelId,
|
||||
normalizeConfiguredProviderCatalogModelId,
|
||||
normalizeConfiguredProviderCatalogModelRef,
|
||||
normalizeProviderModelIdWithPolicies,
|
||||
normalizeStaticProviderModelIdWithPolicies,
|
||||
setCurrentManifestModelIdNormalizationRecords,
|
||||
type ManifestModelIdNormalizationProvider,
|
||||
type ManifestModelIdNormalizationRecord,
|
||||
} from "../../packages/model-catalog-core/src/provider-model-id-normalization.js";
|
||||
|
||||
@@ -237,6 +237,44 @@ export const sharedVitestConfig = {
|
||||
find: "@openclaw/llm-core",
|
||||
replacement: path.join(repoRoot, "packages", "llm-core", "src", "index.ts"),
|
||||
},
|
||||
{
|
||||
find: "@openclaw/model-catalog-core/configured-model-refs",
|
||||
replacement: path.join(
|
||||
repoRoot,
|
||||
"packages",
|
||||
"model-catalog-core",
|
||||
"src",
|
||||
"configured-model-refs.ts",
|
||||
),
|
||||
},
|
||||
{
|
||||
find: "@openclaw/model-catalog-core/provider-id",
|
||||
replacement: path.join(repoRoot, "packages", "model-catalog-core", "src", "provider-id.ts"),
|
||||
},
|
||||
{
|
||||
find: "@openclaw/model-catalog-core/provider-model-id-normalization",
|
||||
replacement: path.join(
|
||||
repoRoot,
|
||||
"packages",
|
||||
"model-catalog-core",
|
||||
"src",
|
||||
"provider-model-id-normalization.ts",
|
||||
),
|
||||
},
|
||||
{
|
||||
find: "@openclaw/model-catalog-core/provider-model-id-normalize",
|
||||
replacement: path.join(
|
||||
repoRoot,
|
||||
"packages",
|
||||
"model-catalog-core",
|
||||
"src",
|
||||
"provider-model-id-normalize.ts",
|
||||
),
|
||||
},
|
||||
{
|
||||
find: "@openclaw/model-catalog-core",
|
||||
replacement: path.join(repoRoot, "packages", "model-catalog-core", "src", "index.ts"),
|
||||
},
|
||||
{
|
||||
find: "@openclaw/net-policy/ip",
|
||||
replacement: path.join(repoRoot, "packages", "net-policy", "src", "ip.ts"),
|
||||
|
||||
@@ -36,6 +36,20 @@
|
||||
"@openclaw/llm-core/*": ["./packages/llm-core/src/*"],
|
||||
"@openclaw/llm-runtime": ["./packages/llm-runtime/src/index.ts"],
|
||||
"@openclaw/llm-runtime/*": ["./packages/llm-runtime/src/*"],
|
||||
"@openclaw/model-catalog-core": ["./packages/model-catalog-core/src/index.ts"],
|
||||
"@openclaw/model-catalog-core/configured-model-refs": [
|
||||
"./packages/model-catalog-core/src/configured-model-refs.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-id": [
|
||||
"./packages/model-catalog-core/src/provider-id.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-model-id-normalization": [
|
||||
"./packages/model-catalog-core/src/provider-model-id-normalization.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/provider-model-id-normalize": [
|
||||
"./packages/model-catalog-core/src/provider-model-id-normalize.ts"
|
||||
],
|
||||
"@openclaw/model-catalog-core/*": ["./packages/model-catalog-core/src/*"],
|
||||
"@openclaw/gateway-client": ["./packages/gateway-client/src/index.ts"],
|
||||
"@openclaw/gateway-client/*": ["./packages/gateway-client/src/*"],
|
||||
"@openclaw/gateway-protocol": ["./packages/gateway-protocol/src/index.ts"],
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"packages/llm-core/src/**/*.ts",
|
||||
"packages/markdown-core/src/**/*.ts",
|
||||
"packages/media-generation-core/src/**/*.ts",
|
||||
"packages/model-catalog-core/src/**/*.ts",
|
||||
"packages/memory-host-sdk/src/**/*.ts",
|
||||
"packages/terminal-core/src/**/*.ts",
|
||||
"src/video-generation/dashscope-compatible.ts",
|
||||
|
||||
@@ -466,6 +466,17 @@ function buildLlmCoreDistEntries(): Record<string, string> {
|
||||
};
|
||||
}
|
||||
|
||||
function buildModelCatalogCoreDistEntries(): Record<string, string> {
|
||||
return {
|
||||
index: "packages/model-catalog-core/src/index.ts",
|
||||
"configured-model-refs": "packages/model-catalog-core/src/configured-model-refs.ts",
|
||||
"provider-id": "packages/model-catalog-core/src/provider-id.ts",
|
||||
"provider-model-id-normalization":
|
||||
"packages/model-catalog-core/src/provider-model-id-normalization.ts",
|
||||
"provider-model-id-normalize": "packages/model-catalog-core/src/provider-model-id-normalize.ts",
|
||||
};
|
||||
}
|
||||
|
||||
function buildLlmRuntimeDistEntries(): Record<string, string> {
|
||||
return {
|
||||
index: "packages/llm-runtime/src/index.ts",
|
||||
@@ -650,6 +661,12 @@ export default defineConfig([
|
||||
neverBundle: shouldExternalizeLlmCoreDependency,
|
||||
},
|
||||
}),
|
||||
nodeWorkspacePackageBuildConfig({
|
||||
clean: true,
|
||||
dts: RUN_NODE_SKIP_DTS_BUILD ? false : undefined,
|
||||
entry: buildModelCatalogCoreDistEntries(),
|
||||
outDir: "packages/model-catalog-core/dist",
|
||||
}),
|
||||
nodeWorkspacePackageBuildConfig({
|
||||
clean: true,
|
||||
dts: RUN_NODE_SKIP_DTS_BUILD ? false : undefined,
|
||||
|
||||
Reference in New Issue
Block a user