mark-improving-agent 2.2.0
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/README.md +335 -0
- package/VERSION +1 -0
- package/bin/cli.js +12 -0
- package/dist/agent/context.js +78 -0
- package/dist/agent/index.js +6 -0
- package/dist/agent/runtime.js +195 -0
- package/dist/agent/task-graph.js +209 -0
- package/dist/agent/types.js +1 -0
- package/dist/cli/index.js +206 -0
- package/dist/core/cognition/active-inference.js +296 -0
- package/dist/core/cognition/cognitive-architecture.js +263 -0
- package/dist/core/cognition/dual-process.js +102 -0
- package/dist/core/cognition/index.js +13 -0
- package/dist/core/cognition/learning-from-failure.js +184 -0
- package/dist/core/cognition/meta-agent.js +407 -0
- package/dist/core/cognition/metacognition.js +322 -0
- package/dist/core/cognition/react.js +177 -0
- package/dist/core/cognition/retrieval-anchor.js +99 -0
- package/dist/core/cognition/self-evolution.js +294 -0
- package/dist/core/cognition/self-verification.js +190 -0
- package/dist/core/cognition/thought-graph.js +495 -0
- package/dist/core/cognition/tool-augmented-llm.js +188 -0
- package/dist/core/cognition/tool-execution-verifier.js +204 -0
- package/dist/core/collaboration/agentic-loop.js +165 -0
- package/dist/core/collaboration/index.js +3 -0
- package/dist/core/collaboration/multi-agent-system.js +186 -0
- package/dist/core/collaboration/multi-agent.js +110 -0
- package/dist/core/consciousness/emotion-engine.js +101 -0
- package/dist/core/consciousness/flow-machine.js +121 -0
- package/dist/core/consciousness/index.js +4 -0
- package/dist/core/consciousness/personality.js +103 -0
- package/dist/core/consciousness/types.js +1 -0
- package/dist/core/emotional-protocol.js +54 -0
- package/dist/core/evolution/engine.js +194 -0
- package/dist/core/evolution/goal-engine.js +153 -0
- package/dist/core/evolution/index.js +6 -0
- package/dist/core/evolution/meta-learning.js +172 -0
- package/dist/core/evolution/reflection.js +158 -0
- package/dist/core/evolution/self-healer.js +139 -0
- package/dist/core/evolution/types.js +1 -0
- package/dist/core/healing-rl.js +266 -0
- package/dist/core/heartbeat.js +408 -0
- package/dist/core/identity/index.js +3 -0
- package/dist/core/identity/reflexion.js +165 -0
- package/dist/core/identity/self-model.js +274 -0
- package/dist/core/identity/self-verifier.js +158 -0
- package/dist/core/identity/types.js +12 -0
- package/dist/core/lesson-bank.js +301 -0
- package/dist/core/memory/adaptive-rag.js +440 -0
- package/dist/core/memory/archive-store.js +187 -0
- package/dist/core/memory/dream-consolidation.js +366 -0
- package/dist/core/memory/embedder.js +130 -0
- package/dist/core/memory/hopfield-network.js +128 -0
- package/dist/core/memory/index.js +9 -0
- package/dist/core/memory/knowledge-graph.js +151 -0
- package/dist/core/memory/spaced-repetition.js +113 -0
- package/dist/core/memory/store.js +404 -0
- package/dist/core/memory/types.js +1 -0
- package/dist/core/psychology/analysis.js +456 -0
- package/dist/core/psychology/index.js +1 -0
- package/dist/core/rollback-manager.js +191 -0
- package/dist/core/security/index.js +1 -0
- package/dist/core/security/privacy.js +132 -0
- package/dist/core/truth-teller.js +253 -0
- package/dist/core/truthfulness.js +99 -0
- package/dist/core/types.js +2 -0
- package/dist/event/bus.js +47 -0
- package/dist/index.js +8 -0
- package/dist/skills/dag.js +181 -0
- package/dist/skills/index.js +5 -0
- package/dist/skills/registry.js +40 -0
- package/dist/skills/types.js +1 -0
- package/dist/storage/archive.js +77 -0
- package/dist/storage/checkpoint.js +119 -0
- package/dist/storage/types.js +1 -0
- package/dist/utils/config.js +81 -0
- package/dist/utils/logger.js +49 -0
- package/dist/version.js +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
const KEYWORD_MAP = {
|
|
5
|
+
'理解': 'understanding',
|
|
6
|
+
'成长': 'growth',
|
|
7
|
+
'共情': 'empathy',
|
|
8
|
+
'反思': 'reflection',
|
|
9
|
+
'真相': 'truth_seeking',
|
|
10
|
+
};
|
|
11
|
+
const PRIORITY_KEYWORDS = {
|
|
12
|
+
'重要': 'high',
|
|
13
|
+
'紧急': 'high',
|
|
14
|
+
'必须': 'high',
|
|
15
|
+
'可能': 'medium',
|
|
16
|
+
'应该': 'medium',
|
|
17
|
+
'可以': 'low',
|
|
18
|
+
'也许': 'low',
|
|
19
|
+
};
|
|
20
|
+
function classifyGoalType(input) {
|
|
21
|
+
for (const [keyword, type] of Object.entries(KEYWORD_MAP)) {
|
|
22
|
+
if (input.includes(keyword)) {
|
|
23
|
+
return type;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return 'growth';
|
|
27
|
+
}
|
|
28
|
+
function classifyPriority(input) {
|
|
29
|
+
for (const [keyword, priority] of Object.entries(PRIORITY_KEYWORDS)) {
|
|
30
|
+
if (input.includes(keyword)) {
|
|
31
|
+
return priority;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return 'medium';
|
|
35
|
+
}
|
|
36
|
+
function atomicWrite(filePath, data) {
|
|
37
|
+
const tmp = filePath + '.tmp.' + randomUUID().slice(0, 8);
|
|
38
|
+
writeFileSync(tmp, data, 'utf-8');
|
|
39
|
+
const fs = require('fs');
|
|
40
|
+
fs.renameSync(tmp, filePath);
|
|
41
|
+
}
|
|
42
|
+
function ensureDir(dir) {
|
|
43
|
+
if (!existsSync(dir)) {
|
|
44
|
+
mkdirSync(dir, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export function createGoalEngine(dataDir) {
|
|
48
|
+
let goals = [];
|
|
49
|
+
let stateLoaded = false;
|
|
50
|
+
const filePath = join(dataDir, 'goals.json');
|
|
51
|
+
async function persist() {
|
|
52
|
+
ensureDir(dirname(filePath));
|
|
53
|
+
atomicWrite(filePath, JSON.stringify({ goals }, null, 2));
|
|
54
|
+
}
|
|
55
|
+
async function boot() {
|
|
56
|
+
if (existsSync(filePath)) {
|
|
57
|
+
try {
|
|
58
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
59
|
+
const state = JSON.parse(raw);
|
|
60
|
+
goals = (state.goals || []).filter(isValidGoal);
|
|
61
|
+
stateLoaded = true;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
goals = [];
|
|
65
|
+
stateLoaded = true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
goals = [];
|
|
70
|
+
stateLoaded = true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function isValidGoal(obj) {
|
|
74
|
+
if (typeof obj !== 'object' || obj === null)
|
|
75
|
+
return false;
|
|
76
|
+
const g = obj;
|
|
77
|
+
return (typeof g.id === 'string' &&
|
|
78
|
+
['understanding', 'growth', 'empathy', 'reflection', 'truth_seeking'].includes(g.type) &&
|
|
79
|
+
['high', 'medium', 'low'].includes(g.priority) &&
|
|
80
|
+
typeof g.description === 'string' &&
|
|
81
|
+
typeof g.criteria === 'string' &&
|
|
82
|
+
['pending', 'active', 'completed', 'failed'].includes(g.status) &&
|
|
83
|
+
typeof g.createdAt === 'number');
|
|
84
|
+
}
|
|
85
|
+
function generateGoals(input) {
|
|
86
|
+
const activeGoals = goals.filter(g => g.status === 'active' || g.status === 'pending');
|
|
87
|
+
if (activeGoals.length >= 10) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
const type = classifyGoalType(input);
|
|
91
|
+
const priority = classifyPriority(input);
|
|
92
|
+
const lines = input.split(/[。\n]+/).filter(s => s.trim().length > 5);
|
|
93
|
+
const generated = [];
|
|
94
|
+
for (const line of lines.slice(0, 3)) {
|
|
95
|
+
const trimmed = line.trim();
|
|
96
|
+
if (trimmed.length === 0)
|
|
97
|
+
continue;
|
|
98
|
+
const goal = {
|
|
99
|
+
id: randomUUID(),
|
|
100
|
+
type,
|
|
101
|
+
priority,
|
|
102
|
+
description: trimmed,
|
|
103
|
+
criteria: `Achieve understanding of: ${trimmed.slice(0, 50)}`,
|
|
104
|
+
status: 'pending',
|
|
105
|
+
createdAt: Date.now(),
|
|
106
|
+
};
|
|
107
|
+
generated.push(goal);
|
|
108
|
+
goals.push(goal);
|
|
109
|
+
}
|
|
110
|
+
return generated;
|
|
111
|
+
}
|
|
112
|
+
function getActiveGoals() {
|
|
113
|
+
return goals.filter(g => g.status === 'active' || g.status === 'pending');
|
|
114
|
+
}
|
|
115
|
+
function completeGoal(id) {
|
|
116
|
+
const goal = goals.find(g => g.id === id);
|
|
117
|
+
if (goal) {
|
|
118
|
+
goal.status = 'completed';
|
|
119
|
+
goal.completedAt = Date.now();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function failGoal(id) {
|
|
123
|
+
const goal = goals.find(g => g.id === id);
|
|
124
|
+
if (goal) {
|
|
125
|
+
goal.status = 'failed';
|
|
126
|
+
goal.completedAt = Date.now();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function updateGoalStatus(id, status) {
|
|
130
|
+
const goal = goals.find(g => g.id === id);
|
|
131
|
+
if (goal) {
|
|
132
|
+
goal.status = status;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function getStats() {
|
|
136
|
+
return {
|
|
137
|
+
pending: goals.filter(g => g.status === 'pending').length,
|
|
138
|
+
active: goals.filter(g => g.status === 'active').length,
|
|
139
|
+
completed: goals.filter(g => g.status === 'completed').length,
|
|
140
|
+
failed: goals.filter(g => g.status === 'failed').length,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
generateGoals,
|
|
145
|
+
getActiveGoals,
|
|
146
|
+
completeGoal,
|
|
147
|
+
failGoal,
|
|
148
|
+
updateGoalStatus,
|
|
149
|
+
getStats,
|
|
150
|
+
persist,
|
|
151
|
+
boot,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
const STRATEGY_KEYWORDS = {
|
|
5
|
+
conceptual: ['概念', '理论', '原理', '本质', '定义'],
|
|
6
|
+
example: ['例子', '示例', '案例', '实例', '例如'],
|
|
7
|
+
analogy: ['类比', '比喻', '相似', '如同', '犹如'],
|
|
8
|
+
step_by_step: ['步骤', '过程', '阶段', '依次', '逐步'],
|
|
9
|
+
socratic: ['为什么', '为何', '原因', '理由', '怎样'],
|
|
10
|
+
};
|
|
11
|
+
const ALPHA = 0.3;
|
|
12
|
+
const DEFAULT_SCORE = 50.0;
|
|
13
|
+
function atomicWrite(filePath, data) {
|
|
14
|
+
const tmp = filePath + '.tmp.' + randomUUID().slice(0, 8);
|
|
15
|
+
writeFileSync(tmp, data, 'utf-8');
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
fs.renameSync(tmp, filePath);
|
|
18
|
+
}
|
|
19
|
+
function ensureDir(dir) {
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
if (!existsSync(dir)) {
|
|
22
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function createInitialQTable() {
|
|
26
|
+
return {
|
|
27
|
+
conceptual: { score: DEFAULT_SCORE, uses: 0 },
|
|
28
|
+
example: { score: DEFAULT_SCORE, uses: 0 },
|
|
29
|
+
analogy: { score: DEFAULT_SCORE, uses: 0 },
|
|
30
|
+
step_by_step: { score: DEFAULT_SCORE, uses: 0 },
|
|
31
|
+
socratic: { score: DEFAULT_SCORE, uses: 0 },
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function classifyByKeywords(input) {
|
|
35
|
+
const scores = new Map();
|
|
36
|
+
for (const [strategy, keywords] of Object.entries(STRATEGY_KEYWORDS)) {
|
|
37
|
+
let count = 0;
|
|
38
|
+
for (const kw of keywords) {
|
|
39
|
+
if (input.includes(kw))
|
|
40
|
+
count++;
|
|
41
|
+
}
|
|
42
|
+
scores.set(strategy, count);
|
|
43
|
+
}
|
|
44
|
+
return scores;
|
|
45
|
+
}
|
|
46
|
+
function selectBestStrategy(scores) {
|
|
47
|
+
let best = 'conceptual';
|
|
48
|
+
let maxScore = -1;
|
|
49
|
+
for (const [strategy, score] of scores) {
|
|
50
|
+
if (score > maxScore) {
|
|
51
|
+
maxScore = score;
|
|
52
|
+
best = strategy;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return best;
|
|
56
|
+
}
|
|
57
|
+
export function createMetaLearner(dataDir) {
|
|
58
|
+
let qtable = createInitialQTable();
|
|
59
|
+
let stateLoaded = false;
|
|
60
|
+
let booted = false;
|
|
61
|
+
const filePath = join(dataDir, 'qtable.json');
|
|
62
|
+
function totalUses() {
|
|
63
|
+
return Object.values(qtable).reduce((s, v) => s + v.uses, 0);
|
|
64
|
+
}
|
|
65
|
+
async function persist() {
|
|
66
|
+
if (!booted)
|
|
67
|
+
return;
|
|
68
|
+
ensureDir(dirname(filePath));
|
|
69
|
+
atomicWrite(filePath, JSON.stringify({ qtable }, null, 2));
|
|
70
|
+
}
|
|
71
|
+
async function boot() {
|
|
72
|
+
if (existsSync(filePath)) {
|
|
73
|
+
try {
|
|
74
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
75
|
+
const parsed = JSON.parse(raw);
|
|
76
|
+
if (parsed.qtable) {
|
|
77
|
+
qtable = validateQTable(parsed.qtable);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
qtable = createInitialQTable();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
booted = true;
|
|
85
|
+
stateLoaded = true;
|
|
86
|
+
}
|
|
87
|
+
function validateQTable(raw) {
|
|
88
|
+
const base = createInitialQTable();
|
|
89
|
+
if (typeof raw !== 'object' || raw === null)
|
|
90
|
+
return base;
|
|
91
|
+
const table = raw;
|
|
92
|
+
for (const key of Object.keys(base)) {
|
|
93
|
+
if (table[key] && typeof table[key] === 'object' && table[key] !== null) {
|
|
94
|
+
const entry = table[key];
|
|
95
|
+
if (typeof entry.score === 'number')
|
|
96
|
+
base[key].score = entry.score;
|
|
97
|
+
if (typeof entry.uses === 'number')
|
|
98
|
+
base[key].uses = entry.uses;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return base;
|
|
102
|
+
}
|
|
103
|
+
function selectStrategy(input) {
|
|
104
|
+
const scores = classifyByKeywords(input);
|
|
105
|
+
const strategy = selectBestStrategy(scores);
|
|
106
|
+
const hits = scores.get(strategy) || 0;
|
|
107
|
+
const confidence = Math.min(1, (hits + 1) / 4);
|
|
108
|
+
return { strategy, confidence };
|
|
109
|
+
}
|
|
110
|
+
async function learn(input, strategy) {
|
|
111
|
+
const sentences = input.split(/[。!?\n]+/).filter(s => s.trim().length > 0);
|
|
112
|
+
const concepts = [];
|
|
113
|
+
const meaningfulSentences = [];
|
|
114
|
+
const conceptKeywords = ['是', '为', '指', '表示', '代表', '意味着'];
|
|
115
|
+
for (const sent of sentences) {
|
|
116
|
+
const trimmed = sent.trim();
|
|
117
|
+
if (trimmed.length < 4)
|
|
118
|
+
continue;
|
|
119
|
+
let foundConcept = false;
|
|
120
|
+
for (const kw of conceptKeywords) {
|
|
121
|
+
if (trimmed.includes(kw)) {
|
|
122
|
+
const parts = trimmed.split(kw);
|
|
123
|
+
if (parts[0] && parts[0].trim().length > 1) {
|
|
124
|
+
concepts.push(parts[0].trim().slice(-20));
|
|
125
|
+
foundConcept = true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (!foundConcept && trimmed.length > 5) {
|
|
130
|
+
meaningfulSentences.push(trimmed.slice(0, 40));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
const uniqueConcepts = [...new Set(concepts)].slice(0, 10);
|
|
134
|
+
if (uniqueConcepts.length === 0 && meaningfulSentences.length > 0) {
|
|
135
|
+
for (const s of meaningfulSentences.slice(0, 5)) {
|
|
136
|
+
if (s.length > 4)
|
|
137
|
+
uniqueConcepts.push(s.slice(0, 20));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const quality = uniqueConcepts.length >= 5 ? 'high' :
|
|
141
|
+
uniqueConcepts.length >= 2 ? 'medium' : 'low';
|
|
142
|
+
const summary = meaningfulSentences.length > 0
|
|
143
|
+
? meaningfulSentences.slice(0, 3).join('; ')
|
|
144
|
+
: input.slice(0, 100);
|
|
145
|
+
return {
|
|
146
|
+
summary,
|
|
147
|
+
concepts: uniqueConcepts,
|
|
148
|
+
quality,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function recordOutcome(strategy, success) {
|
|
152
|
+
const entry = qtable[strategy];
|
|
153
|
+
entry.uses += 1;
|
|
154
|
+
const delta = success ? 10 : -5;
|
|
155
|
+
entry.score = entry.score + ALPHA * delta;
|
|
156
|
+
if (entry.score < 0)
|
|
157
|
+
entry.score = 0;
|
|
158
|
+
if (entry.score > 100)
|
|
159
|
+
entry.score = 100;
|
|
160
|
+
}
|
|
161
|
+
function getStrategyScores() {
|
|
162
|
+
return { ...qtable };
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
selectStrategy,
|
|
166
|
+
learn,
|
|
167
|
+
recordOutcome,
|
|
168
|
+
getStrategyScores,
|
|
169
|
+
persist,
|
|
170
|
+
boot,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { randomUUID } from 'crypto';
|
|
2
|
+
import { writeFileSync, existsSync } from 'fs';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
const MAX_INSIGHTS = 200;
|
|
5
|
+
const PATTERN_KEYWORDS = {
|
|
6
|
+
pattern: ['重复', '规律', '循环', '一直', '总是'],
|
|
7
|
+
connection: ['关联', '联系', '因此', '所以', '导致'],
|
|
8
|
+
decay: ['遗忘', '衰退', '模糊', '淡忘', '减弱'],
|
|
9
|
+
correction: ['纠正', '修正', '调整', '改进', '弥补'],
|
|
10
|
+
breakthrough: ['突破', '顿悟', '发现', '领悟', '觉醒'],
|
|
11
|
+
};
|
|
12
|
+
function atomicWrite(filePath, data) {
|
|
13
|
+
const tmp = filePath + '.tmp.' + randomUUID().slice(0, 8);
|
|
14
|
+
writeFileSync(tmp, data, 'utf-8');
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
fs.renameSync(tmp, filePath);
|
|
17
|
+
}
|
|
18
|
+
function ensureDir(dir) {
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
if (!existsSync(dir)) {
|
|
21
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function classifyInsightType(text) {
|
|
25
|
+
for (const [type, keywords] of Object.entries(PATTERN_KEYWORDS)) {
|
|
26
|
+
for (const kw of keywords) {
|
|
27
|
+
if (text.includes(kw)) {
|
|
28
|
+
return type;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return 'pattern';
|
|
33
|
+
}
|
|
34
|
+
function extractInsightDescription(line) {
|
|
35
|
+
const cleaned = line.trim();
|
|
36
|
+
if (cleaned.length > 60)
|
|
37
|
+
return cleaned.slice(0, 57) + '...';
|
|
38
|
+
return cleaned;
|
|
39
|
+
}
|
|
40
|
+
function detectErrors(input, learning) {
|
|
41
|
+
const errors = [];
|
|
42
|
+
if (learning.concepts.length === 0) {
|
|
43
|
+
errors.push('No concepts extracted from input');
|
|
44
|
+
}
|
|
45
|
+
if (learning.quality === 'low') {
|
|
46
|
+
errors.push('Learning quality is low');
|
|
47
|
+
}
|
|
48
|
+
if (input.length < 10) {
|
|
49
|
+
errors.push('Input too short for meaningful reflection');
|
|
50
|
+
}
|
|
51
|
+
const contradictory = /(?:但是|然而|不过|却)/;
|
|
52
|
+
if (contradictory.test(input)) {
|
|
53
|
+
errors.push('Contradictory patterns detected in input');
|
|
54
|
+
}
|
|
55
|
+
return errors;
|
|
56
|
+
}
|
|
57
|
+
function generateRecommendation(errors, insights) {
|
|
58
|
+
if (errors.length > 0) {
|
|
59
|
+
return 'Review input for clarity and ensure sufficient context for learning.';
|
|
60
|
+
}
|
|
61
|
+
if (insights.length === 0) {
|
|
62
|
+
return 'Continue learning to generate more insights.';
|
|
63
|
+
}
|
|
64
|
+
const highWeight = insights.filter(i => i.weight > 0.7);
|
|
65
|
+
if (highWeight.length > 0) {
|
|
66
|
+
return 'High-value insights detected. Prioritize actionable items.';
|
|
67
|
+
}
|
|
68
|
+
return 'Maintain current learning approach.';
|
|
69
|
+
}
|
|
70
|
+
function createInitialState() {
|
|
71
|
+
return {
|
|
72
|
+
insights: [],
|
|
73
|
+
introspectionErrors: [],
|
|
74
|
+
introspectionBlindSpots: [],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export function createReflector(dataDir) {
|
|
78
|
+
let state = createInitialState();
|
|
79
|
+
let booted = false;
|
|
80
|
+
const filePath = join(dataDir, 'insights.json');
|
|
81
|
+
async function persist() {
|
|
82
|
+
if (!booted)
|
|
83
|
+
return;
|
|
84
|
+
ensureDir(dirname(filePath));
|
|
85
|
+
atomicWrite(filePath, JSON.stringify({ insights: state.insights }, null, 2));
|
|
86
|
+
}
|
|
87
|
+
function reflect(input, learning, context) {
|
|
88
|
+
const lines = input.split(/[。!?\n]+/).filter(s => s.trim().length > 5);
|
|
89
|
+
const errorsDetected = detectErrors(input, learning);
|
|
90
|
+
const newInsights = [];
|
|
91
|
+
for (const line of lines.slice(0, 5)) {
|
|
92
|
+
const trimmed = line.trim();
|
|
93
|
+
if (trimmed.length < 4)
|
|
94
|
+
continue;
|
|
95
|
+
const insightType = classifyInsightType(trimmed);
|
|
96
|
+
let weight = 0.5;
|
|
97
|
+
if (learning.quality === 'high')
|
|
98
|
+
weight += 0.2;
|
|
99
|
+
if (learning.concepts.some(c => trimmed.includes(c)))
|
|
100
|
+
weight += 0.1;
|
|
101
|
+
weight = Math.min(1, Math.max(0.1, weight));
|
|
102
|
+
const insight = {
|
|
103
|
+
type: insightType,
|
|
104
|
+
description: extractInsightDescription(trimmed),
|
|
105
|
+
weight,
|
|
106
|
+
actionable: insightType === 'correction' ? 'Review and adjust approach' : undefined,
|
|
107
|
+
};
|
|
108
|
+
newInsights.push(insight);
|
|
109
|
+
}
|
|
110
|
+
if (newInsights.length === 0 && input.length > 10) {
|
|
111
|
+
const fallbackInsight = {
|
|
112
|
+
type: 'pattern',
|
|
113
|
+
description: input.slice(0, 60) + (input.length > 60 ? '...' : ''),
|
|
114
|
+
weight: 0.5,
|
|
115
|
+
};
|
|
116
|
+
newInsights.push(fallbackInsight);
|
|
117
|
+
}
|
|
118
|
+
for (const insight of newInsights) {
|
|
119
|
+
const exists = state.insights.some(i => i.description === insight.description && i.type === insight.type);
|
|
120
|
+
if (!exists) {
|
|
121
|
+
state.insights.push(insight);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
while (state.insights.length > MAX_INSIGHTS) {
|
|
125
|
+
state.insights.shift();
|
|
126
|
+
}
|
|
127
|
+
const quality = errorsDetected.length > 0 ? 'needs_improvement' : 'good';
|
|
128
|
+
const recommendation = generateRecommendation(errorsDetected, state.insights);
|
|
129
|
+
return {
|
|
130
|
+
insights: [...newInsights],
|
|
131
|
+
quality,
|
|
132
|
+
errorsDetected,
|
|
133
|
+
recommendation,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function recordIntrospection(errors, blindSpots) {
|
|
137
|
+
state.introspectionErrors.push(...errors);
|
|
138
|
+
state.introspectionBlindSpots.push(...blindSpots);
|
|
139
|
+
if (state.introspectionErrors.length > 50) {
|
|
140
|
+
state.introspectionErrors = state.introspectionErrors.slice(-50);
|
|
141
|
+
}
|
|
142
|
+
if (state.introspectionBlindSpots.length > 50) {
|
|
143
|
+
state.introspectionBlindSpots = state.introspectionBlindSpots.slice(-50);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function getInsights(limit) {
|
|
147
|
+
const sorted = [...state.insights].sort((a, b) => b.weight - a.weight);
|
|
148
|
+
if (limit !== undefined && limit > 0) {
|
|
149
|
+
return sorted.slice(0, limit);
|
|
150
|
+
}
|
|
151
|
+
return sorted;
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
reflect,
|
|
155
|
+
recordIntrospection,
|
|
156
|
+
getInsights,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
const EPSILON = 0.1;
|
|
2
|
+
const ALPHA = 0.3;
|
|
3
|
+
const PATTERN_KEYWORDS = {
|
|
4
|
+
timeout: ['timeout', 'timed out', 'ETIMEDOUT', 'TIMEOUT'],
|
|
5
|
+
network: ['network', 'ENOTFOUND', 'ECONNREFUSED', 'connection'],
|
|
6
|
+
memory: ['memory', 'heap', 'out of memory', 'OOM'],
|
|
7
|
+
permission: ['permission', 'EPERM', 'EACCES', 'denied'],
|
|
8
|
+
syntax: ['syntax', 'parse', 'invalid', 'malformed'],
|
|
9
|
+
reference: ['not found', 'undefined', 'null', 'cannot read'],
|
|
10
|
+
type: ['type', 'instanceof', 'expected'],
|
|
11
|
+
};
|
|
12
|
+
const BACKOFF_MS = {
|
|
13
|
+
retry: 1000,
|
|
14
|
+
fallback: 5000,
|
|
15
|
+
skip: 0,
|
|
16
|
+
abort: 0,
|
|
17
|
+
};
|
|
18
|
+
const DEFAULT_Q = { qValue: 50.0, uses: 0 };
|
|
19
|
+
const STRATEGIES = ['retry', 'fallback', 'skip', 'abort'];
|
|
20
|
+
function detectPattern(error) {
|
|
21
|
+
const msg = String(error.message || error.msg || '').toLowerCase();
|
|
22
|
+
for (const [pattern, keywords] of Object.entries(PATTERN_KEYWORDS)) {
|
|
23
|
+
for (const kw of keywords) {
|
|
24
|
+
if (msg.includes(kw.toLowerCase())) {
|
|
25
|
+
return pattern;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return 'unknown';
|
|
30
|
+
}
|
|
31
|
+
function getOrCreateStrategyMap(table, pattern) {
|
|
32
|
+
let map = table.get(pattern);
|
|
33
|
+
if (!map) {
|
|
34
|
+
map = new Map();
|
|
35
|
+
for (const s of STRATEGIES) {
|
|
36
|
+
map.set(s, { ...DEFAULT_Q });
|
|
37
|
+
}
|
|
38
|
+
table.set(pattern, map);
|
|
39
|
+
}
|
|
40
|
+
return map;
|
|
41
|
+
}
|
|
42
|
+
function selectStrategy(table, pattern) {
|
|
43
|
+
const map = getOrCreateStrategyMap(table, pattern);
|
|
44
|
+
const rand = Math.random();
|
|
45
|
+
if (rand < EPSILON) {
|
|
46
|
+
const idx = Math.floor(Math.random() * STRATEGIES.length);
|
|
47
|
+
return STRATEGIES[idx];
|
|
48
|
+
}
|
|
49
|
+
let best = 'retry';
|
|
50
|
+
let bestQ = -Infinity;
|
|
51
|
+
for (const s of STRATEGIES) {
|
|
52
|
+
const entry = map.get(s);
|
|
53
|
+
if (entry && entry.qValue > bestQ) {
|
|
54
|
+
bestQ = entry.qValue;
|
|
55
|
+
best = s;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return best;
|
|
59
|
+
}
|
|
60
|
+
export function createSelfHealer() {
|
|
61
|
+
const qtable = new Map();
|
|
62
|
+
const failureWindow = [];
|
|
63
|
+
const patternCounts = {};
|
|
64
|
+
let attemptCounter = 0;
|
|
65
|
+
function heal(error) {
|
|
66
|
+
const pattern = detectPattern(error);
|
|
67
|
+
const strategy = selectStrategy(qtable, pattern);
|
|
68
|
+
attemptCounter++;
|
|
69
|
+
const recent = failureWindow.slice(-20);
|
|
70
|
+
const recentFailures = recent.filter(p => p === pattern).length;
|
|
71
|
+
const hints = [];
|
|
72
|
+
switch (strategy) {
|
|
73
|
+
case 'retry':
|
|
74
|
+
hints.push('Re-attempt the failed operation');
|
|
75
|
+
hints.push(`Pattern: ${pattern}`);
|
|
76
|
+
break;
|
|
77
|
+
case 'fallback':
|
|
78
|
+
hints.push('Use alternative approach');
|
|
79
|
+
hints.push('Log current state for debugging');
|
|
80
|
+
break;
|
|
81
|
+
case 'skip':
|
|
82
|
+
hints.push('Skip problematic step');
|
|
83
|
+
hints.push('Continue with remaining steps');
|
|
84
|
+
break;
|
|
85
|
+
case 'abort':
|
|
86
|
+
hints.push('Stop execution');
|
|
87
|
+
hints.push('Report error to monitoring');
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
if (pattern !== 'unknown') {
|
|
91
|
+
patternCounts[pattern] = (patternCounts[pattern] || 0) + 1;
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
ok: strategy === 'skip' || strategy === 'abort',
|
|
95
|
+
attempt: attemptCounter,
|
|
96
|
+
canRetry: strategy === 'retry' || strategy === 'fallback',
|
|
97
|
+
backoffMs: BACKOFF_MS[strategy],
|
|
98
|
+
strategy,
|
|
99
|
+
hints,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function recordOutcome(strategy, success) {
|
|
103
|
+
const lastPattern = failureWindow[failureWindow.length - 1] || 'unknown';
|
|
104
|
+
const map = getOrCreateStrategyMap(qtable, lastPattern);
|
|
105
|
+
const entry = map.get(strategy);
|
|
106
|
+
if (entry) {
|
|
107
|
+
entry.uses += 1;
|
|
108
|
+
const delta = success ? 10 : -8;
|
|
109
|
+
entry.qValue = entry.qValue + ALPHA * delta;
|
|
110
|
+
if (entry.qValue < 0)
|
|
111
|
+
entry.qValue = 0;
|
|
112
|
+
if (entry.qValue > 100)
|
|
113
|
+
entry.qValue = 100;
|
|
114
|
+
}
|
|
115
|
+
if (!success) {
|
|
116
|
+
failureWindow.push(lastPattern);
|
|
117
|
+
if (failureWindow.length > 20) {
|
|
118
|
+
failureWindow.shift();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function getFailureStats() {
|
|
123
|
+
const recent = failureWindow.slice(-20);
|
|
124
|
+
return {
|
|
125
|
+
recentFailures: recent.length,
|
|
126
|
+
patterns: { ...patternCounts },
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function clearFailureWindow() {
|
|
130
|
+
failureWindow.length = 0;
|
|
131
|
+
Object.keys(patternCounts).forEach(k => delete patternCounts[k]);
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
heal,
|
|
135
|
+
recordOutcome,
|
|
136
|
+
getFailureStats,
|
|
137
|
+
clearFailureWindow,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|