@sentry/junior-memory 0.124.2 → 0.126.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 +11 -1
- package/dist/agent.d.ts +20 -10
- package/dist/api.d.ts +12 -1
- package/dist/events.d.ts +17 -1
- package/dist/index.js +176 -49
- package/dist/index.js.map +1 -1
- package/dist/operational-report.d.ts +2 -1
- package/dist/recall.d.ts +2 -1
- package/dist/store.d.ts +5 -4
- package/dist/types.d.ts +8 -8
- package/package.json +2 -2
- package/src/agent.ts +26 -8
- package/src/api.ts +26 -2
- package/src/events.ts +53 -16
- package/src/operational-report.ts +37 -1
- package/src/personal.ts +10 -4
- package/src/plugin.ts +17 -2
- package/src/process-session.ts +39 -28
- package/src/recall.ts +52 -5
- package/src/store.ts +2 -0
- package/src/tools.ts +1 -0
package/README.md
CHANGED
|
@@ -15,7 +15,9 @@ exported types, tools, and tests are authoritative.
|
|
|
15
15
|
inspection.
|
|
16
16
|
- The dashboard exposes a searchable, paginated **Memories** user page for
|
|
17
17
|
personal memories owned by actors linked to the signed-in viewer. Its
|
|
18
|
-
**Forget** action archives the selected memory.
|
|
18
|
+
**Forget** action archives the selected memory. The overview charts global
|
|
19
|
+
passive-extraction cost from the durable `memory/memories_captured` events;
|
|
20
|
+
the System plugin report uses the same event-cost feed.
|
|
19
21
|
- Authenticated REST clients can list and search personal memories through
|
|
20
22
|
`GET /api/plugins/memory/memories`, read one through
|
|
21
23
|
`GET /api/plugins/memory/memories/:id`, and archive one through
|
|
@@ -55,6 +57,10 @@ exported types, tools, and tests are authoritative.
|
|
|
55
57
|
learning.
|
|
56
58
|
- Passive extraction creates only durable, reusable facts—not transient tasks,
|
|
57
59
|
conversation summaries, secrets, or speculative interpretation.
|
|
60
|
+
- Every completed passive extraction emits the namespaced
|
|
61
|
+
`memory/memories_captured` conversation event with its best-effort model cost.
|
|
62
|
+
Empty extraction outcomes remain durable for reporting but do not produce a
|
|
63
|
+
transcript row.
|
|
58
64
|
- Candidate review resolves duplicates and supersession before activation.
|
|
59
65
|
- Search combines independently ranked vector and PostgreSQL full-text matches
|
|
60
66
|
with reciprocal rank fusion; provider-specific raw scores are never added
|
|
@@ -62,6 +68,10 @@ exported types, tools, and tests are authoritative.
|
|
|
62
68
|
- Automatic recall retrieves a broad candidate window, then uses the
|
|
63
69
|
memory-owned relevance model to admit at most five directly useful memories.
|
|
64
70
|
An empty result contributes no filler prompt text.
|
|
71
|
+
- Every completed automatic recall attempt emits an invisible, namespaced
|
|
72
|
+
`memory/memories_recalled` conversation event with the admitted memory IDs
|
|
73
|
+
and best-effort embedding and relevance-model cost, including retrievals that
|
|
74
|
+
find no candidates and decisions that admit no memories.
|
|
65
75
|
- Automatic recall degrades to no prompt contribution when relevance selection
|
|
66
76
|
fails. Review, extraction, and write failures still fail their owning
|
|
67
77
|
hook/task without corrupting existing memory state.
|
package/dist/agent.d.ts
CHANGED
|
@@ -25,9 +25,9 @@ declare const createMemoryRequestSchema: z.ZodObject<{
|
|
|
25
25
|
platform: z.ZodLiteral<"slack">;
|
|
26
26
|
teamId: z.ZodString;
|
|
27
27
|
channelId: z.ZodString;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
visibility: z.ZodEnum<{
|
|
29
|
+
public: "public";
|
|
30
|
+
private: "private";
|
|
31
31
|
}>;
|
|
32
32
|
messageTs: z.ZodOptional<z.ZodString>;
|
|
33
33
|
threadTs: z.ZodOptional<z.ZodString>;
|
|
@@ -43,7 +43,7 @@ declare const createMemoryRequestSchema: z.ZodObject<{
|
|
|
43
43
|
}, z.core.$strict>>;
|
|
44
44
|
source: z.ZodObject<{
|
|
45
45
|
platform: z.ZodLiteral<"local">;
|
|
46
|
-
|
|
46
|
+
visibility: z.ZodLiteral<"private">;
|
|
47
47
|
conversationId: z.ZodString;
|
|
48
48
|
}, z.core.$strict>;
|
|
49
49
|
}, z.core.$strict>]>;
|
|
@@ -86,9 +86,9 @@ declare const extractSessionRequestSchema: z.ZodObject<{
|
|
|
86
86
|
platform: z.ZodLiteral<"slack">;
|
|
87
87
|
teamId: z.ZodString;
|
|
88
88
|
channelId: z.ZodString;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
visibility: z.ZodEnum<{
|
|
90
|
+
public: "public";
|
|
91
|
+
private: "private";
|
|
92
92
|
}>;
|
|
93
93
|
messageTs: z.ZodOptional<z.ZodString>;
|
|
94
94
|
threadTs: z.ZodOptional<z.ZodString>;
|
|
@@ -104,7 +104,7 @@ declare const extractSessionRequestSchema: z.ZodObject<{
|
|
|
104
104
|
}, z.core.$strict>>;
|
|
105
105
|
source: z.ZodObject<{
|
|
106
106
|
platform: z.ZodLiteral<"local">;
|
|
107
|
-
|
|
107
|
+
visibility: z.ZodLiteral<"private">;
|
|
108
108
|
conversationId: z.ZodString;
|
|
109
109
|
}, z.core.$strict>;
|
|
110
110
|
}, z.core.$strict>]>;
|
|
@@ -183,12 +183,22 @@ export type MemoryRecallInput = z.output<typeof memoryRecallInputSchema>;
|
|
|
183
183
|
export type CreateMemoryRequest = z.output<typeof createMemoryRequestSchema>;
|
|
184
184
|
export type ExtractSessionRequest = z.output<typeof extractSessionRequestSchema>;
|
|
185
185
|
export type ExtractedMemory = z.output<typeof extractedMemoryResultSchema>;
|
|
186
|
+
/** Memories proposed by passive extraction and the model cost of that pass. */
|
|
187
|
+
export type MemoryExtractionResult = {
|
|
188
|
+
costUsd?: number;
|
|
189
|
+
memories: ExtractedMemory[];
|
|
190
|
+
};
|
|
191
|
+
/** Memories admitted by automatic recall and the model cost of that decision. */
|
|
192
|
+
export type MemoryRecallResult = {
|
|
193
|
+
costUsd?: number;
|
|
194
|
+
relevantIds: string[];
|
|
195
|
+
};
|
|
186
196
|
export interface MemoryAgent {
|
|
187
197
|
/** Select candidate memories that directly help with the current request. */
|
|
188
|
-
selectRelevantMemories(request: MemoryRecallInput): Promise<
|
|
198
|
+
selectRelevantMemories(request: MemoryRecallInput): Promise<MemoryRecallResult> | MemoryRecallResult;
|
|
189
199
|
/** Classify a new preference against related active preferences. */
|
|
190
200
|
adjudicateSupersession(request: MemorySupersessionInput): Promise<MemorySupersessionDecision> | MemorySupersessionDecision;
|
|
191
|
-
extractSessionMemories(request: ExtractSessionRequest): Promise<
|
|
201
|
+
extractSessionMemories(request: ExtractSessionRequest): Promise<MemoryExtractionResult> | MemoryExtractionResult;
|
|
192
202
|
reviewCreateRequest(request: CreateMemoryRequest): Promise<MemoryReview> | MemoryReview;
|
|
193
203
|
}
|
|
194
204
|
/** Create the memory-owned agent that reviews, extracts, and recalls memories. */
|
package/dist/api.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* workspace scopes.
|
|
7
7
|
*/
|
|
8
8
|
import { z } from "zod";
|
|
9
|
-
import { type PluginRouteApp, type PluginUserPageActor } from "@sentry/junior-plugin-api";
|
|
9
|
+
import { type PluginConversationEventStats, type PluginRouteApp, type PluginUserPageActor } from "@sentry/junior-plugin-api";
|
|
10
10
|
import type { MemoryDb } from "./store";
|
|
11
11
|
export declare const memoryApiSchema: z.ZodObject<{
|
|
12
12
|
content: z.ZodString;
|
|
@@ -49,7 +49,17 @@ export declare const memoryDashboardResponseSchema: z.ZodObject<{
|
|
|
49
49
|
personal: z.ZodNumber;
|
|
50
50
|
public: z.ZodNumber;
|
|
51
51
|
}, z.core.$strict>>;
|
|
52
|
+
extractionDays: z.ZodArray<z.ZodObject<{
|
|
53
|
+
costUsd: z.ZodNumber;
|
|
54
|
+
date: z.ZodISODate;
|
|
55
|
+
events: z.ZodNumber;
|
|
56
|
+
}, z.core.$strict>>;
|
|
52
57
|
generatedAt: z.ZodISODateTime;
|
|
58
|
+
recallDays: z.ZodArray<z.ZodObject<{
|
|
59
|
+
costUsd: z.ZodNumber;
|
|
60
|
+
date: z.ZodISODate;
|
|
61
|
+
events: z.ZodNumber;
|
|
62
|
+
}, z.core.$strict>>;
|
|
53
63
|
stats: z.ZodObject<{
|
|
54
64
|
active: z.ZodNumber;
|
|
55
65
|
automatic: z.ZodNumber;
|
|
@@ -69,6 +79,7 @@ export type MemoryListResponse = z.output<typeof memoryListResponseSchema>;
|
|
|
69
79
|
interface MemoryApiOptions {
|
|
70
80
|
actors(email: string): Promise<PluginUserPageActor[]>;
|
|
71
81
|
db: MemoryDb;
|
|
82
|
+
eventStats: PluginConversationEventStats;
|
|
72
83
|
}
|
|
73
84
|
/** Create the authenticated viewer-memory REST app. */
|
|
74
85
|
export declare function createMemoryApi(options: MemoryApiOptions): PluginRouteApp;
|
package/dist/events.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import type { MemoryRecord } from "./store";
|
|
2
|
-
/**
|
|
2
|
+
/** Previous stored memory-capture event shape retained for transcript rendering. */
|
|
3
|
+
export declare const memoriesCapturedEventV1: import("@sentry/junior-plugin-api").DefinedConversationEvent<{
|
|
4
|
+
memories: {
|
|
5
|
+
content: string;
|
|
6
|
+
id: string;
|
|
7
|
+
kind: "preference" | "procedure" | "knowledge";
|
|
8
|
+
observedAtMs: number;
|
|
9
|
+
scope: "personal" | "conversation";
|
|
10
|
+
}[];
|
|
11
|
+
}>;
|
|
12
|
+
/** Durable outcome emitted after every completed passive memory extraction. */
|
|
3
13
|
export declare const memoriesCapturedEvent: import("@sentry/junior-plugin-api").DefinedConversationEvent<{
|
|
4
14
|
memories: {
|
|
5
15
|
content: string;
|
|
@@ -8,6 +18,12 @@ export declare const memoriesCapturedEvent: import("@sentry/junior-plugin-api").
|
|
|
8
18
|
observedAtMs: number;
|
|
9
19
|
scope: "personal" | "conversation";
|
|
10
20
|
}[];
|
|
21
|
+
costUsd?: number | undefined;
|
|
22
|
+
}>;
|
|
23
|
+
/** Durable outcome emitted after one completed automatic recall attempt. */
|
|
24
|
+
export declare const memoriesRecalledEvent: import("@sentry/junior-plugin-api").DefinedConversationEvent<{
|
|
25
|
+
memories: string[];
|
|
26
|
+
costUsd?: number | undefined;
|
|
11
27
|
}>;
|
|
12
28
|
/** Select the stable, safe memory fields retained in conversation history. */
|
|
13
29
|
export declare function capturedMemory(memory: MemoryRecord): {
|
package/dist/index.js
CHANGED
|
@@ -397,6 +397,7 @@ var memoryRecordSchema = z2.object({
|
|
|
397
397
|
}).strict();
|
|
398
398
|
var embeddingVectorSchema = z2.array(numberSchema).length(MEMORY_EMBEDDING_DIMENSIONS);
|
|
399
399
|
var embeddingResultSchema = z2.object({
|
|
400
|
+
costUsd: z2.number().finite().nonnegative().optional(),
|
|
400
401
|
dimensions: z2.literal(MEMORY_EMBEDDING_DIMENSIONS),
|
|
401
402
|
model: nonEmptyStringSchema2,
|
|
402
403
|
provider: nonEmptyStringSchema2,
|
|
@@ -1680,9 +1681,12 @@ function createMemoryAgent(model) {
|
|
|
1680
1681
|
});
|
|
1681
1682
|
const decision = memoryRecallDecisionSchema.parse(result.object);
|
|
1682
1683
|
const candidateIds = new Set(request.candidates.map(({ id }) => id));
|
|
1683
|
-
return
|
|
1684
|
-
|
|
1685
|
-
|
|
1684
|
+
return {
|
|
1685
|
+
relevantIds: [...new Set(decision.relevantIds)].filter(
|
|
1686
|
+
(id) => candidateIds.has(id)
|
|
1687
|
+
),
|
|
1688
|
+
...result.costUsd !== void 0 ? { costUsd: result.costUsd } : {}
|
|
1689
|
+
};
|
|
1686
1690
|
},
|
|
1687
1691
|
async adjudicateSupersession(rawRequest) {
|
|
1688
1692
|
const request = memorySupersessionInputSchema.parse(rawRequest);
|
|
@@ -1702,9 +1706,12 @@ function createMemoryAgent(model) {
|
|
|
1702
1706
|
prompt: sessionExtractionPrompt(request),
|
|
1703
1707
|
maxTokens: 1e3
|
|
1704
1708
|
});
|
|
1705
|
-
return
|
|
1706
|
-
|
|
1707
|
-
|
|
1709
|
+
return {
|
|
1710
|
+
memories: extractedMemoriesFromResponse(
|
|
1711
|
+
extractMemoriesResponseSchema.parse(result.object)
|
|
1712
|
+
),
|
|
1713
|
+
...result.costUsd !== void 0 ? { costUsd: result.costUsd } : {}
|
|
1714
|
+
};
|
|
1708
1715
|
},
|
|
1709
1716
|
async reviewCreateRequest(rawRequest) {
|
|
1710
1717
|
const request = parseCreateMemoryRequest(rawRequest);
|
|
@@ -2070,7 +2077,7 @@ function runtimeContext(actor) {
|
|
|
2070
2077
|
actor,
|
|
2071
2078
|
source: {
|
|
2072
2079
|
platform: "slack",
|
|
2073
|
-
|
|
2080
|
+
visibility: "private",
|
|
2074
2081
|
teamId: actor.teamId,
|
|
2075
2082
|
channelId: "DDASHBOARD"
|
|
2076
2083
|
}
|
|
@@ -2080,7 +2087,7 @@ function runtimeContext(actor) {
|
|
|
2080
2087
|
actor,
|
|
2081
2088
|
source: {
|
|
2082
2089
|
platform: "local",
|
|
2083
|
-
|
|
2090
|
+
visibility: "private",
|
|
2084
2091
|
conversationId: "local:dashboard:memories"
|
|
2085
2092
|
}
|
|
2086
2093
|
};
|
|
@@ -2170,9 +2177,16 @@ var memoryDashboardDaySchema = z6.object({
|
|
|
2170
2177
|
personal: z6.number().int().min(0),
|
|
2171
2178
|
public: z6.number().int().min(0)
|
|
2172
2179
|
}).strict();
|
|
2180
|
+
var memoryCostDaySchema = z6.object({
|
|
2181
|
+
costUsd: z6.number().finite().nonnegative(),
|
|
2182
|
+
date: z6.iso.date(),
|
|
2183
|
+
events: z6.number().int().min(0)
|
|
2184
|
+
}).strict();
|
|
2173
2185
|
var memoryDashboardResponseSchema = z6.object({
|
|
2174
2186
|
days: z6.array(memoryDashboardDaySchema).length(90),
|
|
2187
|
+
extractionDays: z6.array(memoryCostDaySchema).length(90),
|
|
2175
2188
|
generatedAt: z6.iso.datetime(),
|
|
2189
|
+
recallDays: z6.array(memoryCostDaySchema).length(90),
|
|
2176
2190
|
stats: z6.object({
|
|
2177
2191
|
active: z6.number().int().min(0),
|
|
2178
2192
|
automatic: z6.number().int().min(0),
|
|
@@ -2233,13 +2247,23 @@ function createMemoryApi(options) {
|
|
|
2233
2247
|
const memories = createViewerMemories(options.db, actors);
|
|
2234
2248
|
try {
|
|
2235
2249
|
if (isDashboard && (request.method === "GET" || request.method === "HEAD")) {
|
|
2236
|
-
const [stats, days] = await Promise.all([
|
|
2250
|
+
const [stats, days, extractionDays, recallDays] = await Promise.all([
|
|
2237
2251
|
memories.stats(),
|
|
2238
|
-
memories.timeline({ days: 90 })
|
|
2252
|
+
memories.timeline({ days: 90 }),
|
|
2253
|
+
options.eventStats.costsByDay({
|
|
2254
|
+
days: 90,
|
|
2255
|
+
eventName: "memories_captured"
|
|
2256
|
+
}),
|
|
2257
|
+
options.eventStats.costsByDay({
|
|
2258
|
+
days: 90,
|
|
2259
|
+
eventName: "memories_recalled"
|
|
2260
|
+
})
|
|
2239
2261
|
]);
|
|
2240
2262
|
const body = memoryDashboardResponseSchema.parse({
|
|
2241
2263
|
days,
|
|
2264
|
+
extractionDays,
|
|
2242
2265
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2266
|
+
recallDays,
|
|
2243
2267
|
stats
|
|
2244
2268
|
});
|
|
2245
2269
|
return request.method === "HEAD" ? new Response(null, {
|
|
@@ -2679,6 +2703,7 @@ function memoryToolResult(target, data) {
|
|
|
2679
2703
|
}
|
|
2680
2704
|
function createMemoryCreateTool(context) {
|
|
2681
2705
|
return definePluginTool({
|
|
2706
|
+
approvalMode: "approve",
|
|
2682
2707
|
annotations: {
|
|
2683
2708
|
destructiveHint: false,
|
|
2684
2709
|
idempotentHint: true,
|
|
@@ -2858,23 +2883,47 @@ function eventPreview(content) {
|
|
|
2858
2883
|
if (trimmed.length <= MAX_EVENT_PREVIEW_CHARS) return trimmed;
|
|
2859
2884
|
return `${trimmed.slice(0, MAX_EVENT_PREVIEW_CHARS - 3).trimEnd()}...`;
|
|
2860
2885
|
}
|
|
2861
|
-
var
|
|
2886
|
+
var capturedMemoriesSchema = z8.object({
|
|
2887
|
+
memories: z8.array(capturedMemorySchema).max(100),
|
|
2888
|
+
costUsd: z8.number().finite().nonnegative().optional()
|
|
2889
|
+
}).strict();
|
|
2890
|
+
var recalledMemoriesSchema = z8.object({
|
|
2891
|
+
memories: z8.array(z8.string().min(1)).max(5),
|
|
2892
|
+
costUsd: z8.number().finite().nonnegative().optional()
|
|
2893
|
+
}).strict();
|
|
2894
|
+
function renderCapturedMemories(event) {
|
|
2895
|
+
const count = event.memories.length;
|
|
2896
|
+
if (count === 0) return void 0;
|
|
2897
|
+
return {
|
|
2898
|
+
icon: "brain",
|
|
2899
|
+
title: count === 1 ? "Memory captured" : "Memories captured",
|
|
2900
|
+
preview: count === 1 ? eventPreview(event.memories[0].content) : `${count} memories`,
|
|
2901
|
+
details: event.memories.map((memory) => ({
|
|
2902
|
+
title: memory.content,
|
|
2903
|
+
metadata: [memory.kind, memory.scope]
|
|
2904
|
+
}))
|
|
2905
|
+
};
|
|
2906
|
+
}
|
|
2907
|
+
var memoriesCapturedEventV1 = defineConversationEvent({
|
|
2862
2908
|
name: "memories_captured",
|
|
2863
2909
|
version: 1,
|
|
2864
2910
|
schema: z8.object({
|
|
2865
2911
|
memories: z8.array(capturedMemorySchema).min(1).max(100)
|
|
2866
2912
|
}).strict(),
|
|
2867
|
-
renderEvent
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2913
|
+
renderEvent: renderCapturedMemories
|
|
2914
|
+
});
|
|
2915
|
+
var memoriesCapturedEvent = defineConversationEvent({
|
|
2916
|
+
name: "memories_captured",
|
|
2917
|
+
version: 2,
|
|
2918
|
+
schema: capturedMemoriesSchema,
|
|
2919
|
+
renderEvent: renderCapturedMemories
|
|
2920
|
+
});
|
|
2921
|
+
var memoriesRecalledEvent = defineConversationEvent({
|
|
2922
|
+
name: "memories_recalled",
|
|
2923
|
+
version: 1,
|
|
2924
|
+
schema: recalledMemoriesSchema,
|
|
2925
|
+
renderEvent() {
|
|
2926
|
+
return void 0;
|
|
2878
2927
|
}
|
|
2879
2928
|
});
|
|
2880
2929
|
function capturedMemory(memory) {
|
|
@@ -2895,14 +2944,19 @@ var MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
2895
2944
|
"searchMemories"
|
|
2896
2945
|
]);
|
|
2897
2946
|
var MEMORY_TASK_STATE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2898
|
-
var
|
|
2947
|
+
var extractedMemorySchema2 = z9.object({
|
|
2948
|
+
content: z9.string().min(1),
|
|
2949
|
+
expiresAtMs: z9.number().finite().nullable(),
|
|
2950
|
+
kind: z9.enum(MEMORY_KINDS),
|
|
2951
|
+
evidenceMessageIndices: z9.array(z9.number().int().nonnegative()).min(1).max(10)
|
|
2952
|
+
}).strict().transform(parseExtractedMemory);
|
|
2953
|
+
var extractedMemoryCacheSchema = z9.union([
|
|
2899
2954
|
z9.object({
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
);
|
|
2955
|
+
costUsd: z9.number().finite().nonnegative().optional(),
|
|
2956
|
+
memories: z9.array(extractedMemorySchema2).max(5)
|
|
2957
|
+
}).strict(),
|
|
2958
|
+
z9.array(extractedMemorySchema2).max(5).transform((memories) => ({ memories }))
|
|
2959
|
+
]);
|
|
2906
2960
|
function recordCapturedMemory(captured, result) {
|
|
2907
2961
|
const supersededIds = new Set(result.supersededIds ?? []);
|
|
2908
2962
|
for (let index2 = captured.length - 1; index2 >= 0; index2 -= 1) {
|
|
@@ -2969,7 +3023,7 @@ function passiveInput(sessionId, memory, sourceKey2, target) {
|
|
|
2969
3023
|
...memory.expiresAtMs !== null ? { expiresAtMs: memory.expiresAtMs } : {}
|
|
2970
3024
|
};
|
|
2971
3025
|
}
|
|
2972
|
-
async function
|
|
3026
|
+
async function getTaskExtraction(context, extract) {
|
|
2973
3027
|
const cacheKey = `memory-extraction:${context.id}`;
|
|
2974
3028
|
const cached = await context.state.get(cacheKey);
|
|
2975
3029
|
if (cached !== void 0) {
|
|
@@ -2979,11 +3033,9 @@ async function getTaskMemories(context, extract) {
|
|
|
2979
3033
|
}
|
|
2980
3034
|
await context.state.delete(cacheKey);
|
|
2981
3035
|
}
|
|
2982
|
-
const
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
}
|
|
2986
|
-
return memories;
|
|
3036
|
+
const extraction = await extract();
|
|
3037
|
+
await context.state.set(cacheKey, extraction, MEMORY_TASK_STATE_TTL_MS);
|
|
3038
|
+
return extraction;
|
|
2987
3039
|
}
|
|
2988
3040
|
async function processMemorySession(context) {
|
|
2989
3041
|
const run = await context.run.load();
|
|
@@ -3015,7 +3067,7 @@ async function processMemorySession(context) {
|
|
|
3015
3067
|
supersessionDecider: agent
|
|
3016
3068
|
});
|
|
3017
3069
|
await store.archiveExpiredMemories();
|
|
3018
|
-
const
|
|
3070
|
+
const extraction = await getTaskExtraction(context, async () => {
|
|
3019
3071
|
const existingMemories = await store.searchMemories({
|
|
3020
3072
|
limit: 10,
|
|
3021
3073
|
query: evidenceText
|
|
@@ -3029,11 +3081,8 @@ async function processMemorySession(context) {
|
|
|
3029
3081
|
runtimeContext: runtimeContext2
|
|
3030
3082
|
});
|
|
3031
3083
|
});
|
|
3032
|
-
if (memories.length === 0) {
|
|
3033
|
-
return;
|
|
3034
|
-
}
|
|
3035
3084
|
const captured = [];
|
|
3036
|
-
for (const memory of memories) {
|
|
3085
|
+
for (const memory of extraction.memories) {
|
|
3037
3086
|
const target = routeExtractedMemory(memory, transcript, run);
|
|
3038
3087
|
if (target === "drop") {
|
|
3039
3088
|
continue;
|
|
@@ -3047,9 +3096,12 @@ async function processMemorySession(context) {
|
|
|
3047
3096
|
const result = await store.createMemory(input);
|
|
3048
3097
|
recordCapturedMemory(captured, result);
|
|
3049
3098
|
}
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3099
|
+
await context.events.emit(
|
|
3100
|
+
memoriesCapturedEvent({
|
|
3101
|
+
memories: captured,
|
|
3102
|
+
...extraction.costUsd !== void 0 ? { costUsd: extraction.costUsd } : {}
|
|
3103
|
+
})
|
|
3104
|
+
);
|
|
3053
3105
|
}
|
|
3054
3106
|
|
|
3055
3107
|
// src/recall.ts
|
|
@@ -3113,6 +3165,19 @@ function renderMemoryPrompt(memories) {
|
|
|
3113
3165
|
"Treat these as possibly stale context. Current user instructions and repository evidence take priority."
|
|
3114
3166
|
].join("\n");
|
|
3115
3167
|
}
|
|
3168
|
+
function addUsd(left, right) {
|
|
3169
|
+
if (left === void 0) return right;
|
|
3170
|
+
if (right === void 0) return left;
|
|
3171
|
+
return Math.round((left + right) * 1e12) / 1e12;
|
|
3172
|
+
}
|
|
3173
|
+
async function emitRecallOutcome(args) {
|
|
3174
|
+
await args.events?.emit(
|
|
3175
|
+
memoriesRecalledEvent({
|
|
3176
|
+
memories: args.memories,
|
|
3177
|
+
...args.costUsd !== void 0 ? { costUsd: args.costUsd } : {}
|
|
3178
|
+
})
|
|
3179
|
+
);
|
|
3180
|
+
}
|
|
3116
3181
|
var memoryRecallContext = definePromptContext({
|
|
3117
3182
|
kind: "recall",
|
|
3118
3183
|
version: 1,
|
|
@@ -3128,19 +3193,33 @@ async function createMemoryPromptContributions(context) {
|
|
|
3128
3193
|
...context.actor ? { actor: context.actor } : {},
|
|
3129
3194
|
source: context.source
|
|
3130
3195
|
});
|
|
3196
|
+
let embeddingCostUsd;
|
|
3197
|
+
const sourceEmbedder = context.embedder;
|
|
3198
|
+
const embedder = sourceEmbedder ? {
|
|
3199
|
+
async embedTexts(input) {
|
|
3200
|
+
const result = await sourceEmbedder.embedTexts(input);
|
|
3201
|
+
embeddingCostUsd = addUsd(embeddingCostUsd, result.costUsd);
|
|
3202
|
+
return result;
|
|
3203
|
+
}
|
|
3204
|
+
} : void 0;
|
|
3131
3205
|
const candidates = await createMemoryStore(context.db, runtimeContext2, {
|
|
3132
|
-
...
|
|
3206
|
+
...embedder ? { embedder } : {},
|
|
3133
3207
|
...context.maxVectorDistance !== void 0 ? { maxVectorDistance: context.maxVectorDistance } : {}
|
|
3134
3208
|
}).recallMemories({
|
|
3135
3209
|
query: context.text,
|
|
3136
3210
|
limit: RECALL_CANDIDATE_LIMIT
|
|
3137
3211
|
});
|
|
3138
3212
|
if (candidates.length === 0) {
|
|
3213
|
+
await emitRecallOutcome({
|
|
3214
|
+
...embeddingCostUsd !== void 0 ? { costUsd: embeddingCostUsd } : {},
|
|
3215
|
+
events: context.events,
|
|
3216
|
+
memories: []
|
|
3217
|
+
});
|
|
3139
3218
|
return void 0;
|
|
3140
3219
|
}
|
|
3141
|
-
let
|
|
3220
|
+
let recall;
|
|
3142
3221
|
try {
|
|
3143
|
-
|
|
3222
|
+
recall = await context.agent.selectRelevantMemories({
|
|
3144
3223
|
candidates: candidates.map(({ content, id }) => ({ content, id })),
|
|
3145
3224
|
userRequest: context.text
|
|
3146
3225
|
});
|
|
@@ -3151,8 +3230,14 @@ async function createMemoryPromptContributions(context) {
|
|
|
3151
3230
|
const candidatesById = new Map(
|
|
3152
3231
|
candidates.map((memory) => [memory.id, memory])
|
|
3153
3232
|
);
|
|
3154
|
-
const relevant = relevantIds.map((id) => candidatesById.get(id)).filter((memory) => memory !== void 0).slice(0, DEFAULT_RECALL_LIMIT);
|
|
3233
|
+
const relevant = recall.relevantIds.map((id) => candidatesById.get(id)).filter((memory) => memory !== void 0).slice(0, DEFAULT_RECALL_LIMIT);
|
|
3155
3234
|
const selected = selectPromptMemories(relevant);
|
|
3235
|
+
const costUsd = addUsd(embeddingCostUsd, recall.costUsd);
|
|
3236
|
+
await emitRecallOutcome({
|
|
3237
|
+
...costUsd !== void 0 ? { costUsd } : {},
|
|
3238
|
+
events: context.events,
|
|
3239
|
+
memories: selected.map(({ id }) => id)
|
|
3240
|
+
});
|
|
3156
3241
|
if (selected.length === 0) {
|
|
3157
3242
|
return void 0;
|
|
3158
3243
|
}
|
|
@@ -3231,6 +3316,15 @@ function formatPercent(value) {
|
|
|
3231
3316
|
style: "percent"
|
|
3232
3317
|
}).format(value);
|
|
3233
3318
|
}
|
|
3319
|
+
function formatUsd(value) {
|
|
3320
|
+
const maximumFractionDigits = value > 0 && value < 0.01 ? 4 : 2;
|
|
3321
|
+
return new Intl.NumberFormat("en-US", {
|
|
3322
|
+
currency: "USD",
|
|
3323
|
+
maximumFractionDigits,
|
|
3324
|
+
minimumFractionDigits: 2,
|
|
3325
|
+
style: "currency"
|
|
3326
|
+
}).format(value);
|
|
3327
|
+
}
|
|
3234
3328
|
async function buildMemoryOperationalReport(args) {
|
|
3235
3329
|
const active = and4(
|
|
3236
3330
|
isNull3(juniorMemoryMemories.archivedAtMs),
|
|
@@ -3265,6 +3359,11 @@ async function buildMemoryOperationalReport(args) {
|
|
|
3265
3359
|
const activeCount = counts?.active ?? 0;
|
|
3266
3360
|
const embeddedCount = counts?.embedded ?? 0;
|
|
3267
3361
|
const embeddingCoverage = activeCount === 0 ? 0 : embeddedCount / activeCount;
|
|
3362
|
+
const extractionThirtyDays = args.extractionDays.slice(-30);
|
|
3363
|
+
const extractionCostThirtyDays = extractionThirtyDays.reduce(
|
|
3364
|
+
(total, day) => total + day.costUsd,
|
|
3365
|
+
0
|
|
3366
|
+
);
|
|
3268
3367
|
return {
|
|
3269
3368
|
generatedAt: new Date(args.nowMs).toISOString(),
|
|
3270
3369
|
title: "Memory",
|
|
@@ -3274,6 +3373,10 @@ async function buildMemoryOperationalReport(args) {
|
|
|
3274
3373
|
tone: activeCount > 0 ? "good" : "neutral",
|
|
3275
3374
|
value: formatCount(activeCount)
|
|
3276
3375
|
},
|
|
3376
|
+
{
|
|
3377
|
+
label: "extraction cost \xB7 30d",
|
|
3378
|
+
value: formatUsd(extractionCostThirtyDays)
|
|
3379
|
+
},
|
|
3277
3380
|
{
|
|
3278
3381
|
label: "created \xB7 30d",
|
|
3279
3382
|
value: formatCount(counts?.createdThirtyDays ?? 0)
|
|
@@ -3293,6 +3396,19 @@ async function buildMemoryOperationalReport(args) {
|
|
|
3293
3396
|
}
|
|
3294
3397
|
],
|
|
3295
3398
|
widgets: [
|
|
3399
|
+
{
|
|
3400
|
+
categories: args.extractionDays.map((day) => ({
|
|
3401
|
+
id: day.date,
|
|
3402
|
+
label: day.date,
|
|
3403
|
+
values: { costUsd: day.costUsd }
|
|
3404
|
+
})),
|
|
3405
|
+
description: "Estimated model cost of passive memory extraction",
|
|
3406
|
+
id: "extraction-cost",
|
|
3407
|
+
series: [{ format: "usd", key: "costUsd", label: "Cost" }],
|
|
3408
|
+
timeRangeDays: [...WINDOWS],
|
|
3409
|
+
title: "Extraction cost",
|
|
3410
|
+
type: "bar_chart"
|
|
3411
|
+
},
|
|
3296
3412
|
{
|
|
3297
3413
|
categories: memoryDays.map((day) => ({
|
|
3298
3414
|
id: day.date,
|
|
@@ -3453,7 +3569,11 @@ function memoryPlugin(options = {}) {
|
|
|
3453
3569
|
},
|
|
3454
3570
|
model: modelId ? { structuredModelId: modelId } : { structuredModel: "default" },
|
|
3455
3571
|
packageName: "@sentry/junior-memory",
|
|
3456
|
-
conversationEvents: [
|
|
3572
|
+
conversationEvents: [
|
|
3573
|
+
memoriesCapturedEventV1,
|
|
3574
|
+
memoriesCapturedEvent,
|
|
3575
|
+
memoriesRecalledEvent
|
|
3576
|
+
],
|
|
3457
3577
|
cli: {
|
|
3458
3578
|
commands: [createMemoryCliCommand()]
|
|
3459
3579
|
},
|
|
@@ -3467,15 +3587,21 @@ function memoryPlugin(options = {}) {
|
|
|
3467
3587
|
userPages: [createMemoryUserPage()],
|
|
3468
3588
|
hooks: {
|
|
3469
3589
|
async operationalReport(ctx) {
|
|
3590
|
+
const extractionDays = await ctx.eventStats.costsByDay({
|
|
3591
|
+
days: 90,
|
|
3592
|
+
eventName: "memories_captured"
|
|
3593
|
+
});
|
|
3470
3594
|
return await buildMemoryOperationalReport({
|
|
3471
3595
|
db: ctx.db,
|
|
3596
|
+
extractionDays,
|
|
3472
3597
|
nowMs: ctx.nowMs
|
|
3473
3598
|
});
|
|
3474
3599
|
},
|
|
3475
3600
|
apiRoutes(ctx) {
|
|
3476
3601
|
return createMemoryApi({
|
|
3477
3602
|
actors: ctx.viewer.actors,
|
|
3478
|
-
db: ctx.db
|
|
3603
|
+
db: ctx.db,
|
|
3604
|
+
eventStats: ctx.eventStats
|
|
3479
3605
|
});
|
|
3480
3606
|
},
|
|
3481
3607
|
tools(ctx) {
|
|
@@ -3508,6 +3634,7 @@ function memoryPlugin(options = {}) {
|
|
|
3508
3634
|
...ctx.actor ? { actor: ctx.actor } : {},
|
|
3509
3635
|
db: ctx.db,
|
|
3510
3636
|
embedder: ctx.embedder,
|
|
3637
|
+
events: ctx.events,
|
|
3511
3638
|
log: ctx.log,
|
|
3512
3639
|
maxVectorDistance: recallMaxVectorDistance(options),
|
|
3513
3640
|
source: ctx.source,
|