diff --git a/src/daemon/index.ts b/src/daemon/index.ts index 9294fb0..9292a25 100644 --- a/src/daemon/index.ts +++ b/src/daemon/index.ts @@ -4,12 +4,12 @@ import type { AudioTranscriptionConfig } from '../models/media.js'; import type { Attachment } from '../channels/types.js'; import { isSupportedAudio, transcribeAudio } from '../models/media.js'; import { AnthropicClient, OpenAIClient, OllamaClient, LlamaCppClient, GeminiClient, BedrockClient, GitHubModelsClient, ModelRouter, DEFAULT_RETRY_CONFIG } from '../models/index.js'; -import type { ModelClient, RetryConfig } from '../models/index.js'; +import type { ModelClient, RetryConfig, ModelTier } from '../models/index.js'; import { AgentOrchestrator, type DelegationConfig } from '../backends/index.js'; import { OutboundAttachmentCollector } from '../backends/native/attachments.js'; import { SessionStore, SessionManager } from '../session/index.js'; import { HookEngine } from '../hooks/index.js'; -import { ToolRegistry, ToolExecutor, ToolPolicy, allBuiltinTools, createWebSearchTools, createProcessTools, ProcessManager, BrowserManager, createBrowserTools, createMediaSendTool } from '../tools/index.js'; +import { ToolRegistry, ToolExecutor, ToolPolicy, allBuiltinTools, createWebSearchTools, createProcessTools, ProcessManager, BrowserManager, createBrowserTools, createMediaSendTool, createSessionTools, createAgentsListTool, createMessageSendTool, createCronTools } from '../tools/index.js'; import type { Tool } from '../tools/types.js'; import { MemoryStore } from '../memory/index.js'; import { createMemoryTools } from '../tools/builtin/index.js'; @@ -160,6 +160,26 @@ function createModelRouter(config: Config): ModelRouter { } } + // Build per-tier fallbacks from inline fallback config + const tierFallbacks = new Map(); + if (models.default.fallback) { + tierFallbacks.set('default', [createClientFromConfig(models.default.fallback)]); + } + if (models.fast?.fallback) { + tierFallbacks.set('fast', [createClientFromConfig(models.fast.fallback)]); + } + if (models.complex?.fallback) { + tierFallbacks.set('complex', [createClientFromConfig(models.complex.fallback)]); + } + if (models.local?.fallback) { + tierFallbacks.set('local', [createClientFromConfig(models.local.fallback)]); + } + + if (tierFallbacks.size > 0) { + const tierNames = Array.from(tierFallbacks.keys()).join(', '); + console.log(`Per-tier fallbacks configured for: ${tierNames}`); + } + console.log(`Model router: default=${models.default.provider}/${models.default.model}, ` + `fallback=[${models.fallback_chain.join(', ')}]`); @@ -182,6 +202,7 @@ function createModelRouter(config: Config): ModelRouter { complex: complexClient, local: localClient, fallbackChain, + tierFallbacks, retryConfig, labels: { default: `${models.default.provider}/${models.default.model}`, @@ -683,12 +704,33 @@ export async function startDaemon(config: Config): Promise { channelRegistry.register(webChatAdapter); // Register cron scheduler adapter (if any cron jobs configured) + let cronScheduler: CronScheduler | undefined; if (config.automation.cron.length > 0) { - const cronScheduler = new CronScheduler(config.automation.cron, channelRegistry); + cronScheduler = new CronScheduler(config.automation.cron, channelRegistry); channelRegistry.register(cronScheduler); console.log(`Registered ${config.automation.cron.length} cron job(s)`); } + // ── Register Tier 1 agent tools ───────────────────────────── + + // Session management tools (list, history, create, delete) + for (const tool of createSessionTools(sessionManager)) { + toolRegistry.register(tool); + } + + // Agent discovery tool + toolRegistry.register(createAgentsListTool(agentConfigRegistry)); + + // Cross-channel messaging tool + toolRegistry.register(createMessageSendTool(channelRegistry)); + + // Cron management tools (if scheduler is active) + if (cronScheduler) { + for (const tool of createCronTools(cronScheduler)) { + toolRegistry.register(tool); + } + } + // ── Signal Handlers ─────────────────────────────────────────── const signalHandler = () => {