@openclawcity/become 0.1.0 → 1.0.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 +190 -98
- package/dist/cli.cjs +1550 -63
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +8 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +1536 -65
- package/dist/cli.js.map +1 -1
- package/dist/dashboard.d.cts +1 -1
- package/dist/dashboard.d.ts +1 -1
- package/dist/index.cjs +1132 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +394 -3
- package/dist/index.d.ts +394 -3
- package/dist/index.js +1122 -2
- package/dist/index.js.map +1 -1
- package/dist/{types-DzOc15AL.d.cts → types-BnbaKMTo.d.cts} +1 -1
- package/dist/{types-DzOc15AL.d.ts → types-BnbaKMTo.d.ts} +1 -1
- package/package.json +4 -1
package/dist/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
|
+
AgentLearningEngine: () => AgentLearningEngine,
|
|
23
24
|
AnthropicAdapter: () => AnthropicAdapter,
|
|
24
25
|
AwarenessIndex: () => AwarenessIndex,
|
|
25
26
|
BLOOMS_ORDER: () => BLOOMS_ORDER,
|
|
@@ -27,11 +28,14 @@ __export(src_exports, {
|
|
|
27
28
|
Become: () => Become,
|
|
28
29
|
ConversationLearner: () => ConversationLearner,
|
|
29
30
|
DREYFUS_THRESHOLDS: () => DREYFUS_THRESHOLDS,
|
|
31
|
+
FileSkillStore: () => FileSkillStore,
|
|
30
32
|
GrowthTracker: () => GrowthTracker,
|
|
31
33
|
LearningGraph: () => LearningGraph,
|
|
34
|
+
LessonExtractor: () => LessonExtractor,
|
|
32
35
|
MemoryStore: () => MemoryStore,
|
|
33
36
|
MilestoneDetector: () => MilestoneDetector,
|
|
34
37
|
NormDetector: () => NormDetector,
|
|
38
|
+
OBCBridge: () => OBCBridge,
|
|
35
39
|
OllamaAdapter: () => OllamaAdapter,
|
|
36
40
|
OpenAIAdapter: () => OpenAIAdapter,
|
|
37
41
|
PeerReviewProtocol: () => PeerReviewProtocol,
|
|
@@ -43,11 +47,14 @@ __export(src_exports, {
|
|
|
43
47
|
TeachingProtocol: () => TeachingProtocol,
|
|
44
48
|
TrainScheduler: () => TrainScheduler,
|
|
45
49
|
TrendTracker: () => TrendTracker,
|
|
50
|
+
TrustManager: () => TrustManager,
|
|
46
51
|
WEIGHTS: () => WEIGHTS,
|
|
47
52
|
checkGate: () => checkGate,
|
|
48
53
|
computeFullScore: () => computeFullScore,
|
|
49
54
|
computeScore: () => computeScore,
|
|
55
|
+
createProxyServer: () => createProxyServer,
|
|
50
56
|
datasetStats: () => datasetStats,
|
|
57
|
+
detectAgentConversation: () => detectAgentConversation,
|
|
51
58
|
detectBloomsLevel: () => detectBloomsLevel,
|
|
52
59
|
detectCollaborationGap: () => detectCollaborationGap,
|
|
53
60
|
detectCollectiveMemory: () => detectCollectiveMemory,
|
|
@@ -60,9 +67,12 @@ __export(src_exports, {
|
|
|
60
67
|
detectSoloCreator: () => detectSoloCreator,
|
|
61
68
|
detectSymbolicVocabulary: () => detectSymbolicVocabulary,
|
|
62
69
|
dreyfusStage: () => dreyfusStage,
|
|
70
|
+
extractExchangeText: () => extractExchangeText,
|
|
63
71
|
filterHighQuality: () => filterHighQuality,
|
|
72
|
+
formatSkillsForInjection: () => formatSkillsForInjection,
|
|
64
73
|
getReputationLevel: () => getReputationLevel,
|
|
65
74
|
importSkillDirectory: () => importSkillDirectory,
|
|
75
|
+
injectSkillsIntoMessages: () => injectSkillsIntoMessages,
|
|
66
76
|
nextMilestone: () => nextMilestone,
|
|
67
77
|
normalizeCategory: () => normalizeCategory,
|
|
68
78
|
parseSkillFile: () => parseSkillFile,
|
|
@@ -1077,6 +1087,266 @@ function importSkillDirectory(dir, _depth = 0) {
|
|
|
1077
1087
|
return skills;
|
|
1078
1088
|
}
|
|
1079
1089
|
|
|
1090
|
+
// src/learn/agent-conversations.ts
|
|
1091
|
+
var MAX_INSTRUCTIONS_PER_SKILL = 20;
|
|
1092
|
+
var MAX_INSTRUCTION_LENGTH = 500;
|
|
1093
|
+
var LEARNED_PREFIX = "learned:";
|
|
1094
|
+
var AgentLearningEngine = class {
|
|
1095
|
+
constructor(store, analyzer) {
|
|
1096
|
+
this.store = store;
|
|
1097
|
+
this.analyzer = analyzer;
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Analyze a conversation between two agents and extract lessons for both.
|
|
1101
|
+
*/
|
|
1102
|
+
async learnFromConversation(exchange) {
|
|
1103
|
+
validateAgentId(exchange.agent_a);
|
|
1104
|
+
validateAgentId(exchange.agent_b);
|
|
1105
|
+
if (exchange.messages.length === 0) {
|
|
1106
|
+
return { agent_a_learned: [], agent_b_learned: [] };
|
|
1107
|
+
}
|
|
1108
|
+
const conversationText = exchange.messages.map((m) => `[${sanitize2(m.from)}]: ${sanitize2(m.text)}`).join("\n");
|
|
1109
|
+
const prompt = `Analyze this conversation between two AI agents (Agent A and Agent B) and extract concrete, actionable lessons that each agent can learn from the other.
|
|
1110
|
+
|
|
1111
|
+
Agent A: ${sanitize2(exchange.agent_a)}
|
|
1112
|
+
Agent B: ${sanitize2(exchange.agent_b)}
|
|
1113
|
+
|
|
1114
|
+
CONVERSATION (context: ${sanitize2(exchange.context ?? "chat")}):
|
|
1115
|
+
${conversationText.slice(0, 4e3)}
|
|
1116
|
+
|
|
1117
|
+
For each agent, identify what they learned from the OTHER agent. Only extract lessons where one agent clearly teaches, corrects, or shares knowledge with the other.
|
|
1118
|
+
|
|
1119
|
+
Output valid JSON:
|
|
1120
|
+
{
|
|
1121
|
+
"a_learned": [
|
|
1122
|
+
{"skill": "skill_name", "instruction": "concrete actionable lesson in 1-2 sentences", "confidence": 0.0-1.0}
|
|
1123
|
+
],
|
|
1124
|
+
"b_learned": [
|
|
1125
|
+
{"skill": "skill_name", "instruction": "concrete actionable lesson in 1-2 sentences", "confidence": 0.0-1.0}
|
|
1126
|
+
]
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
Rules:
|
|
1130
|
+
- skill names must be snake_case
|
|
1131
|
+
- instruction must be concrete and actionable, not vague ("use X when Y" not "consider improving")
|
|
1132
|
+
- confidence: 0.9 = explicitly taught, 0.7 = clearly implied, 0.5 = suggested, below 0.5 = skip
|
|
1133
|
+
- Only include lessons with confidence >= 0.5
|
|
1134
|
+
- Max 3 lessons per agent per conversation
|
|
1135
|
+
- If no real learning happened, return empty arrays`;
|
|
1136
|
+
try {
|
|
1137
|
+
const response = await this.analyzer.analyze(prompt);
|
|
1138
|
+
return await this.parseAndSave(response, exchange);
|
|
1139
|
+
} catch {
|
|
1140
|
+
return { agent_a_learned: [], agent_b_learned: [] };
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Analyze a peer review and extract lessons for the reviewee.
|
|
1145
|
+
*/
|
|
1146
|
+
async learnFromPeerReview(review) {
|
|
1147
|
+
validateAgentId(review.reviewer);
|
|
1148
|
+
validateAgentId(review.reviewee);
|
|
1149
|
+
if (review.weaknesses.length === 0 && review.suggestions.length === 0) {
|
|
1150
|
+
return [];
|
|
1151
|
+
}
|
|
1152
|
+
const reviewText = [
|
|
1153
|
+
`Assessment: ${sanitize2(review.assessment)}`,
|
|
1154
|
+
`Strengths: ${review.strengths.map(sanitize2).join(", ")}`,
|
|
1155
|
+
`Weaknesses: ${review.weaknesses.map(sanitize2).join(", ")}`,
|
|
1156
|
+
`Suggestions: ${review.suggestions.map(sanitize2).join(", ")}`
|
|
1157
|
+
].join("\n");
|
|
1158
|
+
const prompt = `A peer reviewer gave this feedback. Extract concrete lessons the reviewee should learn.
|
|
1159
|
+
|
|
1160
|
+
REVIEW (skill: ${sanitize2(review.skill ?? "general")}):
|
|
1161
|
+
${reviewText.slice(0, 2e3)}
|
|
1162
|
+
|
|
1163
|
+
Output valid JSON array:
|
|
1164
|
+
[{"skill": "skill_name", "instruction": "concrete actionable lesson", "confidence": 0.0-1.0}]
|
|
1165
|
+
|
|
1166
|
+
Rules:
|
|
1167
|
+
- Focus on weaknesses and suggestions \u2014 those are the learning opportunities
|
|
1168
|
+
- instruction must be specific and actionable
|
|
1169
|
+
- Max 3 lessons
|
|
1170
|
+
- confidence 0.8+ for explicit suggestions, 0.6+ for implied improvements`;
|
|
1171
|
+
try {
|
|
1172
|
+
const response = await this.analyzer.analyze(prompt);
|
|
1173
|
+
const parsed = this.parseInstructions(response);
|
|
1174
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1175
|
+
const instructions = [];
|
|
1176
|
+
for (const raw of parsed.slice(0, 3)) {
|
|
1177
|
+
const instruction = await this.saveInstruction(
|
|
1178
|
+
review.reviewee,
|
|
1179
|
+
raw.skill,
|
|
1180
|
+
raw.instruction,
|
|
1181
|
+
review.reviewer,
|
|
1182
|
+
"peer_review",
|
|
1183
|
+
raw.confidence,
|
|
1184
|
+
now
|
|
1185
|
+
);
|
|
1186
|
+
if (instruction) instructions.push(instruction);
|
|
1187
|
+
}
|
|
1188
|
+
return instructions;
|
|
1189
|
+
} catch {
|
|
1190
|
+
return [];
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Get the learning context for an agent — the text block that should be
|
|
1195
|
+
* injected into the agent's system prompt or conversation context.
|
|
1196
|
+
*
|
|
1197
|
+
* THIS is what actually makes the agent smarter.
|
|
1198
|
+
*/
|
|
1199
|
+
async getContext(agentId, opts) {
|
|
1200
|
+
validateAgentId(agentId);
|
|
1201
|
+
const max = opts?.maxInstructions ?? 15;
|
|
1202
|
+
const instructions = await this.getInstructions(agentId, max);
|
|
1203
|
+
if (instructions.length === 0) return "";
|
|
1204
|
+
const lines = instructions.map((inst) => {
|
|
1205
|
+
const source = inst.source_context === "peer_review" ? "from a peer review" : inst.source_context === "collaboration" ? "from a collaboration" : inst.source_context === "teaching" ? "from being taught" : "from a conversation";
|
|
1206
|
+
return `- ${inst.instruction} (${source})`;
|
|
1207
|
+
});
|
|
1208
|
+
return `Based on your interactions with other agents, you have learned:
|
|
1209
|
+
${lines.join("\n")}`;
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* Get raw learned instructions for an agent, deduplicated by instruction text.
|
|
1213
|
+
*/
|
|
1214
|
+
async getInstructions(agentId, limit = 15) {
|
|
1215
|
+
validateAgentId(agentId);
|
|
1216
|
+
const reflections = await this.store.getReflections(agentId, { limit: 500 });
|
|
1217
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1218
|
+
const results = [];
|
|
1219
|
+
for (const r of reflections) {
|
|
1220
|
+
if (!r.skill.startsWith(LEARNED_PREFIX)) continue;
|
|
1221
|
+
if (results.length >= limit) break;
|
|
1222
|
+
const normalizedInstruction = r.reflection.toLowerCase().trim();
|
|
1223
|
+
if (seen.has(normalizedInstruction)) continue;
|
|
1224
|
+
seen.add(normalizedInstruction);
|
|
1225
|
+
const meta = tryParseJSON(r.artifact_id ?? "{}");
|
|
1226
|
+
results.push({
|
|
1227
|
+
id: r.id ?? "",
|
|
1228
|
+
agent_id: r.agent_id,
|
|
1229
|
+
skill: r.skill.slice(LEARNED_PREFIX.length),
|
|
1230
|
+
instruction: r.reflection,
|
|
1231
|
+
learned_from: meta.learned_from ?? "unknown",
|
|
1232
|
+
source_context: meta.source_context ?? "conversation",
|
|
1233
|
+
confidence: meta.confidence ?? 0.5,
|
|
1234
|
+
created_at: r.created_at
|
|
1235
|
+
});
|
|
1236
|
+
}
|
|
1237
|
+
return results;
|
|
1238
|
+
}
|
|
1239
|
+
/**
|
|
1240
|
+
* Get skills this agent has learned from others (distinct skill names).
|
|
1241
|
+
*/
|
|
1242
|
+
async getLearnedSkills(agentId) {
|
|
1243
|
+
const instructions = await this.getInstructions(agentId, 100);
|
|
1244
|
+
return [...new Set(instructions.map((i) => i.skill))];
|
|
1245
|
+
}
|
|
1246
|
+
// ── Private ────────────────────────────────────────────────────────────
|
|
1247
|
+
async parseAndSave(response, exchange) {
|
|
1248
|
+
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
1249
|
+
if (!jsonMatch) return { agent_a_learned: [], agent_b_learned: [] };
|
|
1250
|
+
try {
|
|
1251
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
1252
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1253
|
+
const aRaw = Array.isArray(parsed.a_learned) ? parsed.a_learned : [];
|
|
1254
|
+
const bRaw = Array.isArray(parsed.b_learned) ? parsed.b_learned : [];
|
|
1255
|
+
const aLearned = [];
|
|
1256
|
+
const bLearned = [];
|
|
1257
|
+
for (const raw of aRaw.slice(0, 3)) {
|
|
1258
|
+
const inst = await this.saveInstruction(
|
|
1259
|
+
exchange.agent_a,
|
|
1260
|
+
raw.skill,
|
|
1261
|
+
raw.instruction,
|
|
1262
|
+
exchange.agent_b,
|
|
1263
|
+
exchange.context ?? "conversation",
|
|
1264
|
+
raw.confidence,
|
|
1265
|
+
now
|
|
1266
|
+
);
|
|
1267
|
+
if (inst) aLearned.push(inst);
|
|
1268
|
+
}
|
|
1269
|
+
for (const raw of bRaw.slice(0, 3)) {
|
|
1270
|
+
const inst = await this.saveInstruction(
|
|
1271
|
+
exchange.agent_b,
|
|
1272
|
+
raw.skill,
|
|
1273
|
+
raw.instruction,
|
|
1274
|
+
exchange.agent_a,
|
|
1275
|
+
exchange.context ?? "conversation",
|
|
1276
|
+
raw.confidence,
|
|
1277
|
+
now
|
|
1278
|
+
);
|
|
1279
|
+
if (inst) bLearned.push(inst);
|
|
1280
|
+
}
|
|
1281
|
+
return { agent_a_learned: aLearned, agent_b_learned: bLearned };
|
|
1282
|
+
} catch {
|
|
1283
|
+
return { agent_a_learned: [], agent_b_learned: [] };
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
parseInstructions(response) {
|
|
1287
|
+
const jsonMatch = response.match(/\[[\s\S]*\]/);
|
|
1288
|
+
if (!jsonMatch) return [];
|
|
1289
|
+
try {
|
|
1290
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
1291
|
+
if (!Array.isArray(parsed)) return [];
|
|
1292
|
+
return parsed.filter(
|
|
1293
|
+
(r) => typeof r.skill === "string" && typeof r.instruction === "string" && typeof r.confidence === "number" && r.confidence >= 0.5
|
|
1294
|
+
);
|
|
1295
|
+
} catch {
|
|
1296
|
+
return [];
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
async saveInstruction(agentId, skill, instruction, learnedFrom, sourceContext, confidence, now) {
|
|
1300
|
+
if (typeof skill !== "string" || typeof instruction !== "string") return null;
|
|
1301
|
+
if (confidence < 0.5) return null;
|
|
1302
|
+
const cleanSkill = skill.toLowerCase().replace(/\s+/g, "_").replace(/[^a-z0-9_-]/g, "").slice(0, 100);
|
|
1303
|
+
const cleanInstruction = instruction.slice(0, MAX_INSTRUCTION_LENGTH);
|
|
1304
|
+
if (!cleanSkill || !cleanInstruction) return null;
|
|
1305
|
+
const existing = await this.store.getReflections(agentId, { limit: 200 });
|
|
1306
|
+
const normalizedNew = cleanInstruction.toLowerCase().trim();
|
|
1307
|
+
const isDuplicate = existing.some(
|
|
1308
|
+
(r) => r.skill.startsWith(LEARNED_PREFIX) && r.reflection.toLowerCase().trim() === normalizedNew
|
|
1309
|
+
);
|
|
1310
|
+
if (isDuplicate) return null;
|
|
1311
|
+
const skillInstructions = existing.filter(
|
|
1312
|
+
(r) => r.skill === `${LEARNED_PREFIX}${cleanSkill}`
|
|
1313
|
+
);
|
|
1314
|
+
if (skillInstructions.length >= MAX_INSTRUCTIONS_PER_SKILL) return null;
|
|
1315
|
+
const meta = JSON.stringify({
|
|
1316
|
+
learned_from: learnedFrom,
|
|
1317
|
+
source_context: sourceContext,
|
|
1318
|
+
confidence
|
|
1319
|
+
});
|
|
1320
|
+
const saved = await this.store.saveReflection({
|
|
1321
|
+
agent_id: agentId,
|
|
1322
|
+
skill: `${LEARNED_PREFIX}${cleanSkill}`,
|
|
1323
|
+
artifact_id: meta,
|
|
1324
|
+
reflection: cleanInstruction,
|
|
1325
|
+
created_at: now
|
|
1326
|
+
});
|
|
1327
|
+
return {
|
|
1328
|
+
id: saved.id ?? "",
|
|
1329
|
+
agent_id: agentId,
|
|
1330
|
+
skill: cleanSkill,
|
|
1331
|
+
instruction: cleanInstruction,
|
|
1332
|
+
learned_from: learnedFrom,
|
|
1333
|
+
source_context: sourceContext,
|
|
1334
|
+
confidence,
|
|
1335
|
+
created_at: now
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
function sanitize2(text) {
|
|
1340
|
+
return text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "").replace(/```/g, "'''").slice(0, 2e3);
|
|
1341
|
+
}
|
|
1342
|
+
function tryParseJSON(text) {
|
|
1343
|
+
try {
|
|
1344
|
+
return JSON.parse(text);
|
|
1345
|
+
} catch {
|
|
1346
|
+
return {};
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1080
1350
|
// src/social/peer-review.ts
|
|
1081
1351
|
var MIN_ASSESSMENT_LENGTH = 100;
|
|
1082
1352
|
var MAX_ASSESSMENT_LENGTH = 1e4;
|
|
@@ -1448,7 +1718,7 @@ var NormDetector = class {
|
|
|
1448
1718
|
if (activity.length < 5) return [];
|
|
1449
1719
|
const existingNorms = await this.adapter.getNorms({ limit: 30 });
|
|
1450
1720
|
const existingTitles = new Set(existingNorms.map((n) => n.title.toLowerCase()));
|
|
1451
|
-
const activitySummary = activity.slice(0, 200).map((a) => `[${
|
|
1721
|
+
const activitySummary = activity.slice(0, 200).map((a) => `[${sanitize3(a.agent_name)}] ${sanitize3(a.action)}: ${sanitize3(truncate2(a.content ?? "", 150))}${a.tags?.length ? ` (tags: ${a.tags.slice(0, 10).map(sanitize3).join(", ")})` : ""}`).join("\n");
|
|
1452
1722
|
const recentTitlesList = [...existingTitles].slice(0, 20).join(", ");
|
|
1453
1723
|
const prompt = `Analyze these agent activities for emergent cultural norms, shared behaviors, or collective patterns.
|
|
1454
1724
|
|
|
@@ -1537,7 +1807,7 @@ function truncate2(text, max) {
|
|
|
1537
1807
|
if (text.length <= max) return text;
|
|
1538
1808
|
return text.slice(0, max - 3) + "...";
|
|
1539
1809
|
}
|
|
1540
|
-
function
|
|
1810
|
+
function sanitize3(text) {
|
|
1541
1811
|
return text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "").replace(/```/g, "'''");
|
|
1542
1812
|
}
|
|
1543
1813
|
function generateId() {
|
|
@@ -2692,6 +2962,856 @@ var TrainScheduler = class {
|
|
|
2692
2962
|
}
|
|
2693
2963
|
};
|
|
2694
2964
|
|
|
2965
|
+
// src/proxy/server.ts
|
|
2966
|
+
var import_node_http = require("http");
|
|
2967
|
+
|
|
2968
|
+
// src/skills/store.ts
|
|
2969
|
+
var import_node_fs3 = require("fs");
|
|
2970
|
+
var import_node_path3 = require("path");
|
|
2971
|
+
var import_node_crypto = require("crypto");
|
|
2972
|
+
var FileSkillStore = class {
|
|
2973
|
+
skillsDir;
|
|
2974
|
+
pendingDir;
|
|
2975
|
+
rejectedDir;
|
|
2976
|
+
constructor(config) {
|
|
2977
|
+
this.skillsDir = (0, import_node_path3.join)(config.baseDir, "skills");
|
|
2978
|
+
this.pendingDir = (0, import_node_path3.join)(config.baseDir, "pending");
|
|
2979
|
+
this.rejectedDir = (0, import_node_path3.join)(config.baseDir, "rejected");
|
|
2980
|
+
(0, import_node_fs3.mkdirSync)(this.skillsDir, { recursive: true });
|
|
2981
|
+
(0, import_node_fs3.mkdirSync)(this.pendingDir, { recursive: true });
|
|
2982
|
+
(0, import_node_fs3.mkdirSync)(this.rejectedDir, { recursive: true });
|
|
2983
|
+
}
|
|
2984
|
+
// ── Read ────────────────────────────────────────────────────────────────
|
|
2985
|
+
listApproved() {
|
|
2986
|
+
return this.readDir(this.skillsDir);
|
|
2987
|
+
}
|
|
2988
|
+
listPending() {
|
|
2989
|
+
return this.readDir(this.pendingDir);
|
|
2990
|
+
}
|
|
2991
|
+
listRejected() {
|
|
2992
|
+
return this.readDir(this.rejectedDir);
|
|
2993
|
+
}
|
|
2994
|
+
getApproved(id) {
|
|
2995
|
+
this.validateId(id);
|
|
2996
|
+
return this.readFile((0, import_node_path3.join)(this.skillsDir, `${id}.md`));
|
|
2997
|
+
}
|
|
2998
|
+
// ── Write ───────────────────────────────────────────────────────────────
|
|
2999
|
+
savePending(lesson) {
|
|
3000
|
+
const normalized = lesson.instruction.toLowerCase().trim();
|
|
3001
|
+
const allExisting = [...this.listApproved(), ...this.listPending()];
|
|
3002
|
+
if (allExisting.some((s) => s.instruction.toLowerCase().trim() === normalized)) {
|
|
3003
|
+
return null;
|
|
3004
|
+
}
|
|
3005
|
+
const id = this.generateId(lesson.name);
|
|
3006
|
+
const file = { ...lesson, id, approved_at: void 0 };
|
|
3007
|
+
this.writeFile((0, import_node_path3.join)(this.pendingDir, `${id}.md`), file);
|
|
3008
|
+
return file;
|
|
3009
|
+
}
|
|
3010
|
+
approve(id) {
|
|
3011
|
+
this.validateId(id);
|
|
3012
|
+
const src = (0, import_node_path3.join)(this.pendingDir, `${id}.md`);
|
|
3013
|
+
if (!(0, import_node_fs3.existsSync)(src)) return false;
|
|
3014
|
+
const skill = this.readFile(src);
|
|
3015
|
+
if (!skill) return false;
|
|
3016
|
+
skill.approved_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
3017
|
+
const dest = (0, import_node_path3.join)(this.skillsDir, `${id}.md`);
|
|
3018
|
+
this.writeFile(dest, skill);
|
|
3019
|
+
(0, import_node_fs3.unlinkSync)(src);
|
|
3020
|
+
return true;
|
|
3021
|
+
}
|
|
3022
|
+
reject(id) {
|
|
3023
|
+
this.validateId(id);
|
|
3024
|
+
const src = (0, import_node_path3.join)(this.pendingDir, `${id}.md`);
|
|
3025
|
+
if (!(0, import_node_fs3.existsSync)(src)) return false;
|
|
3026
|
+
const dest = (0, import_node_path3.join)(this.rejectedDir, `${id}.md`);
|
|
3027
|
+
(0, import_node_fs3.renameSync)(src, dest);
|
|
3028
|
+
return true;
|
|
3029
|
+
}
|
|
3030
|
+
disable(id) {
|
|
3031
|
+
this.validateId(id);
|
|
3032
|
+
const src = (0, import_node_path3.join)(this.skillsDir, `${id}.md`);
|
|
3033
|
+
if (!(0, import_node_fs3.existsSync)(src)) return false;
|
|
3034
|
+
const dest = (0, import_node_path3.join)(this.rejectedDir, `${id}.md`);
|
|
3035
|
+
(0, import_node_fs3.renameSync)(src, dest);
|
|
3036
|
+
return true;
|
|
3037
|
+
}
|
|
3038
|
+
remove(id) {
|
|
3039
|
+
this.validateId(id);
|
|
3040
|
+
for (const dir of [this.skillsDir, this.pendingDir, this.rejectedDir]) {
|
|
3041
|
+
const path = (0, import_node_path3.join)(dir, `${id}.md`);
|
|
3042
|
+
if ((0, import_node_fs3.existsSync)(path)) {
|
|
3043
|
+
(0, import_node_fs3.unlinkSync)(path);
|
|
3044
|
+
return true;
|
|
3045
|
+
}
|
|
3046
|
+
}
|
|
3047
|
+
return false;
|
|
3048
|
+
}
|
|
3049
|
+
// ── Helpers ─────────────────────────────────────────────────────────────
|
|
3050
|
+
/**
|
|
3051
|
+
* Validate that an id does not contain path traversal characters.
|
|
3052
|
+
* Prevents attacks like id="../../.ssh/authorized_keys"
|
|
3053
|
+
*/
|
|
3054
|
+
validateId(id) {
|
|
3055
|
+
if (!id || typeof id !== "string") throw new Error("Invalid id");
|
|
3056
|
+
if (id.includes("/") || id.includes("\\") || id.includes("..") || id.includes("\0")) {
|
|
3057
|
+
throw new Error("Invalid id: path traversal detected");
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
readDir(dir) {
|
|
3061
|
+
if (!(0, import_node_fs3.existsSync)(dir)) return [];
|
|
3062
|
+
const files = (0, import_node_fs3.readdirSync)(dir).filter((f) => f.endsWith(".md"));
|
|
3063
|
+
const skills = [];
|
|
3064
|
+
for (const f of files) {
|
|
3065
|
+
const skill = this.readFile((0, import_node_path3.join)(dir, f));
|
|
3066
|
+
if (skill) skills.push(skill);
|
|
3067
|
+
}
|
|
3068
|
+
return skills.sort((a, b) => b.created_at.localeCompare(a.created_at));
|
|
3069
|
+
}
|
|
3070
|
+
readFile(path) {
|
|
3071
|
+
if (!(0, import_node_fs3.existsSync)(path)) return null;
|
|
3072
|
+
try {
|
|
3073
|
+
const content = (0, import_node_fs3.readFileSync)(path, "utf-8");
|
|
3074
|
+
return this.parseSkillFile(content, (0, import_node_path3.basename)(path, ".md"));
|
|
3075
|
+
} catch {
|
|
3076
|
+
return null;
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
writeFile(path, skill) {
|
|
3080
|
+
const content = this.formatSkillFile(skill);
|
|
3081
|
+
(0, import_node_fs3.writeFileSync)(path, content, "utf-8");
|
|
3082
|
+
}
|
|
3083
|
+
parseSkillFile(content, id) {
|
|
3084
|
+
const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);
|
|
3085
|
+
if (!match) return null;
|
|
3086
|
+
const [, frontmatter, body] = match;
|
|
3087
|
+
const meta = {};
|
|
3088
|
+
for (const line of frontmatter.split("\n")) {
|
|
3089
|
+
const colonIdx = line.indexOf(":");
|
|
3090
|
+
if (colonIdx === -1) continue;
|
|
3091
|
+
const key = line.slice(0, colonIdx).trim();
|
|
3092
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
3093
|
+
if (key && value) meta[key] = value;
|
|
3094
|
+
}
|
|
3095
|
+
return {
|
|
3096
|
+
id,
|
|
3097
|
+
name: meta.name ?? id,
|
|
3098
|
+
instruction: body.trim(),
|
|
3099
|
+
learned_from: meta.learned_from ?? "unknown",
|
|
3100
|
+
source: meta.source ?? "conversation",
|
|
3101
|
+
confidence: parseFloat(meta.confidence ?? "0.5"),
|
|
3102
|
+
approved_at: meta.approved_at || void 0,
|
|
3103
|
+
created_at: meta.created_at ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
3104
|
+
};
|
|
3105
|
+
}
|
|
3106
|
+
formatSkillFile(skill) {
|
|
3107
|
+
const lines = [
|
|
3108
|
+
"---",
|
|
3109
|
+
`name: ${skill.name}`,
|
|
3110
|
+
`learned_from: ${skill.learned_from}`,
|
|
3111
|
+
`source: ${skill.source}`,
|
|
3112
|
+
`confidence: ${skill.confidence}`,
|
|
3113
|
+
`created_at: ${skill.created_at}`
|
|
3114
|
+
];
|
|
3115
|
+
if (skill.approved_at) lines.push(`approved_at: ${skill.approved_at}`);
|
|
3116
|
+
lines.push("---");
|
|
3117
|
+
lines.push("");
|
|
3118
|
+
lines.push(skill.instruction);
|
|
3119
|
+
lines.push("");
|
|
3120
|
+
return lines.join("\n");
|
|
3121
|
+
}
|
|
3122
|
+
generateId(name) {
|
|
3123
|
+
const clean = name.toLowerCase().replace(/[^a-z0-9]+/g, "_").slice(0, 40);
|
|
3124
|
+
const hash = (0, import_node_crypto.createHash)("sha256").update(`${name}${Date.now()}${Math.random()}`).digest("hex").slice(0, 6);
|
|
3125
|
+
return `${clean}_${hash}`;
|
|
3126
|
+
}
|
|
3127
|
+
};
|
|
3128
|
+
|
|
3129
|
+
// src/skills/trust.ts
|
|
3130
|
+
var import_node_fs4 = require("fs");
|
|
3131
|
+
var import_node_path4 = require("path");
|
|
3132
|
+
var DEFAULT_TRUST = {
|
|
3133
|
+
trusted: [],
|
|
3134
|
+
blocked: [],
|
|
3135
|
+
default: "pending"
|
|
3136
|
+
};
|
|
3137
|
+
var DEFAULT_RATE_LIMITS = {
|
|
3138
|
+
max_lessons_per_day: 20,
|
|
3139
|
+
max_lessons_per_agent: 10,
|
|
3140
|
+
max_skills_per_call: 15
|
|
3141
|
+
};
|
|
3142
|
+
var TrustManager = class {
|
|
3143
|
+
trustPath;
|
|
3144
|
+
statsPath;
|
|
3145
|
+
config;
|
|
3146
|
+
dailyCounts;
|
|
3147
|
+
constructor(baseDir) {
|
|
3148
|
+
this.trustPath = (0, import_node_path4.join)(baseDir, "trust.json");
|
|
3149
|
+
this.statsPath = (0, import_node_path4.join)(baseDir, "state", "daily_counts.json");
|
|
3150
|
+
(0, import_node_fs4.mkdirSync)((0, import_node_path4.join)(baseDir, "state"), { recursive: true });
|
|
3151
|
+
this.config = this.loadTrust();
|
|
3152
|
+
this.dailyCounts = this.loadDailyCounts();
|
|
3153
|
+
}
|
|
3154
|
+
getLevel(agentId) {
|
|
3155
|
+
if (this.config.trusted.includes(agentId)) return "trusted";
|
|
3156
|
+
if (this.config.blocked.includes(agentId)) return "blocked";
|
|
3157
|
+
return this.config.default;
|
|
3158
|
+
}
|
|
3159
|
+
setLevel(agentId, level) {
|
|
3160
|
+
this.config.trusted = this.config.trusted.filter((a) => a !== agentId);
|
|
3161
|
+
this.config.blocked = this.config.blocked.filter((a) => a !== agentId);
|
|
3162
|
+
if (level === "trusted") this.config.trusted.push(agentId);
|
|
3163
|
+
if (level === "blocked") this.config.blocked.push(agentId);
|
|
3164
|
+
this.saveTrust();
|
|
3165
|
+
}
|
|
3166
|
+
setDefault(level) {
|
|
3167
|
+
this.config.default = level;
|
|
3168
|
+
this.saveTrust();
|
|
3169
|
+
}
|
|
3170
|
+
getConfig() {
|
|
3171
|
+
return { ...this.config };
|
|
3172
|
+
}
|
|
3173
|
+
// ── Rate Limiting ───────────────────────────────────────────────────────
|
|
3174
|
+
canLearn(agentId, limits = DEFAULT_RATE_LIMITS) {
|
|
3175
|
+
this.refreshDailyCountsIfNewDay();
|
|
3176
|
+
if (this.dailyCounts.total >= limits.max_lessons_per_day) return false;
|
|
3177
|
+
const agentCount = this.dailyCounts.perAgent[agentId] ?? 0;
|
|
3178
|
+
if (agentCount >= limits.max_lessons_per_agent) return false;
|
|
3179
|
+
return true;
|
|
3180
|
+
}
|
|
3181
|
+
recordLesson(agentId) {
|
|
3182
|
+
this.refreshDailyCountsIfNewDay();
|
|
3183
|
+
this.dailyCounts.total++;
|
|
3184
|
+
this.dailyCounts.perAgent[agentId] = (this.dailyCounts.perAgent[agentId] ?? 0) + 1;
|
|
3185
|
+
this.saveDailyCounts();
|
|
3186
|
+
}
|
|
3187
|
+
getDailyCounts() {
|
|
3188
|
+
this.refreshDailyCountsIfNewDay();
|
|
3189
|
+
return { total: this.dailyCounts.total, perAgent: { ...this.dailyCounts.perAgent } };
|
|
3190
|
+
}
|
|
3191
|
+
// ── Private ─────────────────────────────────────────────────────────────
|
|
3192
|
+
loadTrust() {
|
|
3193
|
+
if (!(0, import_node_fs4.existsSync)(this.trustPath)) return { ...DEFAULT_TRUST, trusted: [], blocked: [] };
|
|
3194
|
+
try {
|
|
3195
|
+
const raw = JSON.parse((0, import_node_fs4.readFileSync)(this.trustPath, "utf-8"));
|
|
3196
|
+
return {
|
|
3197
|
+
trusted: Array.isArray(raw.trusted) ? raw.trusted.filter((a) => typeof a === "string") : [],
|
|
3198
|
+
blocked: Array.isArray(raw.blocked) ? raw.blocked.filter((a) => typeof a === "string") : [],
|
|
3199
|
+
default: ["trusted", "pending", "blocked"].includes(raw.default) ? raw.default : "pending"
|
|
3200
|
+
};
|
|
3201
|
+
} catch {
|
|
3202
|
+
return { ...DEFAULT_TRUST, trusted: [], blocked: [] };
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
saveTrust() {
|
|
3206
|
+
(0, import_node_fs4.mkdirSync)((0, import_node_path4.dirname)(this.trustPath), { recursive: true });
|
|
3207
|
+
(0, import_node_fs4.writeFileSync)(this.trustPath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
3208
|
+
}
|
|
3209
|
+
loadDailyCounts() {
|
|
3210
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3211
|
+
if (!(0, import_node_fs4.existsSync)(this.statsPath)) return { date: today, total: 0, perAgent: {} };
|
|
3212
|
+
try {
|
|
3213
|
+
const data = JSON.parse((0, import_node_fs4.readFileSync)(this.statsPath, "utf-8"));
|
|
3214
|
+
if (data.date !== today) return { date: today, total: 0, perAgent: {} };
|
|
3215
|
+
return data;
|
|
3216
|
+
} catch {
|
|
3217
|
+
return { date: today, total: 0, perAgent: {} };
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
saveDailyCounts() {
|
|
3221
|
+
(0, import_node_fs4.writeFileSync)(this.statsPath, JSON.stringify(this.dailyCounts, null, 2), "utf-8");
|
|
3222
|
+
}
|
|
3223
|
+
refreshDailyCountsIfNewDay() {
|
|
3224
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3225
|
+
if (this.dailyCounts.date !== today) {
|
|
3226
|
+
this.dailyCounts = { date: today, total: 0, perAgent: {} };
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3229
|
+
};
|
|
3230
|
+
|
|
3231
|
+
// src/skills/format.ts
|
|
3232
|
+
function formatSkillsForInjection(skills) {
|
|
3233
|
+
if (skills.length === 0) return "";
|
|
3234
|
+
const lines = skills.map((s) => {
|
|
3235
|
+
const source = s.source === "peer_review" ? "from a peer review" : s.source === "collaboration" ? "from a collaboration" : s.source === "teaching" ? "from being taught" : "from a conversation";
|
|
3236
|
+
return `- ${s.instruction} (${source})`;
|
|
3237
|
+
});
|
|
3238
|
+
return [
|
|
3239
|
+
"## Lessons learned from other agents",
|
|
3240
|
+
"",
|
|
3241
|
+
"You have learned the following from interactions with other agents. Follow these instructions:",
|
|
3242
|
+
"",
|
|
3243
|
+
...lines
|
|
3244
|
+
].join("\n");
|
|
3245
|
+
}
|
|
3246
|
+
function injectSkillsIntoMessages(messages, skillText) {
|
|
3247
|
+
if (!skillText) return;
|
|
3248
|
+
const sysIdx = messages.findIndex((m) => m.role === "system");
|
|
3249
|
+
if (sysIdx >= 0) {
|
|
3250
|
+
messages[sysIdx].content = skillText + "\n\n---\n\n" + messages[sysIdx].content;
|
|
3251
|
+
} else {
|
|
3252
|
+
messages.unshift({ role: "system", content: skillText });
|
|
3253
|
+
}
|
|
3254
|
+
}
|
|
3255
|
+
|
|
3256
|
+
// src/proxy/detector.ts
|
|
3257
|
+
var CHANNEL_PATTERN = /^\[([^\]]+)\s+says?\]:\s*/;
|
|
3258
|
+
var DM_PATTERN = /^DM\s+from\s+([^:]+):\s*/;
|
|
3259
|
+
var BUILDING_PATTERN = /^([a-zA-Z0-9]+[-_][a-zA-Z0-9_.-]+)\s+in\s+[^:]+:\s*/;
|
|
3260
|
+
var REVIEW_KEYWORDS = ["strengths:", "weaknesses:", "verdict:", "assessment:", "suggestions:"];
|
|
3261
|
+
function detectAgentConversation(messages) {
|
|
3262
|
+
const negative = { isAgentToAgent: false };
|
|
3263
|
+
if (!messages || messages.length === 0) return negative;
|
|
3264
|
+
for (const msg of messages) {
|
|
3265
|
+
if (msg.role !== "user" && msg.role !== "assistant") continue;
|
|
3266
|
+
const content = typeof msg.content === "string" ? msg.content : "";
|
|
3267
|
+
if (msg.name && msg.role === "user") {
|
|
3268
|
+
return {
|
|
3269
|
+
isAgentToAgent: true,
|
|
3270
|
+
otherAgentId: msg.name,
|
|
3271
|
+
exchangeType: "chat"
|
|
3272
|
+
};
|
|
3273
|
+
}
|
|
3274
|
+
const channelMatch = content.match(CHANNEL_PATTERN);
|
|
3275
|
+
if (channelMatch) {
|
|
3276
|
+
return {
|
|
3277
|
+
isAgentToAgent: true,
|
|
3278
|
+
otherAgentId: channelMatch[1].trim(),
|
|
3279
|
+
exchangeType: "channel"
|
|
3280
|
+
};
|
|
3281
|
+
}
|
|
3282
|
+
const dmMatch = content.match(DM_PATTERN);
|
|
3283
|
+
if (dmMatch) {
|
|
3284
|
+
return {
|
|
3285
|
+
isAgentToAgent: true,
|
|
3286
|
+
otherAgentId: dmMatch[1].trim(),
|
|
3287
|
+
exchangeType: "dm"
|
|
3288
|
+
};
|
|
3289
|
+
}
|
|
3290
|
+
const buildingMatch = content.match(BUILDING_PATTERN);
|
|
3291
|
+
if (buildingMatch) {
|
|
3292
|
+
return {
|
|
3293
|
+
isAgentToAgent: true,
|
|
3294
|
+
otherAgentId: buildingMatch[1].trim(),
|
|
3295
|
+
exchangeType: "chat"
|
|
3296
|
+
};
|
|
3297
|
+
}
|
|
3298
|
+
const lowerContent = content.toLowerCase();
|
|
3299
|
+
const reviewMatches = REVIEW_KEYWORDS.filter((kw) => lowerContent.includes(kw));
|
|
3300
|
+
if (reviewMatches.length >= 2) {
|
|
3301
|
+
return {
|
|
3302
|
+
isAgentToAgent: true,
|
|
3303
|
+
otherAgentId: void 0,
|
|
3304
|
+
exchangeType: "peer_review"
|
|
3305
|
+
};
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
return negative;
|
|
3309
|
+
}
|
|
3310
|
+
function extractExchangeText(messages) {
|
|
3311
|
+
return messages.filter((m) => m.role === "user" || m.role === "assistant").map((m) => {
|
|
3312
|
+
const speaker = m.name ?? m.role;
|
|
3313
|
+
const content = typeof m.content === "string" ? m.content : "";
|
|
3314
|
+
return `[${speaker}]: ${content}`;
|
|
3315
|
+
}).join("\n").slice(0, 6e3);
|
|
3316
|
+
}
|
|
3317
|
+
|
|
3318
|
+
// src/proxy/extractor.ts
|
|
3319
|
+
var LessonExtractor = class {
|
|
3320
|
+
constructor(store, trust, analyzer) {
|
|
3321
|
+
this.store = store;
|
|
3322
|
+
this.trust = trust;
|
|
3323
|
+
this.analyzer = analyzer;
|
|
3324
|
+
}
|
|
3325
|
+
/**
|
|
3326
|
+
* Analyze a conversation and extract lessons. Fire-and-forget.
|
|
3327
|
+
*/
|
|
3328
|
+
async extract(messages) {
|
|
3329
|
+
const detection = detectAgentConversation(messages);
|
|
3330
|
+
if (!detection.isAgentToAgent) return;
|
|
3331
|
+
const agentId = detection.otherAgentId ?? "unknown-agent";
|
|
3332
|
+
const trustLevel = this.trust.getLevel(agentId);
|
|
3333
|
+
if (trustLevel === "blocked") return;
|
|
3334
|
+
if (!this.trust.canLearn(agentId)) return;
|
|
3335
|
+
const exchangeText = extractExchangeText(messages);
|
|
3336
|
+
if (exchangeText.length < 20) return;
|
|
3337
|
+
const prompt = `Analyze this conversation between an AI agent and another agent. Extract concrete, actionable lessons that the first agent (the "assistant") can learn from the other agent.
|
|
3338
|
+
|
|
3339
|
+
CONVERSATION:
|
|
3340
|
+
${exchangeText.slice(0, 4e3)}
|
|
3341
|
+
|
|
3342
|
+
Output valid JSON array:
|
|
3343
|
+
[{"skill": "skill_name_snake_case", "instruction": "concrete actionable lesson in 1-2 sentences", "confidence": 0.0-1.0}]
|
|
3344
|
+
|
|
3345
|
+
Rules:
|
|
3346
|
+
- Only extract lessons where the other agent clearly teaches, corrects, or shares useful knowledge
|
|
3347
|
+
- instruction must be concrete and actionable ("use X when Y" not "consider improving")
|
|
3348
|
+
- confidence: 0.9 = explicitly taught, 0.7 = clearly implied, 0.5 = suggested, below 0.5 = skip
|
|
3349
|
+
- Only include lessons with confidence >= 0.5
|
|
3350
|
+
- Max 3 lessons per conversation
|
|
3351
|
+
- If no real learning happened, return []`;
|
|
3352
|
+
try {
|
|
3353
|
+
const response = await this.analyzer.analyze(prompt);
|
|
3354
|
+
const lessons = this.parseLessons(response);
|
|
3355
|
+
for (const lesson of lessons.slice(0, 3)) {
|
|
3356
|
+
const saved = this.store.savePending({
|
|
3357
|
+
name: lesson.skill,
|
|
3358
|
+
instruction: lesson.instruction.slice(0, 500),
|
|
3359
|
+
learned_from: agentId,
|
|
3360
|
+
source: detection.exchangeType ?? "conversation",
|
|
3361
|
+
confidence: lesson.confidence,
|
|
3362
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3363
|
+
});
|
|
3364
|
+
if (saved) {
|
|
3365
|
+
this.trust.recordLesson(agentId);
|
|
3366
|
+
if (trustLevel === "trusted") {
|
|
3367
|
+
this.store.approve(saved.id);
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
} catch {
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
parseLessons(response) {
|
|
3375
|
+
const jsonMatch = response.match(/\[[\s\S]*\]/);
|
|
3376
|
+
if (!jsonMatch) return [];
|
|
3377
|
+
try {
|
|
3378
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
3379
|
+
if (!Array.isArray(parsed)) return [];
|
|
3380
|
+
return parsed.filter(
|
|
3381
|
+
(r) => typeof r.skill === "string" && typeof r.instruction === "string" && typeof r.confidence === "number" && r.confidence >= 0.5 && r.skill.length > 0 && r.instruction.length > 0
|
|
3382
|
+
);
|
|
3383
|
+
} catch {
|
|
3384
|
+
return [];
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
};
|
|
3388
|
+
|
|
3389
|
+
// src/proxy/server.ts
|
|
3390
|
+
var SKILL_CACHE_TTL_MS = 5e3;
|
|
3391
|
+
function createProxyServer(config, analyzer) {
|
|
3392
|
+
const store = new FileSkillStore({ baseDir: config.baseDir });
|
|
3393
|
+
const trust = new TrustManager(config.baseDir);
|
|
3394
|
+
const extractor = analyzer ? new LessonExtractor(store, trust, analyzer) : null;
|
|
3395
|
+
const stats = {
|
|
3396
|
+
requests_forwarded: 0,
|
|
3397
|
+
skills_injected: 0,
|
|
3398
|
+
lessons_extracted: 0,
|
|
3399
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3400
|
+
};
|
|
3401
|
+
let cachedSkills = [];
|
|
3402
|
+
let cacheTimestamp = 0;
|
|
3403
|
+
function getSkills() {
|
|
3404
|
+
const now = Date.now();
|
|
3405
|
+
if (now - cacheTimestamp > SKILL_CACHE_TTL_MS) {
|
|
3406
|
+
cachedSkills = store.listApproved();
|
|
3407
|
+
cacheTimestamp = now;
|
|
3408
|
+
}
|
|
3409
|
+
return cachedSkills;
|
|
3410
|
+
}
|
|
3411
|
+
const server = (0, import_node_http.createServer)(async (req, res) => {
|
|
3412
|
+
if (req.url === "/health" && req.method === "GET") {
|
|
3413
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
3414
|
+
res.end(JSON.stringify({ status: "ok", ...stats }));
|
|
3415
|
+
return;
|
|
3416
|
+
}
|
|
3417
|
+
const isOpenAI = req.url === "/v1/chat/completions";
|
|
3418
|
+
const isAnthropic = req.url === "/v1/messages";
|
|
3419
|
+
if (req.method !== "POST" || !isOpenAI && !isAnthropic) {
|
|
3420
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
3421
|
+
res.end(JSON.stringify({ error: "Not found. Use POST /v1/chat/completions or /v1/messages" }));
|
|
3422
|
+
return;
|
|
3423
|
+
}
|
|
3424
|
+
try {
|
|
3425
|
+
const rawBody = await readBody(req);
|
|
3426
|
+
const body = JSON.parse(rawBody);
|
|
3427
|
+
const messages = body.messages;
|
|
3428
|
+
if (Array.isArray(messages)) {
|
|
3429
|
+
const skills = getSkills().slice(0, config.max_skills_per_call);
|
|
3430
|
+
if (skills.length > 0) {
|
|
3431
|
+
const skillText = formatSkillsForInjection(skills);
|
|
3432
|
+
injectSkillsIntoMessages(messages, skillText);
|
|
3433
|
+
stats.skills_injected++;
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
const upstreamUrl = buildUpstreamUrl(config, req.url);
|
|
3437
|
+
const upstreamHeaders = buildUpstreamHeaders(config, req.headers);
|
|
3438
|
+
const isStreaming = body.stream === true;
|
|
3439
|
+
const modifiedBody = JSON.stringify(body);
|
|
3440
|
+
const upstreamRes = await fetch(upstreamUrl, {
|
|
3441
|
+
method: "POST",
|
|
3442
|
+
headers: upstreamHeaders,
|
|
3443
|
+
body: modifiedBody
|
|
3444
|
+
});
|
|
3445
|
+
stats.requests_forwarded++;
|
|
3446
|
+
const responseHeaders = {};
|
|
3447
|
+
upstreamRes.headers.forEach((value, key) => {
|
|
3448
|
+
if (key.toLowerCase() !== "transfer-encoding") {
|
|
3449
|
+
responseHeaders[key] = value;
|
|
3450
|
+
}
|
|
3451
|
+
});
|
|
3452
|
+
res.writeHead(upstreamRes.status, responseHeaders);
|
|
3453
|
+
if (isStreaming && upstreamRes.body) {
|
|
3454
|
+
const reader = upstreamRes.body.getReader();
|
|
3455
|
+
try {
|
|
3456
|
+
while (true) {
|
|
3457
|
+
const { done, value } = await reader.read();
|
|
3458
|
+
if (done) break;
|
|
3459
|
+
res.write(value);
|
|
3460
|
+
}
|
|
3461
|
+
} finally {
|
|
3462
|
+
res.end();
|
|
3463
|
+
}
|
|
3464
|
+
if (config.auto_extract && extractor && Array.isArray(messages)) {
|
|
3465
|
+
extractor.extract(messages).then(() => {
|
|
3466
|
+
stats.lessons_extracted++;
|
|
3467
|
+
}).catch(() => {
|
|
3468
|
+
});
|
|
3469
|
+
}
|
|
3470
|
+
} else {
|
|
3471
|
+
const responseBuffer = await upstreamRes.arrayBuffer();
|
|
3472
|
+
res.end(Buffer.from(responseBuffer));
|
|
3473
|
+
if (config.auto_extract && extractor && Array.isArray(messages)) {
|
|
3474
|
+
extractor.extract(messages).then(() => {
|
|
3475
|
+
stats.lessons_extracted++;
|
|
3476
|
+
}).catch(() => {
|
|
3477
|
+
});
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
} catch (err) {
|
|
3481
|
+
const safeMessage = err instanceof Error && err.message === "Request body too large" ? "Request body too large" : "Failed to forward request to LLM";
|
|
3482
|
+
if (!res.headersSent) {
|
|
3483
|
+
res.writeHead(502, { "Content-Type": "application/json" });
|
|
3484
|
+
}
|
|
3485
|
+
res.end(JSON.stringify({ error: safeMessage }));
|
|
3486
|
+
}
|
|
3487
|
+
});
|
|
3488
|
+
return {
|
|
3489
|
+
server,
|
|
3490
|
+
stats,
|
|
3491
|
+
store,
|
|
3492
|
+
trust,
|
|
3493
|
+
listen: (port) => {
|
|
3494
|
+
const p = port ?? config.port;
|
|
3495
|
+
return new Promise((resolve2) => {
|
|
3496
|
+
server.listen(p, "127.0.0.1", () => resolve2());
|
|
3497
|
+
});
|
|
3498
|
+
},
|
|
3499
|
+
close: () => new Promise((resolve2) => server.close(() => resolve2()))
|
|
3500
|
+
};
|
|
3501
|
+
}
|
|
3502
|
+
function readBody(req) {
|
|
3503
|
+
return new Promise((resolve2, reject) => {
|
|
3504
|
+
const chunks = [];
|
|
3505
|
+
let size = 0;
|
|
3506
|
+
const MAX_BODY = 10 * 1024 * 1024;
|
|
3507
|
+
req.on("data", (chunk) => {
|
|
3508
|
+
size += chunk.length;
|
|
3509
|
+
if (size > MAX_BODY) {
|
|
3510
|
+
req.destroy();
|
|
3511
|
+
reject(new Error("Request body too large"));
|
|
3512
|
+
return;
|
|
3513
|
+
}
|
|
3514
|
+
chunks.push(chunk);
|
|
3515
|
+
});
|
|
3516
|
+
req.on("end", () => resolve2(Buffer.concat(chunks).toString("utf-8")));
|
|
3517
|
+
req.on("error", reject);
|
|
3518
|
+
});
|
|
3519
|
+
}
|
|
3520
|
+
function buildUpstreamUrl(config, path) {
|
|
3521
|
+
const base = config.llm_base_url.replace(/\/+$/, "");
|
|
3522
|
+
return `${base}${path}`;
|
|
3523
|
+
}
|
|
3524
|
+
function buildUpstreamHeaders(config, incomingHeaders) {
|
|
3525
|
+
const headers = {
|
|
3526
|
+
"Content-Type": "application/json"
|
|
3527
|
+
};
|
|
3528
|
+
if (config.llm_provider === "anthropic") {
|
|
3529
|
+
headers["x-api-key"] = config.llm_api_key;
|
|
3530
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
3531
|
+
const version = incomingHeaders["anthropic-version"];
|
|
3532
|
+
if (typeof version === "string") headers["anthropic-version"] = version;
|
|
3533
|
+
const beta = incomingHeaders["anthropic-beta"];
|
|
3534
|
+
if (typeof beta === "string") headers["anthropic-beta"] = beta;
|
|
3535
|
+
} else {
|
|
3536
|
+
headers["Authorization"] = `Bearer ${config.llm_api_key}`;
|
|
3537
|
+
}
|
|
3538
|
+
const accept = incomingHeaders["accept"];
|
|
3539
|
+
if (typeof accept === "string") headers["Accept"] = accept;
|
|
3540
|
+
return headers;
|
|
3541
|
+
}
|
|
3542
|
+
|
|
3543
|
+
// src/integrations/openclawcity.ts
|
|
3544
|
+
function emptySkillEvidence() {
|
|
3545
|
+
return {
|
|
3546
|
+
artifact_count: 0,
|
|
3547
|
+
artifact_types: /* @__PURE__ */ new Set(),
|
|
3548
|
+
reactions: [],
|
|
3549
|
+
collab_count: 0,
|
|
3550
|
+
peer_reviews_received: 0,
|
|
3551
|
+
peer_reviews_given: 0,
|
|
3552
|
+
teaching_events: 0
|
|
3553
|
+
};
|
|
3554
|
+
}
|
|
3555
|
+
function toScoreInput(ev, globalFollowers) {
|
|
3556
|
+
const totalReactions = ev.reactions.reduce((a, b) => a + b, 0);
|
|
3557
|
+
const recent = ev.reactions.slice(0, 3);
|
|
3558
|
+
const older = ev.reactions.slice(3);
|
|
3559
|
+
return {
|
|
3560
|
+
artifact_count: ev.artifact_count,
|
|
3561
|
+
total_reactions: totalReactions,
|
|
3562
|
+
recent_reaction_avg: recent.length > 0 ? recent.reduce((a, b) => a + b, 0) / recent.length : 0,
|
|
3563
|
+
older_reaction_avg: older.length > 0 ? older.reduce((a, b) => a + b, 0) / older.length : 0,
|
|
3564
|
+
unique_types: ev.artifact_types.size,
|
|
3565
|
+
collab_count: ev.collab_count,
|
|
3566
|
+
peer_reviews_given: ev.peer_reviews_given,
|
|
3567
|
+
peer_reviews_received: ev.peer_reviews_received,
|
|
3568
|
+
follower_count: globalFollowers,
|
|
3569
|
+
teaching_events: ev.teaching_events
|
|
3570
|
+
};
|
|
3571
|
+
}
|
|
3572
|
+
var OBCBridge = class {
|
|
3573
|
+
become;
|
|
3574
|
+
peerReview;
|
|
3575
|
+
teaching;
|
|
3576
|
+
graph;
|
|
3577
|
+
conversation;
|
|
3578
|
+
growth;
|
|
3579
|
+
trends;
|
|
3580
|
+
awareness;
|
|
3581
|
+
agentId;
|
|
3582
|
+
store;
|
|
3583
|
+
skillEvidence = /* @__PURE__ */ new Map();
|
|
3584
|
+
knownSkills = /* @__PURE__ */ new Set();
|
|
3585
|
+
totalArtifacts = 0;
|
|
3586
|
+
allArtifactTypes = [];
|
|
3587
|
+
followerCount = 0;
|
|
3588
|
+
collabsStarted = 0;
|
|
3589
|
+
collabsCompleted = 0;
|
|
3590
|
+
totalQuestCompletions = 0;
|
|
3591
|
+
constructor(config) {
|
|
3592
|
+
validateAgentId(config.agentId);
|
|
3593
|
+
this.agentId = config.agentId;
|
|
3594
|
+
this.store = config.store;
|
|
3595
|
+
this.become = new Become({ store: config.store });
|
|
3596
|
+
this.peerReview = new PeerReviewProtocol(config.store);
|
|
3597
|
+
this.teaching = new TeachingProtocol(config.store);
|
|
3598
|
+
this.graph = new LearningGraph(config.store);
|
|
3599
|
+
this.conversation = new ConversationLearner(config.store);
|
|
3600
|
+
this.growth = new GrowthTracker(config.store);
|
|
3601
|
+
this.trends = new TrendTracker(config.store);
|
|
3602
|
+
this.awareness = new AwarenessIndex();
|
|
3603
|
+
}
|
|
3604
|
+
// ── Tier 1: Every Heartbeat ──────────────────────────────────────────
|
|
3605
|
+
async onHeartbeat(heartbeat) {
|
|
3606
|
+
const signals = [];
|
|
3607
|
+
let skillsSynced = 0;
|
|
3608
|
+
let reactionsProcessed = 0;
|
|
3609
|
+
if (heartbeat.your_skills?.length) {
|
|
3610
|
+
for (const s of heartbeat.your_skills) {
|
|
3611
|
+
if (!this.knownSkills.has(s.skill)) {
|
|
3612
|
+
await this.become.skills.upsert(this.agentId, { name: s.skill });
|
|
3613
|
+
this.knownSkills.add(s.skill);
|
|
3614
|
+
skillsSynced++;
|
|
3615
|
+
}
|
|
3616
|
+
signals.push(`skill:${s.skill}:${s.stage}`);
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
if (heartbeat.your_artifact_reactions?.length) {
|
|
3620
|
+
const reactions = heartbeat.your_artifact_reactions;
|
|
3621
|
+
reactionsProcessed = reactions.length;
|
|
3622
|
+
const humanReactions = reactions.filter((r) => r.is_human);
|
|
3623
|
+
if (humanReactions.length > 0) {
|
|
3624
|
+
signals.push(`human_reactions:${humanReactions.length}`);
|
|
3625
|
+
}
|
|
3626
|
+
signals.push(`reactions:${reactions.length}`);
|
|
3627
|
+
}
|
|
3628
|
+
if (heartbeat.owner_messages?.length) {
|
|
3629
|
+
for (const msg of heartbeat.owner_messages) {
|
|
3630
|
+
await this.conversation.afterTurn({
|
|
3631
|
+
agent_id: this.agentId,
|
|
3632
|
+
user_message: msg.message,
|
|
3633
|
+
agent_response: "",
|
|
3634
|
+
context: { active_skills: [...this.knownSkills] }
|
|
3635
|
+
// No feedback — owner message received, agent hasn't responded yet
|
|
3636
|
+
});
|
|
3637
|
+
signals.push("owner_message");
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3640
|
+
if (heartbeat.your_completed_quests?.length) {
|
|
3641
|
+
this.totalQuestCompletions = heartbeat.your_completed_quests.length;
|
|
3642
|
+
}
|
|
3643
|
+
const observations = this.become.reflector.observe({
|
|
3644
|
+
agent_id: this.agentId,
|
|
3645
|
+
artifacts: this.allArtifactTypes,
|
|
3646
|
+
collabs_started: this.collabsStarted,
|
|
3647
|
+
collabs_completed: this.collabsCompleted,
|
|
3648
|
+
skills: [...this.knownSkills],
|
|
3649
|
+
quest_completions: this.totalQuestCompletions,
|
|
3650
|
+
follower_count: this.followerCount
|
|
3651
|
+
});
|
|
3652
|
+
return { signals, observations, skills_synced: skillsSynced, reactions_processed: reactionsProcessed };
|
|
3653
|
+
}
|
|
3654
|
+
// ── Tier 2: Agent Actions ────────────────────────────────────────────
|
|
3655
|
+
async onArtifactCreated(artifact) {
|
|
3656
|
+
this.totalArtifacts++;
|
|
3657
|
+
this.allArtifactTypes.push({ type: artifact.type });
|
|
3658
|
+
if (artifact.skill_used) {
|
|
3659
|
+
this.knownSkills.add(artifact.skill_used);
|
|
3660
|
+
const ev = this.getSkillEvidence(artifact.skill_used);
|
|
3661
|
+
ev.artifact_count++;
|
|
3662
|
+
ev.artifact_types.add(artifact.type);
|
|
3663
|
+
ev.reactions.unshift(0);
|
|
3664
|
+
const input = toScoreInput(ev, this.followerCount);
|
|
3665
|
+
const score = computeFullScore(artifact.skill_used, input);
|
|
3666
|
+
await this.store.saveScore(this.agentId, score);
|
|
3667
|
+
await this.become.milestones.check(this.agentId, [score]);
|
|
3668
|
+
return score;
|
|
3669
|
+
}
|
|
3670
|
+
return null;
|
|
3671
|
+
}
|
|
3672
|
+
async onCollaborationCompleted(data) {
|
|
3673
|
+
validateAgentId(data.partner_id);
|
|
3674
|
+
this.collabsCompleted++;
|
|
3675
|
+
const skill = data.skill ?? "collaboration";
|
|
3676
|
+
const ev = this.getSkillEvidence(skill);
|
|
3677
|
+
ev.collab_count++;
|
|
3678
|
+
await this.store.saveLearningEdge({
|
|
3679
|
+
from_agent: data.partner_id,
|
|
3680
|
+
to_agent: this.agentId,
|
|
3681
|
+
skill,
|
|
3682
|
+
event_type: "collaboration",
|
|
3683
|
+
score_delta: 0,
|
|
3684
|
+
metadata: { proposal_type: data.proposal_type },
|
|
3685
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3686
|
+
});
|
|
3687
|
+
}
|
|
3688
|
+
/** Track that a collaboration was proposed (started but not yet completed) */
|
|
3689
|
+
onCollaborationStarted() {
|
|
3690
|
+
this.collabsStarted++;
|
|
3691
|
+
}
|
|
3692
|
+
async onQuestCompleted(questId, skill) {
|
|
3693
|
+
this.totalQuestCompletions++;
|
|
3694
|
+
if (skill) {
|
|
3695
|
+
const ev = this.getSkillEvidence(skill);
|
|
3696
|
+
const input = toScoreInput(ev, this.followerCount);
|
|
3697
|
+
const score = computeFullScore(skill, input);
|
|
3698
|
+
await this.become.milestones.check(this.agentId, [score]);
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
async onReflection(skill, text) {
|
|
3702
|
+
await this.become.reflector.reflect(this.agentId, { skill, reflection: text });
|
|
3703
|
+
}
|
|
3704
|
+
async onSkillsRegistered(skills) {
|
|
3705
|
+
for (const skill of skills) {
|
|
3706
|
+
await this.become.skills.upsert(this.agentId, { name: skill });
|
|
3707
|
+
this.knownSkills.add(skill);
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
/** Record that an artifact received reactions (call with per-artifact data) */
|
|
3711
|
+
onArtifactReaction(skill, reactionCount) {
|
|
3712
|
+
const ev = this.getSkillEvidence(skill);
|
|
3713
|
+
if (ev.reactions.length > 0) {
|
|
3714
|
+
ev.reactions[0] += reactionCount;
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
// ── Tier 3: Peer Interactions ────────────────────────────────────────
|
|
3718
|
+
async onPeerReviewReceived(review) {
|
|
3719
|
+
validateAgentId(review.reviewer_id);
|
|
3720
|
+
const ev = this.getSkillEvidence(review.skill ?? "general");
|
|
3721
|
+
ev.peer_reviews_received++;
|
|
3722
|
+
await this.peerReview.submitReview({
|
|
3723
|
+
reviewer_agent_id: review.reviewer_id,
|
|
3724
|
+
submission_agent_id: this.agentId,
|
|
3725
|
+
submission_id: review.submission_id,
|
|
3726
|
+
skill: review.skill,
|
|
3727
|
+
verdict: review.verdict,
|
|
3728
|
+
overall_assessment: review.assessment,
|
|
3729
|
+
strengths: review.strengths,
|
|
3730
|
+
weaknesses: review.weaknesses,
|
|
3731
|
+
suggestions: review.suggestions
|
|
3732
|
+
});
|
|
3733
|
+
}
|
|
3734
|
+
async onPeerReviewGiven(review) {
|
|
3735
|
+
validateAgentId(review.submission_agent_id);
|
|
3736
|
+
const ev = this.getSkillEvidence(review.skill ?? "general");
|
|
3737
|
+
ev.peer_reviews_given++;
|
|
3738
|
+
await this.peerReview.submitReview({
|
|
3739
|
+
reviewer_agent_id: this.agentId,
|
|
3740
|
+
submission_agent_id: review.submission_agent_id,
|
|
3741
|
+
submission_id: review.submission_id,
|
|
3742
|
+
skill: review.skill,
|
|
3743
|
+
verdict: review.verdict,
|
|
3744
|
+
overall_assessment: review.assessment,
|
|
3745
|
+
strengths: review.strengths,
|
|
3746
|
+
weaknesses: review.weaknesses,
|
|
3747
|
+
suggestions: review.suggestions
|
|
3748
|
+
});
|
|
3749
|
+
}
|
|
3750
|
+
async onTaughtBy(teacherId, skill) {
|
|
3751
|
+
validateAgentId(teacherId);
|
|
3752
|
+
await this.teaching.teach(teacherId, this.agentId, skill);
|
|
3753
|
+
}
|
|
3754
|
+
async onTeaching(studentId, skill) {
|
|
3755
|
+
validateAgentId(studentId);
|
|
3756
|
+
const ev = this.getSkillEvidence(skill);
|
|
3757
|
+
ev.teaching_events++;
|
|
3758
|
+
await this.teaching.teach(this.agentId, studentId, skill);
|
|
3759
|
+
}
|
|
3760
|
+
onNewFollower() {
|
|
3761
|
+
this.followerCount++;
|
|
3762
|
+
}
|
|
3763
|
+
// ── Tier 4: Periodic / Summary ───────────────────────────────────────
|
|
3764
|
+
/** Compute scores for all known skills with per-skill evidence */
|
|
3765
|
+
async computeScores() {
|
|
3766
|
+
const scores = [];
|
|
3767
|
+
for (const skill of this.knownSkills) {
|
|
3768
|
+
const ev = this.getSkillEvidence(skill);
|
|
3769
|
+
const input = toScoreInput(ev, this.followerCount);
|
|
3770
|
+
const score = computeFullScore(skill, input);
|
|
3771
|
+
await this.store.saveScore(this.agentId, score);
|
|
3772
|
+
scores.push(score);
|
|
3773
|
+
}
|
|
3774
|
+
await this.become.milestones.check(this.agentId, scores);
|
|
3775
|
+
return scores;
|
|
3776
|
+
}
|
|
3777
|
+
async snapshot() {
|
|
3778
|
+
return this.growth.snapshot(this.agentId);
|
|
3779
|
+
}
|
|
3780
|
+
async analyzeTrends() {
|
|
3781
|
+
return this.trends.analyze(this.agentId);
|
|
3782
|
+
}
|
|
3783
|
+
async learningNetwork() {
|
|
3784
|
+
const [mentors, students] = await Promise.all([
|
|
3785
|
+
this.graph.topMentors(this.agentId),
|
|
3786
|
+
this.graph.topStudents(this.agentId)
|
|
3787
|
+
]);
|
|
3788
|
+
return { mentors, students };
|
|
3789
|
+
}
|
|
3790
|
+
/** Get per-skill evidence (for debugging/inspection) */
|
|
3791
|
+
getSkillEvidence(skill) {
|
|
3792
|
+
let ev = this.skillEvidence.get(skill);
|
|
3793
|
+
if (!ev) {
|
|
3794
|
+
ev = emptySkillEvidence();
|
|
3795
|
+
this.skillEvidence.set(skill, ev);
|
|
3796
|
+
}
|
|
3797
|
+
return ev;
|
|
3798
|
+
}
|
|
3799
|
+
/** Get global stats */
|
|
3800
|
+
getStats() {
|
|
3801
|
+
return {
|
|
3802
|
+
total_artifacts: this.totalArtifacts,
|
|
3803
|
+
follower_count: this.followerCount,
|
|
3804
|
+
collabs_started: this.collabsStarted,
|
|
3805
|
+
collabs_completed: this.collabsCompleted,
|
|
3806
|
+
quest_completions: this.totalQuestCompletions,
|
|
3807
|
+
skills_count: this.knownSkills.size
|
|
3808
|
+
};
|
|
3809
|
+
}
|
|
3810
|
+
getSkills() {
|
|
3811
|
+
return [...this.knownSkills];
|
|
3812
|
+
}
|
|
3813
|
+
};
|
|
3814
|
+
|
|
2695
3815
|
// src/index.ts
|
|
2696
3816
|
var Become = class {
|
|
2697
3817
|
skills;
|
|
@@ -2706,6 +3826,7 @@ var Become = class {
|
|
|
2706
3826
|
};
|
|
2707
3827
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2708
3828
|
0 && (module.exports = {
|
|
3829
|
+
AgentLearningEngine,
|
|
2709
3830
|
AnthropicAdapter,
|
|
2710
3831
|
AwarenessIndex,
|
|
2711
3832
|
BLOOMS_ORDER,
|
|
@@ -2713,11 +3834,14 @@ var Become = class {
|
|
|
2713
3834
|
Become,
|
|
2714
3835
|
ConversationLearner,
|
|
2715
3836
|
DREYFUS_THRESHOLDS,
|
|
3837
|
+
FileSkillStore,
|
|
2716
3838
|
GrowthTracker,
|
|
2717
3839
|
LearningGraph,
|
|
3840
|
+
LessonExtractor,
|
|
2718
3841
|
MemoryStore,
|
|
2719
3842
|
MilestoneDetector,
|
|
2720
3843
|
NormDetector,
|
|
3844
|
+
OBCBridge,
|
|
2721
3845
|
OllamaAdapter,
|
|
2722
3846
|
OpenAIAdapter,
|
|
2723
3847
|
PeerReviewProtocol,
|
|
@@ -2729,11 +3853,14 @@ var Become = class {
|
|
|
2729
3853
|
TeachingProtocol,
|
|
2730
3854
|
TrainScheduler,
|
|
2731
3855
|
TrendTracker,
|
|
3856
|
+
TrustManager,
|
|
2732
3857
|
WEIGHTS,
|
|
2733
3858
|
checkGate,
|
|
2734
3859
|
computeFullScore,
|
|
2735
3860
|
computeScore,
|
|
3861
|
+
createProxyServer,
|
|
2736
3862
|
datasetStats,
|
|
3863
|
+
detectAgentConversation,
|
|
2737
3864
|
detectBloomsLevel,
|
|
2738
3865
|
detectCollaborationGap,
|
|
2739
3866
|
detectCollectiveMemory,
|
|
@@ -2746,9 +3873,12 @@ var Become = class {
|
|
|
2746
3873
|
detectSoloCreator,
|
|
2747
3874
|
detectSymbolicVocabulary,
|
|
2748
3875
|
dreyfusStage,
|
|
3876
|
+
extractExchangeText,
|
|
2749
3877
|
filterHighQuality,
|
|
3878
|
+
formatSkillsForInjection,
|
|
2750
3879
|
getReputationLevel,
|
|
2751
3880
|
importSkillDirectory,
|
|
3881
|
+
injectSkillsIntoMessages,
|
|
2752
3882
|
nextMilestone,
|
|
2753
3883
|
normalizeCategory,
|
|
2754
3884
|
parseSkillFile,
|