Spracherkennung für: .ts vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
import path from "node:path";
import { fileURLToPath } from "node:url";
import { z } from "zod";
import type { ChannelConfigRuntimeSchema } from "../channels/plugins/types.config.js";
import { collectBundledChannelConfigs } from "../plugins/bundled-channel-config-metadata.js";
import { listBundledPluginMetadata } from "../plugins/bundled-plugin-metadata.js";
import { resolveLoaderPackageRoot } from "../plugins/sdk-alias.js";
import type { ChannelsConfig } from "./types.channels.js";
import { ChannelHeartbeatVisibilitySchema } from "./zod-schema.channels.js";
import { ContextVisibilityModeSchema, GroupPolicySchema } from "./zod-schema.core.js";
export * from "./zod-schema.providers-core.js";
export * from "./zod-schema.providers-whatsapp.js";
export { ChannelHeartbeatVisibilitySchema } from "./zod-schema.channels.js";
const ChannelModelByChannelSchema = z
.record(z.string(), z.record(z.string(), z.string()))
.optional();
let directChannelRuntimeSchemasCache: ReadonlyMap<string, ChannelConfigRuntimeSchema> | undefined;
const OPENCLAW_PACKAGE_ROOT =
resolveLoaderPackageRoot({
modulePath: fileURLToPath(import.meta.url),
moduleUrl: import.meta.url,
}) ?? fileURLToPath(new URL("../..", import.meta.url));
function getDirectChannelRuntimeSchema(channelId: string): ChannelConfigRuntimeSchema | undefined {
if (!directChannelRuntimeSchemasCache) {
directChannelRuntimeSchemasCache = new Map();
}
const cached = directChannelRuntimeSchemasCache.get(channelId);
if (cached) {
return cached;
}
for (const entry of listBundledPluginMetadata({
includeChannelConfigs: false,
includeSyntheticChannelConfigs: false,
})) {
const manifestRuntime = entry.manifest.channelConfigs?.[channelId]?.runtime;
if (manifestRuntime) {
(directChannelRuntimeSchemasCache as Map<string, ChannelConfigRuntimeSchema>).set(
channelId,
manifestRuntime,
);
return manifestRuntime;
}
if (!entry.manifest.channels?.includes(channelId)) {
continue;
}
const collectedChannelConfigs = collectBundledChannelConfigs({
pluginDir: path.resolve(OPENCLAW_PACKAGE_ROOT, "extensions", entry.dirName),
manifest: entry.manifest,
...(entry.packageManifest ? { packageManifest: entry.packageManifest } : {}),
});
const collectedRuntime = collectedChannelConfigs?.[channelId]?.runtime;
if (collectedRuntime) {
(directChannelRuntimeSchemasCache as Map<string, ChannelConfigRuntimeSchema>).set(
channelId,
collectedRuntime,
);
return collectedRuntime;
}
}
return undefined;
}
function hasPluginOwnedChannelConfig(
value: ChannelsConfig,
): value is ChannelsConfig & Record<string, unknown> {
return Object.keys(value).some((key) => key !== "defaults" && key !== "modelByChannel");
}
function addLegacyChannelAcpBindingIssues(
value: unknown,
ctx: z.RefinementCtx,
path: Array<string | number> = [],
) {
if (!value || typeof value !== "object") {
return;
}
if (Array.isArray(value)) {
value.forEach((entry, index) => addLegacyChannelAcpBindingIssues(entry, ctx, [...path, index]));
return;
}
const record = value as Record<string, unknown>;
const bindings = record.bindings;
if (bindings && typeof bindings === "object" && !Array.isArray(bindings)) {
const acp = (bindings as Record<string, unknown>).acp;
if (acp && typeof acp === "object") {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: [...path, "bindings", "acp"],
message:
"Legacy channel-local ACP bindings were removed; use top-level bindings[] entries.",
});
}
}
for (const [key, entry] of Object.entries(record)) {
addLegacyChannelAcpBindingIssues(entry, ctx, [...path, key]);
}
}
function normalizeBundledChannelConfigs(
value: ChannelsConfig | undefined,
ctx: z.RefinementCtx,
): ChannelsConfig | undefined {
if (!value || !hasPluginOwnedChannelConfig(value)) {
return value;
}
let next: ChannelsConfig | undefined;
for (const channelId of Object.keys(value)) {
const runtimeSchema = getDirectChannelRuntimeSchema(channelId);
if (!runtimeSchema) {
continue;
}
if (!Object.prototype.hasOwnProperty.call(value, channelId)) {
continue;
}
const parsed = runtimeSchema.safeParse(value[channelId]);
if (!parsed.success) {
for (const issue of parsed.issues) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: issue.message ?? `Invalid channels.${channelId} config.`,
path: [channelId, ...(Array.isArray(issue.path) ? issue.path : [])],
});
}
continue;
}
next ??= { ...value };
next[channelId] = parsed.data as ChannelsConfig[string];
}
return next ?? value;
}
export const ChannelsSchema: z.ZodType<ChannelsConfig | undefined> = z
.object({
defaults: z
.object({
groupPolicy: GroupPolicySchema.optional(),
contextVisibility: ContextVisibilityModeSchema.optional(),
heartbeat: ChannelHeartbeatVisibilitySchema,
})
.strict()
.optional(),
modelByChannel: ChannelModelByChannelSchema,
})
.passthrough() // Allow extension channel configs (nostr, matrix, zalo, etc.)
.superRefine((value, ctx) => {
addLegacyChannelAcpBindingIssues(value, ctx);
})
.transform((value, ctx) => normalizeBundledChannelConfigs(value as ChannelsConfig, ctx))
.optional() as z.ZodType<ChannelsConfig | undefined>;
¤ Dauer der Verarbeitung: 0.31 Sekunden
(vorverarbeitet am 2026-04-27)
¤
*© Formatika GbR, Deutschland
|
|