feat: wire up all Phase 2-6 features into daemon and config

Integrate all new features into the shared infrastructure:
- Config schema: add memory, discord, slack, process, web_search schemas
- Daemon wiring: memory store init, tool registration, channel adapters
- Orchestrator: memory injection into system prompt, extraction on compaction
- Agent: add setSystemPrompt() for dynamic prompt updates
- Channel/tool index: export new adapters and tool factories
- Add @slack/bolt, discord.js, turndown, linkedom, @mozilla/readability deps
- Update state.json with Phase 3b completion (494 tests passing)
This commit is contained in:
William Valentin
2026-02-06 14:24:39 -08:00
parent 6d9e27a591
commit 7a35b22458
12 changed files with 1099 additions and 4 deletions
+72 -2
View File
@@ -5,9 +5,11 @@ import type { ModelClient } from '../models/index.js';
import { AgentOrchestrator, type DelegationConfig } from '../backends/index.js';
import { SessionStore, SessionManager } from '../session/index.js';
import { HookEngine } from '../hooks/index.js';
import { ToolRegistry, ToolExecutor, allBuiltinTools } from '../tools/index.js';
import { ToolRegistry, ToolExecutor, allBuiltinTools, createWebSearchTools, createProcessTools, ProcessManager } from '../tools/index.js';
import { MemoryStore } from '../memory/index.js';
import { createMemoryTools } from '../tools/builtin/index.js';
import { GatewayServer } from '../gateway/index.js';
import { ChannelRegistry, TelegramAdapter, WebChatAdapter } from '../channels/index.js';
import { ChannelRegistry, TelegramAdapter, WebChatAdapter, DiscordAdapter, SlackAdapter } from '../channels/index.js';
import { CronScheduler } from '../automation/index.js';
import type { InboundMessage, OutboundMessage } from '../channels/index.js';
import { McpManager } from '../mcp/index.js';
@@ -144,6 +146,7 @@ function createMessageRouter(deps: {
toolRegistry: ToolRegistry;
toolExecutor: ToolExecutor;
config: Config;
memoryStore?: MemoryStore;
}) {
// Cache agents by session ID to avoid recreating on every message
const agents = new Map<string, AgentOrchestrator>();
@@ -176,6 +179,7 @@ function createMessageRouter(deps: {
} : undefined,
modelName: deps.config.models.default.model,
contextWindow: deps.config.models.default.context_window,
memoryStore: deps.memoryStore,
});
agents.set(sessionId, agent);
}
@@ -228,6 +232,13 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
const dataDir = resolve(homedir(), '.local/share/flynn');
mkdirSync(dataDir, { recursive: true });
// Initialize memory store
const memoryDir = config.memory.dir ?? resolve(dataDir, 'memory');
mkdirSync(memoryDir, { recursive: true });
const memoryStore = config.memory.enabled
? new MemoryStore({ dir: memoryDir, maxContextTokens: config.memory.max_context_tokens })
: undefined;
// Initialize session store and manager
const sessionStore = new SessionStore(resolve(dataDir, 'sessions.db'));
const sessionManager = new SessionManager(sessionStore);
@@ -245,6 +256,42 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
for (const tool of allBuiltinTools) {
toolRegistry.register(tool);
}
// Register memory tools if memory is enabled
if (memoryStore) {
for (const tool of createMemoryTools(memoryStore)) {
toolRegistry.register(tool);
}
}
// Register web search tool if configured with credentials
if (config.web_search.api_key || config.web_search.endpoint) {
for (const tool of createWebSearchTools({
provider: config.web_search.provider,
apiKey: config.web_search.api_key,
endpoint: config.web_search.endpoint,
maxResults: config.web_search.max_results,
})) {
toolRegistry.register(tool);
}
}
// Initialize process manager and register process tools
const processManager = new ProcessManager({
maxConcurrent: config.process.max_concurrent,
maxRuntimeMinutes: config.process.max_runtime_minutes,
bufferSize: config.process.buffer_size,
});
for (const tool of createProcessTools(processManager)) {
toolRegistry.register(tool);
}
lifecycle.onShutdown(async () => {
await processManager.shutdown();
console.log('Process manager stopped');
});
const toolExecutor = new ToolExecutor(toolRegistry, hookEngine);
// Initialize MCP manager and start configured servers
@@ -321,6 +368,7 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
toolRegistry,
toolExecutor,
config,
memoryStore,
}));
// Register Telegram adapter
@@ -331,6 +379,28 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
});
channelRegistry.register(telegramAdapter);
// Register Discord adapter (if configured)
if (config.discord) {
const discordAdapter = new DiscordAdapter({
botToken: config.discord.bot_token,
allowedGuildIds: config.discord.allowed_guild_ids.length > 0 ? config.discord.allowed_guild_ids : undefined,
allowedChannelIds: config.discord.allowed_channel_ids.length > 0 ? config.discord.allowed_channel_ids : undefined,
requireMention: config.discord.require_mention,
});
channelRegistry.register(discordAdapter);
}
// Register Slack adapter (if configured)
if (config.slack) {
const slackAdapter = new SlackAdapter({
botToken: config.slack.bot_token,
appToken: config.slack.app_token,
signingSecret: config.slack.signing_secret,
allowedChannelIds: config.slack.allowed_channel_ids.length > 0 ? config.slack.allowed_channel_ids : undefined,
});
channelRegistry.register(slackAdapter);
}
// Register WebChat adapter (wraps the gateway)
const webChatAdapter = new WebChatAdapter({ gateway });
channelRegistry.register(webChatAdapter);