UNPKG

@gguf/claw

Version:

Multi-channel AI gateway with extensible messaging integrations

1,355 lines (1,343 loc) 217 kB
import { l as normalizeAgentId, n as DEFAULT_AGENT_ID } from "./session-key-9yEYlIQe.js"; import { j as resolveUserPath, k as resolveConfigDir, s as normalizeChatChannelId, t as CHANNEL_IDS, w as isRecord, z as isPlainObject$1 } from "./registry-C8pj8ctW.js"; import { n as resolveConfigPath, r as resolveDefaultConfigCandidates, s as resolveStateDir, u as resolveRequiredHomeDir } from "./paths-DJmOcr7Q.js"; import { J as resolveShellEnvFallbackTimeoutMs, U as DEFAULT_CONTEXT_TOKENS, X as shouldEnableShellEnvFallback, Y as shouldDeferShellEnvFallback, l as parseModelRef, q as loadShellEnvFallback } from "./model-selection-DQIwoYb8.js"; import { c as resolveDefaultAgentId, s as resolveAgentWorkspaceDir } from "./agent-scope-OWMdRegz.js"; import { c as normalizePluginsConfig, d as isPathInside, l as resolveEnableState, t as loadPluginManifestRegistry, u as resolveMemorySlotDecision } from "./manifest-registry-Lzj-fZNH.js"; import { createRequire } from "node:module"; import path from "node:path"; import fs from "node:fs"; import os from "node:os"; import JSON5 from "json5"; import { z } from "zod"; import { isDeepStrictEqual } from "node:util"; import crypto from "node:crypto"; import dotenv from "dotenv"; import AjvPkg from "ajv"; //#region src/infra/scp-host.ts const SSH_TOKEN = /^[A-Za-z0-9._-]+$/; const BRACKETED_IPV6 = /^\[[0-9A-Fa-f:.%]+\]$/; const WHITESPACE = /\s/; function hasControlOrWhitespace(value) { for (const char of value) { const code = char.charCodeAt(0); if (code <= 31 || code === 127 || WHITESPACE.test(char)) return true; } return false; } function normalizeScpRemoteHost(value) { if (typeof value !== "string") return; const trimmed = value.trim(); if (!trimmed) return; if (hasControlOrWhitespace(trimmed)) return; if (trimmed.startsWith("-") || trimmed.includes("/") || trimmed.includes("\\")) return; const firstAt = trimmed.indexOf("@"); const lastAt = trimmed.lastIndexOf("@"); let user; let host = trimmed; if (firstAt !== -1) { if (firstAt !== lastAt || firstAt === 0 || firstAt === trimmed.length - 1) return; user = trimmed.slice(0, firstAt); host = trimmed.slice(firstAt + 1); if (!SSH_TOKEN.test(user)) return; } if (!host || host.startsWith("-") || host.includes("@")) return; if (host.includes(":") && !BRACKETED_IPV6.test(host)) return; if (!SSH_TOKEN.test(host) && !BRACKETED_IPV6.test(host)) return; return user ? `${user}@${host}` : host; } function isSafeScpRemoteHost(value) { return normalizeScpRemoteHost(value) !== void 0; } //#endregion //#region src/media/inbound-path-policy.ts const WILDCARD_SEGMENT = "*"; const WINDOWS_DRIVE_ABS_RE = /^[A-Za-z]:\//; const WINDOWS_DRIVE_ROOT_RE = /^[A-Za-z]:$/; const DEFAULT_IMESSAGE_ATTACHMENT_ROOTS = ["/Users/*/Library/Messages/Attachments"]; function normalizePosixAbsolutePath(value) { const trimmed = value.trim(); if (!trimmed || trimmed.includes("\0")) return; const normalized = path.posix.normalize(trimmed.replaceAll("\\", "/")); if (!(normalized.startsWith("/") || WINDOWS_DRIVE_ABS_RE.test(normalized)) || normalized === "/") return; const withoutTrailingSlash = normalized.endsWith("/") ? normalized.slice(0, -1) : normalized; if (WINDOWS_DRIVE_ROOT_RE.test(withoutTrailingSlash)) return; return withoutTrailingSlash; } function splitPathSegments(value) { return value.split("/").filter(Boolean); } function matchesRootPattern(params) { const candidateSegments = splitPathSegments(params.candidatePath); const rootSegments = splitPathSegments(params.rootPattern); if (candidateSegments.length < rootSegments.length) return false; for (let idx = 0; idx < rootSegments.length; idx += 1) { const expected = rootSegments[idx]; const actual = candidateSegments[idx]; if (expected === WILDCARD_SEGMENT) continue; if (expected !== actual) return false; } return true; } function isValidInboundPathRootPattern(value) { const normalized = normalizePosixAbsolutePath(value); if (!normalized) return false; const segments = splitPathSegments(normalized); if (segments.length === 0) return false; return segments.every((segment) => segment === WILDCARD_SEGMENT || !segment.includes("*")); } function normalizeInboundPathRoots(roots) { const normalized = []; const seen = /* @__PURE__ */ new Set(); for (const root of roots ?? []) { if (typeof root !== "string") continue; if (!isValidInboundPathRootPattern(root)) continue; const candidate = normalizePosixAbsolutePath(root); if (!candidate || seen.has(candidate)) continue; seen.add(candidate); normalized.push(candidate); } return normalized; } function mergeInboundPathRoots(...rootsLists) { const merged = []; const seen = /* @__PURE__ */ new Set(); for (const roots of rootsLists) { const normalized = normalizeInboundPathRoots(roots); for (const root of normalized) { if (seen.has(root)) continue; seen.add(root); merged.push(root); } } return merged; } function isInboundPathAllowed(params) { const candidatePath = normalizePosixAbsolutePath(params.filePath); if (!candidatePath) return false; const roots = normalizeInboundPathRoots(params.roots); const effectiveRoots = roots.length > 0 ? roots : normalizeInboundPathRoots(params.fallbackRoots ?? void 0); if (effectiveRoots.length === 0) return false; return effectiveRoots.some((rootPattern) => matchesRootPattern({ candidatePath, rootPattern })); } function resolveIMessageAccountConfig(params) { const accountId = params.accountId?.trim(); if (!accountId) return; return params.cfg.channels?.imessage?.accounts?.[accountId]; } function resolveIMessageAttachmentRoots(params) { return mergeInboundPathRoots(resolveIMessageAccountConfig(params)?.attachmentRoots, params.cfg.channels?.imessage?.attachmentRoots, DEFAULT_IMESSAGE_ATTACHMENT_ROOTS); } function resolveIMessageRemoteAttachmentRoots(params) { const accountConfig = resolveIMessageAccountConfig(params); return mergeInboundPathRoots(accountConfig?.remoteAttachmentRoots, params.cfg.channels?.imessage?.remoteAttachmentRoots, accountConfig?.attachmentRoots, params.cfg.channels?.imessage?.attachmentRoots, DEFAULT_IMESSAGE_ATTACHMENT_ROOTS); } //#endregion //#region src/config/telegram-custom-commands.ts const TELEGRAM_COMMAND_NAME_PATTERN = /^[a-z0-9_]{1,32}$/; function normalizeTelegramCommandName(value) { const trimmed = value.trim(); if (!trimmed) return ""; return (trimmed.startsWith("/") ? trimmed.slice(1) : trimmed).trim().toLowerCase().replace(/-/g, "_"); } function normalizeTelegramCommandDescription(value) { return value.trim(); } function resolveTelegramCustomCommands(params) { const entries = Array.isArray(params.commands) ? params.commands : []; const reserved = params.reservedCommands ?? /* @__PURE__ */ new Set(); const checkReserved = params.checkReserved !== false; const checkDuplicates = params.checkDuplicates !== false; const seen = /* @__PURE__ */ new Set(); const resolved = []; const issues = []; for (let index = 0; index < entries.length; index += 1) { const entry = entries[index]; const normalized = normalizeTelegramCommandName(String(entry?.command ?? "")); if (!normalized) { issues.push({ index, field: "command", message: "Telegram custom command is missing a command name." }); continue; } if (!TELEGRAM_COMMAND_NAME_PATTERN.test(normalized)) { issues.push({ index, field: "command", message: `Telegram custom command "/${normalized}" is invalid (use a-z, 0-9, underscore; max 32 chars).` }); continue; } if (checkReserved && reserved.has(normalized)) { issues.push({ index, field: "command", message: `Telegram custom command "/${normalized}" conflicts with a native command.` }); continue; } if (checkDuplicates && seen.has(normalized)) { issues.push({ index, field: "command", message: `Telegram custom command "/${normalized}" is duplicated.` }); continue; } const description = normalizeTelegramCommandDescription(String(entry?.description ?? "")); if (!description) { issues.push({ index, field: "description", message: `Telegram custom command "/${normalized}" is missing a description.` }); continue; } if (checkDuplicates) seen.add(normalized); resolved.push({ command: normalized, description }); } return { commands: resolved, issues }; } //#endregion //#region src/cli/parse-duration.ts function parseDurationMs(raw, opts) { const trimmed = String(raw ?? "").trim().toLowerCase(); if (!trimmed) throw new Error("invalid duration (empty)"); const m = /^(\d+(?:\.\d+)?)(ms|s|m|h|d)?$/.exec(trimmed); if (!m) throw new Error(`invalid duration: ${raw}`); const value = Number(m[1]); if (!Number.isFinite(value) || value < 0) throw new Error(`invalid duration: ${raw}`); const unit = m[2] ?? opts?.defaultUnit ?? "ms"; const multiplier = unit === "ms" ? 1 : unit === "s" ? 1e3 : unit === "m" ? 6e4 : unit === "h" ? 36e5 : 864e5; const ms = Math.round(value * multiplier); if (!Number.isFinite(ms)) throw new Error(`invalid duration: ${raw}`); return ms; } //#endregion //#region src/config/zod-schema.agent-model.ts const AgentModelSchema = z.union([z.string(), z.object({ primary: z.string().optional(), fallbacks: z.array(z.string()).optional() }).strict()]); //#endregion //#region src/infra/exec-safety.ts const SHELL_METACHARS = /[;&|`$<>]/; const CONTROL_CHARS = /[\r\n]/; const QUOTE_CHARS = /["']/; const BARE_NAME_PATTERN = /^[A-Za-z0-9._+-]+$/; function isLikelyPath(value) { if (value.startsWith(".") || value.startsWith("~")) return true; if (value.includes("/") || value.includes("\\")) return true; return /^[A-Za-z]:[\\/]/.test(value); } function isSafeExecutableValue(value) { if (!value) return false; const trimmed = value.trim(); if (!trimmed) return false; if (trimmed.includes("\0")) return false; if (CONTROL_CHARS.test(trimmed)) return false; if (SHELL_METACHARS.test(trimmed)) return false; if (QUOTE_CHARS.test(trimmed)) return false; if (isLikelyPath(trimmed)) return true; if (trimmed.startsWith("-")) return false; return BARE_NAME_PATTERN.test(trimmed); } //#endregion //#region src/config/zod-schema.allowdeny.ts const AllowDenyActionSchema = z.union([z.literal("allow"), z.literal("deny")]); const AllowDenyChatTypeSchema = z.union([ z.literal("direct"), z.literal("group"), z.literal("channel"), z.literal("dm") ]).optional(); function createAllowDenyChannelRulesSchema() { return z.object({ default: AllowDenyActionSchema.optional(), rules: z.array(z.object({ action: AllowDenyActionSchema, match: z.object({ channel: z.string().optional(), chatType: AllowDenyChatTypeSchema, keyPrefix: z.string().optional(), rawKeyPrefix: z.string().optional() }).strict().optional() }).strict()).optional() }).strict().optional(); } //#endregion //#region src/config/zod-schema.sensitive.ts const sensitive = z.registry(); //#endregion //#region src/config/zod-schema.core.ts const ModelApiSchema = z.union([ z.literal("openai-completions"), z.literal("openai-responses"), z.literal("anthropic-messages"), z.literal("google-generative-ai"), z.literal("github-copilot"), z.literal("bedrock-converse-stream"), z.literal("ollama") ]); const ModelCompatSchema = z.object({ supportsStore: z.boolean().optional(), supportsDeveloperRole: z.boolean().optional(), supportsReasoningEffort: z.boolean().optional(), supportsUsageInStreaming: z.boolean().optional(), supportsStrictMode: z.boolean().optional(), maxTokensField: z.union([z.literal("max_completion_tokens"), z.literal("max_tokens")]).optional(), thinkingFormat: z.union([ z.literal("openai"), z.literal("zai"), z.literal("qwen") ]).optional(), requiresToolResultName: z.boolean().optional(), requiresAssistantAfterToolResult: z.boolean().optional(), requiresThinkingAsText: z.boolean().optional(), requiresMistralToolIds: z.boolean().optional() }).strict().optional(); const ModelDefinitionSchema = z.object({ id: z.string().min(1), name: z.string().min(1), api: ModelApiSchema.optional(), reasoning: z.boolean().optional(), input: z.array(z.union([z.literal("text"), z.literal("image")])).optional(), cost: z.object({ input: z.number().optional(), output: z.number().optional(), cacheRead: z.number().optional(), cacheWrite: z.number().optional() }).strict().optional(), contextWindow: z.number().positive().optional(), maxTokens: z.number().positive().optional(), headers: z.record(z.string(), z.string()).optional(), compat: ModelCompatSchema }).strict(); const ModelProviderSchema = z.object({ baseUrl: z.string().min(1), apiKey: z.string().optional().register(sensitive), auth: z.union([ z.literal("api-key"), z.literal("aws-sdk"), z.literal("oauth"), z.literal("token") ]).optional(), api: ModelApiSchema.optional(), headers: z.record(z.string(), z.string()).optional(), authHeader: z.boolean().optional(), models: z.array(ModelDefinitionSchema) }).strict(); const BedrockDiscoverySchema = z.object({ enabled: z.boolean().optional(), region: z.string().optional(), providerFilter: z.array(z.string()).optional(), refreshInterval: z.number().int().nonnegative().optional(), defaultContextWindow: z.number().int().positive().optional(), defaultMaxTokens: z.number().int().positive().optional() }).strict().optional(); const ModelsConfigSchema = z.object({ mode: z.union([z.literal("merge"), z.literal("replace")]).optional(), providers: z.record(z.string(), ModelProviderSchema).optional(), bedrockDiscovery: BedrockDiscoverySchema }).strict().optional(); const GroupChatSchema = z.object({ mentionPatterns: z.array(z.string()).optional(), historyLimit: z.number().int().positive().optional() }).strict().optional(); const DmConfigSchema = z.object({ historyLimit: z.number().int().min(0).optional() }).strict(); const IdentitySchema = z.object({ name: z.string().optional(), theme: z.string().optional(), emoji: z.string().optional(), avatar: z.string().optional() }).strict().optional(); const QueueModeSchema = z.union([ z.literal("steer"), z.literal("followup"), z.literal("collect"), z.literal("steer-backlog"), z.literal("steer+backlog"), z.literal("queue"), z.literal("interrupt") ]); const QueueDropSchema = z.union([ z.literal("old"), z.literal("new"), z.literal("summarize") ]); const ReplyToModeSchema = z.union([ z.literal("off"), z.literal("first"), z.literal("all") ]); const GroupPolicySchema = z.enum([ "open", "disabled", "allowlist" ]); const DmPolicySchema = z.enum([ "pairing", "allowlist", "open", "disabled" ]); const BlockStreamingCoalesceSchema = z.object({ minChars: z.number().int().positive().optional(), maxChars: z.number().int().positive().optional(), idleMs: z.number().int().nonnegative().optional() }).strict(); const BlockStreamingChunkSchema = z.object({ minChars: z.number().int().positive().optional(), maxChars: z.number().int().positive().optional(), breakPreference: z.union([ z.literal("paragraph"), z.literal("newline"), z.literal("sentence") ]).optional() }).strict(); const MarkdownTableModeSchema = z.enum([ "off", "bullets", "code" ]); const MarkdownConfigSchema = z.object({ tables: MarkdownTableModeSchema.optional() }).strict().optional(); const TtsProviderSchema = z.enum([ "elevenlabs", "openai", "edge" ]); const TtsModeSchema = z.enum(["final", "all"]); const TtsAutoSchema = z.enum([ "off", "always", "inbound", "tagged" ]); const TtsConfigSchema = z.object({ auto: TtsAutoSchema.optional(), enabled: z.boolean().optional(), mode: TtsModeSchema.optional(), provider: TtsProviderSchema.optional(), summaryModel: z.string().optional(), modelOverrides: z.object({ enabled: z.boolean().optional(), allowText: z.boolean().optional(), allowProvider: z.boolean().optional(), allowVoice: z.boolean().optional(), allowModelId: z.boolean().optional(), allowVoiceSettings: z.boolean().optional(), allowNormalization: z.boolean().optional(), allowSeed: z.boolean().optional() }).strict().optional(), elevenlabs: z.object({ apiKey: z.string().optional().register(sensitive), baseUrl: z.string().optional(), voiceId: z.string().optional(), modelId: z.string().optional(), seed: z.number().int().min(0).max(4294967295).optional(), applyTextNormalization: z.enum([ "auto", "on", "off" ]).optional(), languageCode: z.string().optional(), voiceSettings: z.object({ stability: z.number().min(0).max(1).optional(), similarityBoost: z.number().min(0).max(1).optional(), style: z.number().min(0).max(1).optional(), useSpeakerBoost: z.boolean().optional(), speed: z.number().min(.5).max(2).optional() }).strict().optional() }).strict().optional(), openai: z.object({ apiKey: z.string().optional().register(sensitive), model: z.string().optional(), voice: z.string().optional() }).strict().optional(), edge: z.object({ enabled: z.boolean().optional(), voice: z.string().optional(), lang: z.string().optional(), outputFormat: z.string().optional(), pitch: z.string().optional(), rate: z.string().optional(), volume: z.string().optional(), saveSubtitles: z.boolean().optional(), proxy: z.string().optional(), timeoutMs: z.number().int().min(1e3).max(12e4).optional() }).strict().optional(), prefsPath: z.string().optional(), maxTextLength: z.number().int().min(1).optional(), timeoutMs: z.number().int().min(1e3).max(12e4).optional() }).strict().optional(); const HumanDelaySchema = z.object({ mode: z.union([ z.literal("off"), z.literal("natural"), z.literal("custom") ]).optional(), minMs: z.number().int().nonnegative().optional(), maxMs: z.number().int().nonnegative().optional() }).strict(); const CliBackendWatchdogModeSchema = z.object({ noOutputTimeoutMs: z.number().int().min(1e3).optional(), noOutputTimeoutRatio: z.number().min(.05).max(.95).optional(), minMs: z.number().int().min(1e3).optional(), maxMs: z.number().int().min(1e3).optional() }).strict().optional(); const CliBackendSchema = z.object({ command: z.string(), args: z.array(z.string()).optional(), output: z.union([ z.literal("json"), z.literal("text"), z.literal("jsonl") ]).optional(), resumeOutput: z.union([ z.literal("json"), z.literal("text"), z.literal("jsonl") ]).optional(), input: z.union([z.literal("arg"), z.literal("stdin")]).optional(), maxPromptArgChars: z.number().int().positive().optional(), env: z.record(z.string(), z.string()).optional(), clearEnv: z.array(z.string()).optional(), modelArg: z.string().optional(), modelAliases: z.record(z.string(), z.string()).optional(), sessionArg: z.string().optional(), sessionArgs: z.array(z.string()).optional(), resumeArgs: z.array(z.string()).optional(), sessionMode: z.union([ z.literal("always"), z.literal("existing"), z.literal("none") ]).optional(), sessionIdFields: z.array(z.string()).optional(), systemPromptArg: z.string().optional(), systemPromptMode: z.union([z.literal("append"), z.literal("replace")]).optional(), systemPromptWhen: z.union([ z.literal("first"), z.literal("always"), z.literal("never") ]).optional(), imageArg: z.string().optional(), imageMode: z.union([z.literal("repeat"), z.literal("list")]).optional(), serialize: z.boolean().optional(), reliability: z.object({ watchdog: z.object({ fresh: CliBackendWatchdogModeSchema, resume: CliBackendWatchdogModeSchema }).strict().optional() }).strict().optional() }).strict(); const normalizeAllowFrom = (values) => (values ?? []).map((v) => String(v).trim()).filter(Boolean); const requireOpenAllowFrom = (params) => { if (params.policy !== "open") return; if (normalizeAllowFrom(params.allowFrom).includes("*")) return; params.ctx.addIssue({ code: z.ZodIssueCode.custom, path: params.path, message: params.message }); }; const MSTeamsReplyStyleSchema = z.enum(["thread", "top-level"]); const RetryConfigSchema = z.object({ attempts: z.number().int().min(1).optional(), minDelayMs: z.number().int().min(0).optional(), maxDelayMs: z.number().int().min(0).optional(), jitter: z.number().min(0).max(1).optional() }).strict().optional(); const QueueModeBySurfaceSchema = z.object({ whatsapp: QueueModeSchema.optional(), telegram: QueueModeSchema.optional(), discord: QueueModeSchema.optional(), irc: QueueModeSchema.optional(), slack: QueueModeSchema.optional(), mattermost: QueueModeSchema.optional(), signal: QueueModeSchema.optional(), imessage: QueueModeSchema.optional(), msteams: QueueModeSchema.optional(), webchat: QueueModeSchema.optional() }).strict().optional(); const DebounceMsBySurfaceSchema = z.record(z.string(), z.number().int().nonnegative()).optional(); const QueueSchema = z.object({ mode: QueueModeSchema.optional(), byChannel: QueueModeBySurfaceSchema, debounceMs: z.number().int().nonnegative().optional(), debounceMsByChannel: DebounceMsBySurfaceSchema, cap: z.number().int().positive().optional(), drop: QueueDropSchema.optional() }).strict().optional(); const InboundDebounceSchema = z.object({ debounceMs: z.number().int().nonnegative().optional(), byChannel: DebounceMsBySurfaceSchema }).strict().optional(); const TranscribeAudioSchema = z.object({ command: z.array(z.string()).superRefine((value, ctx) => { const executable = value[0]; if (!isSafeExecutableValue(executable)) ctx.addIssue({ code: z.ZodIssueCode.custom, path: [0], message: "expected safe executable name or path" }); }), timeoutSeconds: z.number().int().positive().optional() }).strict().optional(); const HexColorSchema = z.string().regex(/^#?[0-9a-fA-F]{6}$/, "expected hex color (RRGGBB)"); const ExecutableTokenSchema = z.string().refine(isSafeExecutableValue, "expected safe executable name or path"); const MediaUnderstandingScopeSchema = createAllowDenyChannelRulesSchema(); const MediaUnderstandingCapabilitiesSchema = z.array(z.union([ z.literal("image"), z.literal("audio"), z.literal("video") ])).optional(); const MediaUnderstandingAttachmentsSchema = z.object({ mode: z.union([z.literal("first"), z.literal("all")]).optional(), maxAttachments: z.number().int().positive().optional(), prefer: z.union([ z.literal("first"), z.literal("last"), z.literal("path"), z.literal("url") ]).optional() }).strict().optional(); const DeepgramAudioSchema = z.object({ detectLanguage: z.boolean().optional(), punctuate: z.boolean().optional(), smartFormat: z.boolean().optional() }).strict().optional(); const ProviderOptionValueSchema = z.union([ z.string(), z.number(), z.boolean() ]); const ProviderOptionsSchema = z.record(z.string(), z.record(z.string(), ProviderOptionValueSchema)).optional(); const MediaUnderstandingModelSchema = z.object({ provider: z.string().optional(), model: z.string().optional(), capabilities: MediaUnderstandingCapabilitiesSchema, type: z.union([z.literal("provider"), z.literal("cli")]).optional(), command: z.string().optional(), args: z.array(z.string()).optional(), prompt: z.string().optional(), maxChars: z.number().int().positive().optional(), maxBytes: z.number().int().positive().optional(), timeoutSeconds: z.number().int().positive().optional(), language: z.string().optional(), providerOptions: ProviderOptionsSchema, deepgram: DeepgramAudioSchema, baseUrl: z.string().optional(), headers: z.record(z.string(), z.string()).optional(), profile: z.string().optional(), preferredProfile: z.string().optional() }).strict().optional(); const ToolsMediaUnderstandingSchema = z.object({ enabled: z.boolean().optional(), scope: MediaUnderstandingScopeSchema, maxBytes: z.number().int().positive().optional(), maxChars: z.number().int().positive().optional(), prompt: z.string().optional(), timeoutSeconds: z.number().int().positive().optional(), language: z.string().optional(), providerOptions: ProviderOptionsSchema, deepgram: DeepgramAudioSchema, baseUrl: z.string().optional(), headers: z.record(z.string(), z.string()).optional(), attachments: MediaUnderstandingAttachmentsSchema, models: z.array(MediaUnderstandingModelSchema).optional() }).strict().optional(); const ToolsMediaSchema = z.object({ models: z.array(MediaUnderstandingModelSchema).optional(), concurrency: z.number().int().positive().optional(), image: ToolsMediaUnderstandingSchema.optional(), audio: ToolsMediaUnderstandingSchema.optional(), video: ToolsMediaUnderstandingSchema.optional() }).strict().optional(); const LinkModelSchema = z.object({ type: z.literal("cli").optional(), command: z.string().min(1), args: z.array(z.string()).optional(), timeoutSeconds: z.number().int().positive().optional() }).strict(); const ToolsLinksSchema = z.object({ enabled: z.boolean().optional(), scope: MediaUnderstandingScopeSchema, maxLinks: z.number().int().positive().optional(), timeoutSeconds: z.number().int().positive().optional(), models: z.array(LinkModelSchema).optional() }).strict().optional(); const NativeCommandsSettingSchema = z.union([z.boolean(), z.literal("auto")]); const ProviderCommandsSchema = z.object({ native: NativeCommandsSettingSchema.optional(), nativeSkills: NativeCommandsSettingSchema.optional() }).strict().optional(); //#endregion //#region src/config/zod-schema.agent-runtime.ts const HeartbeatSchema = z.object({ every: z.string().optional(), activeHours: z.object({ start: z.string().optional(), end: z.string().optional(), timezone: z.string().optional() }).strict().optional(), model: z.string().optional(), session: z.string().optional(), includeReasoning: z.boolean().optional(), target: z.string().optional(), to: z.string().optional(), accountId: z.string().optional(), prompt: z.string().optional(), ackMaxChars: z.number().int().nonnegative().optional(), suppressToolErrorWarnings: z.boolean().optional() }).strict().superRefine((val, ctx) => { if (!val.every) return; try { parseDurationMs(val.every, { defaultUnit: "m" }); } catch { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["every"], message: "invalid duration (use ms, s, m, h)" }); } const active = val.activeHours; if (!active) return; const timePattern = /^([01]\d|2[0-3]|24):([0-5]\d)$/; const validateTime = (raw, opts, path) => { if (!raw) return; if (!timePattern.test(raw)) { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["activeHours", path], message: "invalid time (use \"HH:MM\" 24h format)" }); return; } const [hourStr, minuteStr] = raw.split(":"); const hour = Number(hourStr); if (hour === 24 && Number(minuteStr) !== 0) { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["activeHours", path], message: "invalid time (24:00 is the only allowed 24:xx value)" }); return; } if (hour === 24 && !opts.allow24) ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["activeHours", path], message: "invalid time (start cannot be 24:00)" }); }; validateTime(active.start, { allow24: false }, "start"); validateTime(active.end, { allow24: true }, "end"); }).optional(); const SandboxDockerSchema = z.object({ image: z.string().optional(), containerPrefix: z.string().optional(), workdir: z.string().optional(), readOnlyRoot: z.boolean().optional(), tmpfs: z.array(z.string()).optional(), network: z.string().optional(), user: z.string().optional(), capDrop: z.array(z.string()).optional(), env: z.record(z.string(), z.string()).optional(), setupCommand: z.string().optional(), pidsLimit: z.number().int().positive().optional(), memory: z.union([z.string(), z.number()]).optional(), memorySwap: z.union([z.string(), z.number()]).optional(), cpus: z.number().positive().optional(), ulimits: z.record(z.string(), z.union([ z.string(), z.number(), z.object({ soft: z.number().int().nonnegative().optional(), hard: z.number().int().nonnegative().optional() }).strict() ])).optional(), seccompProfile: z.string().optional(), apparmorProfile: z.string().optional(), dns: z.array(z.string()).optional(), extraHosts: z.array(z.string()).optional(), binds: z.array(z.string()).optional() }).strict().superRefine((data, ctx) => { if (data.binds) for (let i = 0; i < data.binds.length; i += 1) { const bind = data.binds[i]?.trim() ?? ""; if (!bind) { ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["binds", i], message: "Sandbox security: bind mount entry must be a non-empty string." }); continue; } const firstColon = bind.indexOf(":"); const source = (firstColon <= 0 ? bind : bind.slice(0, firstColon)).trim(); if (!source.startsWith("/")) ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["binds", i], message: `Sandbox security: bind mount "${bind}" uses a non-absolute source path "${source}". Only absolute POSIX paths are supported for sandbox binds.` }); } if (data.network?.trim().toLowerCase() === "host") ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["network"], message: "Sandbox security: network mode \"host\" is blocked. Use \"bridge\" or \"none\" instead." }); if (data.seccompProfile?.trim().toLowerCase() === "unconfined") ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["seccompProfile"], message: "Sandbox security: seccomp profile \"unconfined\" is blocked. Use a custom seccomp profile file or omit this setting." }); if (data.apparmorProfile?.trim().toLowerCase() === "unconfined") ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["apparmorProfile"], message: "Sandbox security: apparmor profile \"unconfined\" is blocked. Use a named AppArmor profile or omit this setting." }); }).optional(); const SandboxBrowserSchema = z.object({ enabled: z.boolean().optional(), image: z.string().optional(), containerPrefix: z.string().optional(), cdpPort: z.number().int().positive().optional(), vncPort: z.number().int().positive().optional(), noVncPort: z.number().int().positive().optional(), headless: z.boolean().optional(), enableNoVnc: z.boolean().optional(), allowHostControl: z.boolean().optional(), autoStart: z.boolean().optional(), autoStartTimeoutMs: z.number().int().positive().optional(), binds: z.array(z.string()).optional() }).strict().optional(); const SandboxPruneSchema = z.object({ idleHours: z.number().int().nonnegative().optional(), maxAgeDays: z.number().int().nonnegative().optional() }).strict().optional(); const ToolPolicyBaseSchema = z.object({ allow: z.array(z.string()).optional(), alsoAllow: z.array(z.string()).optional(), deny: z.array(z.string()).optional() }).strict(); const ToolPolicySchema = ToolPolicyBaseSchema.superRefine((value, ctx) => { if (value.allow && value.allow.length > 0 && value.alsoAllow && value.alsoAllow.length > 0) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "tools policy cannot set both allow and alsoAllow in the same scope (merge alsoAllow into allow, or remove allow and use profile + alsoAllow)" }); }).optional(); const ToolsWebSearchSchema = z.object({ enabled: z.boolean().optional(), provider: z.union([ z.literal("brave"), z.literal("perplexity"), z.literal("grok") ]).optional(), apiKey: z.string().optional().register(sensitive), maxResults: z.number().int().positive().optional(), timeoutSeconds: z.number().int().positive().optional(), cacheTtlMinutes: z.number().nonnegative().optional(), perplexity: z.object({ apiKey: z.string().optional().register(sensitive), baseUrl: z.string().optional(), model: z.string().optional() }).strict().optional(), grok: z.object({ apiKey: z.string().optional().register(sensitive), model: z.string().optional(), inlineCitations: z.boolean().optional() }).strict().optional() }).strict().optional(); const ToolsWebFetchSchema = z.object({ enabled: z.boolean().optional(), maxChars: z.number().int().positive().optional(), maxCharsCap: z.number().int().positive().optional(), timeoutSeconds: z.number().int().positive().optional(), cacheTtlMinutes: z.number().nonnegative().optional(), maxRedirects: z.number().int().nonnegative().optional(), userAgent: z.string().optional() }).strict().optional(); const ToolsWebSchema = z.object({ search: ToolsWebSearchSchema, fetch: ToolsWebFetchSchema }).strict().optional(); const ToolProfileSchema = z.union([ z.literal("minimal"), z.literal("coding"), z.literal("messaging"), z.literal("full") ]).optional(); function addAllowAlsoAllowConflictIssue(value, ctx, message) { if (value.allow && value.allow.length > 0 && value.alsoAllow && value.alsoAllow.length > 0) ctx.addIssue({ code: z.ZodIssueCode.custom, message }); } const ToolPolicyWithProfileSchema = z.object({ allow: z.array(z.string()).optional(), alsoAllow: z.array(z.string()).optional(), deny: z.array(z.string()).optional(), profile: ToolProfileSchema }).strict().superRefine((value, ctx) => { addAllowAlsoAllowConflictIssue(value, ctx, "tools.byProvider policy cannot set both allow and alsoAllow in the same scope (merge alsoAllow into allow, or remove allow and use profile + alsoAllow)"); }); const ElevatedAllowFromSchema = z.record(z.string(), z.array(z.union([z.string(), z.number()]))).optional(); const ToolExecApplyPatchSchema = z.object({ enabled: z.boolean().optional(), workspaceOnly: z.boolean().optional(), allowModels: z.array(z.string()).optional() }).strict().optional(); const ToolExecBaseShape = { host: z.enum([ "sandbox", "gateway", "node" ]).optional(), security: z.enum([ "deny", "allowlist", "full" ]).optional(), ask: z.enum([ "off", "on-miss", "always" ]).optional(), node: z.string().optional(), pathPrepend: z.array(z.string()).optional(), safeBins: z.array(z.string()).optional(), backgroundMs: z.number().int().positive().optional(), timeoutSec: z.number().int().positive().optional(), cleanupMs: z.number().int().positive().optional(), notifyOnExit: z.boolean().optional(), notifyOnExitEmptySuccess: z.boolean().optional(), applyPatch: ToolExecApplyPatchSchema }; const AgentToolExecSchema = z.object({ ...ToolExecBaseShape, approvalRunningNoticeMs: z.number().int().nonnegative().optional() }).strict().optional(); const ToolExecSchema = z.object(ToolExecBaseShape).strict().optional(); const ToolFsSchema = z.object({ workspaceOnly: z.boolean().optional() }).strict().optional(); const ToolLoopDetectionDetectorSchema = z.object({ genericRepeat: z.boolean().optional(), knownPollNoProgress: z.boolean().optional(), pingPong: z.boolean().optional() }).strict().optional(); const ToolLoopDetectionSchema = z.object({ enabled: z.boolean().optional(), historySize: z.number().int().positive().optional(), warningThreshold: z.number().int().positive().optional(), criticalThreshold: z.number().int().positive().optional(), globalCircuitBreakerThreshold: z.number().int().positive().optional(), detectors: ToolLoopDetectionDetectorSchema }).strict().superRefine((value, ctx) => { if (value.warningThreshold !== void 0 && value.criticalThreshold !== void 0 && value.warningThreshold >= value.criticalThreshold) ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["criticalThreshold"], message: "tools.loopDetection.warningThreshold must be lower than criticalThreshold." }); if (value.criticalThreshold !== void 0 && value.globalCircuitBreakerThreshold !== void 0 && value.criticalThreshold >= value.globalCircuitBreakerThreshold) ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["globalCircuitBreakerThreshold"], message: "tools.loopDetection.criticalThreshold must be lower than globalCircuitBreakerThreshold." }); }).optional(); const AgentSandboxSchema = z.object({ mode: z.union([ z.literal("off"), z.literal("non-main"), z.literal("all") ]).optional(), workspaceAccess: z.union([ z.literal("none"), z.literal("ro"), z.literal("rw") ]).optional(), sessionToolsVisibility: z.union([z.literal("spawned"), z.literal("all")]).optional(), scope: z.union([ z.literal("session"), z.literal("agent"), z.literal("shared") ]).optional(), perSession: z.boolean().optional(), workspaceRoot: z.string().optional(), docker: SandboxDockerSchema, browser: SandboxBrowserSchema, prune: SandboxPruneSchema }).strict().optional(); const AgentToolsSchema = z.object({ profile: ToolProfileSchema, allow: z.array(z.string()).optional(), alsoAllow: z.array(z.string()).optional(), deny: z.array(z.string()).optional(), byProvider: z.record(z.string(), ToolPolicyWithProfileSchema).optional(), elevated: z.object({ enabled: z.boolean().optional(), allowFrom: ElevatedAllowFromSchema }).strict().optional(), exec: AgentToolExecSchema, fs: ToolFsSchema, loopDetection: ToolLoopDetectionSchema, sandbox: z.object({ tools: ToolPolicySchema }).strict().optional() }).strict().superRefine((value, ctx) => { addAllowAlsoAllowConflictIssue(value, ctx, "agent tools cannot set both allow and alsoAllow in the same scope (merge alsoAllow into allow, or remove allow and use profile + alsoAllow)"); }).optional(); const MemorySearchSchema = z.object({ enabled: z.boolean().optional(), sources: z.array(z.union([z.literal("memory"), z.literal("sessions")])).optional(), extraPaths: z.array(z.string()).optional(), experimental: z.object({ sessionMemory: z.boolean().optional() }).strict().optional(), provider: z.union([ z.literal("openai"), z.literal("local"), z.literal("gemini"), z.literal("voyage") ]).optional(), remote: z.object({ baseUrl: z.string().optional(), apiKey: z.string().optional().register(sensitive), headers: z.record(z.string(), z.string()).optional(), batch: z.object({ enabled: z.boolean().optional(), wait: z.boolean().optional(), concurrency: z.number().int().positive().optional(), pollIntervalMs: z.number().int().nonnegative().optional(), timeoutMinutes: z.number().int().positive().optional() }).strict().optional() }).strict().optional(), fallback: z.union([ z.literal("openai"), z.literal("gemini"), z.literal("local"), z.literal("voyage"), z.literal("none") ]).optional(), model: z.string().optional(), local: z.object({ modelPath: z.string().optional(), modelCacheDir: z.string().optional() }).strict().optional(), store: z.object({ driver: z.literal("sqlite").optional(), path: z.string().optional(), vector: z.object({ enabled: z.boolean().optional(), extensionPath: z.string().optional() }).strict().optional() }).strict().optional(), chunking: z.object({ tokens: z.number().int().positive().optional(), overlap: z.number().int().nonnegative().optional() }).strict().optional(), sync: z.object({ onSessionStart: z.boolean().optional(), onSearch: z.boolean().optional(), watch: z.boolean().optional(), watchDebounceMs: z.number().int().nonnegative().optional(), intervalMinutes: z.number().int().nonnegative().optional(), sessions: z.object({ deltaBytes: z.number().int().nonnegative().optional(), deltaMessages: z.number().int().nonnegative().optional() }).strict().optional() }).strict().optional(), query: z.object({ maxResults: z.number().int().positive().optional(), minScore: z.number().min(0).max(1).optional(), hybrid: z.object({ enabled: z.boolean().optional(), vectorWeight: z.number().min(0).max(1).optional(), textWeight: z.number().min(0).max(1).optional(), candidateMultiplier: z.number().int().positive().optional(), mmr: z.object({ enabled: z.boolean().optional(), lambda: z.number().min(0).max(1).optional() }).strict().optional(), temporalDecay: z.object({ enabled: z.boolean().optional(), halfLifeDays: z.number().int().positive().optional() }).strict().optional() }).strict().optional() }).strict().optional(), cache: z.object({ enabled: z.boolean().optional(), maxEntries: z.number().int().positive().optional() }).strict().optional() }).strict().optional(); const AgentEntrySchema = z.object({ id: z.string(), default: z.boolean().optional(), name: z.string().optional(), workspace: z.string().optional(), agentDir: z.string().optional(), model: AgentModelSchema.optional(), skills: z.array(z.string()).optional(), memorySearch: MemorySearchSchema, humanDelay: HumanDelaySchema.optional(), heartbeat: HeartbeatSchema, identity: IdentitySchema, groupChat: GroupChatSchema, subagents: z.object({ allowAgents: z.array(z.string()).optional(), model: z.union([z.string(), z.object({ primary: z.string().optional(), fallbacks: z.array(z.string()).optional() }).strict()]).optional(), thinking: z.string().optional() }).strict().optional(), sandbox: AgentSandboxSchema, tools: AgentToolsSchema }).strict(); const ToolsSchema = z.object({ profile: ToolProfileSchema, allow: z.array(z.string()).optional(), alsoAllow: z.array(z.string()).optional(), deny: z.array(z.string()).optional(), byProvider: z.record(z.string(), ToolPolicyWithProfileSchema).optional(), web: ToolsWebSchema, media: ToolsMediaSchema, links: ToolsLinksSchema, sessions: z.object({ visibility: z.enum([ "self", "tree", "agent", "all" ]).optional() }).strict().optional(), loopDetection: ToolLoopDetectionSchema, message: z.object({ allowCrossContextSend: z.boolean().optional(), crossContext: z.object({ allowWithinProvider: z.boolean().optional(), allowAcrossProviders: z.boolean().optional(), marker: z.object({ enabled: z.boolean().optional(), prefix: z.string().optional(), suffix: z.string().optional() }).strict().optional() }).strict().optional(), broadcast: z.object({ enabled: z.boolean().optional() }).strict().optional() }).strict().optional(), agentToAgent: z.object({ enabled: z.boolean().optional(), allow: z.array(z.string()).optional() }).strict().optional(), elevated: z.object({ enabled: z.boolean().optional(), allowFrom: ElevatedAllowFromSchema }).strict().optional(), exec: ToolExecSchema, fs: ToolFsSchema, subagents: z.object({ tools: ToolPolicySchema }).strict().optional(), sandbox: z.object({ tools: ToolPolicySchema }).strict().optional() }).strict().superRefine((value, ctx) => { addAllowAlsoAllowConflictIssue(value, ctx, "tools cannot set both allow and alsoAllow in the same scope (merge alsoAllow into allow, or remove allow and use profile + alsoAllow)"); }).optional(); //#endregion //#region src/config/zod-schema.channels.ts const ChannelHeartbeatVisibilitySchema = z.object({ showOk: z.boolean().optional(), showAlerts: z.boolean().optional(), useIndicator: z.boolean().optional() }).strict().optional(); //#endregion //#region src/config/zod-schema.providers-core.ts const ToolPolicyBySenderSchema$1 = z.record(z.string(), ToolPolicySchema).optional(); const DiscordIdSchema = z.union([z.string(), z.number()]).refine((value) => typeof value === "string", { message: "Discord IDs must be strings (wrap numeric IDs in quotes)." }); const DiscordIdListSchema = z.array(DiscordIdSchema); const TelegramInlineButtonsScopeSchema = z.enum([ "off", "dm", "group", "all", "allowlist" ]); const TelegramCapabilitiesSchema = z.union([z.array(z.string()), z.object({ inlineButtons: TelegramInlineButtonsScopeSchema.optional() }).strict()]); const TelegramTopicSchema = z.object({ requireMention: z.boolean().optional(), groupPolicy: GroupPolicySchema.optional(), skills: z.array(z.string()).optional(), enabled: z.boolean().optional(), allowFrom: z.array(z.union([z.string(), z.number()])).optional(), systemPrompt: z.string().optional() }).strict(); const TelegramGroupSchema = z.object({ requireMention: z.boolean().optional(), groupPolicy: GroupPolicySchema.optional(), tools: ToolPolicySchema, toolsBySender: ToolPolicyBySenderSchema$1, skills: z.array(z.string()).optional(), enabled: z.boolean().optional(), allowFrom: z.array(z.union([z.string(), z.number()])).optional(), systemPrompt: z.string().optional(), topics: z.record(z.string(), TelegramTopicSchema.optional()).optional() }).strict(); const TelegramCustomCommandSchema = z.object({ command: z.string().transform(normalizeTelegramCommandName), description: z.string().transform(normalizeTelegramCommandDescription) }).strict(); const validateTelegramCustomCommands = (value, ctx) => { if (!value.customCommands || value.customCommands.length === 0) return; const { issues } = resolveTelegramCustomCommands({ commands: value.customCommands, checkReserved: false, checkDuplicates: false }); for (const issue of issues) ctx.addIssue({ code: z.ZodIssueCode.custom, path: [ "customCommands", issue.index, issue.field ], message: issue.message }); }; const TelegramAccountSchemaBase = z.object({ name: z.string().optional(), capabilities: TelegramCapabilitiesSchema.optional(), markdown: MarkdownConfigSchema, enabled: z.boolean().optional(), commands: ProviderCommandsSchema, customCommands: z.array(TelegramCustomCommandSchema).optional(), configWrites: z.boolean().optional(), dmPolicy: DmPolicySchema.optional().default("pairing"), botToken: z.string().optional().register(sensitive), tokenFile: z.string().optional(), replyToMode: ReplyToModeSchema.optional(), groups: z.record(z.string(), TelegramGroupSchema.optional()).optional(), allowFrom: z.array(z.union([z.string(), z.number()])).optional(), defaultTo: z.union([z.string(), z.number()]).optional(), groupAllowFrom: z.array(z.union([z.string(), z.number()])).optional(), groupPolicy: GroupPolicySchema.optional().default("allowlist"), historyLimit: z.number().int().min(0).optional(), dmHistoryLimit: z.number().int().min(0).optional(), dms: z.record(z.string(), DmConfigSchema.optional()).optional(), textChunkLimit: z.number().int().positive().optional(), chunkMode: z.enum(["length", "newline"]).optional(), blockStreaming: z.boolean().optional(), draftChunk: BlockStreamingChunkSchema.optional(), blockStreamingCoalesce: BlockStreamingCoalesceSchema.optional(), streamMode: z.enum([ "off", "partial", "block" ]).optional().default("partial"), mediaMaxMb: z.number().positive().optional(), timeoutSeconds: z.number().int().positive().optional(), retry: RetryConfigSchema, network: z.object({ autoSelectFamily: z.boolean().optional() }).strict().optional(), proxy: z.string().optional(), webhookUrl: z.string().optional(), webhookSecret: z.string().optional().register(sensitive), webhookPath: z.string().optional(), webhookHost: z.string().optional(), actions: z.object({ reactions: z.boolean().optional(), sendMessage: z.boolean().optional(), deleteMessage: z.boolean().optional(), sticker: z.boolean().optional() }).strict().optional(), reactionNotifications: z.enum([ "off", "own", "all" ]).optional(), reactionLevel: z.enum([ "off", "ack", "minimal", "extensive" ]).optional(), heartbeat: ChannelHeartbeatVisibilitySchema, linkPreview: z.boolean().optional(), responsePrefix: z.string().optional(), ackReaction: z.string().optional() }).strict(); const TelegramAccountSchema = TelegramAccountSchemaBase.superRefine((value, ctx) => { requireOpenAllowFrom({ policy: value.dmPolicy, allowFrom: value.allowFrom, ctx, path: ["allowFrom"], message: "channels.telegram.dmPolicy=\"open\" requires channels.telegram.allowFrom to include \"*\"" }); validateTelegramCustomCommands(value, ctx); }); const TelegramConfigSchema = TelegramAccountSchemaBase.extend({ accounts: z.record(z.string(), TelegramAccountSchema.optional()).optional() }).superRefine((value, ctx) => { requireOpenAllowFrom({ policy: value.dmPolicy, allowFrom: value.allowFrom, ctx, path: ["allowFrom"], message: "channels.telegram.dmPolicy=\"open\" requires channels.telegram.allowFrom to include \"*\"" }); validateTelegramCustomCommands(value, ctx); const baseWebhookUrl = typeof value.webhookUrl === "string" ? value.webhookUrl.trim() : ""; const baseWebhookSecret = typeof value.webhookSecret === "string" ? value.webhookSecret.trim() : ""; if (baseWebhookUrl && !baseWebhookSecret) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "channels.telegram.webhookUrl requires channels.telegram.webhookSecret", path: ["webhookSecret"] }); if (!value.accounts) return; for (const [accountId, account] of Object.entries(value.accounts)) { if (!account) continue; if (account.enabled === false) continue; if (!(typeof account.webhookUrl === "string" ? account.webhookUrl.trim() : "")) continue; if (!(typeof account.webhookSecret === "string" ? account.webhookSecret.trim() : "") && !baseWebhookSecret) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "channels.telegram.accounts.*.webhookUrl requires channels.telegram.webhookSecret or channels.telegram.accounts.*.webhookSecret", path: [ "accounts", accountId, "webhookSecret" ] }); } }); const DiscordDmSchema = z.object({ enabled: z.boolean().optional(), policy: DmPolicySchema.optional(), allowFrom: DiscordIdListSchema.optional(), groupEnabled: z.boolean().optional(), groupChannels: DiscordIdListSchema.optional() }).strict(); const DiscordGuildChannelSchema = z.object({ allow: z.boolean().optional(), requireMention: z.boolean().optional(), tools: ToolPolicySchema, toolsBySender: ToolPolicyBySenderSchema$1, skills: z.array(z.string()).optional(), enabled: z.boolean().optional(), users: DiscordIdListSchema.optional(), roles: DiscordIdListSchema.optional(), systemPrompt: z.string().optional(), includeThreadStarter: z.boolean().optional(), autoThread: z.boolean().optional() }).strict(); const DiscordGuildSchema = z.object({ slug: z.string().optional(), requireMention: z.boolean().optional(), tools: ToolPolicySchema, toolsBySender: ToolPolicyBySenderSchema$1, reactionNotifications: z.enum([ "off", "own", "all", "allowlist" ]).optional(), users: DiscordIdListSchema.optional(), roles: DiscordIdListSchema.optional(), channels: z.record(z.string(), DiscordGuildChannelSchema.optional()).optional() }).strict(); const DiscordUiSchema = z.object({ components: z.object({ accentColor: HexColorSchema.optional() }).strict().optional() }).strict().optional(); const DiscordVoiceAutoJoinSchema = z.object({ guildId: z.string().min(1), channelId: z.string().mi