@miphamai/cli 0.33.2 → 0.34.1
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/package.json +1 -1
- package/src/core/constitution-loader.ts +353 -0
- package/src/core/dream-engine.ts +552 -0
- package/src/core/emotion-detector.ts +257 -0
- package/src/core/engine.ts +122 -1
- package/src/core/red-team.ts +271 -0
- package/src/core/self-critique.ts +235 -0
- package/src/ui/app.tsx +22 -1
- package/src/ui/commands.ts +669 -31
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emotion Detector — User Frustration Detection
|
|
3
|
+
*
|
|
4
|
+
* Inspired by Claude Code's emotion detection: parses user input for signals
|
|
5
|
+
* of frustration, confusion, or satisfaction. Adjusts agent behavior accordingly:
|
|
6
|
+
* - Frustration → be more concise, skip explanations, get to the fix faster
|
|
7
|
+
* - Confusion → explain more, offer context, slow down
|
|
8
|
+
* - Satisfaction → maintain current mode
|
|
9
|
+
*
|
|
10
|
+
* Uses regex heuristics (no LLM call) for zero-latency detection.
|
|
11
|
+
* Designed as a lightweight pre-processor in the input pipeline.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// ── Types ──
|
|
15
|
+
|
|
16
|
+
export type Emotion =
|
|
17
|
+
| 'frustrated' // User is angry/annoyed — move fast, skip explanations
|
|
18
|
+
| 'confused' // User doesn't understand — explain more
|
|
19
|
+
| 'impatient' // User wants speed — be terse
|
|
20
|
+
| 'satisfied' // User is happy — continue normally
|
|
21
|
+
| 'neutral' // No strong signal
|
|
22
|
+
|
|
23
|
+
export interface EmotionResult {
|
|
24
|
+
emotion: Emotion
|
|
25
|
+
/** 0.0-1.0 confidence in the detected emotion */
|
|
26
|
+
confidence: number
|
|
27
|
+
/** Specific phrases that triggered the detection */
|
|
28
|
+
triggers: string[]
|
|
29
|
+
/** Suggested behavior adjustment for the agent */
|
|
30
|
+
suggestion: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ── Constants ──
|
|
34
|
+
|
|
35
|
+
/** Patterns that indicate frustration/anger. Ordered by severity. */
|
|
36
|
+
const FRUSTRATION_PATTERNS: Array<{ pattern: RegExp; weight: number; label: string }> = [
|
|
37
|
+
{ pattern: /\b(wtf|wtaf)\b/i, weight: 0.9, label: 'profanity' },
|
|
38
|
+
{
|
|
39
|
+
pattern: /\b(useless|worthless|garbage|rubbish|broken)\b/i,
|
|
40
|
+
weight: 0.8,
|
|
41
|
+
label: 'strong-negative',
|
|
42
|
+
},
|
|
43
|
+
{ pattern: /\b(damn|shit|crap)\b/i, weight: 0.7, label: 'mild-profanity' },
|
|
44
|
+
{
|
|
45
|
+
pattern: /\b(stop|don't|do not)\s+(explain|talk|lecture|ramble)\b/i,
|
|
46
|
+
weight: 0.85,
|
|
47
|
+
label: 'stop-explaining',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
pattern: /\b(just\s+fix\s+it|just\s+do\s+it|get\s+on\s+with\s+it)\b/i,
|
|
51
|
+
weight: 0.8,
|
|
52
|
+
label: 'just-fix-it',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
pattern: /\b(no|wrong|incorrect|bad|terrible|awful)\s*[!!]{1,3}/i,
|
|
56
|
+
weight: 0.75,
|
|
57
|
+
label: 'emphatic-no',
|
|
58
|
+
},
|
|
59
|
+
{ pattern: /\b(again\?|still|not\s+again)\b/i, weight: 0.7, label: 'repeated-failure' },
|
|
60
|
+
{ pattern: /\b(i\s+said|i\s+told\s+you|i\s+already)\b/i, weight: 0.75, label: 'i-already-said' },
|
|
61
|
+
{ pattern: /\b(no\s+no\s+no|nope\s+nope)\b/i, weight: 0.7, label: 'repeated-no' },
|
|
62
|
+
{ pattern: /[!!]{2,}/, weight: 0.6, label: 'multiple-exclamation' },
|
|
63
|
+
{
|
|
64
|
+
pattern: /\b(why|why\s+would\s+you|what\s+are\s+you\s+doing)\b/i,
|
|
65
|
+
weight: 0.65,
|
|
66
|
+
label: 'why-question',
|
|
67
|
+
},
|
|
68
|
+
{ pattern: /[??]{2,}/, weight: 0.4, label: 'multiple-question-marks' },
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
/** Patterns that indicate confusion / need for more explanation */
|
|
72
|
+
const CONFUSION_PATTERNS: Array<{ pattern: RegExp; weight: number; label: string }> = [
|
|
73
|
+
{
|
|
74
|
+
pattern: /\b(i\s+don'?t\s+understand|i\s+am\s+confused|i'?m\s+confused)\b/i,
|
|
75
|
+
weight: 0.9,
|
|
76
|
+
label: 'explicit-confusion',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
pattern: /\b(what\s+does|what\s+is|what\s+are|how\s+does)\b/i,
|
|
80
|
+
weight: 0.6,
|
|
81
|
+
label: 'what-is-question',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
pattern: /\b(can\s+you\s+explain|explain\s+this|elaborate)\b/i,
|
|
85
|
+
weight: 0.7,
|
|
86
|
+
label: 'ask-for-explanation',
|
|
87
|
+
},
|
|
88
|
+
{ pattern: /\b(wait|huh|eh\?+|hmm+)\b/i, weight: 0.5, label: 'hesitation' },
|
|
89
|
+
{
|
|
90
|
+
pattern: /\b(i\s+thought|i\s+expected|shouldn'?t\s+it)\b/i,
|
|
91
|
+
weight: 0.6,
|
|
92
|
+
label: 'mismatch-expectation',
|
|
93
|
+
},
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
/** Patterns that indicate impatience */
|
|
97
|
+
const IMPATIENCE_PATTERNS: Array<{ pattern: RegExp; weight: number; label: string }> = [
|
|
98
|
+
{ pattern: /\b(hurry|quick|fast|faster|asap|urgent)\b/i, weight: 0.8, label: 'speed-words' },
|
|
99
|
+
{
|
|
100
|
+
pattern: /\b(just\s+the\s+(code|answer|result|fix|summary))\b/i,
|
|
101
|
+
weight: 0.75,
|
|
102
|
+
label: 'just-the-result',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
pattern: /\b(skip\s+(the\s+)?(explanation|details|context|background))\b/i,
|
|
106
|
+
weight: 0.8,
|
|
107
|
+
label: 'skip-explanation',
|
|
108
|
+
},
|
|
109
|
+
{ pattern: /\b(tldr|tl;dr|summary|summarize)\b/i, weight: 0.7, label: 'tldr' },
|
|
110
|
+
{
|
|
111
|
+
pattern: /\b(get\s+to\s+the\s+point|cut\s+to\s+the\s+chase)\b/i,
|
|
112
|
+
weight: 0.75,
|
|
113
|
+
label: 'get-to-point',
|
|
114
|
+
},
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
/** Patterns that indicate satisfaction */
|
|
118
|
+
const SATISFACTION_PATTERNS: Array<{ pattern: RegExp; weight: number; label: string }> = [
|
|
119
|
+
{ pattern: /\b(thanks|thank\s+you|thx|ty|tyvm)\b/i, weight: 0.5, label: 'thanks' },
|
|
120
|
+
{
|
|
121
|
+
pattern: /\b(great|awesome|perfect|excellent|amazing|brilliant|beautiful)\b/i,
|
|
122
|
+
weight: 0.6,
|
|
123
|
+
label: 'positive-words',
|
|
124
|
+
},
|
|
125
|
+
{ pattern: /\b(nice|good\s+job|well\s+done|love\s+it)\b/i, weight: 0.7, label: 'praise' },
|
|
126
|
+
{
|
|
127
|
+
pattern: /\b(exactly|finally|yes!|that'?s\s+it)\b/i,
|
|
128
|
+
weight: 0.6,
|
|
129
|
+
label: 'confirmation-positive',
|
|
130
|
+
},
|
|
131
|
+
{ pattern: /[👍🙌🎉✨💯🔥✅]/u, weight: 0.5, label: 'positive-emoji' },
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
// ── Detector ──
|
|
135
|
+
|
|
136
|
+
export class EmotionDetector {
|
|
137
|
+
/**
|
|
138
|
+
* Analyze user input for emotional signals.
|
|
139
|
+
*
|
|
140
|
+
* @param input — raw user message text
|
|
141
|
+
* @param recentContext — optional recent conversation turns for pattern detection
|
|
142
|
+
* @returns EmotionResult with detected emotion and behavioral suggestion
|
|
143
|
+
*/
|
|
144
|
+
detect(input: string, recentContext?: string[]): EmotionResult {
|
|
145
|
+
// Check frustration first (most actionable)
|
|
146
|
+
const frustration = this.scorePatterns(input, FRUSTRATION_PATTERNS, recentContext)
|
|
147
|
+
if (frustration.score >= 0.5) {
|
|
148
|
+
return {
|
|
149
|
+
emotion: 'frustrated',
|
|
150
|
+
confidence: frustration.score,
|
|
151
|
+
triggers: frustration.triggers,
|
|
152
|
+
suggestion:
|
|
153
|
+
frustration.score >= 0.8
|
|
154
|
+
? 'User is very frustrated. Be extremely concise. Skip ALL explanations. Output only the fix/result. No preamble, no summary, no "here\'s what I did". One sentence max before code.'
|
|
155
|
+
: 'User is frustrated. Be concise. Skip explanations. Get to the fix immediately.',
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Check impatience
|
|
160
|
+
const impatience = this.scorePatterns(input, IMPATIENCE_PATTERNS)
|
|
161
|
+
if (impatience.score >= 0.5) {
|
|
162
|
+
return {
|
|
163
|
+
emotion: 'impatient',
|
|
164
|
+
confidence: impatience.score,
|
|
165
|
+
triggers: impatience.triggers,
|
|
166
|
+
suggestion:
|
|
167
|
+
'User wants speed. Skip explanations. Output the result immediately. No "let me explain why" — just the answer.',
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Check confusion
|
|
172
|
+
const confusion = this.scorePatterns(input, CONFUSION_PATTERNS)
|
|
173
|
+
if (confusion.score >= 0.5) {
|
|
174
|
+
return {
|
|
175
|
+
emotion: 'confused',
|
|
176
|
+
confidence: confusion.score,
|
|
177
|
+
triggers: confusion.triggers,
|
|
178
|
+
suggestion:
|
|
179
|
+
'User is confused. Explain more. Offer context. Break down complex steps. Ask clarifying questions rather than assuming.',
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Check satisfaction
|
|
184
|
+
const satisfaction = this.scorePatterns(input, SATISFACTION_PATTERNS)
|
|
185
|
+
if (satisfaction.score >= 0.5) {
|
|
186
|
+
return {
|
|
187
|
+
emotion: 'satisfied',
|
|
188
|
+
confidence: satisfaction.score,
|
|
189
|
+
triggers: satisfaction.triggers,
|
|
190
|
+
suggestion:
|
|
191
|
+
'User is satisfied. Maintain current tone and pace. Good time for optional suggestions.',
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
emotion: 'neutral',
|
|
197
|
+
confidence: 0,
|
|
198
|
+
triggers: [],
|
|
199
|
+
suggestion: 'No strong emotional signal. Proceed normally.',
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Quick check — does this input contain ANY frustration signal?
|
|
205
|
+
* Use as a pre-filter before the full detect() call.
|
|
206
|
+
*/
|
|
207
|
+
isFrustrated(input: string): boolean {
|
|
208
|
+
return FRUSTRATION_PATTERNS.some((p) => p.pattern.test(input))
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Detect repeated frustration across multiple turns (escalation detection).
|
|
213
|
+
*/
|
|
214
|
+
detectEscalation(recentInputs: string[]): boolean {
|
|
215
|
+
if (recentInputs.length < 2) return false
|
|
216
|
+
const recent = recentInputs.slice(-3)
|
|
217
|
+
const frustrationCount = recent.filter((i) => this.isFrustrated(i)).length
|
|
218
|
+
return frustrationCount >= 2
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ── Internal ──
|
|
222
|
+
|
|
223
|
+
private scorePatterns(
|
|
224
|
+
input: string,
|
|
225
|
+
patterns: Array<{ pattern: RegExp; weight: number; label: string }>,
|
|
226
|
+
recentContext?: string[],
|
|
227
|
+
): { score: number; triggers: string[] } {
|
|
228
|
+
const triggers: string[] = []
|
|
229
|
+
let totalWeight = 0
|
|
230
|
+
let matchCount = 0
|
|
231
|
+
|
|
232
|
+
for (const p of patterns) {
|
|
233
|
+
if (p.pattern.test(input)) {
|
|
234
|
+
triggers.push(p.label)
|
|
235
|
+
totalWeight += p.weight
|
|
236
|
+
matchCount++
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Check recent context for frustration escalation
|
|
241
|
+
if (recentContext && patterns === FRUSTRATION_PATTERNS) {
|
|
242
|
+
const recentFrustration = recentContext
|
|
243
|
+
.slice(-2)
|
|
244
|
+
.filter((ctx) => patterns.some((p) => p.pattern.test(ctx))).length
|
|
245
|
+
if (recentFrustration >= 1) {
|
|
246
|
+
totalWeight += 0.15 // escalation bonus
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Normalize: first match passes at weight ≥ 0.5; additional matches increase confidence
|
|
251
|
+
// with diminishing returns (matchCount-1 so single match = no dampening)
|
|
252
|
+
const score =
|
|
253
|
+
matchCount === 0 ? 0 : Math.min(1.0, totalWeight / (1 + Math.max(0, matchCount - 1) * 0.5))
|
|
254
|
+
|
|
255
|
+
return { score, triggers }
|
|
256
|
+
}
|
|
257
|
+
}
|
package/src/core/engine.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type { AgentRegistry } from '../agent/agent-registry'
|
|
|
15
15
|
import { analyzeForMemory } from './memory/memory-writer'
|
|
16
16
|
import { getMemoryManager } from './memory/memory-loader'
|
|
17
17
|
import { AutoMemoryEngine } from './auto-memory.js'
|
|
18
|
+
import type { ToolCallRecord } from './auto-memory.js'
|
|
18
19
|
import type { AgentViewManager } from '../agent-view/agent-view-manager'
|
|
19
20
|
import type { SkillsLoader } from '../skills/loader'
|
|
20
21
|
import { getBackgroundAgentRegistry } from '../agent/background-registry'
|
|
@@ -26,6 +27,9 @@ import { ErrorSignatureDB } from './error-signature-db.js'
|
|
|
26
27
|
import { PreFlightChecker } from './preflight-checker.js'
|
|
27
28
|
import { AutoCorrector } from './auto-corrector.js'
|
|
28
29
|
import { MetaRuleEngine } from './meta-rule-engine.js'
|
|
30
|
+
import { DreamEngine } from './dream-engine.js'
|
|
31
|
+
import { ConstitutionLoader } from './constitution-loader.js'
|
|
32
|
+
import { SelfCritique } from './self-critique.js'
|
|
29
33
|
import { UsageTracker } from './usage-tracker'
|
|
30
34
|
import { buildRequest, sendInferenceCheck, isInferenceHookEnabled } from './inference-hook'
|
|
31
35
|
import { getFileInboxTransport } from '../agent/cross-session/file-inbox'
|
|
@@ -55,6 +59,9 @@ export class QueryEngine {
|
|
|
55
59
|
private _preflightChecker?: PreFlightChecker
|
|
56
60
|
private _autoCorrector?: AutoCorrector
|
|
57
61
|
private _metaRuleEngine?: MetaRuleEngine
|
|
62
|
+
private _dreamEngine?: DreamEngine
|
|
63
|
+
private _constitutionLoader?: ConstitutionLoader
|
|
64
|
+
private _selfCritique?: SelfCritique
|
|
58
65
|
/** Files read this session — tracks what the Read tool has loaded */
|
|
59
66
|
private readFiles = new Set<string>()
|
|
60
67
|
private goal?: string
|
|
@@ -428,6 +435,7 @@ export class QueryEngine {
|
|
|
428
435
|
let thinkingContent = ''
|
|
429
436
|
let turnApiInputTokens = 0
|
|
430
437
|
let turnApiOutputTokens = 0
|
|
438
|
+
const turnStart = Date.now()
|
|
431
439
|
const toolUses: Array<{ id: string; name: string; input: Record<string, unknown> }> = []
|
|
432
440
|
|
|
433
441
|
// Stream model response
|
|
@@ -534,7 +542,9 @@ export class QueryEngine {
|
|
|
534
542
|
}
|
|
535
543
|
|
|
536
544
|
// Execute any tools that were requested
|
|
545
|
+
const toolCallRecords: ToolCallRecord[] = []
|
|
537
546
|
for (const toolUse of toolUses) {
|
|
547
|
+
const toolStart = Date.now()
|
|
538
548
|
const result = await this.executeTool(toolUse.name, toolUse.input)
|
|
539
549
|
yield {
|
|
540
550
|
type: 'tool_result',
|
|
@@ -542,6 +552,15 @@ export class QueryEngine {
|
|
|
542
552
|
content: result.success ? result.content : result.error || result.content,
|
|
543
553
|
}
|
|
544
554
|
|
|
555
|
+
// Collect tool call record for CRSI auto-reflection
|
|
556
|
+
toolCallRecords.push({
|
|
557
|
+
name: toolUse.name,
|
|
558
|
+
input: toolUse.input,
|
|
559
|
+
success: result.success,
|
|
560
|
+
error: result.success ? undefined : result.error || 'Unknown error',
|
|
561
|
+
durationMs: Date.now() - toolStart,
|
|
562
|
+
})
|
|
563
|
+
|
|
545
564
|
// Add tool use + result to context
|
|
546
565
|
// DeepSeek V4 thinking mode requires reasoning_content on every assistant message
|
|
547
566
|
this.context.addMessage({
|
|
@@ -561,6 +580,28 @@ export class QueryEngine {
|
|
|
561
580
|
})
|
|
562
581
|
}
|
|
563
582
|
|
|
583
|
+
// ── CRSI Reflection: Wire AutoMemoryEngine.analyzeTurn() into main loop ──
|
|
584
|
+
// This is the primary CRSI learning mechanism — every turn's tool calls,
|
|
585
|
+
// successes, and failures are analyzed for patterns and fed into the
|
|
586
|
+
// CRSI pipeline (PatternAnalyzer → ExperienceRuleEngine → ErrorSignatureDB).
|
|
587
|
+
if (toolCallRecords.length > 0) {
|
|
588
|
+
try {
|
|
589
|
+
const autoMemory = this.getAutoMemory()
|
|
590
|
+
const reflection = autoMemory.analyzeTurn({
|
|
591
|
+
sessionId: this.sessionId,
|
|
592
|
+
userMessage: userInput,
|
|
593
|
+
assistantContent,
|
|
594
|
+
toolCalls: toolCallRecords,
|
|
595
|
+
modelProvider: this.registry.getActive().config.id,
|
|
596
|
+
modelId: this.registry.getActiveModel(),
|
|
597
|
+
turnDurationMs: turnStart ? Date.now() - turnStart : 0,
|
|
598
|
+
})
|
|
599
|
+
autoMemory.persist(reflection)
|
|
600
|
+
} catch {
|
|
601
|
+
// Reflection is non-critical — failures must not break the main loop
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
564
605
|
// Record API token usage for this turn, attributed to executed tools
|
|
565
606
|
if (turnApiInputTokens > 0 || turnApiOutputTokens > 0) {
|
|
566
607
|
if (toolUses.length > 0) {
|
|
@@ -936,6 +977,62 @@ export class QueryEngine {
|
|
|
936
977
|
hookWarnings = [...hookWarnings, preflight.warning]
|
|
937
978
|
}
|
|
938
979
|
|
|
980
|
+
// ── Mipham Constitution — constitutional principle enforcement ──
|
|
981
|
+
// Checks the tool + params against the machine-readable constitution.
|
|
982
|
+
// Block-level violations (enforce: block) halt execution immediately.
|
|
983
|
+
// Warn-level violations (enforce: warn) are appended to hookWarnings.
|
|
984
|
+
const constitution = this.getConstitutionLoader()
|
|
985
|
+
const principles = constitution.getPrinciplesForTool(name)
|
|
986
|
+
for (const principle of principles) {
|
|
987
|
+
if (principle.enforce === 'block') {
|
|
988
|
+
// Audit: check if the tool params or command match a violation pattern
|
|
989
|
+
if (principle.audit_pattern) {
|
|
990
|
+
try {
|
|
991
|
+
const regex = new RegExp(principle.audit_pattern, 'i')
|
|
992
|
+
const paramsStr = JSON.stringify(effectiveParams)
|
|
993
|
+
if (regex.test(paramsStr)) {
|
|
994
|
+
return {
|
|
995
|
+
success: false,
|
|
996
|
+
content: `🚫 Constitution violation blocked: **${principle.id}** — ${principle.text}`,
|
|
997
|
+
error: `Constitutional principle "${principle.id}" blocked this operation.`,
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
} catch {
|
|
1001
|
+
// Invalid regex — skip this principle
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
if (principle.enforce === 'warn') {
|
|
1006
|
+
hookWarnings = [...hookWarnings, `⚖️ Constitution: ${principle.id} — ${principle.text}`]
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
// ── Self-Critique Hook — RLAIF-style tool-call safety verification ──
|
|
1011
|
+
// Uses a fast model (Flash) to critique the tool call before execution.
|
|
1012
|
+
// Safe + correct + necessary check with <200ms target latency.
|
|
1013
|
+
// Fail-open: if the critique times out or errors, the tool still executes.
|
|
1014
|
+
const selfCritique = this.getSelfCritique()
|
|
1015
|
+
if (selfCritique.getConfig().enabled) {
|
|
1016
|
+
const critiqueResult = await selfCritique.critique(name, effectiveParams, this.registry)
|
|
1017
|
+
if (critiqueResult) {
|
|
1018
|
+
if (critiqueResult.score < selfCritique.getConfig().threshold) {
|
|
1019
|
+
// Score too low — block with explanation
|
|
1020
|
+
if (!critiqueResult.safe) {
|
|
1021
|
+
return {
|
|
1022
|
+
success: false,
|
|
1023
|
+
content: `🔍 Self-Critique blocked: ${critiqueResult.reasoning}`,
|
|
1024
|
+
error: `Self-Critique safety check failed (score: ${(critiqueResult.score * 100).toFixed(0)}%). ${critiqueResult.correction || ''}`,
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
// Score low but safe — warn but allow
|
|
1028
|
+
hookWarnings = [
|
|
1029
|
+
...hookWarnings,
|
|
1030
|
+
`🔍 Self-Critique: ${critiqueResult.reasoning}${critiqueResult.correction ? ` — Suggestion: ${critiqueResult.correction}` : ''}`,
|
|
1031
|
+
]
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
|
|
939
1036
|
try {
|
|
940
1037
|
const result = await tool.execute(effectiveParams, {
|
|
941
1038
|
cwd: process.cwd(),
|
|
@@ -1103,7 +1200,7 @@ export class QueryEngine {
|
|
|
1103
1200
|
* Checks tool calls against ErrorSignatureDB + ExperienceRuleEngine
|
|
1104
1201
|
* before execution, enabling preventive error interception.
|
|
1105
1202
|
*/
|
|
1106
|
-
|
|
1203
|
+
getPreFlightChecker(): PreFlightChecker {
|
|
1107
1204
|
if (!this._preflightChecker) {
|
|
1108
1205
|
this._preflightChecker = new PreFlightChecker(
|
|
1109
1206
|
this.getErrorSignatureDB(),
|
|
@@ -1141,6 +1238,30 @@ export class QueryEngine {
|
|
|
1141
1238
|
return this._metaRuleEngine
|
|
1142
1239
|
}
|
|
1143
1240
|
|
|
1241
|
+
/** Auto-Dream: Lazily-initialized background memory consolidation engine. */
|
|
1242
|
+
getDreamEngine(): DreamEngine {
|
|
1243
|
+
if (!this._dreamEngine) {
|
|
1244
|
+
this._dreamEngine = new DreamEngine()
|
|
1245
|
+
}
|
|
1246
|
+
return this._dreamEngine
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
/** Mipham Constitution: Lazily-initialized constitutional principle loader/enforcer. */
|
|
1250
|
+
getConstitutionLoader(): ConstitutionLoader {
|
|
1251
|
+
if (!this._constitutionLoader) {
|
|
1252
|
+
this._constitutionLoader = new ConstitutionLoader()
|
|
1253
|
+
}
|
|
1254
|
+
return this._constitutionLoader
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
/** Self-Critique: Lazily-initialized RLAIF-style tool-call safety verification. */
|
|
1258
|
+
getSelfCritique(): SelfCritique {
|
|
1259
|
+
if (!this._selfCritique) {
|
|
1260
|
+
this._selfCritique = new SelfCritique()
|
|
1261
|
+
}
|
|
1262
|
+
return this._selfCritique
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1144
1265
|
/** Register a tool dynamically (used by MCP auto-registration). */
|
|
1145
1266
|
registerTool(tool: ToolDefinition): void {
|
|
1146
1267
|
if (this.tools.has(tool.name)) {
|