@timmeck/brain-core 2.36.80 → 2.36.82

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.
@@ -567,6 +567,19 @@ canvas{display:block;width:100%;height:100%}
567
567
 
568
568
  <!-- ════ Page 5: Intelligence ═══════════════════════ -->
569
569
  <div class="page" id="page-intelligence">
570
+ <!-- Autonomous Research -->
571
+ <div class="section">
572
+ <div class="section-title"><span class="icon">&#x1F50D;</span> Autonomous Research — <span data-t="Selbstgesteuerte Forschung">Selbstgesteuerte Forschung</span></div>
573
+ <p style="font-size:12px;color:var(--text-dim);margin-bottom:12px" data-t="Brain gibt sich selbst Forschungsauftr&auml;ge: Wissensl&uuml;cken &rarr; Missionen &rarr; Web-Recherche &rarr; Insights.">Brain gibt sich selbst Forschungsauftr&auml;ge: Wissensl&uuml;cken &rarr; Missionen &rarr; Web-Recherche &rarr; Insights.</p>
574
+ <div class="grid grid-4">
575
+ <div class="card" style="text-align:center"><div class="card-value" id="auto-enabled" style="color:var(--text-dim)">&#x2014;</div><div class="card-sub">Status</div></div>
576
+ <div class="card" style="text-align:center"><div class="card-value" id="auto-cycles" style="color:var(--cyan)">0</div><div class="card-sub">Cycles</div></div>
577
+ <div class="card" style="text-align:center"><div class="card-value" id="auto-missions" style="color:var(--green)">0/5</div><div class="card-sub" data-t="Missionen heute">Missionen heute</div></div>
578
+ <div class="card" style="text-align:center"><div class="card-value" id="auto-next" style="color:var(--yellow);font-size:14px">&#x2014;</div><div class="card-sub" data-t="N&auml;chster Cycle">N&auml;chster Cycle</div></div>
579
+ </div>
580
+ <div id="autoRecentTopics" style="margin-top:12px"></div>
581
+ </div>
582
+
570
583
  <!-- RAG Pipeline -->
571
584
  <div class="section">
572
585
  <div class="section-title"><span class="icon">&#x1F50D;</span> RAG Pipeline — <span data-t="Vektor-Suche">Vektor-Suche</span></div>
