@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/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) => `[${sanitize2(a.agent_name)}] ${sanitize2(a.action)}: ${sanitize2(truncate2(a.content ?? "", 150))}${a.tags?.length ? ` (tags: ${a.tags.slice(0, 10).map(sanitize2).join(", ")})` : ""}`).join("\n");
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 sanitize2(text) {
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,