import { z } from 'zod'; // --------------------------------------------------------------------------- // Mattermost // --------------------------------------------------------------------------- export const MattermostDmConfigSchema = z.object({ enabled: z.boolean().default(true), allowFrom: z.array(z.string()).default([]), }); export type MattermostDmConfig = z.infer; export const MattermostConfigSchema = z.object({ serverUrl: z.string(), token: z.string(), scheme: z.enum(['https', 'http']).default('https'), port: z.number().int().default(443), basePath: z.string().default(''), allowFrom: z.array(z.string()).default([]), groupPolicy: z.enum(['open', 'mention', 'allowlist']).default('mention'), groupAllowFrom: z.array(z.string()).default([]), dm: MattermostDmConfigSchema.default(() => ({ enabled: true, allowFrom: [] })), replyInThread: z.boolean().default(true), }); export type MattermostConfig = z.infer; // --------------------------------------------------------------------------- // Channels // --------------------------------------------------------------------------- export const ChannelsConfigSchema = z.object({ mattermost: MattermostConfigSchema.optional(), sendProgress: z.boolean().default(true), sendToolHints: z.boolean().default(true), }); export type ChannelsConfig = z.infer; // --------------------------------------------------------------------------- // Agent // --------------------------------------------------------------------------- export const AgentConfigSchema = z.object({ model: z.string().default('anthropic/claude-sonnet-4-5'), workspacePath: z.string().default('~/.nanobot'), maxTokens: z.number().int().default(4096), contextWindowTokens: z.number().int().default(65536), temperature: z.number().default(0.7), maxToolIterations: z.number().int().default(40), }); export type AgentConfig = z.infer; // --------------------------------------------------------------------------- // Providers // --------------------------------------------------------------------------- export const ProviderConfigSchema = z.object({ apiKey: z.string().optional(), apiBase: z.string().optional(), }); export type ProviderConfig = z.infer; export const ProvidersConfigSchema = z.object({ anthropic: ProviderConfigSchema.optional(), openai: ProviderConfigSchema.optional(), google: ProviderConfigSchema.optional(), openrouter: ProviderConfigSchema.optional(), ollama: ProviderConfigSchema.optional(), }); export type ProvidersConfig = z.infer; // --------------------------------------------------------------------------- // Tools // --------------------------------------------------------------------------- export const ExecToolConfigSchema = z.object({ timeout: z.number().int().default(120), pathAppend: z.string().optional(), denyPatterns: z.array(z.string()).default([]), restrictToWorkspace: z.boolean().default(false), }); export type ExecToolConfig = z.infer; export const WebToolConfigSchema = z.object({ braveApiKey: z.string().optional(), proxy: z.string().optional(), }); export type WebToolConfig = z.infer; export const ToolsConfigSchema = z.object({ exec: ExecToolConfigSchema.default(() => ({ timeout: 120, denyPatterns: [], restrictToWorkspace: false, })), web: WebToolConfigSchema.default(() => ({})), restrictToWorkspace: z.boolean().default(false), }); export type ToolsConfig = z.infer; // --------------------------------------------------------------------------- // Heartbeat // --------------------------------------------------------------------------- export const HeartbeatConfigSchema = z.object({ enabled: z.boolean().default(false), intervalMinutes: z.number().int().default(30), }); export type HeartbeatConfig = z.infer; // --------------------------------------------------------------------------- // Root config // --------------------------------------------------------------------------- export const ConfigSchema = z.object({ agent: AgentConfigSchema.default(() => ({ model: 'anthropic/claude-sonnet-4-5', workspacePath: '~/.nanobot', maxTokens: 4096, contextWindowTokens: 65536, temperature: 0.7, maxToolIterations: 40, })), providers: ProvidersConfigSchema.default(() => ({})), channels: ChannelsConfigSchema.default(() => ({ sendProgress: true, sendToolHints: true })), tools: ToolsConfigSchema.default(() => ({ exec: { timeout: 120, denyPatterns: [], restrictToWorkspace: false }, web: {}, restrictToWorkspace: false, })), heartbeat: HeartbeatConfigSchema.default(() => ({ enabled: false, intervalMinutes: 30 })), }); export type Config = z.infer;