@mastra/opencode 0.1.11-alpha.1 → 0.1.11-alpha.2
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/CHANGELOG.md +8 -0
- package/dist/index.cjs +273 -307
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +272 -305
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @mastra/opencode
|
|
2
2
|
|
|
3
|
+
## 0.1.11-alpha.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`a211d09`](https://github.com/mastra-ai/mastra/commit/a211d09185dc65a746534914cf38b67f21ee9bac), [`05db566`](https://github.com/mastra-ai/mastra/commit/05db566fcbdcbf33d0bffca0c72ec30129e2e3ca), [`e075db9`](https://github.com/mastra-ai/mastra/commit/e075db9715c836bae5dfc37c50248492af397c3b), [`8124754`](https://github.com/mastra-ai/mastra/commit/8124754ae89fbc69f8136d1df4a91904d0f84c4e)]:
|
|
8
|
+
- @mastra/core@1.54.0-alpha.2
|
|
9
|
+
- @mastra/libsql@1.18.0-alpha.1
|
|
10
|
+
|
|
3
11
|
## 0.1.11-alpha.1
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -1,320 +1,286 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let fs_promises = require("fs/promises");
|
|
3
|
+
let path = require("path");
|
|
4
|
+
let _mastra_libsql = require("@mastra/libsql");
|
|
5
|
+
let _mastra_memory_processors = require("@mastra/memory/processors");
|
|
6
|
+
let _opencode_ai_plugin = require("@opencode-ai/plugin");
|
|
7
|
+
//#region src/index.ts
|
|
8
|
+
/**
|
|
9
|
+
* @mastra/opencode
|
|
10
|
+
*
|
|
11
|
+
* OpenCode plugin that brings Mastra Observational Memory into opencode sessions.
|
|
12
|
+
*
|
|
13
|
+
* Mastra OM compresses long conversation history into structured observations
|
|
14
|
+
* using an Observer (extract) and Reflector (condense) architecture.
|
|
15
|
+
*
|
|
16
|
+
* Configuration is read from .opencode/mastra.json in the project root.
|
|
17
|
+
*
|
|
18
|
+
* @example .opencode/mastra.json
|
|
19
|
+
* ```json
|
|
20
|
+
* {
|
|
21
|
+
* "model": "google/gemini-2.5-flash",
|
|
22
|
+
* "observation": { "messageTokens": 20000 },
|
|
23
|
+
* "reflection": { "observationTokens": 90000 },
|
|
24
|
+
* "storagePath": ".opencode/memory/observations.db"
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
const CONFIG_FILE = ".opencode/mastra.json";
|
|
29
|
+
const DEFAULT_STORAGE_PATH = ".opencode/memory/observations.db";
|
|
12
30
|
async function loadConfig(directory) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
31
|
+
try {
|
|
32
|
+
const raw = await (0, fs_promises.readFile)((0, path.join)(directory, CONFIG_FILE), "utf-8");
|
|
33
|
+
return JSON.parse(raw);
|
|
34
|
+
} catch {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
20
37
|
}
|
|
38
|
+
/** Convert opencode messages to MastraDBMessage format.
|
|
39
|
+
* Preserves all part types including tool invocations, files, images, and reasoning.
|
|
40
|
+
*/
|
|
21
41
|
function convertMessages(messages, sessionId) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
resourceId: sessionId,
|
|
71
|
-
content: {
|
|
72
|
-
format: 2,
|
|
73
|
-
parts: convertedParts
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
}).filter((m) => m !== null);
|
|
42
|
+
return messages.map(({ info, parts }) => {
|
|
43
|
+
const convertedParts = parts.map((part) => {
|
|
44
|
+
const p = part;
|
|
45
|
+
const type = p.type;
|
|
46
|
+
if (type === "text" && p.text) return {
|
|
47
|
+
type: "text",
|
|
48
|
+
text: p.text
|
|
49
|
+
};
|
|
50
|
+
if (type === "tool-invocation") return {
|
|
51
|
+
type: "tool-invocation",
|
|
52
|
+
toolInvocation: {
|
|
53
|
+
toolCallId: p.toolCallId,
|
|
54
|
+
toolName: p.toolName,
|
|
55
|
+
args: p.args,
|
|
56
|
+
result: p.result,
|
|
57
|
+
state: p.state
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
if (type === "file") return {
|
|
61
|
+
type: "file",
|
|
62
|
+
url: p.url,
|
|
63
|
+
mediaType: p.mediaType
|
|
64
|
+
};
|
|
65
|
+
if (type === "image") return {
|
|
66
|
+
type: "image",
|
|
67
|
+
image: p.image
|
|
68
|
+
};
|
|
69
|
+
if (type === "reasoning" && p.reasoning) return {
|
|
70
|
+
type: "reasoning",
|
|
71
|
+
reasoning: p.reasoning
|
|
72
|
+
};
|
|
73
|
+
if (type?.startsWith("data-om-")) return null;
|
|
74
|
+
return null;
|
|
75
|
+
}).filter((p) => p !== null);
|
|
76
|
+
if (convertedParts.length === 0) return null;
|
|
77
|
+
if (info.role !== "user" && info.role !== "assistant") return null;
|
|
78
|
+
return {
|
|
79
|
+
id: info.id,
|
|
80
|
+
role: info.role,
|
|
81
|
+
createdAt: new Date(info.time.created),
|
|
82
|
+
threadId: sessionId,
|
|
83
|
+
resourceId: sessionId,
|
|
84
|
+
content: {
|
|
85
|
+
format: 2,
|
|
86
|
+
parts: convertedParts
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}).filter((m) => m !== null);
|
|
77
90
|
}
|
|
78
91
|
function progressBar(current, total, width = 20) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
92
|
+
const pct = total > 0 ? Math.min(current / total, 1) : 0;
|
|
93
|
+
const filled = Math.round(pct * width);
|
|
94
|
+
return `[${"█".repeat(filled)}${"░".repeat(width - filled)}] ${(pct * 100).toFixed(1)}%`;
|
|
82
95
|
}
|
|
83
96
|
function formatTokens(n) {
|
|
84
|
-
|
|
97
|
+
return n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : String(n);
|
|
85
98
|
}
|
|
86
99
|
function resolveThreshold(t) {
|
|
87
|
-
|
|
100
|
+
return typeof t === "number" ? t : t.max;
|
|
88
101
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
${
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
270
|
-
const omConfig = om.config;
|
|
271
|
-
const obsThreshold = resolveThreshold(omConfig.observation.messageTokens);
|
|
272
|
-
const refThreshold = resolveThreshold(omConfig.reflection.observationTokens);
|
|
273
|
-
const obsTokens = record.observationTokenCount ?? 0;
|
|
274
|
-
const tokenCounter = new processors.TokenCounter();
|
|
275
|
-
let unobservedTokens = 0;
|
|
276
|
-
try {
|
|
277
|
-
const resp = await ctx.client.session.messages({ path: { id: threadId } });
|
|
278
|
-
if (resp.data) {
|
|
279
|
-
const allMastra = convertMessages(resp.data, threadId);
|
|
280
|
-
const unobserved = record.lastObservedAt ? allMastra.filter((m) => m.createdAt > new Date(record.lastObservedAt)) : allMastra;
|
|
281
|
-
unobservedTokens = tokenCounter.countMessages(unobserved);
|
|
282
|
-
}
|
|
283
|
-
} catch {
|
|
284
|
-
unobservedTokens = record.pendingMessageTokens ?? 0;
|
|
285
|
-
}
|
|
286
|
-
const lines = [
|
|
287
|
-
`Observational Memory`,
|
|
288
|
-
`Scope: ${record.scope} | Generations: ${record.generationCount ?? 0}`,
|
|
289
|
-
``,
|
|
290
|
-
`\u2500\u2500 Observation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
|
|
291
|
-
`Unobserved: ${formatTokens(unobservedTokens)} / ${formatTokens(obsThreshold)} tokens`,
|
|
292
|
-
progressBar(unobservedTokens, obsThreshold),
|
|
293
|
-
``,
|
|
294
|
-
`\u2500\u2500 Reflection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
|
|
295
|
-
`Observations: ${formatTokens(obsTokens)} / ${formatTokens(refThreshold)} tokens`,
|
|
296
|
-
progressBar(obsTokens, refThreshold),
|
|
297
|
-
``,
|
|
298
|
-
`\u2500\u2500 Status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`,
|
|
299
|
-
`Last observed: ${record.lastObservedAt ?? "never"}`,
|
|
300
|
-
`Observing: ${record.isObserving ? "yes" : "no"} | Reflecting: ${record.isReflecting ? "yes" : "no"}`
|
|
301
|
-
];
|
|
302
|
-
return lines.join("\n");
|
|
303
|
-
}
|
|
304
|
-
}),
|
|
305
|
-
memory_observations: plugin.tool({
|
|
306
|
-
description: "Show the current active observations stored in Observational Memory.",
|
|
307
|
-
args: {},
|
|
308
|
-
async execute(_args, context) {
|
|
309
|
-
const threadId = context.sessionID;
|
|
310
|
-
const observations = await om.getObservations(threadId);
|
|
311
|
-
return observations ?? "No observations stored yet.";
|
|
312
|
-
}
|
|
313
|
-
})
|
|
314
|
-
}
|
|
315
|
-
};
|
|
102
|
+
const MastraPlugin = async (ctx) => {
|
|
103
|
+
const config = await loadConfig(ctx.directory);
|
|
104
|
+
let credentialsReady = false;
|
|
105
|
+
const resolveCredentials = async () => {
|
|
106
|
+
if (credentialsReady) return;
|
|
107
|
+
try {
|
|
108
|
+
const providersResponse = await ctx.client.config.providers();
|
|
109
|
+
if (providersResponse.data) {
|
|
110
|
+
for (const provider of providersResponse.data.providers) if (provider.key && provider.env) {
|
|
111
|
+
for (const envVar of provider.env) if (!process.env[envVar]) process.env[envVar] = provider.key;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} catch {}
|
|
115
|
+
credentialsReady = true;
|
|
116
|
+
};
|
|
117
|
+
const dbRelativePath = config.storagePath ?? DEFAULT_STORAGE_PATH;
|
|
118
|
+
const dbAbsolutePath = (0, path.join)(ctx.directory, dbRelativePath);
|
|
119
|
+
await (0, fs_promises.mkdir)((0, path.dirname)(dbAbsolutePath), { recursive: true });
|
|
120
|
+
const storagePath = `file:${dbAbsolutePath}`;
|
|
121
|
+
const store = new _mastra_libsql.LibSQLStore({
|
|
122
|
+
id: "mastra-om",
|
|
123
|
+
url: storagePath
|
|
124
|
+
});
|
|
125
|
+
await store.init();
|
|
126
|
+
const storage = await store.getStore("memory");
|
|
127
|
+
if (!storage) throw new Error(`@mastra/opencode: failed to initialize memory storage from ${storagePath}`);
|
|
128
|
+
const om = new _mastra_memory_processors.ObservationalMemory({
|
|
129
|
+
storage,
|
|
130
|
+
model: config.model,
|
|
131
|
+
observation: config.observation,
|
|
132
|
+
reflection: config.reflection,
|
|
133
|
+
scope: config.scope,
|
|
134
|
+
shareTokenBudget: config.shareTokenBudget
|
|
135
|
+
});
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
ctx.client.tui.showToast({ body: {
|
|
138
|
+
title: "Mastra",
|
|
139
|
+
message: "Observational Memory activated",
|
|
140
|
+
variant: "success",
|
|
141
|
+
duration: 3e3
|
|
142
|
+
} });
|
|
143
|
+
}, 500);
|
|
144
|
+
return {
|
|
145
|
+
event: async ({ event }) => {
|
|
146
|
+
if (event.type === "session.created") {
|
|
147
|
+
const sessionId = event.properties.info.id;
|
|
148
|
+
try {
|
|
149
|
+
await om.getOrCreateRecord(sessionId);
|
|
150
|
+
} catch (err) {
|
|
151
|
+
ctx.client.tui.showToast({ body: {
|
|
152
|
+
title: "Mastra",
|
|
153
|
+
message: `Failed to initialize Observational Memory: ${err instanceof Error ? err.message : String(err)}`,
|
|
154
|
+
variant: "error",
|
|
155
|
+
duration: 5e3
|
|
156
|
+
} });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"experimental.chat.messages.transform": async (_input, output) => {
|
|
161
|
+
const sessionId = output.messages[0]?.info.sessionID;
|
|
162
|
+
if (!sessionId) return;
|
|
163
|
+
await resolveCredentials();
|
|
164
|
+
try {
|
|
165
|
+
const mastraMessages = convertMessages(output.messages, sessionId);
|
|
166
|
+
if (mastraMessages.length > 0) await om.observe({
|
|
167
|
+
threadId: sessionId,
|
|
168
|
+
messages: mastraMessages,
|
|
169
|
+
hooks: {
|
|
170
|
+
onObservationStart: () => {
|
|
171
|
+
ctx.client.tui.showToast({ body: {
|
|
172
|
+
title: "Mastra",
|
|
173
|
+
message: "Observing conversation...",
|
|
174
|
+
variant: "info",
|
|
175
|
+
duration: 1e4
|
|
176
|
+
} });
|
|
177
|
+
},
|
|
178
|
+
onObservationEnd: () => {
|
|
179
|
+
ctx.client.tui.showToast({ body: {
|
|
180
|
+
title: "Mastra",
|
|
181
|
+
message: "Observation complete",
|
|
182
|
+
variant: "success",
|
|
183
|
+
duration: 3e3
|
|
184
|
+
} });
|
|
185
|
+
},
|
|
186
|
+
onReflectionStart: () => {
|
|
187
|
+
ctx.client.tui.showToast({ body: {
|
|
188
|
+
title: "Mastra",
|
|
189
|
+
message: "Reflecting on observations...",
|
|
190
|
+
variant: "info",
|
|
191
|
+
duration: 1e4
|
|
192
|
+
} });
|
|
193
|
+
},
|
|
194
|
+
onReflectionEnd: () => {
|
|
195
|
+
ctx.client.tui.showToast({ body: {
|
|
196
|
+
title: "Mastra",
|
|
197
|
+
message: "Reflection complete",
|
|
198
|
+
variant: "success",
|
|
199
|
+
duration: 3e3
|
|
200
|
+
} });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
const record = await om.getRecord(sessionId);
|
|
205
|
+
if (record?.lastObservedAt) {
|
|
206
|
+
const lastObservedAt = new Date(record.lastObservedAt);
|
|
207
|
+
output.messages = output.messages.filter(({ info }) => {
|
|
208
|
+
return new Date(info.time.created) > lastObservedAt;
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
} catch (err) {
|
|
212
|
+
ctx.client.tui.showToast({ body: {
|
|
213
|
+
title: "Mastra",
|
|
214
|
+
message: `Observational Memory error: ${err instanceof Error ? err.message : String(err)}`,
|
|
215
|
+
variant: "error",
|
|
216
|
+
duration: 5e3
|
|
217
|
+
} });
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
"experimental.chat.system.transform": async (input, output) => {
|
|
221
|
+
const sessionId = input.sessionID;
|
|
222
|
+
if (!sessionId) return;
|
|
223
|
+
try {
|
|
224
|
+
const observations = await om.getObservations(sessionId);
|
|
225
|
+
if (!observations) return;
|
|
226
|
+
const optimized = (0, _mastra_memory_processors.optimizeObservationsForContext)(observations);
|
|
227
|
+
output.system.push(`${_mastra_memory_processors.OBSERVATION_CONTEXT_PROMPT}\n\n<observations>\n${optimized}\n</observations>\n\n${_mastra_memory_processors.OBSERVATION_CONTEXT_INSTRUCTIONS}\n\n${_mastra_memory_processors.OBSERVATION_CONTINUATION_HINT}`);
|
|
228
|
+
} catch {}
|
|
229
|
+
},
|
|
230
|
+
tool: {
|
|
231
|
+
memory_status: (0, _opencode_ai_plugin.tool)({
|
|
232
|
+
description: "Show Observational Memory progress — how close the session is to the next observation and reflection cycle.",
|
|
233
|
+
args: {},
|
|
234
|
+
async execute(_args, context) {
|
|
235
|
+
const threadId = context.sessionID;
|
|
236
|
+
const record = await om.getRecord(threadId);
|
|
237
|
+
if (!record) return "No Observational Memory record found for this session.";
|
|
238
|
+
const omConfig = om.config;
|
|
239
|
+
const obsThreshold = resolveThreshold(omConfig.observation.messageTokens);
|
|
240
|
+
const refThreshold = resolveThreshold(omConfig.reflection.observationTokens);
|
|
241
|
+
const obsTokens = record.observationTokenCount ?? 0;
|
|
242
|
+
const tokenCounter = new _mastra_memory_processors.TokenCounter();
|
|
243
|
+
let unobservedTokens = 0;
|
|
244
|
+
try {
|
|
245
|
+
const resp = await ctx.client.session.messages({ path: { id: threadId } });
|
|
246
|
+
if (resp.data) {
|
|
247
|
+
const allMastra = convertMessages(resp.data, threadId);
|
|
248
|
+
const unobserved = record.lastObservedAt ? allMastra.filter((m) => m.createdAt > new Date(record.lastObservedAt)) : allMastra;
|
|
249
|
+
unobservedTokens = tokenCounter.countMessages(unobserved);
|
|
250
|
+
}
|
|
251
|
+
} catch {
|
|
252
|
+
unobservedTokens = record.pendingMessageTokens ?? 0;
|
|
253
|
+
}
|
|
254
|
+
return [
|
|
255
|
+
`Observational Memory`,
|
|
256
|
+
`Scope: ${record.scope} | Generations: ${record.generationCount ?? 0}`,
|
|
257
|
+
``,
|
|
258
|
+
`── Observation ──────────────────────────────`,
|
|
259
|
+
`Unobserved: ${formatTokens(unobservedTokens)} / ${formatTokens(obsThreshold)} tokens`,
|
|
260
|
+
progressBar(unobservedTokens, obsThreshold),
|
|
261
|
+
``,
|
|
262
|
+
`── Reflection ──────────────────────────────`,
|
|
263
|
+
`Observations: ${formatTokens(obsTokens)} / ${formatTokens(refThreshold)} tokens`,
|
|
264
|
+
progressBar(obsTokens, refThreshold),
|
|
265
|
+
``,
|
|
266
|
+
`── Status ──────────────────────────────────`,
|
|
267
|
+
`Last observed: ${record.lastObservedAt ?? "never"}`,
|
|
268
|
+
`Observing: ${record.isObserving ? "yes" : "no"} | Reflecting: ${record.isReflecting ? "yes" : "no"}`
|
|
269
|
+
].join("\n");
|
|
270
|
+
}
|
|
271
|
+
}),
|
|
272
|
+
memory_observations: (0, _opencode_ai_plugin.tool)({
|
|
273
|
+
description: "Show the current active observations stored in Observational Memory.",
|
|
274
|
+
args: {},
|
|
275
|
+
async execute(_args, context) {
|
|
276
|
+
const threadId = context.sessionID;
|
|
277
|
+
return await om.getObservations(threadId) ?? "No observations stored yet.";
|
|
278
|
+
}
|
|
279
|
+
})
|
|
280
|
+
}
|
|
281
|
+
};
|
|
316
282
|
};
|
|
317
|
-
|
|
283
|
+
//#endregion
|
|
318
284
|
exports.MastraPlugin = MastraPlugin;
|
|
319
|
-
|
|
285
|
+
|
|
320
286
|
//# sourceMappingURL=index.cjs.map
|