@timmeck/brain-core 2.36.36 → 2.36.38
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.
- package/dist/causal/engine.d.ts +2 -2
- package/dist/checkpoint/__tests__/checkpoint-manager.test.d.ts +1 -0
- package/dist/checkpoint/__tests__/checkpoint-manager.test.js +160 -0
- package/dist/checkpoint/__tests__/checkpoint-manager.test.js.map +1 -0
- package/dist/checkpoint/checkpoint-manager.d.ts +86 -0
- package/dist/checkpoint/checkpoint-manager.js +219 -0
- package/dist/checkpoint/checkpoint-manager.js.map +1 -0
- package/dist/checkpoint/index.d.ts +2 -0
- package/dist/checkpoint/index.js +2 -0
- package/dist/checkpoint/index.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/llm/index.d.ts +4 -0
- package/dist/llm/index.js +4 -0
- package/dist/llm/index.js.map +1 -1
- package/dist/llm/llm-service.d.ts +21 -0
- package/dist/llm/llm-service.js +45 -0
- package/dist/llm/llm-service.js.map +1 -1
- package/dist/llm/middleware.d.ts +122 -0
- package/dist/llm/middleware.js +185 -0
- package/dist/llm/middleware.js.map +1 -0
- package/dist/llm/structured-output.d.ts +76 -0
- package/dist/llm/structured-output.js +153 -0
- package/dist/llm/structured-output.js.map +1 -0
- package/dist/research/research-orchestrator.d.ts +2 -0
- package/dist/research/research-orchestrator.js +9 -0
- package/dist/research/research-orchestrator.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured LLM Output — Typed ContentBlocks statt nur `{ text: string }`
|
|
3
|
+
*
|
|
4
|
+
* Inspiriert von LangChain's structured output parsing.
|
|
5
|
+
* Ermöglicht es, LLM-Antworten in typisierte Blöcke zu zerlegen:
|
|
6
|
+
* Text, Reasoning, Tool Calls, Citations, JSON.
|
|
7
|
+
*/
|
|
8
|
+
// ── Parsing ─────────────────────────────────────────────
|
|
9
|
+
/**
|
|
10
|
+
* Parse raw LLM output into structured ContentBlocks.
|
|
11
|
+
*
|
|
12
|
+
* Erkennt:
|
|
13
|
+
* - <thinking>...</thinking> → ReasoningBlock
|
|
14
|
+
* - <tool_call>{"name":"...","args":{...}}</tool_call> → ToolCallBlock
|
|
15
|
+
* - <citation source="...">...</citation> → CitationBlock
|
|
16
|
+
* - ```json ... ``` → JsonBlock
|
|
17
|
+
* - Alles andere → TextBlock
|
|
18
|
+
*/
|
|
19
|
+
export function parseStructuredOutput(raw) {
|
|
20
|
+
if (!raw || raw.trim().length === 0)
|
|
21
|
+
return [];
|
|
22
|
+
const blocks = [];
|
|
23
|
+
let remaining = raw;
|
|
24
|
+
// Regex patterns for structured sections
|
|
25
|
+
const patterns = [
|
|
26
|
+
{
|
|
27
|
+
// <thinking>...</thinking>
|
|
28
|
+
regex: /<thinking>([\s\S]*?)<\/thinking>/,
|
|
29
|
+
handler: (m) => ({ type: 'reasoning', content: m[1].trim() }),
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
// <tool_call>{"name":"x","args":{...}}</tool_call>
|
|
33
|
+
regex: /<tool_call>([\s\S]*?)<\/tool_call>/,
|
|
34
|
+
handler: (m) => {
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(m[1].trim());
|
|
37
|
+
return {
|
|
38
|
+
type: 'tool_call',
|
|
39
|
+
toolName: parsed.name ?? parsed.tool ?? 'unknown',
|
|
40
|
+
args: parsed.args ?? parsed.arguments ?? parsed.input ?? {},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return { type: 'text', content: m[0] };
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
// <citation source="...">...</citation>
|
|
50
|
+
regex: /<citation\s+source="([^"]*)">([\s\S]*?)<\/citation>/,
|
|
51
|
+
handler: (m) => ({ type: 'citation', source: m[1], quote: m[2].trim() }),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
// ```json ... ```
|
|
55
|
+
regex: /```json\s*\n([\s\S]*?)\n```/,
|
|
56
|
+
handler: (m) => {
|
|
57
|
+
try {
|
|
58
|
+
return { type: 'json', data: JSON.parse(m[1].trim()) };
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return { type: 'text', content: m[0] };
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
while (remaining.length > 0) {
|
|
67
|
+
// Find the earliest matching pattern
|
|
68
|
+
let earliest = null;
|
|
69
|
+
for (const p of patterns) {
|
|
70
|
+
const match = remaining.match(p.regex);
|
|
71
|
+
if (match && match.index !== undefined) {
|
|
72
|
+
if (!earliest || match.index < earliest.index) {
|
|
73
|
+
earliest = { index: match.index, match, handler: p.handler };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!earliest) {
|
|
78
|
+
// No more patterns found — rest is text
|
|
79
|
+
const trimmed = remaining.trim();
|
|
80
|
+
if (trimmed.length > 0) {
|
|
81
|
+
blocks.push({ type: 'text', content: trimmed });
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
// Text before the match
|
|
86
|
+
const before = remaining.slice(0, earliest.index).trim();
|
|
87
|
+
if (before.length > 0) {
|
|
88
|
+
blocks.push({ type: 'text', content: before });
|
|
89
|
+
}
|
|
90
|
+
// The matched block
|
|
91
|
+
blocks.push(earliest.handler(earliest.match));
|
|
92
|
+
// Continue after the match
|
|
93
|
+
remaining = remaining.slice(earliest.index + earliest.match[0].length);
|
|
94
|
+
}
|
|
95
|
+
return blocks;
|
|
96
|
+
}
|
|
97
|
+
// ── JSON Mode Helper ────────────────────────────────────
|
|
98
|
+
/**
|
|
99
|
+
* Extrahiert JSON aus einer LLM-Antwort.
|
|
100
|
+
* Versucht zuerst die gesamte Antwort als JSON zu parsen,
|
|
101
|
+
* dann sucht es nach ```json Code-Blöcken.
|
|
102
|
+
*/
|
|
103
|
+
export function extractJson(raw) {
|
|
104
|
+
// Try full string
|
|
105
|
+
try {
|
|
106
|
+
return JSON.parse(raw.trim());
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Try code block
|
|
110
|
+
const match = raw.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
|
|
111
|
+
if (match) {
|
|
112
|
+
try {
|
|
113
|
+
return JSON.parse(match[1].trim());
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Validate parsed JSON against a simple schema (key presence check).
|
|
124
|
+
* Returns the data if valid, null otherwise.
|
|
125
|
+
*/
|
|
126
|
+
export function validateJsonSchema(data, requiredKeys) {
|
|
127
|
+
if (!data || typeof data !== 'object')
|
|
128
|
+
return null;
|
|
129
|
+
const obj = data;
|
|
130
|
+
for (const key of requiredKeys) {
|
|
131
|
+
if (!(key in obj))
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
return data;
|
|
135
|
+
}
|
|
136
|
+
// ── Block Helpers ────────────────────────────────────────
|
|
137
|
+
/** Get all blocks of a specific type */
|
|
138
|
+
export function getBlocks(blocks, type) {
|
|
139
|
+
return blocks.filter((b) => b.type === type);
|
|
140
|
+
}
|
|
141
|
+
/** Get combined text from all TextBlocks */
|
|
142
|
+
export function getTextContent(blocks) {
|
|
143
|
+
return getBlocks(blocks, 'text').map(b => b.content).join('\n\n');
|
|
144
|
+
}
|
|
145
|
+
/** Get all tool calls */
|
|
146
|
+
export function getToolCalls(blocks) {
|
|
147
|
+
return getBlocks(blocks, 'tool_call');
|
|
148
|
+
}
|
|
149
|
+
/** Check if response contains reasoning */
|
|
150
|
+
export function hasReasoning(blocks) {
|
|
151
|
+
return blocks.some(b => b.type === 'reasoning');
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=structured-output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-output.js","sourceRoot":"","sources":["../../src/llm/structured-output.ts"],"names":[],"mappings":"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"}
|
|
@@ -118,6 +118,7 @@ export declare class ResearchOrchestrator {
|
|
|
118
118
|
private repoAbsorber;
|
|
119
119
|
private featureRecommender;
|
|
120
120
|
private contradictionResolver;
|
|
121
|
+
private checkpointManager;
|
|
121
122
|
private lastAutoMissionTime;
|
|
122
123
|
private onSuggestionCallback;
|
|
123
124
|
private db;
|
|
@@ -217,6 +218,7 @@ export declare class ResearchOrchestrator {
|
|
|
217
218
|
setRepoAbsorber(absorber: RepoAbsorber): void;
|
|
218
219
|
setFeatureRecommender(recommender: import('../codegen/feature-recommender.js').FeatureRecommender): void;
|
|
219
220
|
setContradictionResolver(resolver: import('../knowledge-graph/contradiction-resolver.js').ContradictionResolver): void;
|
|
221
|
+
setCheckpointManager(cm: import('../checkpoint/checkpoint-manager.js').CheckpointManager): void;
|
|
220
222
|
/** Set the LLMService — propagates to all engines that can use LLM. */
|
|
221
223
|
setLLMService(llm: LLMService): void;
|
|
222
224
|
/** Get the LLMService instance. */
|
|
@@ -69,6 +69,7 @@ export class ResearchOrchestrator {
|
|
|
69
69
|
repoAbsorber = null;
|
|
70
70
|
featureRecommender = null;
|
|
71
71
|
contradictionResolver = null;
|
|
72
|
+
checkpointManager = null;
|
|
72
73
|
lastAutoMissionTime = 0;
|
|
73
74
|
onSuggestionCallback = null;
|
|
74
75
|
db;
|
|
@@ -239,6 +240,7 @@ export class ResearchOrchestrator {
|
|
|
239
240
|
setRepoAbsorber(absorber) { this.repoAbsorber = absorber; }
|
|
240
241
|
setFeatureRecommender(recommender) { this.featureRecommender = recommender; }
|
|
241
242
|
setContradictionResolver(resolver) { this.contradictionResolver = resolver; }
|
|
243
|
+
setCheckpointManager(cm) { this.checkpointManager = cm; }
|
|
242
244
|
/** Set the LLMService — propagates to all engines that can use LLM. */
|
|
243
245
|
setLLMService(llm) {
|
|
244
246
|
this.llmService = llm;
|
|
@@ -1988,6 +1990,13 @@ export class ResearchOrchestrator {
|
|
|
1988
1990
|
duration_ms: duration,
|
|
1989
1991
|
});
|
|
1990
1992
|
}
|
|
1993
|
+
// Checkpoint: persist cycle state for crash recovery / time-travel
|
|
1994
|
+
if (this.checkpointManager) {
|
|
1995
|
+
try {
|
|
1996
|
+
this.checkpointManager.save(`orchestrator-${this.brainName}`, this.cycleCount, { cycleCount: this.cycleCount, insights: insights.length, anomalies: anomalies.length, durationMs: duration }, { workflowType: 'orchestrator', metadata: { brainName: this.brainName } });
|
|
1997
|
+
}
|
|
1998
|
+
catch { /* checkpoint save should never break the cycle */ }
|
|
1999
|
+
}
|
|
1991
2000
|
}
|
|
1992
2001
|
/** Analyze Brain's own state and generate concrete improvement suggestions.
|
|
1993
2002
|
* Tracks suggestion history — if a suggestion repeats 3+ times without resolution,
|