@tpsdev-ai/openclaw-flair 0.3.0 → 0.4.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.
Files changed (2) hide show
  1. package/index.ts +44 -8
  2. package/package.json +7 -5
package/index.ts CHANGED
@@ -87,13 +87,19 @@ async function syncWorkspaceToFlair(
87
87
 
88
88
  // ─── Auto-capture helpers ─────────────────────────────────────────────────────
89
89
 
90
+ // Auto-capture triggers — conservative patterns that indicate genuinely
91
+ // important context, not casual conversation. The LLM has memory_store
92
+ // for explicit saves; auto-capture is a safety net for things it misses.
90
93
  const CAPTURE_TRIGGERS = [
91
- /\b(remember|note that|important:|keep in mind|don't forget)\b/i,
92
- /\b(preference|prefer|always|never|my name is|i am|i'm)\b/i,
93
- /\b(decided|agreed|confirmed|finalized)\b/i,
94
+ /\b(remember this|note for future|important lesson|key decision|for the record)\b/i,
95
+ /\b(my name is|call me|i go by)\b/i,
96
+ /\b(we decided|final decision|agreed to|commitment:)\b/i,
94
97
  ];
95
98
 
99
+ const MIN_CAPTURE_LENGTH = 30; // skip very short messages
100
+
96
101
  function shouldCapture(text: string): boolean {
102
+ if (text.length < MIN_CAPTURE_LENGTH) return false;
97
103
  return CAPTURE_TRIGGERS.some((re) => re.test(text));
98
104
  }
99
105
 
@@ -144,14 +150,22 @@ export default {
144
150
  api.logger.info("openclaw-flair: auto mode — agentId will be resolved from session context");
145
151
  }
146
152
  const maxRecall = cfg.maxRecallResults ?? DEFAULT_MAX_RECALL;
147
- const autoCapture = cfg.autoCapture ?? true;
153
+ const autoCapture = cfg.autoCapture ?? false; // opt-in — trust the LLM to use memory_store
148
154
  const autoRecall = cfg.autoRecall ?? true;
149
155
 
156
+ // Per-session agentId — set from config, env, or session context.
157
+ // IMPORTANT: Only update from before_agent_start if it matches our configured agent,
158
+ // NOT from other agents' cron jobs sharing the same gateway.
150
159
  let currentAgentId: string | undefined = isAutoMode ? fallbackAgentId ?? undefined : cfg.agentId;
160
+ const configuredAgentId = cfg.agentId && cfg.agentId !== "auto" ? cfg.agentId : fallbackAgentId;
151
161
 
152
162
  api.on("before_agent_start", async (event: any, ctx: any) => {
153
163
  const eventAgentId = ctx?.agentId || (event as any).agentId;
154
- if (eventAgentId) currentAgentId = eventAgentId;
164
+ // Only adopt the session agentId if we don't already have one configured,
165
+ // or if it matches our configured agent. Don't let kern's cron overwrite flint's agentId.
166
+ if (eventAgentId && (!configuredAgentId || eventAgentId === configuredAgentId)) {
167
+ currentAgentId = eventAgentId;
168
+ }
155
169
 
156
170
  if (eventAgentId) {
157
171
  try {
@@ -242,15 +256,37 @@ export default {
242
256
  try {
243
257
  const client = getCurrentClient();
244
258
  const memId = `${client.agentId}-${Date.now()}`;
245
- await client.memory.write(text, {
259
+ // If superseding an old memory, archive it
260
+ if (supersedes) {
261
+ try {
262
+ const old = await client.memory.get(supersedes);
263
+ if (old) {
264
+ await client.request("PUT", `/Memory/${supersedes}`, {
265
+ ...old,
266
+ archived: true,
267
+ archivedAt: new Date().toISOString(),
268
+ supersededBy: memId,
269
+ });
270
+ }
271
+ } catch {
272
+ // Old memory not found — continue with the write
273
+ }
274
+ }
275
+
276
+ const result = await client.memory.write(text, {
246
277
  id: memId,
247
278
  tags,
248
279
  durability: durability as any,
249
280
  type: type as any,
281
+ dedup: !supersedes, // skip dedup when explicitly superseding
282
+ dedupThreshold: 0.7,
250
283
  });
284
+ const wasDeduped = result.id !== memId;
251
285
  return {
252
- content: [{ type: "text", text: `Memory stored (id: ${memId})` }],
253
- details: { id: memId },
286
+ content: [{ type: "text", text: wasDeduped
287
+ ? `Similar memory already exists (id: ${result.id}): ${result.content?.slice(0, 200)}`
288
+ : `Memory stored (id: ${memId})` }],
289
+ details: { id: result.id, deduplicated: wasDeduped },
254
290
  };
255
291
  } catch (err: any) {
256
292
  api.logger.warn(`openclaw-flair: store failed: ${err.message}`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tpsdev-ai/openclaw-flair",
3
- "version": "0.3.0",
4
- "description": "OpenClaw memory plugin for Flair agent identity and semantic memory",
3
+ "version": "0.4.0",
4
+ "description": "OpenClaw memory plugin for Flair \u2014 agent identity and semantic memory",
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "exports": {
@@ -30,7 +30,9 @@
30
30
  },
31
31
  "homepage": "https://github.com/tpsdev-ai/flair/tree/main/plugins/openclaw-flair",
32
32
  "openclaw": {
33
- "extensions": ["./index.ts"]
33
+ "extensions": [
34
+ "./index.ts"
35
+ ]
34
36
  },
35
37
  "peerDependencies": {
36
38
  "openclaw": ">=2026.3.7"
@@ -40,6 +42,6 @@
40
42
  },
41
43
  "dependencies": {
42
44
  "@sinclair/typebox": "^0.34.0",
43
- "@tpsdev-ai/flair-client": "^0.1.0"
45
+ "@tpsdev-ai/flair-client": "^0.2.0"
44
46
  }
45
- }
47
+ }