feat: integrate model router, session persistence, and hook engine
- NativeAgent now loads/saves messages to SessionStore - Daemon creates ModelRouter with fallback chain support - Telegram bot handles confirmation callbacks from HookEngine - Session data stored in ~/.local/share/flynn/sessions.db Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+80
-8
@@ -1,39 +1,111 @@
|
||||
import { Bot } from 'grammy';
|
||||
import { Lifecycle } from './lifecycle.js';
|
||||
import type { Config } from '../config/index.js';
|
||||
import { AnthropicClient } from '../models/index.js';
|
||||
import { AnthropicClient, OpenAIClient, OllamaClient, ModelRouter } from '../models/index.js';
|
||||
import { NativeAgent } from '../backends/index.js';
|
||||
import { createTelegramBot } from '../frontends/telegram/index.js';
|
||||
import { SessionStore } from '../session/index.js';
|
||||
import { HookEngine } from '../hooks/index.js';
|
||||
import { resolve } from 'path';
|
||||
import { homedir } from 'os';
|
||||
import { mkdirSync } from 'fs';
|
||||
|
||||
export interface DaemonContext {
|
||||
config: Config;
|
||||
lifecycle: Lifecycle;
|
||||
bot: Bot;
|
||||
agent: NativeAgent;
|
||||
sessionStore: SessionStore;
|
||||
hookEngine: HookEngine;
|
||||
modelRouter: ModelRouter;
|
||||
}
|
||||
|
||||
const SYSTEM_PROMPT = `You are Flynn, a helpful personal AI assistant. You are direct, concise, and helpful. You can help with a variety of tasks including answering questions, providing information, and having conversations.
|
||||
|
||||
Keep responses focused and avoid unnecessary verbosity. Use markdown formatting when it improves readability.`;
|
||||
|
||||
function createModelRouter(config: Config): ModelRouter {
|
||||
const models = config.models;
|
||||
|
||||
// Create default client (required)
|
||||
const defaultClient = new AnthropicClient({
|
||||
model: models.default.model,
|
||||
});
|
||||
|
||||
// Create optional tier clients
|
||||
let fastClient;
|
||||
let complexClient;
|
||||
let localClient;
|
||||
|
||||
if (models.fast) {
|
||||
fastClient = new AnthropicClient({ model: models.fast.model });
|
||||
}
|
||||
|
||||
if (models.complex) {
|
||||
complexClient = new AnthropicClient({ model: models.complex.model });
|
||||
}
|
||||
|
||||
if (models.local) {
|
||||
if (models.local.provider === 'ollama') {
|
||||
localClient = new OllamaClient({
|
||||
model: models.local.model,
|
||||
host: models.local.endpoint,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Build fallback chain
|
||||
const fallbackChain = [];
|
||||
for (const providerName of models.fallback_chain) {
|
||||
if (providerName === 'openai') {
|
||||
fallbackChain.push(new OpenAIClient({ model: 'gpt-4o' }));
|
||||
} else if (providerName === 'local' && localClient) {
|
||||
fallbackChain.push(localClient);
|
||||
}
|
||||
}
|
||||
|
||||
return new ModelRouter({
|
||||
default: defaultClient,
|
||||
fast: fastClient,
|
||||
complex: complexClient,
|
||||
local: localClient,
|
||||
fallbackChain,
|
||||
});
|
||||
}
|
||||
|
||||
export async function startDaemon(config: Config): Promise<DaemonContext> {
|
||||
const lifecycle = new Lifecycle();
|
||||
|
||||
// Initialize model client
|
||||
const modelClient = new AnthropicClient({
|
||||
model: config.models.default.model,
|
||||
// Ensure data directory exists
|
||||
const dataDir = resolve(homedir(), '.local/share/flynn');
|
||||
mkdirSync(dataDir, { recursive: true });
|
||||
|
||||
// Initialize session store
|
||||
const sessionStore = new SessionStore(resolve(dataDir, 'sessions.db'));
|
||||
lifecycle.onShutdown(async () => {
|
||||
sessionStore.close();
|
||||
console.log('Session store closed');
|
||||
});
|
||||
|
||||
// Initialize native agent
|
||||
// Initialize hook engine
|
||||
const hookEngine = new HookEngine(config.hooks);
|
||||
|
||||
// Initialize model router
|
||||
const modelRouter = createModelRouter(config);
|
||||
|
||||
// Initialize native agent with session persistence
|
||||
const agent = new NativeAgent({
|
||||
modelClient,
|
||||
modelClient: modelRouter,
|
||||
systemPrompt: SYSTEM_PROMPT,
|
||||
sessionStore,
|
||||
sessionId: `telegram-${config.telegram.allowed_chat_ids[0]}`,
|
||||
});
|
||||
|
||||
// Initialize Telegram bot
|
||||
// Initialize Telegram bot with hook engine
|
||||
const bot = createTelegramBot({
|
||||
telegram: config.telegram,
|
||||
agent,
|
||||
hookEngine,
|
||||
});
|
||||
|
||||
// Register signal handlers
|
||||
@@ -64,7 +136,7 @@ export async function startDaemon(config: Config): Promise<DaemonContext> {
|
||||
|
||||
console.log('Flynn daemon started');
|
||||
|
||||
return { config, lifecycle, bot, agent };
|
||||
return { config, lifecycle, bot, agent, sessionStore, hookEngine, modelRouter };
|
||||
}
|
||||
|
||||
export { Lifecycle } from './lifecycle.js';
|
||||
|
||||
Reference in New Issue
Block a user