@sentry/junior-memory 0.118.0 → 0.120.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/README.md +23 -7
- package/dist/agent.d.ts +11 -1
- package/dist/api.d.ts +45 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +634 -272
- package/dist/index.js.map +1 -1
- package/dist/personal-store.d.ts +39 -0
- package/dist/personal.d.ts +21 -0
- package/dist/plugin.d.ts +2 -3
- package/dist/ranking.d.ts +20 -0
- package/dist/recall.d.ts +4 -1
- package/dist/store.d.ts +25 -0
- package/dist/user-pages.d.ts +2 -2
- package/migrations/0005_short_jamie_braddock.sql +1 -0
- package/migrations/meta/0005_snapshot.json +364 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +2 -2
- package/src/agent.ts +65 -1
- package/src/api.ts +168 -0
- package/src/db/schema.ts +5 -0
- package/src/index.ts +7 -1
- package/src/personal-store.ts +195 -0
- package/src/personal.ts +120 -0
- package/src/plugin.ts +11 -4
- package/src/ranking.ts +98 -0
- package/src/recall.ts +31 -4
- package/src/store.ts +151 -236
- package/src/user-pages.ts +27 -62
package/dist/index.js
CHANGED
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
desc,
|
|
14
14
|
eq,
|
|
15
15
|
gt,
|
|
16
|
-
ilike,
|
|
17
16
|
inArray,
|
|
18
17
|
isNull,
|
|
19
18
|
isNotNull,
|
|
@@ -106,6 +105,9 @@ var juniorMemoryMemories = pgTable(
|
|
|
106
105
|
index("junior_memory_memories_expiration_idx").on(table.expiresAtMs).where(
|
|
107
106
|
sql`${table.archivedAtMs} IS NULL AND ${table.expiresAtMs} IS NOT NULL`
|
|
108
107
|
),
|
|
108
|
+
index("junior_memory_memories_search_idx").using("gin", sql`to_tsvector('english', ${table.content})`).where(
|
|
109
|
+
sql`${table.archivedAtMs} IS NULL AND ${table.supersededAtMs} IS NULL AND ${table.supersededById} IS NULL`
|
|
110
|
+
),
|
|
109
111
|
uniqueIndex("junior_memory_memories_idempotency_idx").on(table.scope, table.scopeKey, table.idempotencyKey).where(
|
|
110
112
|
sql`${table.idempotencyKey} IS NOT NULL AND ${table.archivedAtMs} IS NULL AND ${table.supersededAtMs} IS NULL AND ${table.supersededById} IS NULL`
|
|
111
113
|
),
|
|
@@ -167,6 +169,63 @@ var juniorMemoryEmbeddings = pgTable(
|
|
|
167
169
|
]
|
|
168
170
|
);
|
|
169
171
|
|
|
172
|
+
// src/ranking.ts
|
|
173
|
+
var RECIPROCAL_RANK_FUSION_K = 60;
|
|
174
|
+
var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
|
|
175
|
+
function reciprocalRank(rank) {
|
|
176
|
+
return 1 / (RECIPROCAL_RANK_FUSION_K + rank);
|
|
177
|
+
}
|
|
178
|
+
function matchScore(match) {
|
|
179
|
+
return (match.vector ? reciprocalRank(match.vector.rank) : 0) + (match.lexical ? reciprocalRank(match.lexical.rank) : 0);
|
|
180
|
+
}
|
|
181
|
+
function currentChannel(match, channelPrefix) {
|
|
182
|
+
return channelPrefix ? match.sourceKey.startsWith(channelPrefix) : false;
|
|
183
|
+
}
|
|
184
|
+
function observedAgeRank(memory, nowMs) {
|
|
185
|
+
const ageMs = Math.max(0, nowMs - memory.observedAtMs);
|
|
186
|
+
if (ageMs <= 7 * ONE_DAY_MS) {
|
|
187
|
+
return 3;
|
|
188
|
+
}
|
|
189
|
+
if (ageMs <= 30 * ONE_DAY_MS) {
|
|
190
|
+
return 2;
|
|
191
|
+
}
|
|
192
|
+
if (ageMs <= 90 * ONE_DAY_MS) {
|
|
193
|
+
return 1;
|
|
194
|
+
}
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
function rankMemoryMatches(matches, options) {
|
|
198
|
+
const byId = /* @__PURE__ */ new Map();
|
|
199
|
+
for (const match of matches) {
|
|
200
|
+
const existing = byId.get(match.memory.id);
|
|
201
|
+
if (!existing) {
|
|
202
|
+
byId.set(match.memory.id, match);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
byId.set(match.memory.id, {
|
|
206
|
+
...existing,
|
|
207
|
+
exactIdentifier: existing.exactIdentifier || match.exactIdentifier,
|
|
208
|
+
...match.lexical ? { lexical: match.lexical } : {},
|
|
209
|
+
...match.vector ? { vector: match.vector } : {}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return [...byId.values()].sort((left, right) => {
|
|
213
|
+
const identifierDelta = Number(right.exactIdentifier) - Number(left.exactIdentifier);
|
|
214
|
+
if (identifierDelta !== 0) {
|
|
215
|
+
return identifierDelta;
|
|
216
|
+
}
|
|
217
|
+
const scoreDelta = matchScore(right) - matchScore(left);
|
|
218
|
+
if (scoreDelta !== 0) {
|
|
219
|
+
return scoreDelta;
|
|
220
|
+
}
|
|
221
|
+
const channelDelta = Number(currentChannel(right, options.channelPrefix)) - Number(currentChannel(left, options.channelPrefix));
|
|
222
|
+
if (channelDelta !== 0) {
|
|
223
|
+
return channelDelta;
|
|
224
|
+
}
|
|
225
|
+
return observedAgeRank(right.memory, options.nowMs) - observedAgeRank(left.memory, options.nowMs) || right.memory.observedAtMs - left.memory.observedAtMs || left.memory.id.localeCompare(right.memory.id);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
170
229
|
// src/scope.ts
|
|
171
230
|
import { isPrivateSource } from "@sentry/junior-plugin-api";
|
|
172
231
|
function sourceConversationKey(ctx) {
|
|
@@ -239,15 +298,11 @@ function deriveVisibleMemoryScopes(ctx) {
|
|
|
239
298
|
var DEFAULT_LIST_LIMIT = 50;
|
|
240
299
|
var DEFAULT_SEARCH_LIMIT = 10;
|
|
241
300
|
var DEFAULT_EXPIRED_ARCHIVE_LIMIT = 100;
|
|
242
|
-
var HIGH_CONFIDENCE_DUPLICATE_DISTANCE = 0.015;
|
|
243
301
|
var PREFERENCE_ADJUDICATION_CANDIDATE_LIMIT = 10;
|
|
244
302
|
var PREFERENCE_ADJUDICATION_VECTOR_LIMIT = 5;
|
|
245
303
|
var VECTOR_SEARCH_OVERFETCH = 4;
|
|
246
304
|
var MAX_MEMORY_CONTENT_CHARS = 4e3;
|
|
247
305
|
var EMBEDDING_METRIC = "cosine";
|
|
248
|
-
var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
|
|
249
|
-
var RELEVANCE_NEAR_TIE_DELTA = 0.01;
|
|
250
|
-
var SOURCE_CHANNEL_BOOST = 0.05;
|
|
251
306
|
var nonEmptyStringSchema2 = z2.string().min(1);
|
|
252
307
|
var memoryContentSchema = z2.string().refine((content) => content.trim().length > 0, {
|
|
253
308
|
message: "Memory content is required."
|
|
@@ -553,20 +608,26 @@ async function archiveExpiredMemoryBatch(args) {
|
|
|
553
608
|
});
|
|
554
609
|
return { archivedCount: archivedIds.length };
|
|
555
610
|
}
|
|
556
|
-
function
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
0
|
|
561
|
-
);
|
|
562
|
-
}
|
|
563
|
-
function searchTerms(query) {
|
|
611
|
+
function structuredQueryIdentifiers(query) {
|
|
612
|
+
const matches = query.toLowerCase().match(
|
|
613
|
+
/(?:[a-z0-9][a-z0-9._-]*\/)+[a-z0-9][a-z0-9._-]*|[a-z0-9]+(?:[._][a-z0-9]+)+|[a-z0-9]+(?:-[a-z0-9]+){2,}/g
|
|
614
|
+
) ?? [];
|
|
564
615
|
return [
|
|
565
|
-
...new Set(
|
|
566
|
-
query.toLowerCase().split(/[^a-z0-9_'-]+/).map((term) => term.trim()).filter((term) => term.length >= 2)
|
|
567
|
-
)
|
|
616
|
+
...new Set(matches.map((identifier) => identifier.replace(/\.+$/, "")))
|
|
568
617
|
];
|
|
569
618
|
}
|
|
619
|
+
function denseRanks(values, key) {
|
|
620
|
+
let previous;
|
|
621
|
+
let rank = 0;
|
|
622
|
+
return values.map((value, index2) => {
|
|
623
|
+
const current = key(value);
|
|
624
|
+
if (index2 === 0 || current !== previous) {
|
|
625
|
+
rank = index2 + 1;
|
|
626
|
+
previous = current;
|
|
627
|
+
}
|
|
628
|
+
return rank;
|
|
629
|
+
});
|
|
630
|
+
}
|
|
570
631
|
async function embedOne(embedder, text2) {
|
|
571
632
|
const normalized = normalizeContent(text2);
|
|
572
633
|
if (!normalized) {
|
|
@@ -657,38 +718,6 @@ async function findExactDuplicateMemory(args) {
|
|
|
657
718
|
).limit(1);
|
|
658
719
|
return rows[0] ? parseMemoryRow(rows[0]) : void 0;
|
|
659
720
|
}
|
|
660
|
-
async function findVectorDuplicateMemory(args) {
|
|
661
|
-
const distance = cosineDistance(
|
|
662
|
-
juniorMemoryEmbeddings.embedding,
|
|
663
|
-
args.embedding.vector
|
|
664
|
-
);
|
|
665
|
-
const rows = await args.db.select({
|
|
666
|
-
contentHash: juniorMemoryEmbeddings.contentHash,
|
|
667
|
-
distance,
|
|
668
|
-
memory: juniorMemoryMemories
|
|
669
|
-
}).from(juniorMemoryMemories).innerJoin(
|
|
670
|
-
juniorMemoryEmbeddings,
|
|
671
|
-
eq(juniorMemoryEmbeddings.memoryId, juniorMemoryMemories.id)
|
|
672
|
-
).where(
|
|
673
|
-
and(
|
|
674
|
-
activeScopedSubjectPredicate(args),
|
|
675
|
-
eq(juniorMemoryEmbeddings.provider, args.embedding.provider),
|
|
676
|
-
eq(juniorMemoryEmbeddings.model, args.embedding.model),
|
|
677
|
-
eq(juniorMemoryEmbeddings.dimensions, MEMORY_EMBEDDING_DIMENSIONS),
|
|
678
|
-
eq(juniorMemoryEmbeddings.metric, EMBEDDING_METRIC),
|
|
679
|
-
lte(distance, HIGH_CONFIDENCE_DUPLICATE_DISTANCE)
|
|
680
|
-
)
|
|
681
|
-
).orderBy(
|
|
682
|
-
distance,
|
|
683
|
-
desc(juniorMemoryMemories.createdAtMs),
|
|
684
|
-
asc(juniorMemoryMemories.id)
|
|
685
|
-
).limit(1);
|
|
686
|
-
const row = rows[0];
|
|
687
|
-
if (!row || hashEmbeddedContent(row.memory.content) !== row.contentHash) {
|
|
688
|
-
return void 0;
|
|
689
|
-
}
|
|
690
|
-
return parseMemoryRow(row.memory);
|
|
691
|
-
}
|
|
692
721
|
async function rememberDuplicateIdempotency(args) {
|
|
693
722
|
if (args.idempotencyKey === void 0) {
|
|
694
723
|
return;
|
|
@@ -823,29 +852,55 @@ async function listVisibleMemories(args) {
|
|
|
823
852
|
).limit(limit);
|
|
824
853
|
return rows.map(parseMemoryRow);
|
|
825
854
|
}
|
|
826
|
-
async function
|
|
827
|
-
const terms = searchTerms(args.query);
|
|
828
|
-
if (terms.length === 0) {
|
|
829
|
-
return [];
|
|
830
|
-
}
|
|
855
|
+
async function searchVisibleLexicalMemories(args) {
|
|
831
856
|
const predicate = activeVisiblePredicate(args);
|
|
832
857
|
if (!predicate) {
|
|
833
858
|
return [];
|
|
834
859
|
}
|
|
835
|
-
const
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
(term) => ilike(juniorMemoryMemories.content, `%${term}%`)
|
|
841
|
-
)
|
|
842
|
-
)
|
|
860
|
+
const queryVector = sql2`to_tsvector('english', ${args.query})`;
|
|
861
|
+
const tsquery = sql2`(
|
|
862
|
+
SELECT COALESCE(
|
|
863
|
+
string_agg(quote_literal(term), ' | ')::tsquery,
|
|
864
|
+
''::tsquery
|
|
843
865
|
)
|
|
866
|
+
FROM unnest(tsvector_to_array(${queryVector})) AS query_terms(term)
|
|
867
|
+
)`;
|
|
868
|
+
const textsearch = sql2`to_tsvector('english', ${juniorMemoryMemories.content})`;
|
|
869
|
+
const textRank = sql2`ts_rank_cd(${textsearch}, ${tsquery})`;
|
|
870
|
+
const identifiers = structuredQueryIdentifiers(args.query);
|
|
871
|
+
const contentTokens = sql2`regexp_split_to_array(lower(${juniorMemoryMemories.content}), '[^a-z0-9._/-]+')`;
|
|
872
|
+
const identifierArray = identifiers.length > 0 ? sql2`ARRAY[${sql2.join(
|
|
873
|
+
identifiers.map((identifier) => sql2`${identifier}`),
|
|
874
|
+
sql2`, `
|
|
875
|
+
)}]::text[]` : void 0;
|
|
876
|
+
const exactIdentifierMatch = identifierArray !== void 0 ? sql2`EXISTS (
|
|
877
|
+
SELECT 1
|
|
878
|
+
FROM unnest(${contentTokens}) AS content_token(value)
|
|
879
|
+
CROSS JOIN unnest(${identifierArray}) AS query_identifier(value)
|
|
880
|
+
WHERE strpos(
|
|
881
|
+
'/' || regexp_replace(content_token.value, '\\.+$', '') || '/',
|
|
882
|
+
'/' || query_identifier.value || '/'
|
|
883
|
+
) > 0
|
|
884
|
+
)` : sql2`false`;
|
|
885
|
+
const rows = await args.db.select({
|
|
886
|
+
exactIdentifierMatch,
|
|
887
|
+
memory: juniorMemoryMemories,
|
|
888
|
+
textRank
|
|
889
|
+
}).from(juniorMemoryMemories).where(and(predicate, sql2`${textsearch} @@ ${tsquery}`)).orderBy(
|
|
890
|
+
...identifiers.length > 0 ? [desc(exactIdentifierMatch)] : [],
|
|
891
|
+
desc(textRank),
|
|
892
|
+
desc(juniorMemoryMemories.observedAtMs),
|
|
893
|
+
asc(juniorMemoryMemories.id)
|
|
894
|
+
).limit(args.limit);
|
|
895
|
+
const ranks = denseRanks(
|
|
896
|
+
rows,
|
|
897
|
+
(row) => `${row.exactIdentifierMatch}:${Number(row.textRank)}`
|
|
844
898
|
);
|
|
845
|
-
return rows.map((row) => ({
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
899
|
+
return rows.map((row, index2) => ({
|
|
900
|
+
exactIdentifier: row.exactIdentifierMatch,
|
|
901
|
+
lexical: { rank: ranks[index2] },
|
|
902
|
+
memory: parseMemoryRow(row.memory),
|
|
903
|
+
sourceKey: row.memory.sourceKey
|
|
849
904
|
}));
|
|
850
905
|
}
|
|
851
906
|
async function searchVisibleVectorMemories(args) {
|
|
@@ -886,7 +941,8 @@ async function searchVisibleVectorMemories(args) {
|
|
|
886
941
|
desc(juniorMemoryMemories.createdAtMs),
|
|
887
942
|
asc(juniorMemoryMemories.id)
|
|
888
943
|
).limit(args.limit);
|
|
889
|
-
|
|
944
|
+
const ranks = denseRanks(rows, (row) => Number(row.distance));
|
|
945
|
+
return rows.flatMap((row, index2) => {
|
|
890
946
|
const distanceValue = Number(row.distance);
|
|
891
947
|
if (row.distance === null || !Number.isFinite(distanceValue) || hashEmbeddedContent(row.memory.content) !== row.contentHash) {
|
|
892
948
|
return [];
|
|
@@ -896,58 +952,16 @@ async function searchVisibleVectorMemories(args) {
|
|
|
896
952
|
}
|
|
897
953
|
return [
|
|
898
954
|
{
|
|
955
|
+
exactIdentifier: false,
|
|
899
956
|
memory: parseMemoryRow(row.memory),
|
|
900
|
-
|
|
901
|
-
|
|
957
|
+
sourceKey: row.memory.sourceKey,
|
|
958
|
+
vector: {
|
|
959
|
+
rank: ranks[index2]
|
|
960
|
+
}
|
|
902
961
|
}
|
|
903
962
|
];
|
|
904
963
|
});
|
|
905
964
|
}
|
|
906
|
-
function sourceBoost(candidate, currentChannelPrefix) {
|
|
907
|
-
if (!currentChannelPrefix) {
|
|
908
|
-
return 0;
|
|
909
|
-
}
|
|
910
|
-
return candidate.sourceKey.startsWith(currentChannelPrefix) ? SOURCE_CHANNEL_BOOST : 0;
|
|
911
|
-
}
|
|
912
|
-
function observedAgeBoost(memory, nowMs) {
|
|
913
|
-
const ageMs = Math.max(0, nowMs - memory.observedAtMs);
|
|
914
|
-
if (ageMs <= 7 * ONE_DAY_MS) {
|
|
915
|
-
return 0.15;
|
|
916
|
-
}
|
|
917
|
-
if (ageMs <= 30 * ONE_DAY_MS) {
|
|
918
|
-
return 0.1;
|
|
919
|
-
}
|
|
920
|
-
if (ageMs <= 90 * ONE_DAY_MS) {
|
|
921
|
-
return 0.05;
|
|
922
|
-
}
|
|
923
|
-
return 0;
|
|
924
|
-
}
|
|
925
|
-
function mergeSearchCandidates(candidates, nowMs, currentChannelKey) {
|
|
926
|
-
const byId = /* @__PURE__ */ new Map();
|
|
927
|
-
for (const candidate of candidates) {
|
|
928
|
-
const existing = byId.get(candidate.memory.id);
|
|
929
|
-
if (existing) {
|
|
930
|
-
existing.score += candidate.score;
|
|
931
|
-
continue;
|
|
932
|
-
}
|
|
933
|
-
byId.set(candidate.memory.id, {
|
|
934
|
-
memory: candidate.memory,
|
|
935
|
-
score: candidate.score,
|
|
936
|
-
sourceKey: candidate.sourceKey
|
|
937
|
-
});
|
|
938
|
-
}
|
|
939
|
-
return [...byId.values()].sort((left, right) => {
|
|
940
|
-
const scoreDelta = right.score - left.score;
|
|
941
|
-
if (Math.abs(scoreDelta) > RELEVANCE_NEAR_TIE_DELTA) {
|
|
942
|
-
return scoreDelta;
|
|
943
|
-
}
|
|
944
|
-
const sourceDelta = sourceBoost(right, currentChannelKey) - sourceBoost(left, currentChannelKey);
|
|
945
|
-
if (sourceDelta !== 0) {
|
|
946
|
-
return sourceDelta;
|
|
947
|
-
}
|
|
948
|
-
return observedAgeBoost(right.memory, nowMs) - observedAgeBoost(left.memory, nowMs) || right.memory.observedAtMs - left.memory.observedAtMs || left.memory.id.localeCompare(right.memory.id);
|
|
949
|
-
}).map((candidate) => candidate.memory);
|
|
950
|
-
}
|
|
951
965
|
function createMemoryStore(db, context, options = {}) {
|
|
952
966
|
const runtimeContext2 = memoryRuntimeContextSchema.parse(context);
|
|
953
967
|
const parsedOptions = memoryStoreOptionsSchema.parse({ now: options.now });
|
|
@@ -1044,24 +1058,6 @@ function createMemoryStore(db, context, options = {}) {
|
|
|
1044
1058
|
candidateEmbedding = void 0;
|
|
1045
1059
|
}
|
|
1046
1060
|
}
|
|
1047
|
-
const vectorDuplicate = candidateEmbedding ? await findVectorDuplicateMemory({
|
|
1048
|
-
db,
|
|
1049
|
-
embedding: candidateEmbedding,
|
|
1050
|
-
kind: input.kind,
|
|
1051
|
-
nowMs,
|
|
1052
|
-
scope,
|
|
1053
|
-
subject
|
|
1054
|
-
}) : void 0;
|
|
1055
|
-
if (vectorDuplicate) {
|
|
1056
|
-
return await reuseDuplicateMemory({
|
|
1057
|
-
content,
|
|
1058
|
-
duplicate: vectorDuplicate,
|
|
1059
|
-
idempotencyKey: input.idempotencyKey,
|
|
1060
|
-
nowMs,
|
|
1061
|
-
scope,
|
|
1062
|
-
subject
|
|
1063
|
-
});
|
|
1064
|
-
}
|
|
1065
1061
|
let supersededIds = [];
|
|
1066
1062
|
if (scopeKind === "personal" && input.kind === "preference" && supersessionDecider && (input.expiresAtMs === void 0 || input.expiresAtMs > nowMs)) {
|
|
1067
1063
|
const preferenceCandidates = await listPreferenceAdjudicationCandidates({
|
|
@@ -1169,6 +1165,41 @@ function createMemoryStore(db, context, options = {}) {
|
|
|
1169
1165
|
});
|
|
1170
1166
|
return { created: false, memory: idempotent };
|
|
1171
1167
|
}
|
|
1168
|
+
async function retrieveVisibleMemories(rawInput, vectorMaxDistance) {
|
|
1169
|
+
const input = searchMemoriesInputSchema.parse(rawInput);
|
|
1170
|
+
const nowMs = getNowMs();
|
|
1171
|
+
const scopes = deriveVisibleMemoryScopes(runtimeContext2);
|
|
1172
|
+
await archiveExpiredMemoryBatch({
|
|
1173
|
+
db,
|
|
1174
|
+
nowMs,
|
|
1175
|
+
scopes
|
|
1176
|
+
});
|
|
1177
|
+
const limit = boundedLimit(input.limit, DEFAULT_SEARCH_LIMIT);
|
|
1178
|
+
const candidateLimit = limit * VECTOR_SEARCH_OVERFETCH;
|
|
1179
|
+
const [vectorMatches, lexicalMatches] = await Promise.all([
|
|
1180
|
+
searchVisibleVectorMemories({
|
|
1181
|
+
db,
|
|
1182
|
+
embedder,
|
|
1183
|
+
limit: candidateLimit,
|
|
1184
|
+
...vectorMaxDistance !== void 0 ? { maxDistance: vectorMaxDistance } : {},
|
|
1185
|
+
nowMs,
|
|
1186
|
+
query: input.query,
|
|
1187
|
+
scopes
|
|
1188
|
+
}),
|
|
1189
|
+
searchVisibleLexicalMemories({
|
|
1190
|
+
db,
|
|
1191
|
+
limit: candidateLimit,
|
|
1192
|
+
nowMs,
|
|
1193
|
+
query: input.query,
|
|
1194
|
+
scopes
|
|
1195
|
+
})
|
|
1196
|
+
]);
|
|
1197
|
+
const channelPrefix = sourceChannelPrefix(runtimeContext2);
|
|
1198
|
+
return rankMemoryMatches([...vectorMatches, ...lexicalMatches], {
|
|
1199
|
+
nowMs,
|
|
1200
|
+
...channelPrefix ? { channelPrefix } : {}
|
|
1201
|
+
}).slice(0, limit).map(({ memory }) => memory);
|
|
1202
|
+
}
|
|
1172
1203
|
return {
|
|
1173
1204
|
async archiveExpiredMemories(input) {
|
|
1174
1205
|
return await archiveExpiredVisibleMemories(input, getNowMs());
|
|
@@ -1211,41 +1242,11 @@ function createMemoryStore(db, context, options = {}) {
|
|
|
1211
1242
|
scopes
|
|
1212
1243
|
});
|
|
1213
1244
|
},
|
|
1245
|
+
async recallMemories(input) {
|
|
1246
|
+
return await retrieveVisibleMemories(input, maxVectorDistance);
|
|
1247
|
+
},
|
|
1214
1248
|
async searchMemories(input) {
|
|
1215
|
-
|
|
1216
|
-
const nowMs = getNowMs();
|
|
1217
|
-
const scopes = deriveVisibleMemoryScopes(runtimeContext2);
|
|
1218
|
-
await archiveExpiredMemoryBatch({
|
|
1219
|
-
db,
|
|
1220
|
-
nowMs,
|
|
1221
|
-
scopes
|
|
1222
|
-
});
|
|
1223
|
-
const limit = boundedLimit(input.limit, DEFAULT_SEARCH_LIMIT);
|
|
1224
|
-
const vectorCandidates = await searchVisibleVectorMemories({
|
|
1225
|
-
db,
|
|
1226
|
-
embedder,
|
|
1227
|
-
limit: limit * VECTOR_SEARCH_OVERFETCH,
|
|
1228
|
-
...maxVectorDistance !== void 0 ? { maxDistance: maxVectorDistance } : {},
|
|
1229
|
-
nowMs,
|
|
1230
|
-
query: input.query,
|
|
1231
|
-
scopes
|
|
1232
|
-
});
|
|
1233
|
-
const candidates = await searchVisibleMemories({
|
|
1234
|
-
db,
|
|
1235
|
-
nowMs,
|
|
1236
|
-
query: input.query,
|
|
1237
|
-
scopes
|
|
1238
|
-
});
|
|
1239
|
-
const terms = searchTerms(input.query);
|
|
1240
|
-
const lexicalCandidates = candidates.map((candidate) => ({
|
|
1241
|
-
...candidate,
|
|
1242
|
-
score: searchScore(candidate.memory, terms)
|
|
1243
|
-
})).filter((item) => item.score > 0);
|
|
1244
|
-
return mergeSearchCandidates(
|
|
1245
|
-
[...vectorCandidates, ...lexicalCandidates],
|
|
1246
|
-
nowMs,
|
|
1247
|
-
sourceChannelPrefix(runtimeContext2)
|
|
1248
|
-
).slice(0, limit);
|
|
1249
|
+
return await retrieveVisibleMemories(input, void 0);
|
|
1249
1250
|
},
|
|
1250
1251
|
async archiveMemory(input) {
|
|
1251
1252
|
input = archiveMemoryInputSchema.parse(input);
|
|
@@ -1294,6 +1295,19 @@ var memoryRejectReasonSchema = z3.enum([
|
|
|
1294
1295
|
"assistant_or_system_detail",
|
|
1295
1296
|
"unsupported_scope"
|
|
1296
1297
|
]);
|
|
1298
|
+
var memoryRecallCandidateSchema = z3.object({
|
|
1299
|
+
content: z3.string().min(1),
|
|
1300
|
+
id: z3.string().min(1)
|
|
1301
|
+
}).strict();
|
|
1302
|
+
var memoryRecallInputSchema = z3.object({
|
|
1303
|
+
candidates: z3.array(memoryRecallCandidateSchema).min(1).max(20),
|
|
1304
|
+
userRequest: z3.string().min(1)
|
|
1305
|
+
}).strict();
|
|
1306
|
+
var memoryRecallDecisionSchema = z3.object({
|
|
1307
|
+
relevantIds: z3.array(z3.string().min(1)).max(20).describe(
|
|
1308
|
+
"Candidate ids whose memories directly help with the current request, ordered by relevance."
|
|
1309
|
+
)
|
|
1310
|
+
}).strict();
|
|
1297
1311
|
var createMemoryRequestSchema = z3.object({
|
|
1298
1312
|
content: z3.string().min(1),
|
|
1299
1313
|
expiresAtMs: z3.number().finite().optional(),
|
|
@@ -1399,6 +1413,13 @@ var MEMORY_EXTRACTION_SYSTEM = [
|
|
|
1399
1413
|
"Reject secrets, credentials, private or sensitive personal details, gossip, speculative claims about other people, assistant/system implementation details, vague references, and low-durability chatter.",
|
|
1400
1414
|
"If no public, durable, self-contained memory remains after rewriting, return an empty memories array."
|
|
1401
1415
|
].join("\n");
|
|
1416
|
+
var MEMORY_RECALL_SYSTEM = [
|
|
1417
|
+
"You are Junior's memory recall relevance agent.",
|
|
1418
|
+
"Select only memories that would directly help answer the user's current request.",
|
|
1419
|
+
"Reject memories that merely share a company, product family, repository vocabulary, programming language, or general engineering context.",
|
|
1420
|
+
"Prefer specific matches on the exact repository, workflow, command, test, CI setup, project, or user preference being asked about.",
|
|
1421
|
+
"An empty relevantIds array is correct when no candidate is directly helpful."
|
|
1422
|
+
].join("\n");
|
|
1402
1423
|
var MEMORY_PREFERENCE_ADJUDICATION_SYSTEM = [
|
|
1403
1424
|
"You are Junior's memory preference adjudication agent.",
|
|
1404
1425
|
"Classify how one new actor preference relates to existing active actor preferences.",
|
|
@@ -1598,6 +1619,21 @@ function sessionExtractionPrompt(request) {
|
|
|
1598
1619
|
"</memory-extraction-input>"
|
|
1599
1620
|
].join("\n");
|
|
1600
1621
|
}
|
|
1622
|
+
function recallRelevancePrompt(request) {
|
|
1623
|
+
return [
|
|
1624
|
+
"<memory-recall-input>",
|
|
1625
|
+
"<user-request>",
|
|
1626
|
+
escapeXml(request.userRequest),
|
|
1627
|
+
"</user-request>",
|
|
1628
|
+
"",
|
|
1629
|
+
"<candidate-memories>",
|
|
1630
|
+
escapeXml(JSON.stringify(request.candidates)),
|
|
1631
|
+
"</candidate-memories>",
|
|
1632
|
+
"",
|
|
1633
|
+
"Return only ids from candidate-memories. Preserve the most relevant candidates first.",
|
|
1634
|
+
"</memory-recall-input>"
|
|
1635
|
+
].join("\n");
|
|
1636
|
+
}
|
|
1601
1637
|
function preferenceAdjudicationPrompt(request) {
|
|
1602
1638
|
return [
|
|
1603
1639
|
"<memory-preference-adjudication-input>",
|
|
@@ -1630,6 +1666,20 @@ function preferenceAdjudicationPrompt(request) {
|
|
|
1630
1666
|
}
|
|
1631
1667
|
function createMemoryAgent(model) {
|
|
1632
1668
|
return {
|
|
1669
|
+
async selectRelevantMemories(rawRequest) {
|
|
1670
|
+
const request = memoryRecallInputSchema.parse(rawRequest);
|
|
1671
|
+
const result = await model.completeObject({
|
|
1672
|
+
schema: memoryRecallDecisionSchema,
|
|
1673
|
+
system: MEMORY_RECALL_SYSTEM,
|
|
1674
|
+
prompt: recallRelevancePrompt(request),
|
|
1675
|
+
maxTokens: 400
|
|
1676
|
+
});
|
|
1677
|
+
const decision = memoryRecallDecisionSchema.parse(result.object);
|
|
1678
|
+
const candidateIds = new Set(request.candidates.map(({ id }) => id));
|
|
1679
|
+
return [...new Set(decision.relevantIds)].filter(
|
|
1680
|
+
(id) => candidateIds.has(id)
|
|
1681
|
+
);
|
|
1682
|
+
},
|
|
1633
1683
|
async adjudicateSupersession(rawRequest) {
|
|
1634
1684
|
const request = memorySupersessionInputSchema.parse(rawRequest);
|
|
1635
1685
|
const result = await model.completeObject({
|
|
@@ -1698,9 +1748,317 @@ function parseCreateMemoryRequest(request) {
|
|
|
1698
1748
|
return createMemoryRequestSchema.parse(request);
|
|
1699
1749
|
}
|
|
1700
1750
|
|
|
1751
|
+
// src/api.ts
|
|
1752
|
+
import { z as z6 } from "zod";
|
|
1753
|
+
import {
|
|
1754
|
+
pluginApiRouteRequestContextSchema
|
|
1755
|
+
} from "@sentry/junior-plugin-api";
|
|
1756
|
+
|
|
1757
|
+
// src/personal.ts
|
|
1758
|
+
import { z as z5 } from "zod";
|
|
1759
|
+
|
|
1760
|
+
// src/personal-store.ts
|
|
1761
|
+
import { and as and2, asc as asc2, desc as desc2, eq as eq2, gt as gt2, ilike, lt, or as or2, sql as sql3 } from "drizzle-orm";
|
|
1762
|
+
import { z as z4 } from "zod";
|
|
1763
|
+
var nonEmptyStringSchema3 = z4.string().min(1);
|
|
1764
|
+
var personalMemoryCursorSchema = z4.object({
|
|
1765
|
+
createdAtMs: z4.number().finite(),
|
|
1766
|
+
id: nonEmptyStringSchema3
|
|
1767
|
+
}).strict();
|
|
1768
|
+
var personalMemoryPageInputSchema = z4.object({
|
|
1769
|
+
cursor: personalMemoryCursorSchema.optional(),
|
|
1770
|
+
limit: z4.number().int().min(1).max(50),
|
|
1771
|
+
query: z4.string().max(200).optional()
|
|
1772
|
+
}).strict();
|
|
1773
|
+
var PersonalMemoryNotFoundError = class extends Error {
|
|
1774
|
+
constructor() {
|
|
1775
|
+
super("Memory was not found for the authenticated viewer.");
|
|
1776
|
+
this.name = "PersonalMemoryNotFoundError";
|
|
1777
|
+
}
|
|
1778
|
+
};
|
|
1779
|
+
function personalScopes(runtimeContexts) {
|
|
1780
|
+
return [
|
|
1781
|
+
...new Map(
|
|
1782
|
+
runtimeContexts.map((context) => {
|
|
1783
|
+
const scope = deriveMemoryScope(context, "personal");
|
|
1784
|
+
return [`${scope.scope}:${scope.scopeKey}`, scope];
|
|
1785
|
+
})
|
|
1786
|
+
).values()
|
|
1787
|
+
];
|
|
1788
|
+
}
|
|
1789
|
+
function searchTerms(query) {
|
|
1790
|
+
return [
|
|
1791
|
+
...new Set(
|
|
1792
|
+
query.toLowerCase().split(/[^a-z0-9_'-]+/).map((term) => term.trim()).filter((term) => term.length >= 2)
|
|
1793
|
+
)
|
|
1794
|
+
];
|
|
1795
|
+
}
|
|
1796
|
+
function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
|
|
1797
|
+
const scopes = personalScopes(runtimeContexts);
|
|
1798
|
+
const getNowMs = () => options.now?.() ?? Date.now();
|
|
1799
|
+
return {
|
|
1800
|
+
async archive(id) {
|
|
1801
|
+
const memoryId = nonEmptyStringSchema3.parse(id);
|
|
1802
|
+
const nowMs = getNowMs();
|
|
1803
|
+
const predicate = activeVisiblePredicate({ nowMs, scopes });
|
|
1804
|
+
if (!predicate) {
|
|
1805
|
+
throw new PersonalMemoryNotFoundError();
|
|
1806
|
+
}
|
|
1807
|
+
const updated = await db.update(juniorMemoryMemories).set({
|
|
1808
|
+
archivedAtMs: nowMs,
|
|
1809
|
+
archiveReason: "user_removed"
|
|
1810
|
+
}).where(and2(predicate, eq2(juniorMemoryMemories.id, memoryId))).returning();
|
|
1811
|
+
if (!updated[0]) {
|
|
1812
|
+
throw new PersonalMemoryNotFoundError();
|
|
1813
|
+
}
|
|
1814
|
+
await db.delete(juniorMemoryEmbeddings).where(eq2(juniorMemoryEmbeddings.memoryId, memoryId));
|
|
1815
|
+
return parseMemoryRow(updated[0]);
|
|
1816
|
+
},
|
|
1817
|
+
async get(id) {
|
|
1818
|
+
const memoryId = nonEmptyStringSchema3.parse(id);
|
|
1819
|
+
const nowMs = getNowMs();
|
|
1820
|
+
const predicate = activeVisiblePredicate({ nowMs, scopes });
|
|
1821
|
+
if (!predicate) {
|
|
1822
|
+
throw new PersonalMemoryNotFoundError();
|
|
1823
|
+
}
|
|
1824
|
+
const rows = await db.select().from(juniorMemoryMemories).where(and2(predicate, eq2(juniorMemoryMemories.id, memoryId))).limit(1);
|
|
1825
|
+
if (!rows[0]) {
|
|
1826
|
+
throw new PersonalMemoryNotFoundError();
|
|
1827
|
+
}
|
|
1828
|
+
return parseMemoryRow(rows[0]);
|
|
1829
|
+
},
|
|
1830
|
+
async list(input) {
|
|
1831
|
+
input = personalMemoryPageInputSchema.parse(input);
|
|
1832
|
+
const nowMs = getNowMs();
|
|
1833
|
+
await archiveExpiredMemoryBatch({ db, nowMs, scopes });
|
|
1834
|
+
const active = activeVisiblePredicate({ nowMs, scopes });
|
|
1835
|
+
if (!active) {
|
|
1836
|
+
return { memories: [] };
|
|
1837
|
+
}
|
|
1838
|
+
const cursor = input.cursor ? or2(
|
|
1839
|
+
lt(juniorMemoryMemories.createdAtMs, input.cursor.createdAtMs),
|
|
1840
|
+
and2(
|
|
1841
|
+
eq2(juniorMemoryMemories.createdAtMs, input.cursor.createdAtMs),
|
|
1842
|
+
gt2(juniorMemoryMemories.id, input.cursor.id)
|
|
1843
|
+
)
|
|
1844
|
+
) : void 0;
|
|
1845
|
+
const terms = input.query ? searchTerms(input.query) : [];
|
|
1846
|
+
const search = input.query === void 0 ? void 0 : terms.length === 0 ? sql3`false` : or2(
|
|
1847
|
+
...terms.map(
|
|
1848
|
+
(term) => ilike(juniorMemoryMemories.content, `%${term}%`)
|
|
1849
|
+
)
|
|
1850
|
+
);
|
|
1851
|
+
const rows = await db.select().from(juniorMemoryMemories).where(and2(active, cursor, search)).orderBy(
|
|
1852
|
+
desc2(juniorMemoryMemories.createdAtMs),
|
|
1853
|
+
asc2(juniorMemoryMemories.id)
|
|
1854
|
+
).limit(input.limit + 1);
|
|
1855
|
+
const hasNextPage = rows.length > input.limit;
|
|
1856
|
+
const memories = rows.slice(0, input.limit).map(parseMemoryRow);
|
|
1857
|
+
const last = memories.at(-1);
|
|
1858
|
+
return {
|
|
1859
|
+
memories,
|
|
1860
|
+
...hasNextPage && last ? {
|
|
1861
|
+
nextCursor: {
|
|
1862
|
+
createdAtMs: last.createdAtMs,
|
|
1863
|
+
id: last.id
|
|
1864
|
+
}
|
|
1865
|
+
} : {}
|
|
1866
|
+
};
|
|
1867
|
+
}
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
// src/personal.ts
|
|
1872
|
+
var cursorSchema = z5.object({
|
|
1873
|
+
createdAtMs: z5.number().finite(),
|
|
1874
|
+
id: z5.string().min(1),
|
|
1875
|
+
query: z5.string().max(200).optional(),
|
|
1876
|
+
version: z5.literal(1)
|
|
1877
|
+
}).strict();
|
|
1878
|
+
var InvalidMemoryCursorError = class extends Error {
|
|
1879
|
+
constructor() {
|
|
1880
|
+
super("Memory cursor is invalid.");
|
|
1881
|
+
this.name = "InvalidMemoryCursorError";
|
|
1882
|
+
}
|
|
1883
|
+
};
|
|
1884
|
+
function runtimeContext(actor) {
|
|
1885
|
+
if (actor.platform === "slack") {
|
|
1886
|
+
return {
|
|
1887
|
+
actor,
|
|
1888
|
+
source: {
|
|
1889
|
+
platform: "slack",
|
|
1890
|
+
type: "priv",
|
|
1891
|
+
teamId: actor.teamId,
|
|
1892
|
+
channelId: "DDASHBOARD"
|
|
1893
|
+
}
|
|
1894
|
+
};
|
|
1895
|
+
}
|
|
1896
|
+
return {
|
|
1897
|
+
actor,
|
|
1898
|
+
source: {
|
|
1899
|
+
platform: "local",
|
|
1900
|
+
type: "priv",
|
|
1901
|
+
conversationId: "local:dashboard:memories"
|
|
1902
|
+
}
|
|
1903
|
+
};
|
|
1904
|
+
}
|
|
1905
|
+
function decodeCursor(value, query) {
|
|
1906
|
+
if (!value) return void 0;
|
|
1907
|
+
try {
|
|
1908
|
+
const parsed = cursorSchema.parse(
|
|
1909
|
+
JSON.parse(Buffer.from(value, "base64url").toString("utf8"))
|
|
1910
|
+
);
|
|
1911
|
+
if (parsed.query !== query) {
|
|
1912
|
+
throw new InvalidMemoryCursorError();
|
|
1913
|
+
}
|
|
1914
|
+
return { createdAtMs: parsed.createdAtMs, id: parsed.id };
|
|
1915
|
+
} catch {
|
|
1916
|
+
throw new InvalidMemoryCursorError();
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
function encodeCursor(cursor, query) {
|
|
1920
|
+
return Buffer.from(
|
|
1921
|
+
JSON.stringify({ ...cursor, ...query ? { query } : {}, version: 1 }),
|
|
1922
|
+
"utf8"
|
|
1923
|
+
).toString("base64url");
|
|
1924
|
+
}
|
|
1925
|
+
function createViewerMemories(db, actors) {
|
|
1926
|
+
const collection = createPersonalMemoryCollection(
|
|
1927
|
+
db,
|
|
1928
|
+
actors.map(runtimeContext)
|
|
1929
|
+
);
|
|
1930
|
+
return {
|
|
1931
|
+
async archive(id) {
|
|
1932
|
+
return await collection.archive(id);
|
|
1933
|
+
},
|
|
1934
|
+
async get(id) {
|
|
1935
|
+
return await collection.get(id);
|
|
1936
|
+
},
|
|
1937
|
+
async list(input) {
|
|
1938
|
+
const query = input.query?.trim() || void 0;
|
|
1939
|
+
const page = await collection.list({
|
|
1940
|
+
cursor: decodeCursor(input.cursor, query),
|
|
1941
|
+
limit: input.limit,
|
|
1942
|
+
...query ? { query } : {}
|
|
1943
|
+
});
|
|
1944
|
+
return {
|
|
1945
|
+
memories: page.memories,
|
|
1946
|
+
...page.nextCursor ? { nextCursor: encodeCursor(page.nextCursor, query) } : {}
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
};
|
|
1950
|
+
}
|
|
1951
|
+
|
|
1952
|
+
// src/api.ts
|
|
1953
|
+
var memoryApiSchema = z6.object({
|
|
1954
|
+
content: z6.string().min(1),
|
|
1955
|
+
createdAt: z6.iso.datetime(),
|
|
1956
|
+
expiresAt: z6.iso.datetime().optional(),
|
|
1957
|
+
id: z6.string().min(1),
|
|
1958
|
+
kind: z6.enum(["preference", "procedure", "knowledge"]),
|
|
1959
|
+
observedAt: z6.iso.datetime()
|
|
1960
|
+
}).strict();
|
|
1961
|
+
var memoryListResponseSchema = z6.object({
|
|
1962
|
+
memories: z6.array(memoryApiSchema),
|
|
1963
|
+
nextCursor: z6.string().min(1).optional()
|
|
1964
|
+
}).strict();
|
|
1965
|
+
var memoryListQuerySchema = z6.object({
|
|
1966
|
+
cursor: z6.string().min(1).max(1e3).optional(),
|
|
1967
|
+
limit: z6.coerce.number().int().min(1).max(50).default(25),
|
|
1968
|
+
q: z6.string().trim().max(200).optional()
|
|
1969
|
+
}).strict();
|
|
1970
|
+
function json(body, status = 200) {
|
|
1971
|
+
return Response.json(body, {
|
|
1972
|
+
headers: { "cache-control": "no-store" },
|
|
1973
|
+
status
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1976
|
+
function apiMemory(memory) {
|
|
1977
|
+
return {
|
|
1978
|
+
content: memory.content,
|
|
1979
|
+
createdAt: new Date(memory.createdAtMs).toISOString(),
|
|
1980
|
+
...memory.expiresAtMs !== void 0 ? { expiresAt: new Date(memory.expiresAtMs).toISOString() } : {},
|
|
1981
|
+
id: memory.id,
|
|
1982
|
+
kind: memory.kind,
|
|
1983
|
+
observedAt: new Date(memory.observedAtMs).toISOString()
|
|
1984
|
+
};
|
|
1985
|
+
}
|
|
1986
|
+
function viewerEmail(context) {
|
|
1987
|
+
const parsed = pluginApiRouteRequestContextSchema.safeParse(context);
|
|
1988
|
+
if (!parsed.success || parsed.data.auth.user.emailVerified !== true) {
|
|
1989
|
+
return void 0;
|
|
1990
|
+
}
|
|
1991
|
+
return parsed.data.auth.user.email?.trim().toLowerCase() || void 0;
|
|
1992
|
+
}
|
|
1993
|
+
function createMemoryApi(options) {
|
|
1994
|
+
return {
|
|
1995
|
+
async fetch(request, context) {
|
|
1996
|
+
const email = viewerEmail(context);
|
|
1997
|
+
if (!email) {
|
|
1998
|
+
return json({ error: "Authentication required." }, 401);
|
|
1999
|
+
}
|
|
2000
|
+
const url = new URL(request.url);
|
|
2001
|
+
const memoryPath = /^\/memories\/([^/]+)$/.exec(url.pathname);
|
|
2002
|
+
const isCollection = url.pathname === "/memories";
|
|
2003
|
+
if (!isCollection && !memoryPath) {
|
|
2004
|
+
return json({ error: "Not found." }, 404);
|
|
2005
|
+
}
|
|
2006
|
+
const actors = await options.actors(email);
|
|
2007
|
+
const memories = createViewerMemories(options.db, actors);
|
|
2008
|
+
try {
|
|
2009
|
+
if (isCollection && (request.method === "GET" || request.method === "HEAD")) {
|
|
2010
|
+
const query = memoryListQuerySchema.parse({
|
|
2011
|
+
cursor: url.searchParams.get("cursor") ?? void 0,
|
|
2012
|
+
limit: url.searchParams.get("limit") ?? void 0,
|
|
2013
|
+
q: url.searchParams.get("q") ?? void 0
|
|
2014
|
+
});
|
|
2015
|
+
const page = await memories.list({
|
|
2016
|
+
cursor: query.cursor,
|
|
2017
|
+
limit: query.limit,
|
|
2018
|
+
...query.q ? { query: query.q } : {}
|
|
2019
|
+
});
|
|
2020
|
+
const body = memoryListResponseSchema.parse({
|
|
2021
|
+
memories: page.memories.map(apiMemory),
|
|
2022
|
+
...page.nextCursor ? { nextCursor: page.nextCursor } : {}
|
|
2023
|
+
});
|
|
2024
|
+
return request.method === "HEAD" ? new Response(null, {
|
|
2025
|
+
headers: { "cache-control": "no-store" },
|
|
2026
|
+
status: 200
|
|
2027
|
+
}) : json(body);
|
|
2028
|
+
}
|
|
2029
|
+
if (memoryPath && (request.method === "GET" || request.method === "HEAD")) {
|
|
2030
|
+
const memory = memoryApiSchema.parse(
|
|
2031
|
+
apiMemory(await memories.get(decodeURIComponent(memoryPath[1])))
|
|
2032
|
+
);
|
|
2033
|
+
return request.method === "HEAD" ? new Response(null, {
|
|
2034
|
+
headers: { "cache-control": "no-store" },
|
|
2035
|
+
status: 200
|
|
2036
|
+
}) : json(memory);
|
|
2037
|
+
}
|
|
2038
|
+
if (memoryPath && request.method === "DELETE") {
|
|
2039
|
+
await memories.archive(decodeURIComponent(memoryPath[1]));
|
|
2040
|
+
return new Response(null, {
|
|
2041
|
+
headers: { "cache-control": "no-store" },
|
|
2042
|
+
status: 204
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
} catch (error) {
|
|
2046
|
+
if (error instanceof z6.ZodError || error instanceof InvalidMemoryCursorError) {
|
|
2047
|
+
return json({ error: "Invalid memory request." }, 400);
|
|
2048
|
+
}
|
|
2049
|
+
if (error instanceof PersonalMemoryNotFoundError) {
|
|
2050
|
+
return json({ error: error.message }, 404);
|
|
2051
|
+
}
|
|
2052
|
+
throw error;
|
|
2053
|
+
}
|
|
2054
|
+
return json({ error: "Method not allowed." }, 405);
|
|
2055
|
+
}
|
|
2056
|
+
};
|
|
2057
|
+
}
|
|
2058
|
+
|
|
1701
2059
|
// src/cli/search.ts
|
|
1702
2060
|
import { InvalidArgumentError, Option } from "commander";
|
|
1703
|
-
import { and as
|
|
2061
|
+
import { and as and3, desc as desc3, eq as eq3, gt as gt3, ilike as ilike2, isNull as isNull2, or as or3 } from "drizzle-orm";
|
|
1704
2062
|
|
|
1705
2063
|
// src/cli/format.ts
|
|
1706
2064
|
function formatDate(ms) {
|
|
@@ -1742,13 +2100,13 @@ async function runSearch(ctx, queryParts, options) {
|
|
|
1742
2100
|
)
|
|
1743
2101
|
];
|
|
1744
2102
|
const db = ctx.db;
|
|
1745
|
-
const activeExpirationPredicate =
|
|
2103
|
+
const activeExpirationPredicate = or3(
|
|
1746
2104
|
isNull2(juniorMemoryMemories.expiresAtMs),
|
|
1747
|
-
|
|
2105
|
+
gt3(juniorMemoryMemories.expiresAtMs, nowMs)
|
|
1748
2106
|
);
|
|
1749
2107
|
const predicates = [
|
|
1750
|
-
|
|
1751
|
-
|
|
2108
|
+
eq3(juniorMemoryMemories.scope, options.scope),
|
|
2109
|
+
eq3(juniorMemoryMemories.scopeKey, options.scopeKey),
|
|
1752
2110
|
isNull2(juniorMemoryMemories.archivedAtMs),
|
|
1753
2111
|
isNull2(juniorMemoryMemories.supersededAtMs),
|
|
1754
2112
|
isNull2(juniorMemoryMemories.supersededById)
|
|
@@ -1757,14 +2115,14 @@ async function runSearch(ctx, queryParts, options) {
|
|
|
1757
2115
|
predicates.push(activeExpirationPredicate);
|
|
1758
2116
|
}
|
|
1759
2117
|
if (terms.length > 0) {
|
|
1760
|
-
const termPredicate =
|
|
2118
|
+
const termPredicate = or3(
|
|
1761
2119
|
...terms.map((term) => ilike2(juniorMemoryMemories.content, `%${term}%`))
|
|
1762
2120
|
);
|
|
1763
2121
|
if (termPredicate) {
|
|
1764
2122
|
predicates.push(termPredicate);
|
|
1765
2123
|
}
|
|
1766
2124
|
}
|
|
1767
|
-
const rows = await db.select().from(juniorMemoryMemories).where(
|
|
2125
|
+
const rows = await db.select().from(juniorMemoryMemories).where(and3(...predicates)).orderBy(desc3(juniorMemoryMemories.createdAtMs)).limit(options.limit);
|
|
1768
2126
|
if (rows.length === 0) {
|
|
1769
2127
|
await ctx.io.writeOutput("No memories matched.\n");
|
|
1770
2128
|
return 0;
|
|
@@ -1794,10 +2152,10 @@ function configureMemorySearchCommand(parent, junior) {
|
|
|
1794
2152
|
}
|
|
1795
2153
|
|
|
1796
2154
|
// src/cli/show.ts
|
|
1797
|
-
import { eq as
|
|
2155
|
+
import { eq as eq4 } from "drizzle-orm";
|
|
1798
2156
|
async function runShow(ctx, id) {
|
|
1799
2157
|
const db = ctx.db;
|
|
1800
|
-
const rows = await db.select().from(juniorMemoryMemories).where(
|
|
2158
|
+
const rows = await db.select().from(juniorMemoryMemories).where(eq4(juniorMemoryMemories.id, id)).limit(1);
|
|
1801
2159
|
if (!rows[0]) {
|
|
1802
2160
|
await ctx.io.writeError(`Memory not found: ${id}
|
|
1803
2161
|
`);
|
|
@@ -1836,7 +2194,7 @@ import {
|
|
|
1836
2194
|
PluginToolInputError,
|
|
1837
2195
|
pluginToolResultSchema
|
|
1838
2196
|
} from "@sentry/junior-plugin-api";
|
|
1839
|
-
import { z as
|
|
2197
|
+
import { z as z7 } from "zod";
|
|
1840
2198
|
var MAX_TOOL_CONTENT_CHARS = 4e3;
|
|
1841
2199
|
var DEFAULT_RESULT_LIMIT = 20;
|
|
1842
2200
|
var DEFAULT_SEARCH_LIMIT2 = 10;
|
|
@@ -1963,23 +2321,23 @@ function requireMemoryContent(value) {
|
|
|
1963
2321
|
}
|
|
1964
2322
|
return value;
|
|
1965
2323
|
}
|
|
1966
|
-
var createMemoryInputSchema2 =
|
|
1967
|
-
content:
|
|
2324
|
+
var createMemoryInputSchema2 = z7.object({
|
|
2325
|
+
content: z7.string().min(1).max(MAX_TOOL_CONTENT_CHARS).describe(
|
|
1968
2326
|
"Self-contained public/shareable memory candidate. Include the subject in natural language when it matters; do not rely on surrounding chat context."
|
|
1969
2327
|
),
|
|
1970
|
-
expires_at:
|
|
2328
|
+
expires_at: z7.string().min(1).describe(
|
|
1971
2329
|
'Expiration selector. Omit or use "never" when the memory should not expire, or use an exact ISO timestamp such as "2027-06-21T00:00:00Z".'
|
|
1972
2330
|
).optional()
|
|
1973
2331
|
}).strict();
|
|
1974
|
-
var removeMemoryInputSchema =
|
|
1975
|
-
id:
|
|
2332
|
+
var removeMemoryInputSchema = z7.object({
|
|
2333
|
+
id: z7.string().min(1).describe("Memory id or unambiguous short id prefix to remove.")
|
|
1976
2334
|
}).strict();
|
|
1977
|
-
var listMemoriesInputSchema2 =
|
|
1978
|
-
limit:
|
|
2335
|
+
var listMemoriesInputSchema2 = z7.object({
|
|
2336
|
+
limit: z7.number().min(1).max(50).describe("Maximum number of visible memories to return.").optional()
|
|
1979
2337
|
}).strict();
|
|
1980
|
-
var searchMemoriesInputSchema2 =
|
|
1981
|
-
query:
|
|
1982
|
-
limit:
|
|
2338
|
+
var searchMemoriesInputSchema2 = z7.object({
|
|
2339
|
+
query: z7.string().min(1).describe("Search query for visible memory content."),
|
|
2340
|
+
limit: z7.number().min(1).max(50).describe("Maximum number of matching memories to return.").optional()
|
|
1983
2341
|
}).strict();
|
|
1984
2342
|
var memoryToolProjectionSchema = Type.Object(
|
|
1985
2343
|
{
|
|
@@ -1991,44 +2349,44 @@ var memoryToolProjectionSchema = Type.Object(
|
|
|
1991
2349
|
},
|
|
1992
2350
|
{ additionalProperties: false }
|
|
1993
2351
|
);
|
|
1994
|
-
var memoryProjectionOutputSchema =
|
|
1995
|
-
id:
|
|
1996
|
-
content:
|
|
1997
|
-
createdAtMs:
|
|
1998
|
-
observedAtMs:
|
|
1999
|
-
expiresAtMs:
|
|
2352
|
+
var memoryProjectionOutputSchema = z7.object({
|
|
2353
|
+
id: z7.string(),
|
|
2354
|
+
content: z7.string(),
|
|
2355
|
+
createdAtMs: z7.number(),
|
|
2356
|
+
observedAtMs: z7.number(),
|
|
2357
|
+
expiresAtMs: z7.number().optional()
|
|
2000
2358
|
});
|
|
2001
|
-
var memoryCreateDataOutputSchema =
|
|
2002
|
-
created:
|
|
2359
|
+
var memoryCreateDataOutputSchema = z7.object({
|
|
2360
|
+
created: z7.boolean(),
|
|
2003
2361
|
memory: memoryProjectionOutputSchema
|
|
2004
2362
|
});
|
|
2005
|
-
var memorySingleDataOutputSchema =
|
|
2363
|
+
var memorySingleDataOutputSchema = z7.object({
|
|
2006
2364
|
memory: memoryProjectionOutputSchema
|
|
2007
2365
|
});
|
|
2008
|
-
var memoryManyDataOutputSchema =
|
|
2009
|
-
memories:
|
|
2366
|
+
var memoryManyDataOutputSchema = z7.object({
|
|
2367
|
+
memories: z7.array(memoryProjectionOutputSchema)
|
|
2010
2368
|
});
|
|
2011
2369
|
var memoryCreateOutputSchema = pluginToolResultSchema.extend({
|
|
2012
|
-
ok:
|
|
2013
|
-
status:
|
|
2014
|
-
target:
|
|
2370
|
+
ok: z7.literal(true),
|
|
2371
|
+
status: z7.literal("success"),
|
|
2372
|
+
target: z7.string(),
|
|
2015
2373
|
data: memoryCreateDataOutputSchema,
|
|
2016
|
-
created:
|
|
2374
|
+
created: z7.boolean(),
|
|
2017
2375
|
memory: memoryProjectionOutputSchema
|
|
2018
2376
|
});
|
|
2019
2377
|
var memorySingleOutputSchema = pluginToolResultSchema.extend({
|
|
2020
|
-
ok:
|
|
2021
|
-
status:
|
|
2022
|
-
target:
|
|
2378
|
+
ok: z7.literal(true),
|
|
2379
|
+
status: z7.literal("success"),
|
|
2380
|
+
target: z7.string(),
|
|
2023
2381
|
data: memorySingleDataOutputSchema,
|
|
2024
2382
|
memory: memoryProjectionOutputSchema
|
|
2025
2383
|
});
|
|
2026
2384
|
var memoryManyOutputSchema = pluginToolResultSchema.extend({
|
|
2027
|
-
ok:
|
|
2028
|
-
status:
|
|
2029
|
-
target:
|
|
2385
|
+
ok: z7.literal(true),
|
|
2386
|
+
status: z7.literal("success"),
|
|
2387
|
+
target: z7.string(),
|
|
2030
2388
|
data: memoryManyDataOutputSchema,
|
|
2031
|
-
memories:
|
|
2389
|
+
memories: z7.array(memoryProjectionOutputSchema)
|
|
2032
2390
|
});
|
|
2033
2391
|
function parseMemoryToolInput(schema, input) {
|
|
2034
2392
|
const result = schema.safeParse(input);
|
|
@@ -2219,7 +2577,7 @@ import {
|
|
|
2219
2577
|
getSourceKey as getSourceKey2,
|
|
2220
2578
|
isPrivateSource as isPrivateSource2
|
|
2221
2579
|
} from "@sentry/junior-plugin-api";
|
|
2222
|
-
import { z as
|
|
2580
|
+
import { z as z8 } from "zod";
|
|
2223
2581
|
var MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
2224
2582
|
"createMemory",
|
|
2225
2583
|
"listMemories",
|
|
@@ -2227,12 +2585,12 @@ var MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
2227
2585
|
"searchMemories"
|
|
2228
2586
|
]);
|
|
2229
2587
|
var MEMORY_TASK_STATE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2230
|
-
var extractedMemoryCacheSchema =
|
|
2231
|
-
|
|
2232
|
-
content:
|
|
2233
|
-
expiresAtMs:
|
|
2234
|
-
kind:
|
|
2235
|
-
evidenceMessageIndices:
|
|
2588
|
+
var extractedMemoryCacheSchema = z8.array(
|
|
2589
|
+
z8.object({
|
|
2590
|
+
content: z8.string().min(1),
|
|
2591
|
+
expiresAtMs: z8.number().finite().nullable(),
|
|
2592
|
+
kind: z8.enum(MEMORY_KINDS),
|
|
2593
|
+
evidenceMessageIndices: z8.array(z8.number().int().nonnegative()).min(1).max(10)
|
|
2236
2594
|
}).strict().transform(parseExtractedMemory)
|
|
2237
2595
|
);
|
|
2238
2596
|
function isRunActorInstruction(entry) {
|
|
@@ -2371,8 +2729,9 @@ async function processMemorySession(context) {
|
|
|
2371
2729
|
import {
|
|
2372
2730
|
definePromptContext
|
|
2373
2731
|
} from "@sentry/junior-plugin-api";
|
|
2374
|
-
import { z as
|
|
2732
|
+
import { z as z9 } from "zod";
|
|
2375
2733
|
var DEFAULT_RECALL_LIMIT = 5;
|
|
2734
|
+
var RECALL_CANDIDATE_LIMIT = 20;
|
|
2376
2735
|
var MAX_PROMPT_CHARS = 4e3;
|
|
2377
2736
|
var MAX_MEMORY_LINE_CHARS = 600;
|
|
2378
2737
|
function trimContent(content, maxLength) {
|
|
@@ -2385,15 +2744,15 @@ function trimContent(content, maxLength) {
|
|
|
2385
2744
|
function formatObservedDate(observedAtMs) {
|
|
2386
2745
|
return new Date(observedAtMs).toISOString().slice(0, 10);
|
|
2387
2746
|
}
|
|
2388
|
-
var recalledMemorySchema =
|
|
2389
|
-
id:
|
|
2390
|
-
content:
|
|
2391
|
-
observedAtMs:
|
|
2392
|
-
scope:
|
|
2393
|
-
kind:
|
|
2747
|
+
var recalledMemorySchema = z9.object({
|
|
2748
|
+
id: z9.string().min(1),
|
|
2749
|
+
content: z9.string().min(1).max(MAX_MEMORY_LINE_CHARS),
|
|
2750
|
+
observedAtMs: z9.number().finite(),
|
|
2751
|
+
scope: z9.enum(["personal", "conversation"]),
|
|
2752
|
+
kind: z9.enum(["preference", "procedure", "knowledge"])
|
|
2394
2753
|
}).strict();
|
|
2395
|
-
var memoryRecallContextSchema =
|
|
2396
|
-
memories:
|
|
2754
|
+
var memoryRecallContextSchema = z9.object({
|
|
2755
|
+
memories: z9.array(recalledMemorySchema).min(1).max(DEFAULT_RECALL_LIMIT)
|
|
2397
2756
|
}).strict();
|
|
2398
2757
|
function selectPromptMemories(memories) {
|
|
2399
2758
|
const header = "Relevant memories for this request:";
|
|
@@ -2442,14 +2801,31 @@ async function createMemoryPromptContributions(context) {
|
|
|
2442
2801
|
...context.actor ? { actor: context.actor } : {},
|
|
2443
2802
|
source: context.source
|
|
2444
2803
|
});
|
|
2445
|
-
const
|
|
2804
|
+
const candidates = await createMemoryStore(context.db, runtimeContext2, {
|
|
2446
2805
|
...context.embedder ? { embedder: context.embedder } : {},
|
|
2447
2806
|
...context.maxVectorDistance !== void 0 ? { maxVectorDistance: context.maxVectorDistance } : {}
|
|
2448
|
-
}).
|
|
2807
|
+
}).recallMemories({
|
|
2449
2808
|
query: context.text,
|
|
2450
|
-
limit:
|
|
2809
|
+
limit: RECALL_CANDIDATE_LIMIT
|
|
2451
2810
|
});
|
|
2452
|
-
|
|
2811
|
+
if (candidates.length === 0) {
|
|
2812
|
+
return void 0;
|
|
2813
|
+
}
|
|
2814
|
+
let relevantIds;
|
|
2815
|
+
try {
|
|
2816
|
+
relevantIds = await context.agent.selectRelevantMemories({
|
|
2817
|
+
candidates: candidates.map(({ content, id }) => ({ content, id })),
|
|
2818
|
+
userRequest: context.text
|
|
2819
|
+
});
|
|
2820
|
+
} catch {
|
|
2821
|
+
context.log.warn("memory_recall_selection_failed");
|
|
2822
|
+
return void 0;
|
|
2823
|
+
}
|
|
2824
|
+
const candidatesById = new Map(
|
|
2825
|
+
candidates.map((memory) => [memory.id, memory])
|
|
2826
|
+
);
|
|
2827
|
+
const relevant = relevantIds.map((id) => candidatesById.get(id)).filter((memory) => memory !== void 0).slice(0, DEFAULT_RECALL_LIMIT);
|
|
2828
|
+
const selected = selectPromptMemories(relevant);
|
|
2453
2829
|
if (selected.length === 0) {
|
|
2454
2830
|
return void 0;
|
|
2455
2831
|
}
|
|
@@ -2460,28 +2836,6 @@ async function createMemoryPromptContributions(context) {
|
|
|
2460
2836
|
}
|
|
2461
2837
|
|
|
2462
2838
|
// src/user-pages.ts
|
|
2463
|
-
var MEMORY_PAGE_LIMIT = 100;
|
|
2464
|
-
function runtimeContext(actor) {
|
|
2465
|
-
if (actor.platform === "slack") {
|
|
2466
|
-
return {
|
|
2467
|
-
actor,
|
|
2468
|
-
source: {
|
|
2469
|
-
platform: "slack",
|
|
2470
|
-
type: "priv",
|
|
2471
|
-
teamId: actor.teamId,
|
|
2472
|
-
channelId: "DDASHBOARD"
|
|
2473
|
-
}
|
|
2474
|
-
};
|
|
2475
|
-
}
|
|
2476
|
-
return {
|
|
2477
|
-
actor,
|
|
2478
|
-
source: {
|
|
2479
|
-
platform: "local",
|
|
2480
|
-
type: "priv",
|
|
2481
|
-
conversationId: "local:dashboard:memories"
|
|
2482
|
-
}
|
|
2483
|
-
};
|
|
2484
|
-
}
|
|
2485
2839
|
function memoryKindLabel(kind) {
|
|
2486
2840
|
return kind.charAt(0).toUpperCase() + kind.slice(1);
|
|
2487
2841
|
}
|
|
@@ -2491,35 +2845,35 @@ function rememberedDate(createdAtMs) {
|
|
|
2491
2845
|
timeZone: "UTC"
|
|
2492
2846
|
}).format(new Date(createdAtMs));
|
|
2493
2847
|
}
|
|
2494
|
-
async function readPersonalMemories(db, actors) {
|
|
2495
|
-
const memories = await Promise.all(
|
|
2496
|
-
actors.flatMap((actor) => {
|
|
2497
|
-
const context = runtimeContext(actor);
|
|
2498
|
-
return context ? [
|
|
2499
|
-
createMemoryStore(db, context).listPersonalMemories({
|
|
2500
|
-
limit: MEMORY_PAGE_LIMIT
|
|
2501
|
-
})
|
|
2502
|
-
] : [];
|
|
2503
|
-
})
|
|
2504
|
-
);
|
|
2505
|
-
return [
|
|
2506
|
-
...new Map(memories.flat().map((memory) => [memory.id, memory])).values()
|
|
2507
|
-
].sort((left, right) => right.createdAtMs - left.createdAtMs).slice(0, MEMORY_PAGE_LIMIT);
|
|
2508
|
-
}
|
|
2509
2848
|
function createMemoryUserPage() {
|
|
2510
2849
|
return {
|
|
2511
2850
|
id: "memories",
|
|
2512
2851
|
label: "Memories",
|
|
2513
2852
|
description: "Personal facts and preferences Junior remembers about you.",
|
|
2514
|
-
async read(ctx) {
|
|
2515
|
-
const
|
|
2853
|
+
async read(ctx, input) {
|
|
2854
|
+
const page = await createViewerMemories(
|
|
2516
2855
|
ctx.db,
|
|
2517
2856
|
ctx.viewer.actors
|
|
2518
|
-
)
|
|
2857
|
+
).list({
|
|
2858
|
+
cursor: input.cursor,
|
|
2859
|
+
limit: input.limit,
|
|
2860
|
+
...input.query ? { query: input.query } : {}
|
|
2861
|
+
});
|
|
2519
2862
|
return {
|
|
2520
2863
|
type: "list",
|
|
2521
|
-
emptyText: "No personal memories yet.",
|
|
2522
|
-
|
|
2864
|
+
emptyText: input.query ? "No memories matched your search." : "No personal memories yet.",
|
|
2865
|
+
...page.nextCursor ? { nextCursor: page.nextCursor } : {},
|
|
2866
|
+
searchPlaceholder: "Search memories",
|
|
2867
|
+
records: page.memories.map((memory) => ({
|
|
2868
|
+
actions: [
|
|
2869
|
+
{
|
|
2870
|
+
confirmation: "Forget this memory?",
|
|
2871
|
+
href: `/api/plugins/memory/memories/${encodeURIComponent(memory.id)}`,
|
|
2872
|
+
label: "Forget",
|
|
2873
|
+
method: "DELETE",
|
|
2874
|
+
tone: "danger"
|
|
2875
|
+
}
|
|
2876
|
+
],
|
|
2523
2877
|
id: memory.id,
|
|
2524
2878
|
title: memory.content,
|
|
2525
2879
|
metadata: [
|
|
@@ -2574,7 +2928,7 @@ function memoryCreateToolContext(ctx) {
|
|
|
2574
2928
|
supersessionDecider: ctx.supersessionDecider
|
|
2575
2929
|
};
|
|
2576
2930
|
}
|
|
2577
|
-
function
|
|
2931
|
+
function memoryPlugin(options = {}) {
|
|
2578
2932
|
const modelId = memoryModelId(options);
|
|
2579
2933
|
return defineJuniorPlugin({
|
|
2580
2934
|
manifest: {
|
|
@@ -2596,6 +2950,12 @@ function createMemoryPlugin(options = {}) {
|
|
|
2596
2950
|
},
|
|
2597
2951
|
userPages: [createMemoryUserPage()],
|
|
2598
2952
|
hooks: {
|
|
2953
|
+
apiRoutes(ctx) {
|
|
2954
|
+
return createMemoryApi({
|
|
2955
|
+
actors: ctx.viewer.actors,
|
|
2956
|
+
db: ctx.db
|
|
2957
|
+
});
|
|
2958
|
+
},
|
|
2599
2959
|
tools(ctx) {
|
|
2600
2960
|
const agent = createMemoryAgent(ctx.model);
|
|
2601
2961
|
const context = memoryToolContext({
|
|
@@ -2621,10 +2981,12 @@ function createMemoryPlugin(options = {}) {
|
|
|
2621
2981
|
},
|
|
2622
2982
|
async userPrompt(ctx) {
|
|
2623
2983
|
return await createMemoryPromptContributions({
|
|
2984
|
+
agent: createMemoryAgent(ctx.model),
|
|
2624
2985
|
...ctx.conversationId ? { conversationId: ctx.conversationId } : {},
|
|
2625
2986
|
...ctx.actor ? { actor: ctx.actor } : {},
|
|
2626
2987
|
db: ctx.db,
|
|
2627
2988
|
embedder: ctx.embedder,
|
|
2989
|
+
log: ctx.log,
|
|
2628
2990
|
maxVectorDistance: recallMaxVectorDistance(options),
|
|
2629
2991
|
source: ctx.source,
|
|
2630
2992
|
text: ctx.text
|
|
@@ -2633,11 +2995,11 @@ function createMemoryPlugin(options = {}) {
|
|
|
2633
2995
|
}
|
|
2634
2996
|
});
|
|
2635
2997
|
}
|
|
2636
|
-
var memoryPlugin = createMemoryPlugin();
|
|
2637
2998
|
export {
|
|
2638
2999
|
MEMORY_KINDS,
|
|
2639
|
-
createMemoryPlugin,
|
|
2640
3000
|
createMemoryStore,
|
|
3001
|
+
memoryApiSchema,
|
|
3002
|
+
memoryListResponseSchema,
|
|
2641
3003
|
memoryPlugin
|
|
2642
3004
|
};
|
|
2643
3005
|
//# sourceMappingURL=index.js.map
|