openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
189 lines (188 loc) • 7.08 kB
JavaScript
import { I as toJSONSchema } from "./json-schema-processors-C6KO_BFy.mjs";
import { Fn as object, Jn as string, Lt as boolean, Nt as array, Pn as number, Un as record, or as union } from "./schemas-BOYIvvln.mjs";
import { n as ZodIssueCode } from "./compat-CVCDeluo.mjs";
import { O as evaluateDmPolicyAllowFromDependency, o as DmPolicySchema } from "./zod-schema.core-MaNAY9dn.mjs";
import { n as validateJsonSchemaValue, t as parseJsonSchemaIssuePath } from "./schema-validator-qnYkiHpy.mjs";
import { o as ToolPolicySchema } from "./zod-schema.agent-runtime-cX-pI-Mt.mjs";
//#region src/channels/plugins/config-schema.ts
/** Shared allowlist entry shape for channel sender/user ids. */
const AllowFromEntrySchema = union([string(), number()]);
/** Optional allowlist array used by channel config schema builders. */
const AllowFromListSchema = array(AllowFromEntrySchema).optional();
/** Validate one policy scope; the channel owns account selection and refinement ordering. */
function refineChannelDmPolicy(params) {
const { channelId, value, accountId, ctx } = params;
const account = accountId === void 0 ? value : value.accounts?.[accountId];
if (!account) return;
const policy = account.dmPolicy ?? value.dmPolicy;
const violation = evaluateDmPolicyAllowFromDependency({
policy,
allowFrom: account.allowFrom ?? value.allowFrom
});
if (!violation) return;
const root = `channels.${channelId}`;
const owner = accountId === void 0 ? root : `${root}.accounts.*`;
const inherited = accountId === void 0 ? "" : ` (or ${root}.allowFrom)`;
const requirement = violation === "open_requires_wildcard" ? "include \"*\"" : "contain at least one sender ID";
ctx.addIssue({
code: ZodIssueCode.custom,
path: accountId === void 0 ? ["allowFrom"] : [
"accounts",
accountId,
"allowFrom"
],
message: `${owner}.dmPolicy="${policy}" requires ${owner}.allowFrom${inherited} to ${requirement}`
});
}
/** Canonical per-group/room channel policy shape. */
const ChannelGroupEntrySchema = object({
requireMention: boolean().optional(),
tools: ToolPolicySchema,
toolsBySender: record(string(), ToolPolicySchema).optional(),
skills: array(string()).optional(),
enabled: boolean().optional(),
allowFrom: AllowFromListSchema,
systemPrompt: string().optional()
}).strict();
/** Extend the canonical group/room policy shape with channel-owned fields. */
function buildGroupEntrySchema(extraShape, options) {
const omitted = new Set(options?.omit ?? []);
const baseShape = Object.fromEntries(Object.entries(ChannelGroupEntrySchema.shape).filter(([key]) => !omitted.has(key)));
return object({
...baseShape,
...extraShape ?? {}
}).strict();
}
/** Build the common nested DM config block used by channel account schemas. */
function buildNestedDmConfigSchema(extraShape) {
const baseShape = {
enabled: boolean().optional(),
policy: DmPolicySchema.optional(),
allowFrom: AllowFromListSchema
};
return object(extraShape ? {
...baseShape,
...extraShape
} : baseShape).optional();
}
/** Add `accounts` catchall and `defaultAccount` fields to a channel account schema. */
function buildCatchallMultiAccountChannelSchema(accountSchema) {
return buildMultiAccountChannelSchema(accountSchema, { accountsMode: "catchall" });
}
/** Add the standard accounts/defaultAccount envelope and optional shared account/root refinement. */
function buildMultiAccountChannelSchema(baseSchema, options = {}) {
const refine = options.refine;
const rawAccountSchema = options.accountSchema ?? baseSchema;
const accountSchema = refine ? rawAccountSchema.superRefine((value, ctx) => {
return refine(value, ctx);
}) : rawAccountSchema;
const accountValueSchema = options.optionalAccount ? accountSchema.optional() : accountSchema;
const accountsSchema = options.accountsMode === "catchall" ? object({}).catchall(accountValueSchema).optional() : record(string(), accountValueSchema).optional();
const channelSchema = baseSchema.extend({
accounts: accountsSchema,
defaultAccount: string().optional()
});
return refine ? channelSchema.superRefine((value, ctx) => {
return refine(value, ctx);
}) : channelSchema;
}
function cloneRuntimeIssue(issue) {
const record = issue && typeof issue === "object" ? issue : {};
const path = Array.isArray(record.path) ? record.path.filter((segment) => {
const kind = typeof segment;
return kind === "string" || kind === "number";
}) : void 0;
return {
...record,
...path ? { path } : {}
};
}
function safeParseRuntimeSchema(schema, value) {
const result = schema.safeParse(value);
if (result.success) return {
success: true,
data: result.data
};
return {
success: false,
issues: result.error.issues.map((issue) => cloneRuntimeIssue(issue))
};
}
function safeParseJsonSchema(schema, cacheKey, value) {
const result = validateJsonSchemaValue({
schema,
cacheKey,
value,
applyDefaults: true
});
if (result.ok) return {
success: true,
data: result.value
};
return {
success: false,
issues: result.errors.map((issue) => ({
path: parseJsonSchemaIssuePath(issue.path),
message: issue.message
}))
};
}
/** Build a channel config schema from JSON Schema with runtime validation/default support. */
function buildJsonChannelConfigSchema(schema, options) {
return {
schema,
...options?.uiHints ? { uiHints: options.uiHints } : {},
runtime: options?.runtime ?? { safeParse: (value) => safeParseJsonSchema(schema, options?.cacheKey ?? "channel-config-schema:json", value) }
};
}
/** Build a channel config schema from Zod, exporting JSON Schema when available. */
function buildChannelConfigSchema(schema, options) {
return {
schema: "_zod" in schema ? toJSONSchema(schema, {
target: "draft-07",
...options?.jsonSchemaMode ? { io: options.jsonSchemaMode } : {},
unrepresentable: "any"
}) : {
type: "object",
additionalProperties: true
},
...options?.uiHints ? { uiHints: options.uiHints } : {},
runtime: { safeParse: (value) => safeParseRuntimeSchema(schema, value) }
};
}
/** Return a channel config schema for channels that intentionally accept no config keys. */
function emptyChannelConfigSchema() {
return {
schema: {
type: "object",
additionalProperties: false,
properties: {}
},
runtime: { safeParse(value) {
if (value === void 0) return {
success: true,
data: void 0
};
if (!value || typeof value !== "object" || Array.isArray(value)) return {
success: false,
issues: [{
path: [],
message: "expected config object"
}]
};
if (Object.keys(value).length > 0) return {
success: false,
issues: [{
path: [],
message: "config must be empty"
}]
};
return {
success: true,
data: value
};
} }
};
}
//#endregion
export { buildGroupEntrySchema as a, buildNestedDmConfigSchema as c, buildChannelConfigSchema as i, emptyChannelConfigSchema as l, ChannelGroupEntrySchema as n, buildJsonChannelConfigSchema as o, buildCatchallMultiAccountChannelSchema as r, buildMultiAccountChannelSchema as s, AllowFromListSchema as t, refineChannelDmPolicy as u };