diff --git a/extensions/codex-supervisor/src/plugin-tools.ts b/extensions/codex-supervisor/src/plugin-tools.ts index 903572352bcf..059bb76a3d71 100644 --- a/extensions/codex-supervisor/src/plugin-tools.ts +++ b/extensions/codex-supervisor/src/plugin-tools.ts @@ -1,5 +1,4 @@ import { jsonResult, readStringParam, type AnyAgentTool } from "openclaw/plugin-sdk/core"; -import { asSafeIntegerInRange } from "openclaw/plugin-sdk/number-runtime"; import { Type } from "typebox"; import { redactCodexSupervisorEndpoint, @@ -74,14 +73,13 @@ function readIntegerParam(params: Record, key: string): number if (value === undefined) { return undefined; } - const integer = asSafeIntegerInRange(value, { min: 1, max: 1000 }); - if (integer === undefined) { - if (typeof value === "number" && Number.isInteger(value)) { - throw new Error(`${key} must be between 1 and 1000`); - } + if (typeof value !== "number" || !Number.isInteger(value)) { throw new Error(`${key} must be an integer`); } - return integer; + if (value < 1 || value > 1000) { + throw new Error(`${key} must be between 1 and 1000`); + } + return value; } function readModeParam(params: Record): CodexSupervisorTurnMode | undefined { diff --git a/extensions/tsconfig.package-boundary.paths.json b/extensions/tsconfig.package-boundary.paths.json index edc5ec7dbbc8..f4f195676bb1 100644 --- a/extensions/tsconfig.package-boundary.paths.json +++ b/extensions/tsconfig.package-boundary.paths.json @@ -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/media-generation-core": [ + "../dist/plugin-sdk/packages/media-generation-core/src/index.d.ts" + ], + "@openclaw/media-generation-core/capability-model-ref": [ + "../dist/plugin-sdk/packages/media-generation-core/src/capability-model-ref.d.ts" + ], + "@openclaw/media-generation-core/catalog": [ + "../dist/plugin-sdk/packages/media-generation-core/src/catalog.d.ts" + ], + "@openclaw/media-generation-core/model-ref": [ + "../dist/plugin-sdk/packages/media-generation-core/src/model-ref.d.ts" + ], + "@openclaw/media-generation-core/normalization": [ + "../dist/plugin-sdk/packages/media-generation-core/src/normalization.d.ts" + ], + "@openclaw/media-generation-core/*": [ + "../dist/plugin-sdk/packages/media-generation-core/src/*.d.ts" + ], "@openclaw/*.js": ["../packages/plugin-sdk/dist/extensions/*.d.ts", "../extensions/*"], "@openclaw/*": ["../packages/plugin-sdk/dist/extensions/*", "../extensions/*"], "openclaw/plugin-sdk/qa-channel": ["../dist/plugin-sdk/src/plugin-sdk/qa-channel.d.ts"], diff --git a/extensions/xai/tsconfig.json b/extensions/xai/tsconfig.json index 9a551441649e..b59b12cbf102 100644 --- a/extensions/xai/tsconfig.json +++ b/extensions/xai/tsconfig.json @@ -111,6 +111,24 @@ "@openclaw/llm-core/*": [ "../../dist/plugin-sdk/packages/llm-core/src/*.d.ts" ], + "@openclaw/media-generation-core": [ + "../../dist/plugin-sdk/packages/media-generation-core/src/index.d.ts" + ], + "@openclaw/media-generation-core/capability-model-ref": [ + "../../dist/plugin-sdk/packages/media-generation-core/src/capability-model-ref.d.ts" + ], + "@openclaw/media-generation-core/catalog": [ + "../../dist/plugin-sdk/packages/media-generation-core/src/catalog.d.ts" + ], + "@openclaw/media-generation-core/model-ref": [ + "../../dist/plugin-sdk/packages/media-generation-core/src/model-ref.d.ts" + ], + "@openclaw/media-generation-core/normalization": [ + "../../dist/plugin-sdk/packages/media-generation-core/src/normalization.d.ts" + ], + "@openclaw/media-generation-core/*": [ + "../../dist/plugin-sdk/packages/media-generation-core/src/*.d.ts" + ], "@openclaw/*.js": ["../../packages/plugin-sdk/dist/extensions/*.d.ts", "../*"], "@openclaw/*": ["../*"], "openclaw/plugin-sdk/qa-channel": [ diff --git a/packages/media-generation-core/package.json b/packages/media-generation-core/package.json new file mode 100644 index 000000000000..92e640aa5270 --- /dev/null +++ b/packages/media-generation-core/package.json @@ -0,0 +1,41 @@ +{ + "name": "@openclaw/media-generation-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" + }, + "./capability-model-ref": { + "types": "./dist/capability-model-ref.d.mts", + "import": "./dist/capability-model-ref.mjs", + "default": "./dist/capability-model-ref.mjs" + }, + "./catalog": { + "types": "./dist/catalog.d.mts", + "import": "./dist/catalog.mjs", + "default": "./dist/catalog.mjs" + }, + "./model-ref": { + "types": "./dist/model-ref.d.mts", + "import": "./dist/model-ref.mjs", + "default": "./dist/model-ref.mjs" + }, + "./normalization": { + "types": "./dist/normalization.d.mts", + "import": "./dist/normalization.mjs", + "default": "./dist/normalization.mjs" + } + }, + "scripts": { + "build": "tsdown src/index.ts src/capability-model-ref.ts src/catalog.ts src/model-ref.ts src/normalization.ts --no-config --platform node --format esm --dts --out-dir dist --clean" + } +} diff --git a/src/media-generation/capability-model-ref.ts b/packages/media-generation-core/src/capability-model-ref.ts similarity index 85% rename from src/media-generation/capability-model-ref.ts rename to packages/media-generation-core/src/capability-model-ref.ts index fc3a751b370f..23d218013ddb 100644 --- a/src/media-generation/capability-model-ref.ts +++ b/packages/media-generation-core/src/capability-model-ref.ts @@ -1,4 +1,4 @@ -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { normalizeOptionalString } from "./string.js"; export type CapabilityModelProviderCandidate = { id: string; @@ -19,10 +19,7 @@ function normalizeProviderForMatch( normalizeProviderId: ProviderIdNormalizer | undefined, ): string | undefined { const normalized = normalizeOptionalString(value); - if (!normalized) { - return undefined; - } - return normalizeProviderId ? normalizeProviderId(normalized) : normalized; + return normalized && normalizeProviderId ? normalizeProviderId(normalized) : normalized; } export function findCapabilityProviderById(params: { @@ -36,11 +33,12 @@ export function findCapabilityProviderById { const providerId = normalizeProviderForMatch(provider.id, params.normalizeProviderId); - if (providerId === selectedProvider) { - return true; - } - return (provider.aliases ?? []).some( - (alias) => normalizeProviderForMatch(alias, params.normalizeProviderId) === selectedProvider, + return ( + providerId === selectedProvider || + (provider.aliases ?? []).some( + (alias) => + normalizeProviderForMatch(alias, params.normalizeProviderId) === selectedProvider, + ) ); }); } diff --git a/src/media-generation/catalog.test.ts b/packages/media-generation-core/src/catalog.test.ts similarity index 100% rename from src/media-generation/catalog.test.ts rename to packages/media-generation-core/src/catalog.test.ts diff --git a/src/media-generation/catalog.ts b/packages/media-generation-core/src/catalog.ts similarity index 62% rename from src/media-generation/catalog.ts rename to packages/media-generation-core/src/catalog.ts index 29f5770451ca..2619311aff75 100644 --- a/src/media-generation/catalog.ts +++ b/packages/media-generation-core/src/catalog.ts @@ -1,23 +1,27 @@ -import type { - UnifiedModelCatalogEntry, - UnifiedModelCatalogKind, - UnifiedModelCatalogSource, -} from "../model-catalog/types.js"; -import { normalizeUniqueSingleOrTrimmedStringList } from "../shared/string-normalization.js"; +import { uniqueTrimmedStrings } from "./string.js"; -export type MediaGenerationCatalogKind = Extract< - UnifiedModelCatalogKind, - "image_generation" | "video_generation" | "music_generation" ->; +export type MediaGenerationCatalogKind = + | "image_generation" + | "video_generation" + | "music_generation"; -export type MediaGenerationCatalogSource = Extract< - UnifiedModelCatalogSource, - "static" | "live" | "cache" | "configured" ->; +export type MediaGenerationCatalogSource = "static" | "live" | "cache" | "configured"; -export type MediaGenerationCatalogEntry = UnifiedModelCatalogEntry & { +export type MediaGenerationCatalogEntry = { kind: MediaGenerationCatalogKind; + provider: string; + model: string; + label?: string; source: MediaGenerationCatalogSource; + default?: boolean; + configured?: boolean; + capabilities?: TCapabilities; + modes?: readonly string[]; + authEnvVars?: readonly string[]; + docsPath?: string; + fetchedAt?: number; + expiresAt?: number; + warnings?: readonly string[]; }; export type MediaGenerationCatalogProvider = { @@ -30,10 +34,7 @@ export type MediaGenerationCatalogProvider = { }; function uniqueModels(provider: { defaultModel?: string; models?: readonly string[] }): string[] { - return normalizeUniqueSingleOrTrimmedStringList([ - provider.defaultModel, - ...(provider.models ?? []), - ]); + return uniqueTrimmedStrings([provider.defaultModel, ...(provider.models ?? [])]); } export function synthesizeMediaGenerationCatalogEntries(params: { @@ -41,8 +42,7 @@ export function synthesizeMediaGenerationCatalogEntries(params: { provider: MediaGenerationCatalogProvider; modes?: readonly string[]; }): Array> { - const models = uniqueModels(params.provider); - return models.map((model) => { + return uniqueModels(params.provider).map((model) => { const entry: MediaGenerationCatalogEntry = { kind: params.kind, provider: params.provider.id, diff --git a/packages/media-generation-core/src/index.ts b/packages/media-generation-core/src/index.ts new file mode 100644 index 000000000000..a716b439172e --- /dev/null +++ b/packages/media-generation-core/src/index.ts @@ -0,0 +1,4 @@ +export * from "./capability-model-ref.js"; +export * from "./catalog.js"; +export * from "./model-ref.js"; +export * from "./normalization.js"; diff --git a/packages/media-generation-core/src/model-ref.test.ts b/packages/media-generation-core/src/model-ref.test.ts new file mode 100644 index 000000000000..a8c92f50d5ec --- /dev/null +++ b/packages/media-generation-core/src/model-ref.test.ts @@ -0,0 +1,74 @@ +import { describe, expect, it } from "vitest"; +import { + resolveCapabilityModelRefForProviders, + resolveCapabilityProviderModelOnlyRef, +} from "./capability-model-ref.js"; +import { parseGenerationModelRef } from "./model-ref.js"; + +describe("media-generation model refs", () => { + it("parses provider/model refs without splitting slash-containing model ids", () => { + expect(parseGenerationModelRef("fal/fal-ai/flux/dev")).toEqual({ + provider: "fal", + model: "fal-ai/flux/dev", + }); + }); + + it("rejects incomplete provider/model refs", () => { + expect(parseGenerationModelRef(undefined)).toBeNull(); + expect(parseGenerationModelRef("openai")).toBeNull(); + expect(parseGenerationModelRef("/gpt-image-2")).toBeNull(); + expect(parseGenerationModelRef("openai/")).toBeNull(); + }); + + it("resolves model-only refs from provider metadata", () => { + expect( + resolveCapabilityProviderModelOnlyRef({ + raw: "fal-ai/flux/dev", + providers: [ + { + id: "fal", + defaultModel: "fal-ai/flux/dev", + models: ["fal-ai/flux/dev/image-to-image"], + }, + ], + }), + ).toEqual({ provider: "fal", model: "fal-ai/flux/dev" }); + }); + + it("keeps explicit provider refs ahead of colliding model-only refs", () => { + expect( + resolveCapabilityModelRefForProviders({ + raw: "google/lyria-3-pro-preview", + parseModelRef: parseGenerationModelRef, + providers: [ + { + id: "google", + defaultModel: "lyria-3-clip-preview", + models: ["lyria-3-pro-preview"], + }, + { + id: "openrouter", + defaultModel: "google/lyria-3-pro-preview", + }, + ], + }), + ).toEqual({ provider: "google", model: "lyria-3-pro-preview" }); + }); + + it("matches provider aliases through a caller-supplied normalizer", () => { + expect( + resolveCapabilityModelRefForProviders({ + raw: "openai-codex/gpt-image-2", + parseModelRef: parseGenerationModelRef, + normalizeProviderId: (value) => value.toLowerCase(), + providers: [ + { + id: "openai", + aliases: ["openai-codex"], + defaultModel: "gpt-image-2", + }, + ], + }), + ).toEqual({ provider: "openai-codex", model: "gpt-image-2" }); + }); +}); diff --git a/src/media-generation/model-ref.ts b/packages/media-generation-core/src/model-ref.ts similarity index 73% rename from src/media-generation/model-ref.ts rename to packages/media-generation-core/src/model-ref.ts index 913a89d1684e..366459bcfdb6 100644 --- a/src/media-generation/model-ref.ts +++ b/packages/media-generation-core/src/model-ref.ts @@ -1,6 +1,6 @@ -import { normalizeOptionalString } from "../shared/string-coerce.js"; +import { normalizeOptionalString } from "./string.js"; -type ParsedGenerationModelRef = { +export type ParsedGenerationModelRef = { provider: string; model: string; }; @@ -16,8 +16,5 @@ export function parseGenerationModelRef(raw: string | undefined): ParsedGenerati } const provider = normalizeOptionalString(trimmed.slice(0, slashIndex)); const model = normalizeOptionalString(trimmed.slice(slashIndex + 1)); - if (!provider || !model) { - return null; - } - return { provider, model }; + return provider && model ? { provider, model } : null; } diff --git a/src/media-generation/normalization.types.ts b/packages/media-generation-core/src/normalization.ts similarity index 56% rename from src/media-generation/normalization.types.ts rename to packages/media-generation-core/src/normalization.ts index 633585c8b6a1..71b329a891c2 100644 --- a/src/media-generation/normalization.types.ts +++ b/packages/media-generation-core/src/normalization.ts @@ -13,3 +13,15 @@ export type MediaGenerationNormalizationMetadataInput = { resolution?: MediaNormalizationEntry; durationSeconds?: MediaNormalizationEntry; }; + +export function hasMediaNormalizationEntry( + entry: MediaNormalizationEntry | undefined, +): entry is MediaNormalizationEntry { + return Boolean( + entry && + (entry.requested !== undefined || + entry.applied !== undefined || + entry.derivedFrom !== undefined || + (entry.supportedValues?.length ?? 0) > 0), + ); +} diff --git a/packages/media-generation-core/src/string.ts b/packages/media-generation-core/src/string.ts new file mode 100644 index 000000000000..f830769126a8 --- /dev/null +++ b/packages/media-generation-core/src/string.ts @@ -0,0 +1,21 @@ +export function normalizeOptionalString(value: unknown): string | undefined { + if (typeof value !== "string") { + return undefined; + } + const trimmed = value.trim(); + return trimmed ? trimmed : undefined; +} + +export function uniqueTrimmedStrings(values: readonly unknown[]): string[] { + const seen = new Set(); + const result: string[] = []; + for (const value of values) { + const normalized = normalizeOptionalString(value); + if (!normalized || seen.has(normalized)) { + continue; + } + seen.add(normalized); + result.push(normalized); + } + return result; +} diff --git a/packages/plugin-sdk/tsconfig.json b/packages/plugin-sdk/tsconfig.json index 39baf5eba6cf..9fb52e38e68d 100644 --- a/packages/plugin-sdk/tsconfig.json +++ b/packages/plugin-sdk/tsconfig.json @@ -13,6 +13,7 @@ "tsBuildInfoFile": "dist/.tsbuildinfo" }, "include": [ + "../../packages/media-generation-core/src/**/*.ts", "../../src/plugin-sdk/**/*.ts", "../../src/video-generation/dashscope-compatible.ts", "../../src/video-generation/types.ts", @@ -21,6 +22,7 @@ "exclude": [ "node_modules", "dist", + "../../packages/**/*.test.ts", "../../src/**/*.test.ts", "../../src/plugin-sdk/AGENTS.md", "../../src/plugin-sdk/CLAUDE.md" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c2eb77f872a5..9ace48322421 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1812,6 +1812,8 @@ importers: specifier: workspace:* version: link:../llm-core + packages/media-generation-core: {} + packages/memory-host-sdk: {} packages/net-policy: diff --git a/scripts/build-all.mjs b/scripts/build-all.mjs index decfab23dc05..fcd089f04dac 100644 --- a/scripts/build-all.mjs +++ b/scripts/build-all.mjs @@ -53,6 +53,7 @@ export const BUILD_ALL_STEPS = [ "src/plugin-sdk", "packages/llm-core/src", "packages/memory-host-sdk/src", + "packages/media-generation-core/src", "src/types", "src/video-generation/dashscope-compatible.ts", "src/video-generation/types.ts", diff --git a/scripts/lib/extension-package-boundary.ts b/scripts/lib/extension-package-boundary.ts index 254e4b6ef856..cce9d7e0e354 100644 --- a/scripts/lib/extension-package-boundary.ts +++ b/scripts/lib/extension-package-boundary.ts @@ -59,6 +59,24 @@ 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/media-generation-core": [ + "../dist/plugin-sdk/packages/media-generation-core/src/index.d.ts", + ], + "@openclaw/media-generation-core/capability-model-ref": [ + "../dist/plugin-sdk/packages/media-generation-core/src/capability-model-ref.d.ts", + ], + "@openclaw/media-generation-core/catalog": [ + "../dist/plugin-sdk/packages/media-generation-core/src/catalog.d.ts", + ], + "@openclaw/media-generation-core/model-ref": [ + "../dist/plugin-sdk/packages/media-generation-core/src/model-ref.d.ts", + ], + "@openclaw/media-generation-core/normalization": [ + "../dist/plugin-sdk/packages/media-generation-core/src/normalization.d.ts", + ], + "@openclaw/media-generation-core/*": [ + "../dist/plugin-sdk/packages/media-generation-core/src/*.d.ts", + ], "@openclaw/*.js": ["../packages/plugin-sdk/dist/extensions/*.d.ts", "../extensions/*"], "@openclaw/*": ["../packages/plugin-sdk/dist/extensions/*", "../extensions/*"], "openclaw/plugin-sdk/qa-channel": ["../dist/plugin-sdk/src/plugin-sdk/qa-channel.d.ts"], diff --git a/scripts/prepare-extension-package-boundary-artifacts.mjs b/scripts/prepare-extension-package-boundary-artifacts.mjs index ebd6ff510fc9..38498b4f6929 100644 --- a/scripts/prepare-extension-package-boundary-artifacts.mjs +++ b/scripts/prepare-extension-package-boundary-artifacts.mjs @@ -17,6 +17,7 @@ const PLUGIN_SDK_TYPE_INPUTS = [ "src/auto-reply", "packages/llm-core/src", "packages/memory-host-sdk/src", + "packages/media-generation-core/src", "src/video-generation/dashscope-compatible.ts", "src/video-generation/types.ts", "src/types", @@ -32,6 +33,11 @@ const ROOT_DTS_REQUIRED_OUTPUTS = [ "dist/plugin-sdk/packages/llm-core/src/utils/diagnostics.d.ts", "dist/plugin-sdk/packages/llm-core/src/utils/event-stream.d.ts", "dist/plugin-sdk/packages/llm-core/src/validation.d.ts", + "dist/plugin-sdk/packages/media-generation-core/src/capability-model-ref.d.ts", + "dist/plugin-sdk/packages/media-generation-core/src/catalog.d.ts", + "dist/plugin-sdk/packages/media-generation-core/src/index.d.ts", + "dist/plugin-sdk/packages/media-generation-core/src/model-ref.d.ts", + "dist/plugin-sdk/packages/media-generation-core/src/normalization.d.ts", "dist/plugin-sdk/error-runtime.d.ts", "dist/plugin-sdk/plugin-entry.d.ts", "dist/plugin-sdk/provider-auth.d.ts", @@ -40,6 +46,11 @@ const ROOT_DTS_REQUIRED_OUTPUTS = [ const PACKAGE_DTS_INPUTS = ["packages/plugin-sdk/tsconfig.json", ...PLUGIN_SDK_TYPE_INPUTS]; const PACKAGE_DTS_STAMP = "packages/plugin-sdk/dist/.boundary-dts.stamp"; const PACKAGE_DTS_REQUIRED_OUTPUTS = [ + "packages/plugin-sdk/dist/packages/media-generation-core/src/capability-model-ref.d.ts", + "packages/plugin-sdk/dist/packages/media-generation-core/src/catalog.d.ts", + "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/src/plugin-sdk/error-runtime.d.ts", "packages/plugin-sdk/dist/src/plugin-sdk/plugin-entry.d.ts", "packages/plugin-sdk/dist/src/plugin-sdk/provider-auth.d.ts", diff --git a/scripts/protocol-gen-swift.ts b/scripts/protocol-gen-swift.ts index b5d82e714736..d23b5afb2163 100644 --- a/scripts/protocol-gen-swift.ts +++ b/scripts/protocol-gen-swift.ts @@ -40,36 +40,48 @@ const STRICT_LITERAL_STRUCTS = new Set([ "PluginsSessionActionFailureResult", ]); -const DEFAULTED_OPTIONAL_INIT_PARAMS: Record> = { - SessionOperationEvent: new Set(["agentId"]), - SessionsCompactionListParams: new Set(["agentId"]), - SessionsCompactionGetParams: new Set(["agentId"]), - SessionsCompactionBranchParams: new Set(["agentId"]), - SessionsCompactionRestoreParams: new Set(["agentId"]), - SessionsSendParams: new Set(["agentId"]), - SessionsMessagesSubscribeParams: new Set(["agentId"]), - SessionsMessagesUnsubscribeParams: new Set(["agentId"]), - SessionsAbortParams: new Set(["agentId"]), - SessionsPatchParams: new Set(["agentId"]), - SessionsResetParams: new Set(["agentId"]), - SessionsDeleteParams: new Set(["agentId"]), - SessionsCompactParams: new Set(["agentId"]), - SessionsUsageParams: new Set(["agentId", "agentScope"]), - ChatHistoryParams: new Set(["agentId"]), - ChatSendParams: new Set(["agentId"]), - ChatAbortParams: new Set(["agentId"]), - ChatInjectParams: new Set(["agentId"]), - ChatDeltaEvent: new Set(["agentId"]), - ChatFinalEvent: new Set(["agentId"]), - ChatAbortedEvent: new Set(["agentId"]), - ChatErrorEvent: new Set(["agentId"]), - ArtifactsListParams: new Set(["agentId"]), - ArtifactsGetParams: new Set(["agentId"]), - ArtifactsDownloadParams: new Set(["agentId"]), - MessageActionParams: new Set(["inboundTurnKind"]), - CronRunLogEntry: new Set(["errorReason", "failureNotificationDelivery"]), - ExecApprovalRequestParams: new Set(["requireDeliveryRoute", "suppressDelivery"]), -}; +const DEFAULTED_OPTIONAL_INIT_PARAM_ENTRIES: readonly [string, readonly string[]][] = [ + ["SessionOperationEvent", ["agentId"]], + ["SessionsCompactionListParams", ["agentId"]], + ["SessionsCompactionGetParams", ["agentId"]], + ["SessionsCompactionBranchParams", ["agentId"]], + ["SessionsCompactionRestoreParams", ["agentId"]], + ["SessionsSendParams", ["agentId"]], + ["SessionsMessagesSubscribeParams", ["agentId"]], + ["SessionsMessagesUnsubscribeParams", ["agentId"]], + ["SessionsAbortParams", ["agentId"]], + ["SessionsPatchParams", ["agentId"]], + ["SessionsResetParams", ["agentId"]], + ["SessionsDeleteParams", ["agentId"]], + ["SessionsCompactParams", ["agentId"]], + ["SessionsUsageParams", ["agentId", "agentScope"]], + ["ChatHistoryParams", ["agentId"]], + ["ChatSendParams", ["agentId"]], + ["ChatAbortParams", ["agentId"]], + ["ChatInjectParams", ["agentId"]], + ["ChatDeltaEvent", ["agentId"]], + ["ChatFinalEvent", ["agentId"]], + ["ChatAbortedEvent", ["agentId"]], + ["ChatErrorEvent", ["agentId"]], + ["ArtifactsListParams", ["agentId"]], + ["ArtifactsGetParams", ["agentId"]], + ["ArtifactsDownloadParams", ["agentId"]], + ["ChatAbortParams", ["agentId"]], + ["ChatAbortedEvent", ["agentId"]], + ["ChatDeltaEvent", ["agentId"]], + ["ChatErrorEvent", ["agentId"]], + ["ChatFinalEvent", ["agentId"]], + ["ChatHistoryParams", ["agentId"]], + ["ChatInjectParams", ["agentId"]], + ["ChatSendParams", ["agentId"]], + ["MessageActionParams", ["inboundTurnKind"]], + ["CronRunLogEntry", ["errorReason", "failureNotificationDelivery"]], + ["ExecApprovalRequestParams", ["requireDeliveryRoute", "suppressDelivery"]], +]; + +const DEFAULTED_OPTIONAL_INIT_PARAMS: Record> = Object.fromEntries( + DEFAULTED_OPTIONAL_INIT_PARAM_ENTRIES.map(([name, params]) => [name, new Set(params)]), +); const header = `// Generated by scripts/protocol-gen-swift.ts — do not edit by hand\n// swiftlint:disable file_length\nimport Foundation\n\npublic let GATEWAY_PROTOCOL_VERSION = ${PROTOCOL_VERSION}\npublic let GATEWAY_MIN_PROTOCOL_VERSION = ${MIN_CLIENT_PROTOCOL_VERSION}\n\nprivate struct GatewayAnyCodingKey: CodingKey, Hashable {\n let stringValue: String\n let intValue: Int?\n\n init?(stringValue: String) {\n self.stringValue = stringValue\n self.intValue = nil\n }\n\n init?(intValue: Int) {\n self.stringValue = String(intValue)\n self.intValue = intValue\n }\n}\n\npublic enum ErrorCode: String, Codable, Sendable {\n${Object.values( ErrorCodes, diff --git a/scripts/run-node-watch-paths.mjs b/scripts/run-node-watch-paths.mjs index 596d24c7e6b3..7a40c2deb690 100644 --- a/scripts/run-node-watch-paths.mjs +++ b/scripts/run-node-watch-paths.mjs @@ -10,6 +10,7 @@ const RUN_NODE_PACKAGE_SOURCE_ROOTS = [ // src/ so edits restart the same process that consumes them. "packages/gateway-client/src", "packages/gateway-protocol/src", + "packages/media-generation-core/src", "packages/net-policy/src", ]; diff --git a/src/agents/bash-tools.exec-host-node.test.ts b/src/agents/bash-tools.exec-host-node.test.ts index c7c4a0b96880..26c40f6ca5ff 100644 --- a/src/agents/bash-tools.exec-host-node.test.ts +++ b/src/agents/bash-tools.exec-host-node.test.ts @@ -5,6 +5,8 @@ import { MAX_SAFE_TIMEOUT_DELAY_MS } from "../utils/timer-delay.js"; type StrictInlineEvalBoundary = typeof import("./bash-tools.exec-host-shared.js").enforceStrictInlineEvalApprovalBoundary; type ExecAutoReviewer = typeof import("../infra/exec-auto-review.js").defaultExecAutoReviewer; +type ExecAsk = import("../infra/exec-approvals.js").ExecAsk; +type ExecSecurity = import("../infra/exec-approvals.js").ExecSecurity; type MockAllowlistSegment = { raw?: string; resolution: null; @@ -17,11 +19,21 @@ type MockAllowlistResult = { segments: MockAllowlistSegment[]; segmentAllowlistEntries: unknown[]; }; -type MockExecApprovalAllowlistEntry = { +type MockExecAllowlistEntry = { pattern: string; - source?: string; + source?: "allow-always"; commandText?: string; }; +type MockExecApprovalsResolved = { + allowlist: MockExecAllowlistEntry[]; + file: { version: 1; agents: Record }; + agent: { + security: ExecSecurity; + ask: ExecAsk; + askFallback: "deny"; + autoAllowSkills: false; + }; +}; const INLINE_EVAL_HIT = { executable: "python3", @@ -60,16 +72,18 @@ const evaluateShellAllowlistMock = vi.hoisted(() => ), ); const resolveExecApprovalsFromFileMock = vi.hoisted(() => - vi.fn(() => ({ - allowlist: [] as MockExecApprovalAllowlistEntry[], - file: { version: 1, agents: {} }, - agent: { - security: "full", - ask: "off", - askFallback: "deny", - autoAllowSkills: false, - }, - })), + vi.fn( + (): MockExecApprovalsResolved => ({ + allowlist: [], + file: { version: 1, agents: {} }, + agent: { + security: "full", + ask: "off", + askFallback: "deny", + autoAllowSkills: false, + }, + }), + ), ); const requiresExecApprovalMock = vi.hoisted(() => vi.fn(() => true)); const hasDurableExecApprovalMock = vi.hoisted(() => vi.fn(() => false)); diff --git a/src/agents/tools/media-generate-tool-actions-shared.ts b/src/agents/tools/media-generate-tool-actions-shared.ts index 5901fea97fde..89b593678e51 100644 --- a/src/agents/tools/media-generate-tool-actions-shared.ts +++ b/src/agents/tools/media-generate-tool-actions-shared.ts @@ -1,9 +1,9 @@ -import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { listMediaGenerationProviderModels, synthesizeMediaGenerationCatalogEntries, type MediaGenerationCatalogKind, -} from "../../media-generation/catalog.js"; +} from "../../../packages/media-generation-core/src/catalog.js"; +import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { getProviderEnvVars } from "../../secrets/provider-env-vars.js"; import type { AuthProfileStore } from "../auth-profiles/types.js"; import { isCapabilityProviderConfigured } from "./media-tool-shared.js"; diff --git a/src/agents/tools/media-tool-shared.ts b/src/agents/tools/media-tool-shared.ts index d0dc26126894..f8685ca9a212 100644 --- a/src/agents/tools/media-tool-shared.ts +++ b/src/agents/tools/media-tool-shared.ts @@ -1,11 +1,11 @@ +import { + findCapabilityProviderById, + resolveCapabilityModelRefForProviders, +} from "../../../packages/media-generation-core/src/capability-model-ref.js"; import type { AgentModelConfig } from "../../config/types.agents-shared.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import type { SsrFPolicy } from "../../infra/net/ssrf.js"; import type { Model } from "../../llm/types.js"; -import { - findCapabilityProviderById, - resolveCapabilityModelRefForProviders, -} from "../../media-generation/capability-model-ref.js"; import { resolveChannelInboundAttachmentRootsForChannel } from "../../media/channel-inbound-roots.js"; import { normalizeInboundPathRoots } from "../../media/inbound-path-policy.js"; import { getDefaultLocalRoots } from "../../media/local-media-access.js"; diff --git a/src/image-generation/model-ref.ts b/src/image-generation/model-ref.ts index 3e198b8938a5..dbfb5a003339 100644 --- a/src/image-generation/model-ref.ts +++ b/src/image-generation/model-ref.ts @@ -1,4 +1,4 @@ -import { parseGenerationModelRef } from "../media-generation/model-ref.js"; +import { parseGenerationModelRef } from "../../packages/media-generation-core/src/model-ref.js"; export function parseImageGenerationModelRef( raw: string | undefined, diff --git a/src/image-generation/types.ts b/src/image-generation/types.ts index 9c42c0907217..fa9c042ea9b8 100644 --- a/src/image-generation/types.ts +++ b/src/image-generation/types.ts @@ -1,7 +1,7 @@ +import type { MediaNormalizationEntry } from "../../packages/media-generation-core/src/normalization.js"; import type { AuthProfileStore } from "../agents/auth-profiles/types.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import type { SsrFPolicy } from "../infra/net/ssrf.js"; -import type { MediaNormalizationEntry } from "../media-generation/normalization.types.js"; export type GeneratedImageAsset = { buffer: Buffer; diff --git a/src/infra/net/http-connect-tunnel.test.ts b/src/infra/net/http-connect-tunnel.test.ts index df4bd59a078f..bcfdd1037209 100644 --- a/src/infra/net/http-connect-tunnel.test.ts +++ b/src/infra/net/http-connect-tunnel.test.ts @@ -342,6 +342,7 @@ describe("openHttpConnectTunnel", () => { targetPort: 443, timeoutMs: 1, }); + void tunnel.catch(() => undefined); const rejected = expect(tunnel).rejects.toThrow( "Proxy CONNECT failed via http://proxy.example:8080: Proxy CONNECT timed out after 1ms", ); @@ -364,6 +365,7 @@ describe("openHttpConnectTunnel", () => { targetPort: 443, timeoutMs: Number.MAX_SAFE_INTEGER, }); + void tunnel.catch(() => undefined); const rejected = expect(tunnel).rejects.toThrow( `Proxy CONNECT failed via http://proxy.example:8080: Proxy CONNECT timed out after ${MAX_TIMER_TIMEOUT_MS}ms`, ); diff --git a/src/infra/watch-node.test.ts b/src/infra/watch-node.test.ts index cf4685297341..74dbf880263f 100644 --- a/src/infra/watch-node.test.ts +++ b/src/infra/watch-node.test.ts @@ -132,6 +132,7 @@ describe("watch-node script", () => { expect(watchPaths).toContain("extensions"); expect(watchPaths).toContain("packages/gateway-client/src"); expect(watchPaths).toContain("packages/gateway-protocol/src"); + expect(watchPaths).toContain("packages/media-generation-core/src"); expect(watchPaths).toContain("packages/net-policy/src"); expect(watchPaths).toContain("tsdown.config.ts"); expect(watchOptions.ignoreInitial).toBe(true); @@ -140,6 +141,10 @@ describe("watch-node script", () => { expect(watchOptions.ignored("packages/gateway-client/src/client.ts")).toBe(false); expect(watchOptions.ignored("packages/gateway-client/src/client.test.ts")).toBe(true); expect(watchOptions.ignored("packages/gateway-protocol/src/schema/cron.ts")).toBe(false); + expect(watchOptions.ignored("packages/media-generation-core/src/model-ref.ts")).toBe(false); + expect(watchOptions.ignored("packages/media-generation-core/src/model-ref.test.ts")).toBe( + true, + ); expect(watchOptions.ignored("packages/net-policy/src/ip.ts")).toBe(false); expect(watchOptions.ignored("packages/net-policy/src/ip.test.ts")).toBe(true); expect(watchOptions.ignored("extensions")).toBe(false); diff --git a/src/media-generation/runtime-shared.ts b/src/media-generation/runtime-shared.ts index 94a4c087c04b..03358eec6161 100644 --- a/src/media-generation/runtime-shared.ts +++ b/src/media-generation/runtime-shared.ts @@ -1,3 +1,5 @@ +import { resolveCapabilityModelRefForProviders } from "../../packages/media-generation-core/src/capability-model-ref.js"; +import type { MediaGenerationNormalizationMetadataInput } from "../../packages/media-generation-core/src/normalization.js"; import { listProfilesForProvider } from "../agents/auth-profiles.js"; import { ensureAuthProfileStore } from "../agents/auth-profiles.js"; import { DEFAULT_PROVIDER } from "../agents/defaults.js"; @@ -14,23 +16,17 @@ import { formatErrorMessage } from "../infra/errors.js"; import { getProviderEnvVars as getDefaultProviderEnvVars } from "../secrets/provider-env-vars.js"; import { clampTimerTimeoutMs } from "../shared/number-coercion.js"; import { normalizeOptionalString } from "../shared/string-coerce.js"; -import { resolveCapabilityModelRefForProviders } from "./capability-model-ref.js"; -import type { +export type { MediaGenerationNormalizationMetadataInput, MediaNormalizationEntry, MediaNormalizationValue, -} from "./normalization.types.js"; +} from "../../packages/media-generation-core/src/normalization.js"; +export { hasMediaNormalizationEntry } from "../../packages/media-generation-core/src/normalization.js"; export type ParsedProviderModelRef = { provider: string; model: string; }; -export type { - MediaGenerationNormalizationMetadataInput, - MediaNormalizationEntry, - MediaNormalizationValue, -} from "./normalization.types.js"; - export function recordCapabilityCandidateFailure(params: { attempts: FallbackAttempt[]; provider: string; @@ -48,18 +44,6 @@ export function recordCapabilityCandidateFailure(params: { }); } -export function hasMediaNormalizationEntry( - entry: MediaNormalizationEntry | undefined, -): entry is MediaNormalizationEntry { - return Boolean( - entry && - (entry.requested !== undefined || - entry.applied !== undefined || - entry.derivedFrom !== undefined || - (entry.supportedValues?.length ?? 0) > 0), - ); -} - const IMAGE_RESOLUTION_ORDER = ["1K", "2K", "4K"] as const; export function resolveMediaProviderDefaultTimeoutMs( diff --git a/src/music-generation/model-ref.ts b/src/music-generation/model-ref.ts index d4075cab05bb..5ec8098dae86 100644 --- a/src/music-generation/model-ref.ts +++ b/src/music-generation/model-ref.ts @@ -1,4 +1,4 @@ -import { parseGenerationModelRef } from "../media-generation/model-ref.js"; +import { parseGenerationModelRef } from "../../packages/media-generation-core/src/model-ref.js"; export function parseMusicGenerationModelRef( raw: string | undefined, diff --git a/src/music-generation/types.ts b/src/music-generation/types.ts index 4094b6dd69dc..ce5806acff79 100644 --- a/src/music-generation/types.ts +++ b/src/music-generation/types.ts @@ -1,6 +1,6 @@ +import type { MediaNormalizationEntry } from "../../packages/media-generation-core/src/normalization.js"; import type { AuthProfileStore } from "../agents/auth-profiles/types.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { MediaNormalizationEntry } from "../media-generation/normalization.types.js"; export type MusicGenerationOutputFormat = "mp3" | "wav"; diff --git a/src/plugins/contracts/extension-package-project-boundaries.test.ts b/src/plugins/contracts/extension-package-project-boundaries.test.ts index 105595d3d1b6..afe0b53ac96b 100644 --- a/src/plugins/contracts/extension-package-project-boundaries.test.ts +++ b/src/plugins/contracts/extension-package-project-boundaries.test.ts @@ -194,6 +194,7 @@ describe("opt-in extension package boundaries", () => { expect(tsconfig.compilerOptions?.outDir).toBe("dist"); expect(tsconfig.compilerOptions?.rootDir).toBe("../.."); expect(tsconfig.include).toEqual([ + "../../packages/media-generation-core/src/**/*.ts", "../../src/plugin-sdk/**/*.ts", "../../src/video-generation/dashscope-compatible.ts", "../../src/video-generation/types.ts", diff --git a/src/plugins/model-catalog-registration.ts b/src/plugins/model-catalog-registration.ts index 7643acac879e..1a086566fd80 100644 --- a/src/plugins/model-catalog-registration.ts +++ b/src/plugins/model-catalog-registration.ts @@ -1,13 +1,13 @@ +import { + synthesizeMediaGenerationCatalogEntries, + type MediaGenerationCatalogKind, + type MediaGenerationCatalogProvider, +} from "../../packages/media-generation-core/src/catalog.js"; import { synthesizeVoiceModelCatalogEntries, type VoiceModelCapabilities, type VoiceModelProvider, } from "../../packages/speech-core/voice-models.js"; -import { - synthesizeMediaGenerationCatalogEntries, - type MediaGenerationCatalogKind, - type MediaGenerationCatalogProvider, -} from "../media-generation/catalog.js"; import type { UnifiedModelCatalogEntry, UnifiedModelCatalogSource, diff --git a/src/plugins/sdk-alias.test.ts b/src/plugins/sdk-alias.test.ts index fe8d129f7fe4..bbaf850d7ec2 100644 --- a/src/plugins/sdk-alias.test.ts +++ b/src/plugins/sdk-alias.test.ts @@ -1378,6 +1378,18 @@ describe("plugin sdk alias helpers", () => { srcFile: "index.ts", distFile: "index.mjs", }); + const mediaGenerationCore = writeWorkspacePackageEntry({ + root: fixture.root, + packageDir: "media-generation-core", + srcFile: "index.ts", + distFile: "index.mjs", + }); + const mediaGenerationModelRef = writeWorkspacePackageEntry({ + root: fixture.root, + packageDir: "media-generation-core", + srcFile: "model-ref.ts", + distFile: "model-ref.mjs", + }); const netPolicyIp = writeWorkspacePackageEntry({ root: fixture.root, packageDir: "net-policy", @@ -1388,6 +1400,8 @@ describe("plugin sdk alias helpers", () => { fs.rmSync(gatewayClientTimeouts.distFile); fs.rmSync(gatewayProtocol.distFile); fs.rmSync(gatewayProtocolSchema.distFile); + fs.rmSync(mediaGenerationCore.distFile); + fs.rmSync(mediaGenerationModelRef.distFile); fs.rmSync(netPolicy.distFile); fs.rmSync(netPolicyIp.distFile); const sourcePluginEntry = writePluginEntry( @@ -1411,6 +1425,12 @@ describe("plugin sdk alias helpers", () => { expect(fs.realpathSync(aliases["@openclaw/gateway-protocol/schema"] ?? "")).toBe( fs.realpathSync(gatewayProtocolSchema.srcFile), ); + expect(fs.realpathSync(aliases["@openclaw/media-generation-core"] ?? "")).toBe( + fs.realpathSync(mediaGenerationCore.srcFile), + ); + expect(fs.realpathSync(aliases["@openclaw/media-generation-core/model-ref"] ?? "")).toBe( + fs.realpathSync(mediaGenerationModelRef.srcFile), + ); expect(fs.realpathSync(aliases["@openclaw/net-policy"] ?? "")).toBe( fs.realpathSync(netPolicy.srcFile), ); @@ -1433,6 +1453,12 @@ describe("plugin sdk alias helpers", () => { srcFile: "connect-error-details.ts", distFile: "connect-error-details.mjs", }); + const mediaGenerationCore = writeWorkspacePackageEntry({ + root: fixture.root, + packageDir: "media-generation-core", + srcFile: "catalog.ts", + distFile: "catalog.mjs", + }); const netPolicy = writeWorkspacePackageEntry({ root: fixture.root, packageDir: "net-policy", @@ -1454,6 +1480,9 @@ describe("plugin sdk alias helpers", () => { expect(fs.realpathSync(aliases["@openclaw/gateway-protocol/connect-error-details"] ?? "")).toBe( fs.realpathSync(gatewayProtocol.distFile), ); + expect(fs.realpathSync(aliases["@openclaw/media-generation-core/catalog"] ?? "")).toBe( + fs.realpathSync(mediaGenerationCore.distFile), + ); expect(fs.realpathSync(aliases["@openclaw/net-policy/redact-sensitive-url"] ?? "")).toBe( fs.realpathSync(netPolicy.distFile), ); diff --git a/src/plugins/sdk-alias.ts b/src/plugins/sdk-alias.ts index e6ef21ce31f8..29bb514d2efb 100644 --- a/src/plugins/sdk-alias.ts +++ b/src/plugins/sdk-alias.ts @@ -560,6 +560,41 @@ const WORKSPACE_PACKAGE_ALIAS_ENTRIES = [ srcFile: "version.ts", distFile: "version.mjs", }, + { + packageName: "@openclaw/media-generation-core", + packageDir: "media-generation-core", + subpath: "", + srcFile: "index.ts", + distFile: "index.mjs", + }, + { + packageName: "@openclaw/media-generation-core", + packageDir: "media-generation-core", + subpath: "capability-model-ref", + srcFile: "capability-model-ref.ts", + distFile: "capability-model-ref.mjs", + }, + { + packageName: "@openclaw/media-generation-core", + packageDir: "media-generation-core", + subpath: "catalog", + srcFile: "catalog.ts", + distFile: "catalog.mjs", + }, + { + packageName: "@openclaw/media-generation-core", + packageDir: "media-generation-core", + subpath: "model-ref", + srcFile: "model-ref.ts", + distFile: "model-ref.mjs", + }, + { + packageName: "@openclaw/media-generation-core", + packageDir: "media-generation-core", + subpath: "normalization", + srcFile: "normalization.ts", + distFile: "normalization.mjs", + }, { packageName: "@openclaw/net-policy", packageDir: "net-policy", diff --git a/src/video-generation/model-ref.ts b/src/video-generation/model-ref.ts index 1ce67d3c234d..f620882084af 100644 --- a/src/video-generation/model-ref.ts +++ b/src/video-generation/model-ref.ts @@ -1,4 +1,4 @@ -import { parseGenerationModelRef } from "../media-generation/model-ref.js"; +import { parseGenerationModelRef } from "../../packages/media-generation-core/src/model-ref.js"; export function parseVideoGenerationModelRef( raw: string | undefined, diff --git a/src/video-generation/types.ts b/src/video-generation/types.ts index d017cca1c5e7..9c9d7e624166 100644 --- a/src/video-generation/types.ts +++ b/src/video-generation/types.ts @@ -1,6 +1,6 @@ +import type { MediaNormalizationEntry } from "../../packages/media-generation-core/src/normalization.js"; import type { AuthProfileStore } from "../agents/auth-profiles/types.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; -import type { MediaNormalizationEntry } from "../media-generation/normalization.types.js"; export type GeneratedVideoAsset = { /** Raw video bytes. Required for local delivery; omit when url is provided instead. */ diff --git a/src/wizard/setup.official-plugins.test.ts b/src/wizard/setup.official-plugins.test.ts index 63747be97cf4..b1460843104e 100644 --- a/src/wizard/setup.official-plugins.test.ts +++ b/src/wizard/setup.official-plugins.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { createWizardPrompter } from "../../test/helpers/wizard-prompter.js"; import { createNonExitingRuntime } from "../runtime.js"; -import type { WizardPrompter } from "./prompts.js"; +import type { WizardMultiSelectParams, WizardPrompter } from "./prompts.js"; const ensureOnboardingPluginInstalled = vi.hoisted(() => vi.fn(async ({ cfg }: { cfg: Record }) => ({ @@ -92,9 +92,9 @@ describe("setupOfficialPluginInstalls", () => { }); it("installs selected optional official plugins through the shared onboarding installer", async () => { - const multiselect = vi.fn(async () => ["diagnostics-otel"]); + const multiselect = vi.fn(async (_params: WizardMultiSelectParams) => ["diagnostics-otel"]); const prompter = createWizardPrompter({ - multiselect: multiselect as WizardPrompter["multiselect"], + multiselect: multiselect as unknown as WizardPrompter["multiselect"], }); const runtime = createNonExitingRuntime(); @@ -105,14 +105,19 @@ describe("setupOfficialPluginInstalls", () => { workspaceDir: "/tmp/workspace", }); - expect(multiselect).toHaveBeenCalledExactlyOnceWith({ - message: "Install optional plugins", - options: [ - { - value: "__skip__", - label: "Skip for now", - hint: "Continue without installing optional plugins", - }, + expect(multiselect).toHaveBeenCalledTimes(1); + const prompt = multiselect.mock.calls[0]?.[0]; + if (!prompt) { + throw new Error("expected optional plugin multiselect prompt"); + } + expect(prompt.message).toBe("Install optional plugins"); + expect(prompt.options[0]).toEqual({ + value: "__skip__", + label: "Skip for now", + hint: "Continue without installing optional plugins", + }); + expect(prompt.options).toEqual( + expect.arrayContaining([ { value: "acpx", label: "ACPX Runtime", @@ -128,58 +133,8 @@ describe("setupOfficialPluginInstalls", () => { label: "Diagnostics Prometheus", hint: "OpenClaw diagnostics Prometheus exporter", }, - { - value: "diffs-language-pack", - label: "Diff Viewer Language Pack", - hint: "OpenClaw diffs viewer syntax highlighting language pack", - }, - { - value: "diffs", - label: "Diffs", - hint: "OpenClaw diff viewer plugin", - }, - { - value: "copilot", - label: "GitHub Copilot agent runtime", - hint: "OpenClaw GitHub Copilot agent runtime plugin", - }, - { - value: "google-meet", - label: "Google Meet", - hint: "OpenClaw Google Meet participant plugin", - }, - { - value: "lobster", - label: "Lobster", - hint: "Lobster workflow tool plugin (typed pipelines + resumable approvals)", - }, - { - value: "memory-lancedb", - label: "Memory LanceDB", - hint: "OpenClaw LanceDB-backed long-term memory plugin with auto-recall/capture", - }, - { - value: "openshell", - label: "OpenShell Sandbox", - hint: "OpenClaw OpenShell sandbox backend", - }, - { - value: "pixverse", - label: "PixVerse", - hint: "OpenClaw PixVerse video generation provider plugin", - }, - { - value: "tokenjuice", - label: "Tokenjuice", - hint: "OpenClaw tokenjuice exec output compaction plugin", - }, - { - value: "voice-call", - label: "Voice Call", - hint: "OpenClaw voice-call plugin", - }, - ], - }); + ]), + ); expect(ensureOnboardingPluginInstalled).toHaveBeenCalledExactlyOnceWith({ cfg: {}, entry: { diff --git a/test/scripts/crabbox-wrapper.test.ts b/test/scripts/crabbox-wrapper.test.ts index 561bdc0cb390..cf6854e99d2f 100644 --- a/test/scripts/crabbox-wrapper.test.ts +++ b/test/scripts/crabbox-wrapper.test.ts @@ -1,5 +1,12 @@ import { spawnSync } from "node:child_process"; -import { chmodSync, mkdirSync, mkdtempSync, rmSync, statSync, writeFileSync } from "node:fs"; +import { + chmodSync, + mkdirSync, + mkdtempSync, + rmSync, + statSync, + writeFileSync, +} from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; diff --git a/tsconfig.json b/tsconfig.json index 10bb13102fb4..824098403be2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -51,6 +51,20 @@ ], "@openclaw/gateway-protocol/version": ["./packages/gateway-protocol/src/version.ts"], "@openclaw/gateway-protocol/*": ["./packages/gateway-protocol/src/*"], + "@openclaw/media-generation-core": ["./packages/media-generation-core/src/index.ts"], + "@openclaw/media-generation-core/capability-model-ref": [ + "./packages/media-generation-core/src/capability-model-ref.ts" + ], + "@openclaw/media-generation-core/catalog": [ + "./packages/media-generation-core/src/catalog.ts" + ], + "@openclaw/media-generation-core/model-ref": [ + "./packages/media-generation-core/src/model-ref.ts" + ], + "@openclaw/media-generation-core/normalization": [ + "./packages/media-generation-core/src/normalization.ts" + ], + "@openclaw/media-generation-core/*": ["./packages/media-generation-core/src/*"], "@openclaw/net-policy": ["./packages/net-policy/src/index.ts"], "@openclaw/net-policy/ip": ["./packages/net-policy/src/ip.ts"], "@openclaw/net-policy/ipv4": ["./packages/net-policy/src/ipv4.ts"], diff --git a/tsconfig.plugin-sdk.dts.json b/tsconfig.plugin-sdk.dts.json index 3e4c4a6e2910..e2ca8f327c69 100644 --- a/tsconfig.plugin-sdk.dts.json +++ b/tsconfig.plugin-sdk.dts.json @@ -14,10 +14,11 @@ "include": [ "src/plugin-sdk/**/*.ts", "packages/llm-core/src/**/*.ts", + "packages/media-generation-core/src/**/*.ts", "packages/memory-host-sdk/src/**/*.ts", "src/video-generation/dashscope-compatible.ts", "src/video-generation/types.ts", "src/types/**/*.d.ts" ], - "exclude": ["node_modules", "dist", "src/**/*.test.ts"] + "exclude": ["node_modules", "dist", "packages/**/*.test.ts", "src/**/*.test.ts"] } diff --git a/tsdown.config.ts b/tsdown.config.ts index 36c5cd3c3e4d..ee8f2bb11dbc 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -384,6 +384,16 @@ function buildNetPolicyDistEntries(): Record { }; } +function buildMediaGenerationCoreDistEntries(): Record { + return { + index: "packages/media-generation-core/src/index.ts", + "capability-model-ref": "packages/media-generation-core/src/capability-model-ref.ts", + catalog: "packages/media-generation-core/src/catalog.ts", + "model-ref": "packages/media-generation-core/src/model-ref.ts", + normalization: "packages/media-generation-core/src/normalization.ts", + }; +} + function buildSpeechCoreDistEntries(): Record { return { api: "packages/speech-core/api.ts", @@ -523,6 +533,12 @@ export default defineConfig([ neverBundle: shouldExternalizeNetPolicyDependency, }, }), + nodeWorkspacePackageBuildConfig({ + clean: true, + dts: RUN_NODE_SKIP_DTS_BUILD ? false : undefined, + entry: buildMediaGenerationCoreDistEntries(), + outDir: "packages/media-generation-core/dist", + }), nodeWorkspacePackageBuildConfig({ clean: true, dts: RUN_NODE_SKIP_DTS_BUILD ? false : undefined,