opencode-mastra-om 0.1.4 → 0.1.6
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.js +189 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -179825,38 +179825,75 @@ var MastraPlugin = async (ctx) => {
|
|
|
179825
179825
|
}
|
|
179826
179826
|
const om = new ObservationalMemory(omOptions);
|
|
179827
179827
|
omLog(`[init] ObservationalMemory created, model=${config2.model ?? "default"}`);
|
|
179828
|
-
const backupObservations = async (threadId,
|
|
179828
|
+
const backupObservations = async (threadId, trigger) => {
|
|
179829
179829
|
try {
|
|
179830
179830
|
const record3 = await om.getRecord(threadId);
|
|
179831
179831
|
const observations = record3?.activeObservations;
|
|
179832
179832
|
if (!observations)
|
|
179833
179833
|
return;
|
|
179834
|
-
const generationCount = record3?.generationCount ?? 0;
|
|
179835
|
-
const lookupKey = threadId;
|
|
179836
|
-
const savedAt = new Date().toISOString();
|
|
179837
179834
|
const db = store.turso;
|
|
179838
179835
|
if (!db)
|
|
179839
179836
|
return;
|
|
179837
|
+
const snap = {
|
|
179838
|
+
lookupKey: threadId,
|
|
179839
|
+
generationCount: record3.generationCount ?? 0,
|
|
179840
|
+
observations,
|
|
179841
|
+
observationTokenCount: record3.observationTokenCount ?? 0,
|
|
179842
|
+
lastObservedAt: record3.lastObservedAt ?? null,
|
|
179843
|
+
lastReflectionAt: record3.lastReflectionAt ?? null,
|
|
179844
|
+
pendingMessageTokens: record3.pendingMessageTokens ?? 0,
|
|
179845
|
+
observedMessageIds: record3.observedMessageIds ?? "[]",
|
|
179846
|
+
trigger,
|
|
179847
|
+
savedAt: new Date().toISOString()
|
|
179848
|
+
};
|
|
179840
179849
|
await db.execute({
|
|
179841
|
-
sql: `INSERT INTO mastra_om_backups
|
|
179842
|
-
|
|
179850
|
+
sql: `INSERT INTO mastra_om_backups
|
|
179851
|
+
(id, lookupKey, slot, generationCount, observations, observationTokenCount,
|
|
179852
|
+
lastObservedAt, lastReflectionAt, pendingMessageTokens, observedMessageIds, trigger, savedAt)
|
|
179853
|
+
SELECT hex(randomblob(16)), lookupKey, 2, generationCount, observations, observationTokenCount,
|
|
179854
|
+
lastObservedAt, lastReflectionAt, pendingMessageTokens, observedMessageIds, trigger, savedAt
|
|
179843
179855
|
FROM mastra_om_backups WHERE lookupKey = ? AND slot = 1
|
|
179844
179856
|
ON CONFLICT(lookupKey, slot) DO UPDATE SET
|
|
179845
179857
|
generationCount = excluded.generationCount,
|
|
179846
179858
|
observations = excluded.observations,
|
|
179859
|
+
observationTokenCount = excluded.observationTokenCount,
|
|
179860
|
+
lastObservedAt = excluded.lastObservedAt,
|
|
179861
|
+
lastReflectionAt = excluded.lastReflectionAt,
|
|
179862
|
+
pendingMessageTokens = excluded.pendingMessageTokens,
|
|
179863
|
+
observedMessageIds = excluded.observedMessageIds,
|
|
179864
|
+
trigger = excluded.trigger,
|
|
179847
179865
|
savedAt = excluded.savedAt`,
|
|
179848
|
-
args: [
|
|
179866
|
+
args: [threadId]
|
|
179849
179867
|
});
|
|
179850
179868
|
await db.execute({
|
|
179851
|
-
sql: `INSERT INTO mastra_om_backups
|
|
179852
|
-
|
|
179869
|
+
sql: `INSERT INTO mastra_om_backups
|
|
179870
|
+
(id, lookupKey, slot, generationCount, observations, observationTokenCount,
|
|
179871
|
+
lastObservedAt, lastReflectionAt, pendingMessageTokens, observedMessageIds, trigger, savedAt)
|
|
179872
|
+
VALUES (hex(randomblob(16)), ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
179853
179873
|
ON CONFLICT(lookupKey, slot) DO UPDATE SET
|
|
179854
179874
|
generationCount = excluded.generationCount,
|
|
179855
179875
|
observations = excluded.observations,
|
|
179876
|
+
observationTokenCount = excluded.observationTokenCount,
|
|
179877
|
+
lastObservedAt = excluded.lastObservedAt,
|
|
179878
|
+
lastReflectionAt = excluded.lastReflectionAt,
|
|
179879
|
+
pendingMessageTokens = excluded.pendingMessageTokens,
|
|
179880
|
+
observedMessageIds = excluded.observedMessageIds,
|
|
179881
|
+
trigger = excluded.trigger,
|
|
179856
179882
|
savedAt = excluded.savedAt`,
|
|
179857
|
-
args: [
|
|
179883
|
+
args: [
|
|
179884
|
+
threadId,
|
|
179885
|
+
snap.generationCount,
|
|
179886
|
+
snap.observations,
|
|
179887
|
+
snap.observationTokenCount,
|
|
179888
|
+
snap.lastObservedAt,
|
|
179889
|
+
snap.lastReflectionAt,
|
|
179890
|
+
snap.pendingMessageTokens,
|
|
179891
|
+
snap.observedMessageIds,
|
|
179892
|
+
snap.trigger,
|
|
179893
|
+
snap.savedAt
|
|
179894
|
+
]
|
|
179858
179895
|
});
|
|
179859
|
-
omLog(`[backup] ${
|
|
179896
|
+
omLog(`[backup] ${trigger} — saved gen ${snap.generationCount} to slot 1, rotated old slot 1 → slot 2`);
|
|
179860
179897
|
} catch (err) {
|
|
179861
179898
|
omLog(`[backup] failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
179862
179899
|
}
|
|
@@ -180008,7 +180045,7 @@ ${OBSERVATION_CONTINUATION_HINT}`);
|
|
|
180008
180045
|
}
|
|
180009
180046
|
}),
|
|
180010
180047
|
om_observe: tool5({
|
|
180011
|
-
description: "Manually trigger an observation cycle right now, without waiting for the token threshold.",
|
|
180048
|
+
description: "Manually trigger an observation cycle right now, without waiting for the token threshold. Automatically chunks large message sets if chunkTokens is configured.",
|
|
180012
180049
|
args: {},
|
|
180013
180050
|
async execute(_args, context2) {
|
|
180014
180051
|
const threadId = context2.sessionID;
|
|
@@ -180019,8 +180056,54 @@ ${OBSERVATION_CONTINUATION_HINT}`);
|
|
|
180019
180056
|
return "No messages to observe.";
|
|
180020
180057
|
const mastraMessages = convertMessages2(resp.data, threadId);
|
|
180021
180058
|
await backupObservations(threadId, "pre-observe");
|
|
180022
|
-
|
|
180023
|
-
|
|
180059
|
+
const chunkTokens = config2.chunkTokens;
|
|
180060
|
+
if (!chunkTokens) {
|
|
180061
|
+
await runObserve(threadId, mastraMessages);
|
|
180062
|
+
return "Observation cycle triggered. Check om_status for results.";
|
|
180063
|
+
}
|
|
180064
|
+
const tokenCounter = new TokenCounter;
|
|
180065
|
+
const chunks = [];
|
|
180066
|
+
let currentChunk = [];
|
|
180067
|
+
let currentTokens = 0;
|
|
180068
|
+
for (const msg of mastraMessages) {
|
|
180069
|
+
const msgTokens = tokenCounter.countMessages([msg]);
|
|
180070
|
+
if (currentTokens + msgTokens > chunkTokens && currentChunk.length > 0) {
|
|
180071
|
+
chunks.push(currentChunk);
|
|
180072
|
+
currentChunk = [msg];
|
|
180073
|
+
currentTokens = msgTokens;
|
|
180074
|
+
} else {
|
|
180075
|
+
currentChunk.push(msg);
|
|
180076
|
+
currentTokens += msgTokens;
|
|
180077
|
+
}
|
|
180078
|
+
}
|
|
180079
|
+
if (currentChunk.length > 0)
|
|
180080
|
+
chunks.push(currentChunk);
|
|
180081
|
+
if (chunks.length === 1) {
|
|
180082
|
+
await runObserve(threadId, mastraMessages);
|
|
180083
|
+
return "Observation cycle triggered (single chunk). Check om_status for results.";
|
|
180084
|
+
}
|
|
180085
|
+
omLog(`[observe] chunked into ${chunks.length} chunks of ~${chunkTokens} tokens each`);
|
|
180086
|
+
ctx.client.tui.showToast({
|
|
180087
|
+
body: { title: "Mastra OM", message: `Observing in ${chunks.length} chunks...`, variant: "info", duration: 5000 }
|
|
180088
|
+
});
|
|
180089
|
+
const refThreshold = resolveThreshold(omOptions.reflection?.observationTokens ?? 60000);
|
|
180090
|
+
const reflectAt = Math.floor(refThreshold * 0.8);
|
|
180091
|
+
for (let i = 0;i < chunks.length; i++) {
|
|
180092
|
+
omLog(`[observe] processing chunk ${i + 1}/${chunks.length} (${chunks[i].length} messages)`);
|
|
180093
|
+
await runObserve(threadId, chunks[i]);
|
|
180094
|
+
if (i < chunks.length - 1) {
|
|
180095
|
+
const record3 = await om.getRecord(threadId);
|
|
180096
|
+
const obsTokens = record3?.observationTokenCount ?? 0;
|
|
180097
|
+
if (obsTokens >= reflectAt) {
|
|
180098
|
+
omLog(`[observe] observations at ${obsTokens} tokens (>= ${reflectAt}), reflecting before next chunk`);
|
|
180099
|
+
ctx.client.tui.showToast({
|
|
180100
|
+
body: { title: "Mastra OM", message: `Reflecting between chunks (${i + 1}/${chunks.length})...`, variant: "info", duration: 5000 }
|
|
180101
|
+
});
|
|
180102
|
+
await om.reflect(threadId);
|
|
180103
|
+
}
|
|
180104
|
+
}
|
|
180105
|
+
}
|
|
180106
|
+
return `Observation complete — processed ${chunks.length} chunks, ${mastraMessages.length} messages total. Check om_status for results.`;
|
|
180024
180107
|
} catch (err) {
|
|
180025
180108
|
const msg = err instanceof Error ? err.message : String(err);
|
|
180026
180109
|
lastError = msg;
|
|
@@ -180063,6 +180146,98 @@ ${OBSERVATION_CONTINUATION_HINT}`);
|
|
|
180063
180146
|
}
|
|
180064
180147
|
}
|
|
180065
180148
|
}),
|
|
180149
|
+
om_restore: tool5({
|
|
180150
|
+
description: "Restore observational memory from backup slot 1 (most recent) or slot 2 (one generation older).",
|
|
180151
|
+
args: { slot: { type: "number", description: "1 = most recent backup, 2 = one generation older" } },
|
|
180152
|
+
async execute(args, context2) {
|
|
180153
|
+
const threadId = context2.sessionID;
|
|
180154
|
+
const slot = args.slot === 2 ? 2 : 1;
|
|
180155
|
+
try {
|
|
180156
|
+
const db = store.turso;
|
|
180157
|
+
if (!db)
|
|
180158
|
+
return "Raw DB access unavailable.";
|
|
180159
|
+
const result = await db.execute({
|
|
180160
|
+
sql: `SELECT * FROM mastra_om_backups WHERE lookupKey = ? AND slot = ?`,
|
|
180161
|
+
args: [threadId, slot]
|
|
180162
|
+
});
|
|
180163
|
+
const row = result.rows?.[0];
|
|
180164
|
+
if (!row)
|
|
180165
|
+
return `No backup found in slot ${slot}.`;
|
|
180166
|
+
await db.execute({
|
|
180167
|
+
sql: `UPDATE mastra_observational_memory SET
|
|
180168
|
+
activeObservations = ?,
|
|
180169
|
+
generationCount = ?,
|
|
180170
|
+
observationTokenCount = ?,
|
|
180171
|
+
lastObservedAt = ?,
|
|
180172
|
+
lastReflectionAt = ?,
|
|
180173
|
+
pendingMessageTokens = ?,
|
|
180174
|
+
observedMessageIds = ?
|
|
180175
|
+
WHERE lookupKey = ?`,
|
|
180176
|
+
args: [
|
|
180177
|
+
row.observations,
|
|
180178
|
+
row.generationCount,
|
|
180179
|
+
row.observationTokenCount,
|
|
180180
|
+
row.lastObservedAt,
|
|
180181
|
+
row.lastReflectionAt,
|
|
180182
|
+
row.pendingMessageTokens,
|
|
180183
|
+
row.observedMessageIds,
|
|
180184
|
+
threadId
|
|
180185
|
+
]
|
|
180186
|
+
});
|
|
180187
|
+
omLog(`[restore] restored slot ${slot} — gen ${row.generationCount}, saved at ${row.savedAt}, trigger=${row.trigger}`);
|
|
180188
|
+
return [
|
|
180189
|
+
`✅ Restored from slot ${slot}`,
|
|
180190
|
+
` Generation: ${row.generationCount}`,
|
|
180191
|
+
` Saved at: ${row.savedAt}`,
|
|
180192
|
+
` Trigger: ${row.trigger}`,
|
|
180193
|
+
` Observation tokens: ${row.observationTokenCount}`,
|
|
180194
|
+
` Last observed: ${row.lastObservedAt ?? "never"}`,
|
|
180195
|
+
` Last reflection: ${row.lastReflectionAt ?? "never"}`
|
|
180196
|
+
].join(`
|
|
180197
|
+
`);
|
|
180198
|
+
} catch (err) {
|
|
180199
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
180200
|
+
return `Restore failed: ${msg}`;
|
|
180201
|
+
}
|
|
180202
|
+
}
|
|
180203
|
+
}),
|
|
180204
|
+
om_reset: tool5({
|
|
180205
|
+
description: "Reset observational memory for this session to a clean slate. Backs up current state first so it can be restored via om_restore.",
|
|
180206
|
+
args: {},
|
|
180207
|
+
async execute(_args, context2) {
|
|
180208
|
+
const threadId = context2.sessionID;
|
|
180209
|
+
try {
|
|
180210
|
+
const db = store.turso;
|
|
180211
|
+
if (!db)
|
|
180212
|
+
return "Raw DB access unavailable.";
|
|
180213
|
+
await backupObservations(threadId, "pre-reset");
|
|
180214
|
+
await db.execute({
|
|
180215
|
+
sql: `UPDATE mastra_observational_memory SET
|
|
180216
|
+
activeObservations = '',
|
|
180217
|
+
generationCount = 0,
|
|
180218
|
+
observationTokenCount = 0,
|
|
180219
|
+
lastObservedAt = NULL,
|
|
180220
|
+
lastReflectionAt = NULL,
|
|
180221
|
+
pendingMessageTokens = 0,
|
|
180222
|
+
observedMessageIds = '[]',
|
|
180223
|
+
bufferedObservations = NULL,
|
|
180224
|
+
bufferedObservationTokens = 0,
|
|
180225
|
+
bufferedMessageIds = NULL,
|
|
180226
|
+
bufferedReflection = NULL,
|
|
180227
|
+
bufferedReflectionTokens = 0,
|
|
180228
|
+
bufferedReflectionInputTokens = 0,
|
|
180229
|
+
reflectedObservationLineCount = 0
|
|
180230
|
+
WHERE lookupKey = ?`,
|
|
180231
|
+
args: [threadId]
|
|
180232
|
+
});
|
|
180233
|
+
omLog(`[reset] observations cleared for ${threadId}`);
|
|
180234
|
+
return "✅ Observational memory reset. Previous state saved to backup slot 1 — use om_restore to recover if needed.";
|
|
180235
|
+
} catch (err) {
|
|
180236
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
180237
|
+
return `Reset failed: ${msg}`;
|
|
180238
|
+
}
|
|
180239
|
+
}
|
|
180240
|
+
}),
|
|
180066
180241
|
om_config: tool5({
|
|
180067
180242
|
description: "Show the current Mastra Observational Memory configuration.",
|
|
180068
180243
|
args: {},
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "opencode-mastra-om",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.6",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"description": "Enhanced Mastra Observational Memory plugin for OpenCode — persistent cross-session memory with observation, reflection, and manual trigger tools",
|