@@ -1331,6 +1344,28 @@ function renderIntelligence() {
1331
1344
  const d = state.intelligence;
1332
1345
  if (!d) return;
1333
1346
 
1347
+ // Autonomous Research
1348
+ if (d.autonomousResearch) {
1349
+ const a = d.autonomousResearch;
1350
+ setText('auto-enabled', a.enabled ? (a.running ? '&#x1F7E2; Active' : '&#x1F7E1; Enabled') : '&#x26AB; Off');
1351
+ document.getElementById('auto-enabled').style.color = a.enabled ? (a.running ? 'var(--green)' : 'var(--yellow)') : 'var(--text-dim)';
1352
+ setText('auto-cycles', a.cyclesCompleted || 0);
1353
+ setText('auto-missions', `${a.missionsLaunchedToday || 0}/${a.maxMissionsPerDay || 5}`);
1354
+ if (a.nextCycleAt) {
1355
+ const mins = Math.max(0, Math.round((a.nextCycleAt - Date.now()) / 60000));
1356
+ setText('auto-next', `${mins}min`);
1357
+ } else {
1358
+ setText('auto-next', '—');
1359
+ }
1360
+ const topicEl = document.getElementById('autoRecentTopics');
1361
+ if (topicEl && a.recentTopics && a.recentTopics.length) {
1362
+ topicEl.innerHTML = '<div style="font-size:12px;color:var(--text-dim);margin-bottom:4px">' + t('Letzte Themen') + ':</div>' +
1363
+ a.recentTopics.slice(0, 5).map(topic => `<div class="card" style="padding:4px 12px;margin-bottom:2px;font-size:12px">${escHtml(topic)}</div>`).join('');
1364
+ } else if (topicEl) {
1365
+ topicEl.innerHTML = '<div class="empty" style="font-size:12px">' + t('Noch keine autonomen Forschungen') + '</div>';
1366
+ }
1367
+ }
1368
+
1334
1369
  // RAG
1335
1370
  if (d.rag) {
1336
1371
  setText('int-rag-total', (d.rag.totalVectors || 0).toLocaleString());
@@ -0,0 +1,188 @@
1
+ import type Database from 'better-sqlite3';
2
+ export interface BrowserAgentConfig {
3
+ /** Max steps per task. Default: 25 */
4
+ maxSteps?: number;
5
+ /** Max consecutive failures before abort. Default: 5 */
6
+ failureThreshold?: number;
7
+ /** Page timeout in ms. Default: 30_000 */
8
+ pageTimeoutMs?: number;
9
+ /** Allowed domains (empty = all allowed). Default: [] */
10
+ allowedDomains?: string[];
11
+ /** Blocked domains. Default: common ad/tracking domains */
12
+ blockedDomains?: string[];
13
+ /** Max concurrent pages. Default: 3 */
14
+ maxPages?: number;
15
+ /** Screenshot on each step for LLM context. Default: false */
16
+ screenshotEachStep?: boolean;
17
+ /** Max actions the LLM can return per step. Default: 5 */
18
+ actionsPerStep?: number;
19
+ /** Stall detection: max URL repeats before declaring stall. Default: 3 */
20
+ maxUrlRepeats?: number;
21
+ }
22
+ export type BrowserActionType = 'navigate' | 'click' | 'fill' | 'select' | 'scroll_down' | 'scroll_up' | 'wait' | 'screenshot' | 'extract' | 'back' | 'evaluate' | 'done' | 'fail';
23
+ export interface BrowserAction {
24
+ type: BrowserActionType;
25
+ selector?: string;
26
+ value?: string;
27
+ url?: string;
28
+ script?: string;
29
+ description?: string;
30
+ /** For 'extract': key to store extracted data under */
31
+ extractKey?: string;
32
+ /** For 'done'/'fail': final message */
33
+ message?: string;
34
+ }
35
+ export interface BrowserStepResult {
36
+ step: number;
37
+ actions: BrowserAction[];
38
+ results: ActionResult[];
39
+ pageState?: PageState;
40
+ stallDetected: boolean;
41
+ durationMs: number;
42
+ }
43
+ export interface ActionResult {
44
+ action: BrowserAction;
45
+ success: boolean;
46
+ url?: string;
47
+ error?: string;
48
+ extractedText?: string;
49
+ screenshot?: string;
50
+ durationMs: number;
51
+ }
52
+ export interface BrowserTaskResult {
53
+ taskId: string;
54
+ status: 'completed' | 'failed' | 'aborted' | 'stalled';
55
+ steps: BrowserStepResult[];
56
+ extractedData: Record<string, string>;
57
+ screenshots: string[];
58
+ totalTokensUsed: number;
59
+ consecutiveFailures: number;
60
+ error?: string;
61
+ finalMessage?: string;
62
+ durationMs: number;
63
+ }
64
+ export interface DOMElement {
65
+ tag: string;
66
+ id?: string;
67
+ classes?: string[];
68
+ text?: string;
69
+ href?: string;
70
+ type?: string;
71
+ name?: string;
72
+ placeholder?: string;
73
+ ariaLabel?: string;
74
+ rect?: {
75
+ x: number;
76
+ y: number;
77
+ width: number;
78
+ height: number;
79
+ };
80
+ }
81
+ export interface PageState {
82
+ url: string;
83
+ title: string;
84
+ interactiveElements: DOMElement[];
85
+ links: DOMElement[];
86
+ forms: Array<{
87
+ action?: string;
88
+ method?: string;
89
+ fields: DOMElement[];
90
+ }>;
91
+ textContent: string;
92
+ headings: Array<{
93
+ level: number;
94
+ text: string;
95
+ }>;
96
+ }
97
+ export interface BrowserAgentStatus {
98
+ activeTasks: number;
99
+ completedTasks: number;
100
+ stalledTasks: number;
101
+ totalSteps: number;
102
+ totalTokensUsed: number;
103
+ pagesOpen: number;
104
+ browserConnected: boolean;
105
+ }
106
+ export interface BrowserActionPlanner {
107
+ /**
108
+ * Given the current task, page state, and step history,
109
+ * return the next action(s) to execute.
110
+ * Return a 'done' or 'fail' action to end the task.
111
+ */
112
+ planNextActions(context: PlannerContext): Promise<PlannerResult>;
113
+ }
114
+ export interface PlannerContext {
115
+ task: string;
116
+ currentStep: number;
117
+ maxSteps: number;
118
+ pageState: PageState;
119
+ previousSteps: Array<{
120
+ step: number;
121
+ actions: string[];
122
+ results: string[];
123
+ url: string;
124
+ }>;
125
+ extractedData: Record<string, string>;
126
+ consecutiveFailures: number;
127
+ }
128
+ export interface PlannerResult {
129
+ actions: BrowserAction[];
130
+ reasoning?: string;
131
+ tokensUsed?: number;
132
+ }
133
+ export declare class StallDetector {
134
+ private readonly maxRepeats;
135
+ private urlHistory;
136
+ private actionHistory;
137
+ constructor(maxRepeats?: number);
138
+ record(url: string, actions: string[]): void;
139
+ isStalled(): boolean;
140
+ reset(): void;
141
+ }
142
+ export declare function runBrowserAgentMigration(db: Database.Database): void;
143
+ export declare function parseLLMActions(text: string): BrowserAction[];
144
+ /** Build the system prompt for the browser agent LLM. */
145
+ export declare function buildBrowserSystemPrompt(): string;
146
+ /** Build the user prompt for each step. */
147
+ export declare function buildStepPrompt(context: PlannerContext): string;
148
+ export declare class BrowserAgent {
149
+ private readonly db;
150
+ private readonly config;
151
+ private readonly log;
152
+ private browser;
153
+ private planner;
154
+ private activeTasks;
155
+ private completedTasks;
156
+ private stalledTasks;
157
+ private totalSteps;
158
+ private totalTokensUsed;
159
+ private openPages;
160
+ private readonly stmtLogAction;
161
+ constructor(db: Database.Database, config?: BrowserAgentConfig);
162
+ /** Set the LLM planner for autonomous action selection. */
163
+ setPlanner(planner: BrowserActionPlanner): void;
164
+ /** Check if a URL is allowed by domain whitelist/blacklist. */
165
+ isDomainAllowed(url: string): boolean;
166
+ /** Get or launch the browser instance (lazy init). */
167
+ private getBrowser;
168
+ /** Shutdown the browser. */
169
+ shutdown(): Promise<void>;
170
+ /** Analyze the current page DOM to understand interactive elements. */
171
+ analyzePage(page: unknown): Promise<PageState>;
172
+ /** Execute a single browser action. */
173
+ executeAction(page: unknown, action: BrowserAction): Promise<ActionResult>;
174
+ /** Execute a pre-defined sequence of browser actions. No LLM needed. */
175
+ executeTask(taskId: string, actions: BrowserAction[]): Promise<BrowserTaskResult>;
176
+ /**
177
+ * Execute a task autonomously using the LLM feedback loop.
178
+ *
179
+ * Loop:
180
+ * 1. analyzePage() → Page State
181
+ * 2. planner.planNextActions(context) → Actions
182
+ * 3. Execute actions → Results
183
+ * 4. Check for 'done'/'fail'/stall → End or loop
184
+ */
185
+ runAutonomous(taskId: string, task: string): Promise<BrowserTaskResult>;
186
+ getStatus(): BrowserAgentStatus;
187
+ getConfig(): Readonly<Required<BrowserAgentConfig>>;
188
+ }