@timmeck/brain-core 2.36.80 → 2.36.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,246 @@
1
+ // ── Autonomous Research Loop ─────────────────────────────────
2
+ //
3
+ // Brain gibt sich selbst Forschungsaufträge. Kein Mensch nötig.
4
+ //
5
+ // Loop: CuriosityEngine → DesireEngine → MissionEngine
6
+ // → Brave Search + Playwright → Insight → Hypothese → Test
7
+ //
8
+ // Guards: max missions/day, budget check, cooldown between cycles.
9
+ import { getLogger } from '../utils/logger.js';
10
+ // ── Migration ───────────────────────────────────────────
11
+ export function runAutonomousResearchMigration(db) {
12
+ db.exec(`
13
+ CREATE TABLE IF NOT EXISTS autonomous_research_log (
14
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
15
+ topic TEXT NOT NULL,
16
+ source TEXT NOT NULL,
17
+ mission_id INTEGER,
18
+ action TEXT NOT NULL,
19
+ reason TEXT,
20
+ created_at TEXT DEFAULT (datetime('now'))
21
+ );
22
+ CREATE INDEX IF NOT EXISTS idx_auto_research_created ON autonomous_research_log(created_at);
23
+ `);
24
+ }
25
+ // ── Engine ──────────────────────────────────────────────
26
+ export class AutonomousResearchLoop {
27
+ db;
28
+ config;
29
+ log = getLogger();
30
+ ts = null;
31
+ journal = null;
32
+ sources = {};
33
+ timer = null;
34
+ cyclesCompleted = 0;
35
+ lastCycleAt = null;
36
+ lastTopic = null;
37
+ recentTopics = [];
38
+ // Prepared statements
39
+ stmtLogAction;
40
+ stmtCountToday;
41
+ stmtRecentTopics;
42
+ constructor(db, config = {}) {
43
+ this.db = db;
44
+ this.config = {
45
+ maxMissionsPerDay: config.maxMissionsPerDay ?? 5,
46
+ cycleCooldownMs: config.cycleCooldownMs ?? 30 * 60_000, // 30min
47
+ minGapScore: config.minGapScore ?? 0.5,
48
+ minDesirePriority: config.minDesirePriority ?? 5,
49
+ missionDepth: config.missionDepth ?? 'standard',
50
+ enabled: config.enabled ?? false,
51
+ };
52
+ runAutonomousResearchMigration(db);
53
+ this.stmtLogAction = db.prepare('INSERT INTO autonomous_research_log (topic, source, mission_id, action, reason) VALUES (?, ?, ?, ?, ?)');
54
+ this.stmtCountToday = db.prepare(`SELECT COUNT(*) as c FROM autonomous_research_log WHERE action = 'mission_launched' AND created_at > datetime('now', '-24 hours')`);
55
+ this.stmtRecentTopics = db.prepare(`SELECT DISTINCT topic FROM autonomous_research_log WHERE action = 'mission_launched' ORDER BY id DESC LIMIT 10`);
56
+ }
57
+ // ── Setters ──────────────────────────────────────────
58
+ setThoughtStream(stream) { this.ts = stream; }
59
+ setJournal(journal) { this.journal = journal; }
60
+ setSources(sources) { this.sources = sources; }
61
+ /** Update config at runtime. */
62
+ updateConfig(partial) {
63
+ if (partial.maxMissionsPerDay !== undefined)
64
+ this.config.maxMissionsPerDay = partial.maxMissionsPerDay;
65
+ if (partial.cycleCooldownMs !== undefined)
66
+ this.config.cycleCooldownMs = partial.cycleCooldownMs;
67
+ if (partial.minGapScore !== undefined)
68
+ this.config.minGapScore = partial.minGapScore;
69
+ if (partial.minDesirePriority !== undefined)
70
+ this.config.minDesirePriority = partial.minDesirePriority;
71
+ if (partial.missionDepth !== undefined)
72
+ this.config.missionDepth = partial.missionDepth;
73
+ if (partial.enabled !== undefined)
74
+ this.config.enabled = partial.enabled;
75
+ }
76
+ // ── Lifecycle ─────────────────────────────────────────
77
+ /** Start the autonomous research timer. */
78
+ start() {
79
+ if (this.timer)
80
+ return;
81
+ if (!this.config.enabled) {
82
+ this.log.info('[autonomous-research] Not enabled — skipping start');
83
+ return;
84
+ }
85
+ this.timer = setInterval(() => {
86
+ this.cycle().catch(err => this.log.error(`[autonomous-research] Cycle error: ${err.message}`));
87
+ }, this.config.cycleCooldownMs);
88
+ this.log.info(`[autonomous-research] Started (interval: ${(this.config.cycleCooldownMs / 60_000).toFixed(0)}min, max: ${this.config.maxMissionsPerDay}/day)`);
89
+ }
90
+ /** Stop the timer. */
91
+ stop() {
92
+ if (this.timer) {
93
+ clearInterval(this.timer);
94
+ this.timer = null;
95
+ this.log.info('[autonomous-research] Stopped');
96
+ }
97
+ }
98
+ // ── Core Cycle ─────────────────────────────────────────
99
+ /** Run one autonomous research cycle. Can be called manually or by timer. */
100
+ async cycle() {
101
+ // Guard: enabled?
102
+ if (!this.config.enabled) {
103
+ return { action: 'skipped_disabled', reason: 'Autonomous research not enabled' };
104
+ }
105
+ // Guard: cooldown?
106
+ if (this.lastCycleAt && Date.now() - this.lastCycleAt < this.config.cycleCooldownMs * 0.9) {
107
+ return { action: 'skipped_cooldown', reason: 'Cooldown not elapsed' };
108
+ }
109
+ // Guard: daily budget?
110
+ const todayCount = this.stmtCountToday.get().c;
111
+ if (todayCount >= this.config.maxMissionsPerDay) {
112
+ return { action: 'skipped_budget', reason: `Daily limit reached (${todayCount}/${this.config.maxMissionsPerDay})` };
113
+ }
114
+ // Guard: token budget?
115
+ if (this.sources.checkBudget) {
116
+ const budget = this.sources.checkBudget('autonomous_research');
117
+ if (!budget.allowed) {
118
+ return { action: 'skipped_budget', reason: budget.reason ?? 'Token budget exhausted' };
119
+ }
120
+ }
121
+ // Step 1: Select research target
122
+ const target = this.selectTarget();
123
+ if (!target) {
124
+ this.lastCycleAt = Date.now();
125
+ this.cyclesCompleted++;
126
+ return { action: 'skipped_no_target', reason: 'No gaps or desires above threshold' };
127
+ }
128
+ // Step 2: Check we haven't researched this recently
129
+ const recentTopics = this.stmtRecentTopics.all().map(r => r.topic);
130
+ if (recentTopics.some(t => this.topicOverlap(t, target.topic) > 0.7)) {
131
+ this.log.debug(`[autonomous-research] Skipping "${target.topic}" — too similar to recent research`);
132
+ this.lastCycleAt = Date.now();
133
+ return { action: 'skipped_no_target', reason: `Topic "${target.topic}" too similar to recent research` };
134
+ }
135
+ // Step 3: Launch mission
136
+ if (!this.sources.createMission) {
137
+ return { action: 'skipped_no_target', reason: 'MissionEngine not wired' };
138
+ }
139
+ this.ts?.emit('research', 'exploring', `Autonomous research: "${target.topic}" (source: ${target.source})`, 'notable');
140
+ const mission = this.sources.createMission(target.topic, this.config.missionDepth);
141
+ // Step 4: Log
142
+ this.stmtLogAction.run(target.topic, target.source, mission.id ?? null, 'mission_launched', null);
143
+ this.lastCycleAt = Date.now();
144
+ this.lastTopic = target.topic;
145
+ this.recentTopics = [target.topic, ...this.recentTopics.slice(0, 9)];
146
+ this.cyclesCompleted++;
147
+ // Step 5: Observe for hypothesis engine
148
+ if (this.sources.observeHypothesis) {
149
+ this.sources.observeHypothesis({
150
+ source: 'autonomous_research',
151
+ type: 'mission_launched',
152
+ value: 1,
153
+ timestamp: Date.now(),
154
+ });
155
+ }
156
+ // Step 6: Journal entry
157
+ if (this.journal) {
158
+ try {
159
+ this.journal.recordDiscovery(`Autonomous research: ${target.topic}`, `Self-directed research mission launched. Source: ${target.source}. Depth: ${this.config.missionDepth}.`, { mission_id: mission.id, source: target.source }, 'routine');
160
+ }
161
+ catch { /* best effort */ }
162
+ }
163
+ this.log.info(`[autonomous-research] Mission launched: "${target.topic}" (id: ${mission.id}, source: ${target.source})`);
164
+ return { action: 'mission_launched', topic: target.topic, missionId: mission.id };
165
+ }
166
+ // ── Target Selection ──────────────────────────────────
167
+ /** Select the best research target from curiosity gaps and desires. */
168
+ selectTarget() {
169
+ const candidates = [];
170
+ // Source 1: Curiosity gaps
171
+ if (this.sources.getCuriosityGaps) {
172
+ const gaps = this.sources.getCuriosityGaps(5);
173
+ for (const gap of gaps) {
174
+ if (gap.gapScore >= this.config.minGapScore) {
175
+ // Use the first question as research topic, or the gap topic itself
176
+ const topic = gap.questions[0] ?? gap.topic;
177
+ candidates.push({ topic, source: `curiosity_gap:${gap.gapType}`, score: gap.gapScore });
178
+ }
179
+ }
180
+ }
181
+ // Source 2: Desires
182
+ if (this.sources.getDesires) {
183
+ const desires = this.sources.getDesires();
184
+ for (const desire of desires) {
185
+ if (desire.priority >= this.config.minDesirePriority) {
186
+ // Extract topic from desire suggestion
187
+ const topic = this.extractTopicFromDesire(desire.suggestion);
188
+ if (topic) {
189
+ candidates.push({ topic, source: `desire:${desire.key}`, score: desire.priority / 10 });
190
+ }
191
+ }
192
+ }
193
+ }
194
+ if (candidates.length === 0)
195
+ return null;
196
+ // Sort by score descending, pick the best
197
+ candidates.sort((a, b) => b.score - a.score);
198
+ return candidates[0];
199
+ }
200
+ /** Extract a researchable topic from a desire suggestion string. */
201
+ extractTopicFromDesire(suggestion) {
202
+ // Try to extract quoted topic
203
+ const match = suggestion.match(/"([^"]+)"/);
204
+ if (match)
205
+ return match[1];
206
+ // Try to extract after "regarding" or "about"
207
+ const aboutMatch = suggestion.match(/(?:regarding|about|gap:?)\s+"?([^"]+)"?/i);
208
+ if (aboutMatch)
209
+ return aboutMatch[1].trim();
210
+ // Fallback: use the suggestion itself if short enough
211
+ if (suggestion.length < 100)
212
+ return suggestion;
213
+ return null;
214
+ }
215
+ /** Simple topic overlap check (Jaccard on words). */
216
+ topicOverlap(a, b) {
217
+ const wordsA = new Set(a.toLowerCase().split(/\W+/).filter(w => w.length > 2));
218
+ const wordsB = new Set(b.toLowerCase().split(/\W+/).filter(w => w.length > 2));
219
+ if (wordsA.size === 0 || wordsB.size === 0)
220
+ return 0;
221
+ let intersection = 0;
222
+ for (const w of wordsA)
223
+ if (wordsB.has(w))
224
+ intersection++;
225
+ return intersection / Math.max(wordsA.size, wordsB.size);
226
+ }
227
+ // ── Status ─────────────────────────────────────────────
228
+ getStatus() {
229
+ const todayCount = this.stmtCountToday.get().c;
230
+ return {
231
+ enabled: this.config.enabled,
232
+ running: this.timer !== null,
233
+ cyclesCompleted: this.cyclesCompleted,
234
+ missionsLaunchedToday: todayCount,
235
+ maxMissionsPerDay: this.config.maxMissionsPerDay,
236
+ lastCycleAt: this.lastCycleAt,
237
+ nextCycleAt: this.lastCycleAt ? this.lastCycleAt + this.config.cycleCooldownMs : null,
238
+ lastTopic: this.lastTopic,
239
+ recentTopics: this.recentTopics,
240
+ };
241
+ }
242
+ getConfig() {
243
+ return { ...this.config };
244
+ }
245
+ }
246
+ //# sourceMappingURL=autonomous-research-loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autonomous-research-loop.js","sourceRoot":"","sources":["../../src/research/autonomous-research-loop.ts"],"names":[],"mappings":"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"}
@@ -143,6 +143,7 @@ export declare class ResearchOrchestrator {
143
143
  private governanceLayer;
144
144
  private adaptiveScheduler;
145
145
  private cycleOutcomeTracker;
146
+ private conversationMemory;
146
147
  private lastAutoMissionTime;
147
148
  private lastGoalMissionTime;
148
149
  private roadmapBootstrapped;
@@ -180,6 +181,8 @@ export declare class ResearchOrchestrator {
180
181
  setAdaptiveScheduler(scheduler: AdaptiveScheduler): void;
181
182
  /** Set the CycleOutcomeTracker for long-term cycle metrics. */
182
183
  setCycleOutcomeTracker(tracker: import('./cycle-outcome-tracker.js').CycleOutcomeTracker): void;
184
+ /** Set ConversationMemory for auto-remembering cycle outcomes. */
185
+ setConversationMemory(memory: import('../memory/conversation-memory.js').ConversationMemory): void;
183
186
  /** Get the AdaptiveScheduler instance. */
184
187
  getAdaptiveScheduler(): AdaptiveScheduler | null;
185
188
  /** Set the DataMiner instance for DB-driven engine feeding. */
@@ -91,6 +91,7 @@ export class ResearchOrchestrator {
91
91
  governanceLayer = null;
92
92
  adaptiveScheduler = null;
93
93
  cycleOutcomeTracker = null;
94
+ conversationMemory = null;
94
95
  lastAutoMissionTime = 0;
95
96
  lastGoalMissionTime = 0;
96
97
  roadmapBootstrapped = false;
@@ -156,6 +157,10 @@ export class ResearchOrchestrator {
156
157
  setCycleOutcomeTracker(tracker) {
157
158
  this.cycleOutcomeTracker = tracker;
158
159
  }
160
+ /** Set ConversationMemory for auto-remembering cycle outcomes. */
161
+ setConversationMemory(memory) {
162
+ this.conversationMemory = memory;
163
+ }
159
164
  /** Get the AdaptiveScheduler instance. */
160
165
  getAdaptiveScheduler() {
161
166
  return this.adaptiveScheduler;
@@ -3177,6 +3182,29 @@ export class ResearchOrchestrator {
3177
3182
  this.log.debug(`[orchestrator] CycleOutcomeTracker error: ${err.message}`);
3178
3183
  }
3179
3184
  }
3185
+ // Auto-remember notable cycles in ConversationMemory
3186
+ if (this.conversationMemory) {
3187
+ try {
3188
+ const hypSummary2 = this.hypothesisEngine.getSummary();
3189
+ const notable = insights.length > 0 || (hypSummary2.confirmed ?? 0) > 0;
3190
+ if (notable) {
3191
+ const summary = [
3192
+ `Cycle #${this.cycleCount}: ${insights.length} insights`,
3193
+ hypSummary2.confirmed ? `${hypSummary2.confirmed} hypotheses confirmed` : null,
3194
+ hypSummary2.rejected ? `${hypSummary2.rejected} rejected` : null,
3195
+ `${Math.round(duration / 1000)}s`,
3196
+ ].filter(Boolean).join(', ');
3197
+ this.conversationMemory.remember(summary, {
3198
+ category: 'fact',
3199
+ key: `cycle_${this.cycleCount}`,
3200
+ importance: (hypSummary2.confirmed ?? 0) > 0 ? 8 : 6,
3201
+ tags: ['cycle', 'autonomous', this.brainName],
3202
+ source: 'inferred',
3203
+ });
3204
+ }
3205
+ }
3206
+ catch { /* best effort */ }
3207
+ }
3180
3208
  // Step-profiling summary: log slow steps if any
3181
3209
  if (stepTimings.length > 0) {
3182
3210
  this.log.warn(`[orchestrator] Cycle #${this.cycleCount} slow steps: ${stepTimings.map(s => `${s.step}(${s.ms}ms)`).join(', ')}`);