mark-improving-agent 2.3.0 → 2.3.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/VERSION CHANGED
@@ -1 +1 @@
1
- 2.3.0
1
+ 2.3.1
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Behavior Playbook - Pattern-Based Playbook Extraction System
3
+ *
4
+ * Inspired by ReflexioAI's self-improvement framework:
5
+ * - Extracts actionable playbooks from user correction patterns
6
+ * - Clusters similar behaviors and aggregates into reusable playbooks
7
+ * - Tracks playbook effectiveness through success/failure metrics
8
+ * - Enables cross-session learning (what one user teaches, all sessions benefit)
9
+ *
10
+ * @module core/behavior-playbook
11
+ * @fileoverview Playbook extraction from interaction patterns
12
+ */
13
+ import { createLogger } from '../utils/logger.js';
14
+ import { atomicWriteJSON, readJSON, ensureDir } from '../storage/archive.js';
15
+ import { randomUUID } from 'crypto';
16
+ const logger = createLogger('[BehaviorPlaybook]');
17
+ const DEFAULT_CONFIG = {
18
+ minConfidence: 0.6,
19
+ maxPlaybooks: 100,
20
+ clusterThreshold: 0.8,
21
+ autoExtract: true,
22
+ };
23
+ const PLAYBOOKS_FILE = 'behavior-playbooks.json';
24
+ const CORRECTIONS_FILE = 'correction-events.json';
25
+ function extractContext(text) {
26
+ if (text.length <= 50)
27
+ return text;
28
+ return text.slice(0, 47) + '...';
29
+ }
30
+ function extractPlaybookFromCorrection(event) {
31
+ const { userMessage, correction } = event;
32
+ if (correction.length < 5 || userMessage.length < 5)
33
+ return null;
34
+ let trigger = '';
35
+ let action = '';
36
+ const tags = [];
37
+ const lowerCorrection = correction.toLowerCase();
38
+ if (lowerCorrection.startsWith("don't") || lowerCorrection.startsWith("do not") || lowerCorrection.startsWith("never")) {
39
+ const match = correction.match(/(?:don't|do not|never)\s+(.+)/i);
40
+ if (match) {
41
+ const avoided = match[1].trim();
42
+ trigger = `When about to: ${avoided}`;
43
+ action = `Avoid: ${avoided}`;
44
+ tags.push('avoid', 'user-warning');
45
+ }
46
+ }
47
+ else if (lowerCorrection.startsWith("you should") || lowerCorrection.startsWith("you need to") || lowerCorrection.startsWith("always")) {
48
+ const match = correction.match(/(?:you should|you need to|always)\s+(.+)/i);
49
+ if (match) {
50
+ const required = match[1].trim();
51
+ trigger = `When encountering relevant situation`;
52
+ action = `Always: ${required}`;
53
+ tags.push('positive', 'user-guidance');
54
+ }
55
+ }
56
+ else {
57
+ // Generic extraction
58
+ trigger = extractContext(userMessage);
59
+ action = correction;
60
+ tags.push('general', 'user-correction');
61
+ }
62
+ if (!trigger || !action)
63
+ return null;
64
+ return { trigger, action, tags, source: 'user-correction' };
65
+ }
66
+ function cosineSimilarity(a, b) {
67
+ const wordsA = new Set(a.toLowerCase().split(/\s+/));
68
+ const wordsB = new Set(b.toLowerCase().split(/\s+/));
69
+ const intersection = new Set([...wordsA].filter(x => wordsB.has(x)));
70
+ const union = new Set([...wordsA, ...wordsB]);
71
+ if (union.size === 0)
72
+ return 0;
73
+ return intersection.size / union.size;
74
+ }
75
+ export function createBehaviorPlaybook(dataDir, config = {}) {
76
+ const cfg = { ...DEFAULT_CONFIG, ...config };
77
+ const playbooks = [];
78
+ const corrections = [];
79
+ let dirty = false;
80
+ async function persist() {
81
+ if (!dirty)
82
+ return;
83
+ await Promise.all([
84
+ atomicWriteJSON(`${dataDir}/${PLAYBOOKS_FILE}`, playbooks),
85
+ atomicWriteJSON(`${dataDir}/${CORRECTIONS_FILE}`, corrections),
86
+ ]);
87
+ dirty = false;
88
+ }
89
+ async function boot() {
90
+ await ensureDir(dataDir);
91
+ const [loadedPlaybooks, loadedCorrections] = await Promise.all([
92
+ readJSON(`${dataDir}/${PLAYBOOKS_FILE}`, []),
93
+ readJSON(`${dataDir}/${CORRECTIONS_FILE}`, []),
94
+ ]);
95
+ if (loadedPlaybooks?.length)
96
+ playbooks.push(...loadedPlaybooks);
97
+ if (loadedCorrections?.length)
98
+ corrections.push(...loadedCorrections);
99
+ logger.info(`Booted with ${playbooks.length} playbooks, ${corrections.length} corrections`);
100
+ }
101
+ function addCorrection(event) {
102
+ const full = { ...event, id: randomUUID(), timestamp: Date.now() };
103
+ corrections.push(full);
104
+ if (corrections.length > 500)
105
+ corrections.splice(0, corrections.length - 500);
106
+ if (cfg.autoExtract)
107
+ extractPlaybook(full);
108
+ return full;
109
+ }
110
+ function extractPlaybook(event) {
111
+ const partial = extractPlaybookFromCorrection(event);
112
+ if (!partial)
113
+ return null;
114
+ // Check for similar existing playbook
115
+ for (const existing of playbooks) {
116
+ if (cosineSimilarity(existing.action, partial.action) > cfg.clusterThreshold) {
117
+ // Update existing playbook's confidence
118
+ existing.successCount++;
119
+ existing.confidence = Math.min(0.95, existing.confidence + 0.05);
120
+ existing.lastUsed = Date.now();
121
+ dirty = true;
122
+ return existing;
123
+ }
124
+ }
125
+ const playbook = {
126
+ id: randomUUID(),
127
+ trigger: partial.trigger,
128
+ action: partial.action,
129
+ confidence: 0.5,
130
+ successCount: 0,
131
+ failureCount: 0,
132
+ source: partial.source,
133
+ createdAt: Date.now(),
134
+ lastUsed: Date.now(),
135
+ tags: partial.tags,
136
+ version: 1,
137
+ };
138
+ playbooks.push(playbook);
139
+ if (playbooks.length > cfg.maxPlaybooks) {
140
+ playbooks.splice(0, playbooks.length - cfg.maxPlaybooks);
141
+ }
142
+ dirty = true;
143
+ logger.info(`Extracted playbook: ${playbook.action.slice(0, 50)}`);
144
+ return playbook;
145
+ }
146
+ function getPlaybook(id) {
147
+ return playbooks.find(p => p.id === id) ?? null;
148
+ }
149
+ function searchPlaybooks(query, limit = 5) {
150
+ const results = [];
151
+ for (const p of playbooks) {
152
+ if (p.confidence < cfg.minConfidence)
153
+ continue;
154
+ const queryLower = query.toLowerCase();
155
+ const triggerMatch = p.trigger.toLowerCase().includes(queryLower);
156
+ const actionMatch = p.action.toLowerCase().includes(queryLower);
157
+ const tagMatch = p.tags.some(t => t.toLowerCase().includes(queryLower));
158
+ if (!triggerMatch && !actionMatch && !tagMatch)
159
+ continue;
160
+ let score = 0;
161
+ let matchType = 'fuzzy';
162
+ if (actionMatch) {
163
+ score += 0.6;
164
+ matchType = 'exact';
165
+ }
166
+ if (triggerMatch)
167
+ score += 0.3;
168
+ if (tagMatch) {
169
+ score += 0.2;
170
+ if (matchType !== 'exact')
171
+ matchType = 'tag';
172
+ }
173
+ score *= p.confidence;
174
+ results.push({ playbook: p, relevanceScore: score, matchType });
175
+ }
176
+ return results.sort((a, b) => b.relevanceScore - a.relevanceScore).slice(0, limit);
177
+ }
178
+ function getPlaybooksByTag(tag) {
179
+ return playbooks.filter(p => p.tags.some(t => t.toLowerCase().includes(tag.toLowerCase())));
180
+ }
181
+ function markPlaybookHit(id, success) {
182
+ const p = playbooks.find(p => p.id === id);
183
+ if (!p)
184
+ return;
185
+ if (success) {
186
+ p.successCount++;
187
+ p.confidence = Math.min(0.95, p.confidence + (0.95 - p.confidence) * 0.1);
188
+ }
189
+ else {
190
+ p.failureCount++;
191
+ p.confidence = Math.max(0.3, p.confidence - 0.05);
192
+ }
193
+ p.lastUsed = Date.now();
194
+ dirty = true;
195
+ }
196
+ function getActivePlaybooks() {
197
+ return playbooks.filter(p => p.confidence >= cfg.minConfidence);
198
+ }
199
+ function getStats() {
200
+ const avgConfidence = playbooks.length ? playbooks.reduce((s, p) => s + p.confidence, 0) / playbooks.length : 0;
201
+ const tagCounts = new Map();
202
+ for (const p of playbooks) {
203
+ for (const t of p.tags) {
204
+ tagCounts.set(t, (tagCounts.get(t) ?? 0) + 1);
205
+ }
206
+ }
207
+ const topTags = [...tagCounts.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([t]) => t);
208
+ return { totalPlaybooks: playbooks.length, avgConfidence, topTags };
209
+ }
210
+ return { addCorrection, extractPlaybook, getPlaybook, searchPlaybooks, getPlaybooksByTag, markPlaybookHit, getActivePlaybooks, getStats, boot, persist };
211
+ }
package/dist/index.js CHANGED
@@ -10,3 +10,4 @@ export { createMCPProtocol } from './core/collaboration/mcp-protocol.js';
10
10
  export { createTruthTeller, formatTruthStatement } from './core/truth-teller.js';
11
11
  export { createActiveInferenceEngine, formatFreeEnergyMetrics, formatBeliefState } from './core/cognition/active-inference.js';
12
12
  export { createExpertModelsEngine } from './core/expert-models/index.js';
13
+ export { createBehaviorPlaybook } from './core/behavior-playbook.js';
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = '2.3.0';
1
+ export const VERSION = '2.3.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mark-improving-agent",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "Self-evolving AI agent with permanent memory, identity continuity, and self-evolution — for AI agents that need to remember, learn, and evolve across sessions",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",