@nowledge/openclaw-nowledge-mem 0.2.7

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.
@@ -0,0 +1,208 @@
1
+ /**
2
+ * nowledge_mem_timeline — browse recent activity from the feed.
3
+ *
4
+ * Wraps GET /agent/feed/events with human-readable grouping by day.
5
+ * Answers questions like:
6
+ * - "What was I working on last week?"
7
+ * - "What happened yesterday?"
8
+ * - "Show me insights from the past 3 days"
9
+ * - "What memories did I save this month?"
10
+ *
11
+ * The feed records every meaningful event: memories saved, documents
12
+ * ingested, insights generated, daily briefings, crystals created.
13
+ * This gives a chronological picture of what the user has been doing.
14
+ */
15
+
16
+ const EVENT_TYPE_LABELS = {
17
+ memory_created: "Memory saved",
18
+ insight_generated: "Insight",
19
+ pattern_detected: "Pattern",
20
+ agent_observation: "Observation",
21
+ daily_briefing: "Daily briefing",
22
+ crystal_created: "Crystal",
23
+ flag_contradiction: "Flag: contradiction",
24
+ flag_stale: "Flag: stale",
25
+ flag_merge_candidate: "Flag: duplicate",
26
+ flag_review: "Flag: review",
27
+ source_ingested: "Document ingested",
28
+ source_extracted: "Knowledge extracted from document",
29
+ working_memory_updated: "Working Memory updated",
30
+ evolves_detected: "Knowledge evolution detected",
31
+ kg_extraction: "Entity extraction",
32
+ url_captured: "URL captured",
33
+ };
34
+
35
+ function labelForType(eventType) {
36
+ return EVENT_TYPE_LABELS[eventType] || eventType;
37
+ }
38
+
39
+ // Tier-1 events are high-signal user-facing ones
40
+ const TIER1_TYPES = new Set([
41
+ "memory_created",
42
+ "insight_generated",
43
+ "pattern_detected",
44
+ "agent_observation",
45
+ "daily_briefing",
46
+ "crystal_created",
47
+ "flag_contradiction",
48
+ "flag_stale",
49
+ "flag_merge_candidate",
50
+ "source_ingested",
51
+ "source_extracted",
52
+ "url_captured",
53
+ ]);
54
+
55
+ export function createTimelineTool(client, logger) {
56
+ return {
57
+ name: "nowledge_mem_timeline",
58
+ description:
59
+ "Browse the user's recent knowledge activity — what they saved, read, worked on, or learned. " +
60
+ "Use for temporal questions like 'what was I doing last week?', 'what did I work on yesterday?', " +
61
+ "'show me recent insights', or 'what documents did I add this month?'. " +
62
+ "Returns a day-by-day feed grouped chronologically. Results include memoryIds so you can " +
63
+ "pass them directly to memory_get or nowledge_mem_connections for deeper exploration. " +
64
+ "Use event_type to filter: memory_created (saved knowledge), crystal_created (synthesized insights), " +
65
+ "insight_generated (agent observations), source_ingested (Library documents), " +
66
+ "source_extracted (knowledge from docs), daily_briefing (morning briefings), url_captured. " +
67
+ "For exact date queries ('what was I doing last Tuesday?') use date_from + date_to (YYYY-MM-DD).",
68
+ parameters: {
69
+ type: "object",
70
+ properties: {
71
+ last_n_days: {
72
+ type: "integer",
73
+ description:
74
+ "How many days back to look. 1=today, 7=this week, 30=this month. Default: 7. Ignored when date_from is set.",
75
+ },
76
+ date_from: {
77
+ type: "string",
78
+ description:
79
+ "Exact start date YYYY-MM-DD. Use with date_to for a precise range ('last Tuesday' → compute the date).",
80
+ },
81
+ date_to: {
82
+ type: "string",
83
+ description:
84
+ "Exact end date YYYY-MM-DD (inclusive). Defaults to today when date_from is set.",
85
+ },
86
+ event_type: {
87
+ type: "string",
88
+ description:
89
+ "Filter to a specific event type: memory_created, insight_generated, source_ingested, " +
90
+ "source_extracted, daily_briefing, crystal_created, url_captured",
91
+ },
92
+ tier1_only: {
93
+ type: "boolean",
94
+ description:
95
+ "Only show high-signal events (memories, insights, documents). Default: true.",
96
+ },
97
+ },
98
+ },
99
+ async execute(_toolCallId, params) {
100
+ const safeParams = params && typeof params === "object" ? params : {};
101
+ const lastNDays = Math.min(
102
+ 365,
103
+ Math.max(1, Math.trunc(Number(safeParams.last_n_days ?? 7) || 7)),
104
+ );
105
+ const dateFrom = safeParams.date_from
106
+ ? String(safeParams.date_from).trim()
107
+ : undefined;
108
+ const dateTo = safeParams.date_to
109
+ ? String(safeParams.date_to).trim()
110
+ : undefined;
111
+ const eventType = safeParams.event_type
112
+ ? String(safeParams.event_type).trim()
113
+ : undefined;
114
+ const tier1Only = safeParams.tier1_only !== false; // default true
115
+
116
+ try {
117
+ const events = await client.feedEvents({
118
+ lastNDays,
119
+ eventType,
120
+ tier1Only,
121
+ limit: 100,
122
+ dateFrom,
123
+ dateTo,
124
+ });
125
+
126
+ if (events.length === 0) {
127
+ const rangeLabel =
128
+ lastNDays === 1
129
+ ? "today"
130
+ : `the last ${lastNDays} day${lastNDays > 1 ? "s" : ""}`;
131
+ return {
132
+ content: [
133
+ {
134
+ type: "text",
135
+ text: `No activity found for ${rangeLabel}. Nowledge Mem may not be running or no events have been recorded yet.`,
136
+ },
137
+ ],
138
+ };
139
+ }
140
+
141
+ const filtered = events;
142
+
143
+ // Group by date (YYYY-MM-DD from created_at)
144
+ const byDay = new Map();
145
+ for (const event of filtered) {
146
+ const raw = event.created_at || event.timestamp || "";
147
+ const date = raw.slice(0, 10) || "unknown";
148
+ if (!byDay.has(date)) byDay.set(date, []);
149
+ byDay.get(date).push(event);
150
+ }
151
+
152
+ // Sort days newest first
153
+ const sortedDays = [...byDay.entries()].sort(([a], [b]) =>
154
+ b.localeCompare(a),
155
+ );
156
+
157
+ const lines = sortedDays.map(([date, evts]) => {
158
+ const items = evts
159
+ .slice(0, 20) // cap per day
160
+ .map((e) => {
161
+ const label = labelForType(e.event_type);
162
+ const title =
163
+ e.title || e.description || e.content?.slice(0, 80) || "";
164
+ // Surface memoryId for events that create/relate to memories
165
+ // so the agent can follow up with memory_get or nowledge_mem_connections
166
+ const memoryIds = [
167
+ ...(e.related_memory_ids ?? []),
168
+ ...(e.memory_id ? [e.memory_id] : []),
169
+ ];
170
+ const idHint =
171
+ memoryIds.length > 0
172
+ ? ` (id: ${memoryIds[0]}${memoryIds.length > 1 ? ` +${memoryIds.length - 1}` : ""})`
173
+ : "";
174
+ return ` - [${label}] ${title}${idHint}`;
175
+ })
176
+ .join("\n");
177
+ return `**${date}**\n${items}`;
178
+ });
179
+
180
+ const header = dateFrom
181
+ ? `Activity ${dateFrom}${dateTo && dateTo !== dateFrom ? ` → ${dateTo}` : ""}:`
182
+ : lastNDays === 1
183
+ ? "Today's activity:"
184
+ : `Activity over the last ${lastNDays} days:`;
185
+
186
+ return {
187
+ content: [
188
+ {
189
+ type: "text",
190
+ text: [header, "", ...lines].join("\n"),
191
+ },
192
+ ],
193
+ details: {
194
+ lastNDays,
195
+ eventCount: filtered.length,
196
+ dayCount: sortedDays.length,
197
+ },
198
+ };
199
+ } catch (err) {
200
+ const msg = err instanceof Error ? err.message : String(err);
201
+ logger.error(`timeline failed: ${msg}`);
202
+ return {
203
+ content: [{ type: "text", text: `Failed to get timeline: ${msg}` }],
204
+ };
205
+ }
206
+ },
207
+ };
208
+ }