P3 - SubAgent SDK: - src/subagent.ts: researcher, coder, analyst, content-writer - Mind.runSubAgent() → SubAgentFactory.create() → execute() - Результаты сохраняются в long-term memory - Heartbeat.notify(subagent-complete) после завершения P4 - SQLite persistence (5 таблиц, WAL): - src/database.ts: thoughts, notepads, self_observations, long_term, embeddings - memory.ts → Database (полная замена in-memory) - index.ts: dbPath → ~/.local/share/spark-mind/spark-mind.db P5 - Telegram Channel Layer: - src/telegram.ts: https module (SNI fix), MAX Messenger API - mind.ts: sendReply() → Telegram + console fallback - index.ts: TelegramMessenger(config) → Mind Fixes: - FK constraint: long_term INSERT → long_term_embeddings INSERT - JSON parse: nested objects, markdown fences - P5 telegram: graceful degradation on SSL error
61 lines
2.6 KiB
TypeScript
61 lines
2.6 KiB
TypeScript
/**
|
|
* Spark Mind — MVP self-hosted автономного агента.
|
|
*
|
|
* Концепт позаимствован из Animus (Craigtut): heartbeat, 4 слоя памяти,
|
|
* persona в 8 слоёв. Движок — Spark X2.5-4B (локально, self-hosted).
|
|
*
|
|
* Структура:
|
|
* heartbeat.ts — ядро: 5 триггеров тика, состояния Cold/Warm
|
|
* memory.ts — 4 слоя памяти (short/working/core self/long-term)
|
|
* persona.ts — 8 слоёв → системный промпт
|
|
* mind.ts — оркестратор: heartbeat + memory + persona + Spark LLM
|
|
*/
|
|
|
|
import { Heartbeat, DEFAULT_CONFIG } from './src/heartbeat.js';
|
|
import { MemorySystem } from './src/memory.js';
|
|
import { DEFAULT_PERSONA } from './src/persona.js';
|
|
import { Mind, SparkLLMClient } from './src/mind.js';
|
|
import { OllamaEmbeddingClient } from './src/embedding.js';
|
|
import { SubAgentFactory } from './src/subagent.js';
|
|
import { TelegramMessenger } from './src/telegram.js';
|
|
import { join } from 'node:path';
|
|
import { homedir } from 'node:os';
|
|
|
|
const HEARTBEAT_MS = 5 * 60 * 1000; // 5 мин — idle-мысли
|
|
const DB_PATH = join(homedir(), '.local/share/spark-mind/spark-mind.db');
|
|
|
|
const heartbeat = new Heartbeat({ intervalMs: HEARTBEAT_MS });
|
|
// Embeddings: bge-m3 (dim=1024) — та же модель, что в content-atom
|
|
const embedding = new OllamaEmbeddingClient('http://localhost:11434');
|
|
const memory = new MemorySystem({ recentCount: 10, dbPath: DB_PATH }, embedding); // last 10 thoughts + SQLite
|
|
// Sub-agents: researcher, coder, analyst, content-writer
|
|
const agentFactory = new SubAgentFactory();
|
|
|
|
// Telegram: MAX Messenger API (nik_bot → user_id 140245519)
|
|
const telegramConfig: import('./src/telegram.js').TelegramConfig = {
|
|
botUrl: 'https://bot.qw4.ru/bot/nik_bot',
|
|
userId: '140245519',
|
|
};
|
|
const telegram = new TelegramMessenger(telegramConfig);
|
|
|
|
const mind = new Mind(
|
|
heartbeat,
|
|
memory,
|
|
DEFAULT_PERSONA,
|
|
new SparkLLMClient('http://localhost:11434', 'ornith-1.5-9b:latest'), // Ornith-9B — движок
|
|
agentFactory,
|
|
telegram,
|
|
);
|
|
|
|
// Подключаем heartbeat к оркестратору — теперь тики реально обрабатываются
|
|
heartbeat.setOnTick((trigger) => mind.handleTick(trigger));
|
|
|
|
// Старт heartbeat
|
|
heartbeat.start();
|
|
console.log('[spark-mind] started — heartbeat every', HEARTBEAT_MS / 1000, 's');
|
|
|
|
// Демо: симулируем тик через 10 сек (в прода — реальные триггеры)
|
|
setTimeout(() => {
|
|
void mind.handleTick({ type: 'message', contactId: 'demo', text: 'Привет' });
|
|
}, 10_000);
|