@sentry/junior-memory 0.197.0 → 0.199.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/dist/index.d.ts +887 -7
- package/package.json +5 -6
- package/dist/agent.d.ts +0 -280
- package/dist/api.d.ts +0 -121
- package/dist/cli/format.d.ts +0 -5
- package/dist/cli/index.d.ts +0 -3
- package/dist/cli/search.d.ts +0 -4
- package/dist/cli/show.d.ts +0 -4
- package/dist/db/schema.d.ts +0 -479
- package/dist/events.d.ts +0 -35
- package/dist/operational-report.d.ts +0 -8
- package/dist/plugin.d.ts +0 -9
- package/dist/process-session.d.ts +0 -9
- package/dist/ranking.d.ts +0 -18
- package/dist/recall.d.ts +0 -41
- package/dist/scope.d.ts +0 -19
- package/dist/store.d.ts +0 -229
- package/dist/tools.d.ts +0 -164
- package/dist/types.d.ts +0 -78
- package/dist/user-pages.d.ts +0 -4
- package/dist/viewer.d.ts +0 -91
- package/src/agent.ts +0 -663
- package/src/api.ts +0 -288
- package/src/cli/format.ts +0 -30
- package/src/cli/index.ts +0 -15
- package/src/cli/search.ts +0 -119
- package/src/cli/show.ts +0 -44
- package/src/db/schema.ts +0 -147
- package/src/events.ts +0 -107
- package/src/index.ts +0 -25
- package/src/operational-report.ts +0 -228
- package/src/plugin.ts +0 -186
- package/src/process-session.ts +0 -311
- package/src/ranking.ts +0 -107
- package/src/recall.ts +0 -212
- package/src/scope.ts +0 -75
- package/src/store.ts +0 -1578
- package/src/tools.ts +0 -586
- package/src/types.ts +0 -37
- package/src/user-pages.ts +0 -99
- package/src/viewer.ts +0 -441
package/src/tools.ts
DELETED
|
@@ -1,586 +0,0 @@
|
|
|
1
|
-
import { Type, type Static } from "@sinclair/typebox";
|
|
2
|
-
import { Value } from "@sinclair/typebox/value";
|
|
3
|
-
import {
|
|
4
|
-
definePluginTool,
|
|
5
|
-
getSourceKey,
|
|
6
|
-
PluginToolInputError,
|
|
7
|
-
type PluginToolOutput,
|
|
8
|
-
type Source,
|
|
9
|
-
type Actor,
|
|
10
|
-
type Identity,
|
|
11
|
-
type User,
|
|
12
|
-
pluginToolOutputSchema,
|
|
13
|
-
} from "@sentry/junior-plugin-api";
|
|
14
|
-
import { z } from "zod";
|
|
15
|
-
import {
|
|
16
|
-
createMemoryStore,
|
|
17
|
-
type CreateMemoryInput,
|
|
18
|
-
type MemoryEmbeddingProvider,
|
|
19
|
-
type MemoryDb,
|
|
20
|
-
type MemoryRecord,
|
|
21
|
-
type MemorySupersessionDecider,
|
|
22
|
-
} from "./store";
|
|
23
|
-
import {
|
|
24
|
-
parseCreateMemoryRequest,
|
|
25
|
-
parseMemoryReview,
|
|
26
|
-
type MemoryAgent,
|
|
27
|
-
} from "./agent";
|
|
28
|
-
import {
|
|
29
|
-
memoryRuntimeContextSchema,
|
|
30
|
-
type MemoryKind,
|
|
31
|
-
type MemoryRuntimeContext,
|
|
32
|
-
} from "./types";
|
|
33
|
-
|
|
34
|
-
export type MemoryReviewer = Pick<MemoryAgent, "reviewCreateRequest">;
|
|
35
|
-
|
|
36
|
-
const MAX_TOOL_CONTENT_CHARS = 4_000;
|
|
37
|
-
const DEFAULT_RESULT_LIMIT = 20;
|
|
38
|
-
const DEFAULT_SEARCH_LIMIT = 10;
|
|
39
|
-
|
|
40
|
-
const KNOWN_TOOL_INPUT_ERROR_MESSAGES = new Set([
|
|
41
|
-
"Conversation memory requires conversation context.",
|
|
42
|
-
"Conversation-subject memory requires conversation context.",
|
|
43
|
-
"Memory content is required.",
|
|
44
|
-
"Memory content exceeds the maximum length.",
|
|
45
|
-
"Memory id is required.",
|
|
46
|
-
"Memory was not found in the current context.",
|
|
47
|
-
"Memory id prefix is ambiguous.",
|
|
48
|
-
"Private memory requires a User.",
|
|
49
|
-
"User memory requires a User.",
|
|
50
|
-
]);
|
|
51
|
-
|
|
52
|
-
/** Runtime-owned context used to bind memory tools to visible scopes. */
|
|
53
|
-
export interface MemoryToolContext {
|
|
54
|
-
agent: MemoryReviewer;
|
|
55
|
-
conversationId?: string;
|
|
56
|
-
db: MemoryDb;
|
|
57
|
-
embedder?: MemoryEmbeddingProvider;
|
|
58
|
-
locationId?: string;
|
|
59
|
-
actor?: Actor;
|
|
60
|
-
source: Source;
|
|
61
|
-
users: {
|
|
62
|
-
resolveActor(): Promise<{ identity: Identity; user?: User } | undefined>;
|
|
63
|
-
};
|
|
64
|
-
userText?: string;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface MemoryCreateToolContext extends MemoryToolContext {
|
|
68
|
-
supersessionDecider?: MemorySupersessionDecider;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function throwToolInputError(message: string): never {
|
|
72
|
-
throw new PluginToolInputError(message);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function asToolInputError(error: unknown): never {
|
|
76
|
-
if (error instanceof PluginToolInputError) {
|
|
77
|
-
throw error;
|
|
78
|
-
}
|
|
79
|
-
if (
|
|
80
|
-
error instanceof Error &&
|
|
81
|
-
KNOWN_TOOL_INPUT_ERROR_MESSAGES.has(error.message)
|
|
82
|
-
) {
|
|
83
|
-
throw new PluginToolInputError(error.message, { cause: error });
|
|
84
|
-
}
|
|
85
|
-
throw error;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function memoryRuntimeContext(
|
|
89
|
-
context: MemoryToolContext,
|
|
90
|
-
): Promise<MemoryRuntimeContext> {
|
|
91
|
-
const actorUser = (await context.users.resolveActor())?.user;
|
|
92
|
-
return memoryRuntimeContextSchema.parse({
|
|
93
|
-
...(context.conversationId
|
|
94
|
-
? { conversationId: context.conversationId }
|
|
95
|
-
: undefined),
|
|
96
|
-
...(context.actor ? { actor: context.actor } : undefined),
|
|
97
|
-
...(context.locationId ? { locationId: context.locationId } : undefined),
|
|
98
|
-
source: context.source,
|
|
99
|
-
...(actorUser ? { userId: actorUser.id } : undefined),
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function memoryStore(
|
|
104
|
-
context: MemoryToolContext,
|
|
105
|
-
runtimeContext: MemoryRuntimeContext,
|
|
106
|
-
options: { supersessionDecider?: MemorySupersessionDecider } = {},
|
|
107
|
-
) {
|
|
108
|
-
return createMemoryStore(context.db, runtimeContext, {
|
|
109
|
-
embedder: context.embedder,
|
|
110
|
-
...(options.supersessionDecider
|
|
111
|
-
? { supersessionDecider: options.supersessionDecider }
|
|
112
|
-
: undefined),
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function boundedLimit(value: number | undefined, fallback: number): number {
|
|
117
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
118
|
-
return fallback;
|
|
119
|
-
}
|
|
120
|
-
return Math.min(50, Math.max(1, Math.floor(value)));
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function digitAt(value: string, index: number): boolean {
|
|
124
|
-
const code = value.charCodeAt(index);
|
|
125
|
-
return code >= 48 && code <= 57;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function readDigits(
|
|
129
|
-
value: string,
|
|
130
|
-
start: number,
|
|
131
|
-
length: number,
|
|
132
|
-
): number | undefined {
|
|
133
|
-
for (let index = start; index < start + length; index++) {
|
|
134
|
-
if (!digitAt(value, index)) {
|
|
135
|
-
return undefined;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return Number(value.slice(start, start + length));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function parseIsoTimestampParts(value: string) {
|
|
142
|
-
if (
|
|
143
|
-
value.length < 20 ||
|
|
144
|
-
value[4] !== "-" ||
|
|
145
|
-
value[7] !== "-" ||
|
|
146
|
-
value[10] !== "T" ||
|
|
147
|
-
value[13] !== ":" ||
|
|
148
|
-
value[16] !== ":"
|
|
149
|
-
) {
|
|
150
|
-
return undefined;
|
|
151
|
-
}
|
|
152
|
-
const year = readDigits(value, 0, 4);
|
|
153
|
-
const month = readDigits(value, 5, 2);
|
|
154
|
-
const day = readDigits(value, 8, 2);
|
|
155
|
-
const hour = readDigits(value, 11, 2);
|
|
156
|
-
const minute = readDigits(value, 14, 2);
|
|
157
|
-
const second = readDigits(value, 17, 2);
|
|
158
|
-
if (
|
|
159
|
-
year === undefined ||
|
|
160
|
-
month === undefined ||
|
|
161
|
-
day === undefined ||
|
|
162
|
-
hour === undefined ||
|
|
163
|
-
minute === undefined ||
|
|
164
|
-
second === undefined
|
|
165
|
-
) {
|
|
166
|
-
return undefined;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
let zoneStart = 19;
|
|
170
|
-
if (value[zoneStart] === ".") {
|
|
171
|
-
zoneStart += 1;
|
|
172
|
-
const fractionStart = zoneStart;
|
|
173
|
-
while (zoneStart < value.length && digitAt(value, zoneStart)) {
|
|
174
|
-
zoneStart += 1;
|
|
175
|
-
}
|
|
176
|
-
if (zoneStart === fractionStart) {
|
|
177
|
-
return undefined;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (value[zoneStart] === "Z") {
|
|
182
|
-
if (zoneStart !== value.length - 1) {
|
|
183
|
-
return undefined;
|
|
184
|
-
}
|
|
185
|
-
} else if (value[zoneStart] === "+" || value[zoneStart] === "-") {
|
|
186
|
-
if (
|
|
187
|
-
zoneStart !== value.length - 6 ||
|
|
188
|
-
value[zoneStart + 3] !== ":" ||
|
|
189
|
-
readDigits(value, zoneStart + 1, 2) === undefined ||
|
|
190
|
-
readDigits(value, zoneStart + 4, 2) === undefined
|
|
191
|
-
) {
|
|
192
|
-
return undefined;
|
|
193
|
-
}
|
|
194
|
-
} else {
|
|
195
|
-
return undefined;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return { day, hour, minute, month, second, year };
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function parseExpiresAt(value: string | undefined): number | undefined {
|
|
202
|
-
if (!value) {
|
|
203
|
-
return undefined;
|
|
204
|
-
}
|
|
205
|
-
if (value === "never") {
|
|
206
|
-
return undefined;
|
|
207
|
-
}
|
|
208
|
-
const parts = parseIsoTimestampParts(value);
|
|
209
|
-
const expiresAtMs = Date.parse(value);
|
|
210
|
-
if (!parts || !Number.isFinite(expiresAtMs)) {
|
|
211
|
-
throwToolInputError('expires_at must be "never" or a valid ISO timestamp.');
|
|
212
|
-
}
|
|
213
|
-
const calendarDate = new Date(
|
|
214
|
-
Date.UTC(parts.year, parts.month - 1, parts.day),
|
|
215
|
-
);
|
|
216
|
-
if (
|
|
217
|
-
calendarDate.getUTCFullYear() !== parts.year ||
|
|
218
|
-
calendarDate.getUTCMonth() !== parts.month - 1 ||
|
|
219
|
-
calendarDate.getUTCDate() !== parts.day ||
|
|
220
|
-
parts.hour > 23 ||
|
|
221
|
-
parts.minute > 59 ||
|
|
222
|
-
parts.second > 59
|
|
223
|
-
) {
|
|
224
|
-
throwToolInputError('expires_at must be "never" or a valid ISO timestamp.');
|
|
225
|
-
}
|
|
226
|
-
return expiresAtMs;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function requireToolCallId(value: string | undefined): string {
|
|
230
|
-
if (!value) {
|
|
231
|
-
throwToolInputError("Memory creation requires a tool call id.");
|
|
232
|
-
}
|
|
233
|
-
return value;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function requireMemoryContent(value: string): string {
|
|
237
|
-
if (value.trim().length === 0) {
|
|
238
|
-
throwToolInputError("Memory content is required.");
|
|
239
|
-
}
|
|
240
|
-
return value;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const createMemoryInputSchema = z
|
|
244
|
-
.object({
|
|
245
|
-
content: z
|
|
246
|
-
.string()
|
|
247
|
-
.min(1)
|
|
248
|
-
.max(MAX_TOOL_CONTENT_CHARS)
|
|
249
|
-
.describe(
|
|
250
|
-
"Self-contained memory candidate. Include the subject in natural language when it matters; do not rely on surrounding chat context.",
|
|
251
|
-
),
|
|
252
|
-
expires_at: z
|
|
253
|
-
.string()
|
|
254
|
-
.min(1)
|
|
255
|
-
.describe(
|
|
256
|
-
'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".',
|
|
257
|
-
)
|
|
258
|
-
.optional(),
|
|
259
|
-
})
|
|
260
|
-
.strict();
|
|
261
|
-
|
|
262
|
-
const removeMemoryInputSchema = z
|
|
263
|
-
.object({
|
|
264
|
-
id: z
|
|
265
|
-
.string()
|
|
266
|
-
.min(1)
|
|
267
|
-
.describe("Memory id or unambiguous short id prefix to remove."),
|
|
268
|
-
})
|
|
269
|
-
.strict();
|
|
270
|
-
|
|
271
|
-
const listMemoriesInputSchema = z
|
|
272
|
-
.object({
|
|
273
|
-
limit: z
|
|
274
|
-
.number()
|
|
275
|
-
.min(1)
|
|
276
|
-
.max(50)
|
|
277
|
-
.describe("Maximum number of visible memories to return.")
|
|
278
|
-
.optional(),
|
|
279
|
-
})
|
|
280
|
-
.strict();
|
|
281
|
-
|
|
282
|
-
const searchMemoriesInputSchema = z
|
|
283
|
-
.object({
|
|
284
|
-
query: z
|
|
285
|
-
.string()
|
|
286
|
-
.min(1)
|
|
287
|
-
.describe("Search query for visible memory content."),
|
|
288
|
-
limit: z
|
|
289
|
-
.number()
|
|
290
|
-
.min(1)
|
|
291
|
-
.max(50)
|
|
292
|
-
.describe("Maximum number of matching memories to return.")
|
|
293
|
-
.optional(),
|
|
294
|
-
})
|
|
295
|
-
.strict();
|
|
296
|
-
|
|
297
|
-
const memoryToolProjectionSchema = Type.Object(
|
|
298
|
-
{
|
|
299
|
-
id: Type.String({ minLength: 1 }),
|
|
300
|
-
content: Type.String({ minLength: 1 }),
|
|
301
|
-
createdAtMs: Type.Number(),
|
|
302
|
-
observedAtMs: Type.Number(),
|
|
303
|
-
expiresAtMs: Type.Optional(Type.Number()),
|
|
304
|
-
},
|
|
305
|
-
{ additionalProperties: false },
|
|
306
|
-
);
|
|
307
|
-
type MemoryToolProjection = Static<typeof memoryToolProjectionSchema>;
|
|
308
|
-
|
|
309
|
-
type MemoryStructuredToolResult<TData extends Record<string, unknown>> =
|
|
310
|
-
PluginToolOutput &
|
|
311
|
-
TData & {
|
|
312
|
-
target: string;
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
const memoryProjectionOutputSchema = z.object({
|
|
316
|
-
id: z.string(),
|
|
317
|
-
content: z.string(),
|
|
318
|
-
createdAtMs: z.number(),
|
|
319
|
-
observedAtMs: z.number(),
|
|
320
|
-
expiresAtMs: z.number().optional(),
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
const memoryCreateOutputSchema = pluginToolOutputSchema.extend({
|
|
324
|
-
target: z.string(),
|
|
325
|
-
created: z.boolean(),
|
|
326
|
-
memory: memoryProjectionOutputSchema,
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
const memorySingleOutputSchema = pluginToolOutputSchema.extend({
|
|
330
|
-
target: z.string(),
|
|
331
|
-
memory: memoryProjectionOutputSchema,
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
const memoryManyOutputSchema = pluginToolOutputSchema.extend({
|
|
335
|
-
target: z.string(),
|
|
336
|
-
memories: z.array(memoryProjectionOutputSchema),
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
function parseMemoryToolInput<T>(schema: z.ZodType<T>, input: unknown): T {
|
|
340
|
-
const result = schema.safeParse(input);
|
|
341
|
-
if (!result.success) {
|
|
342
|
-
throw new PluginToolInputError("Invalid memory tool input.", {
|
|
343
|
-
cause: result.error,
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
return result.data;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
function sourceIdempotencyKey(context: MemoryToolContext): string {
|
|
350
|
-
const sourceKey = getSourceKey(context.source);
|
|
351
|
-
if (!sourceKey) {
|
|
352
|
-
throwToolInputError("Memory creation requires source message context.");
|
|
353
|
-
}
|
|
354
|
-
return sourceKey;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
function createInput(
|
|
358
|
-
context: MemoryToolContext,
|
|
359
|
-
input: { content: string; expiresAtMs?: number; kind: MemoryKind },
|
|
360
|
-
toolCallId: string,
|
|
361
|
-
) {
|
|
362
|
-
return {
|
|
363
|
-
content: requireMemoryContent(input.content),
|
|
364
|
-
idempotencyKey: `tool:${sourceIdempotencyKey(context)}:${toolCallId}`,
|
|
365
|
-
kind: input.kind,
|
|
366
|
-
...(input.expiresAtMs !== undefined
|
|
367
|
-
? { expiresAtMs: input.expiresAtMs }
|
|
368
|
-
: undefined),
|
|
369
|
-
} satisfies CreateMemoryInput;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function targetForKind(kind: MemoryKind): "actor" | "conversation" {
|
|
373
|
-
if (kind === "preference") {
|
|
374
|
-
return "actor";
|
|
375
|
-
}
|
|
376
|
-
return "conversation";
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/** Return the model-visible projection without hidden ownership/source fields. */
|
|
380
|
-
function compactMemory(memory: MemoryRecord): MemoryToolProjection {
|
|
381
|
-
return Value.Parse(memoryToolProjectionSchema, {
|
|
382
|
-
id: memory.id,
|
|
383
|
-
content: memory.content,
|
|
384
|
-
createdAtMs: memory.createdAtMs,
|
|
385
|
-
observedAtMs: memory.observedAtMs,
|
|
386
|
-
...(memory.expiresAtMs !== undefined
|
|
387
|
-
? { expiresAtMs: memory.expiresAtMs }
|
|
388
|
-
: undefined),
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
function memoryToolResult<TData extends Record<string, unknown>>(
|
|
393
|
-
target: string,
|
|
394
|
-
data: TData,
|
|
395
|
-
): MemoryStructuredToolResult<TData> {
|
|
396
|
-
return {
|
|
397
|
-
target,
|
|
398
|
-
...data,
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/** Create a tool that submits an explicit memory candidate for storage. */
|
|
403
|
-
export function createMemoryCreateTool(context: MemoryCreateToolContext) {
|
|
404
|
-
return definePluginTool({
|
|
405
|
-
approvalMode: "approve",
|
|
406
|
-
annotations: {
|
|
407
|
-
destructiveHint: false,
|
|
408
|
-
idempotentHint: true,
|
|
409
|
-
openWorldHint: false,
|
|
410
|
-
readOnlyHint: false,
|
|
411
|
-
},
|
|
412
|
-
description:
|
|
413
|
-
"Explicit memory-write tool. Use only when the latest user message directly asks Junior to remember, store, save, or forget-and-replace a fact. Do not use for ordinary statements like 'I prefer X', 'I use Y', or 'X goes before Y' unless the user also asks you to remember/store/save it; passive memory learning handles those after the visible reply. Pass one self-contained natural-language candidate preserving the user's explicit memory intent. Do not ask the user to rephrase ordinary first-person facts, and do not rewrite them into display-name or third-person wording. Do not include secrets, private personal details, medical/legal/financial/sensitive facts, or another person's personal preference, opinion, habit, identity, relationship, workflow, or private life. Junior sets access, Location, Source, and subject. The memory agent rewrites the content and sets the memory kind.",
|
|
414
|
-
executionMode: "sequential",
|
|
415
|
-
inputSchema: createMemoryInputSchema,
|
|
416
|
-
outputSchema: memoryCreateOutputSchema,
|
|
417
|
-
execute: async (input, options) => {
|
|
418
|
-
const parsedInput = parseMemoryToolInput(createMemoryInputSchema, input);
|
|
419
|
-
const toolCallId = requireToolCallId(options.toolCallId);
|
|
420
|
-
const requestedExpiresAtMs = parseExpiresAt(parsedInput.expires_at);
|
|
421
|
-
const runtimeContext = await memoryRuntimeContext(context);
|
|
422
|
-
const store = memoryStore(context, runtimeContext, {
|
|
423
|
-
supersessionDecider: context.supersessionDecider,
|
|
424
|
-
});
|
|
425
|
-
const review = await (async () => {
|
|
426
|
-
try {
|
|
427
|
-
return parseMemoryReview(
|
|
428
|
-
await context.agent.reviewCreateRequest(
|
|
429
|
-
parseCreateMemoryRequest({
|
|
430
|
-
content: requireMemoryContent(parsedInput.content),
|
|
431
|
-
...(requestedExpiresAtMs !== undefined
|
|
432
|
-
? { expiresAtMs: requestedExpiresAtMs }
|
|
433
|
-
: undefined),
|
|
434
|
-
runtimeContext,
|
|
435
|
-
...(context.userText?.trim()
|
|
436
|
-
? {
|
|
437
|
-
sourceContext: {
|
|
438
|
-
currentUserText: context.userText.trim(),
|
|
439
|
-
},
|
|
440
|
-
}
|
|
441
|
-
: undefined),
|
|
442
|
-
}),
|
|
443
|
-
),
|
|
444
|
-
);
|
|
445
|
-
} catch (error) {
|
|
446
|
-
if (error instanceof PluginToolInputError) {
|
|
447
|
-
throw error;
|
|
448
|
-
}
|
|
449
|
-
const detail =
|
|
450
|
-
error instanceof Error && error.message.trim()
|
|
451
|
-
? `: ${error.message}`
|
|
452
|
-
: "";
|
|
453
|
-
throw new PluginToolInputError(
|
|
454
|
-
`Memory agent review failed${detail}`,
|
|
455
|
-
{ cause: error },
|
|
456
|
-
);
|
|
457
|
-
}
|
|
458
|
-
})();
|
|
459
|
-
if (review.decision === "reject") {
|
|
460
|
-
throw new PluginToolInputError(
|
|
461
|
-
`Memory was not stored: ${review.reason}`,
|
|
462
|
-
);
|
|
463
|
-
}
|
|
464
|
-
const memoryInput = createInput(
|
|
465
|
-
context,
|
|
466
|
-
{
|
|
467
|
-
content: review.content,
|
|
468
|
-
kind: review.kind,
|
|
469
|
-
...(review.expiresAtMs !== undefined
|
|
470
|
-
? { expiresAtMs: review.expiresAtMs }
|
|
471
|
-
: requestedExpiresAtMs !== undefined
|
|
472
|
-
? { expiresAtMs: requestedExpiresAtMs }
|
|
473
|
-
: {}),
|
|
474
|
-
},
|
|
475
|
-
toolCallId,
|
|
476
|
-
);
|
|
477
|
-
const result = await (async () => {
|
|
478
|
-
try {
|
|
479
|
-
if (targetForKind(review.kind) === "conversation") {
|
|
480
|
-
return await store.createConversationMemory(memoryInput);
|
|
481
|
-
}
|
|
482
|
-
return await store.createMemory(memoryInput);
|
|
483
|
-
} catch (error) {
|
|
484
|
-
asToolInputError(error);
|
|
485
|
-
}
|
|
486
|
-
})();
|
|
487
|
-
return memoryToolResult("createMemory", {
|
|
488
|
-
created: result.created,
|
|
489
|
-
memory: compactMemory(result.memory),
|
|
490
|
-
});
|
|
491
|
-
},
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
/** Create a tool that archives a visible memory in the active context. */
|
|
496
|
-
export function createMemoryRemoveTool(context: MemoryToolContext) {
|
|
497
|
-
return definePluginTool({
|
|
498
|
-
annotations: {
|
|
499
|
-
destructiveHint: true,
|
|
500
|
-
idempotentHint: true,
|
|
501
|
-
openWorldHint: false,
|
|
502
|
-
readOnlyHint: false,
|
|
503
|
-
},
|
|
504
|
-
description:
|
|
505
|
-
"Forget one private memory owned by the current User. Public memories are read-only. Use only ids or short id prefixes returned by listMemories or searchMemories. Never remove memories by hidden Actor, provider, scope, or subject ids.",
|
|
506
|
-
executionMode: "sequential",
|
|
507
|
-
inputSchema: removeMemoryInputSchema,
|
|
508
|
-
outputSchema: memorySingleOutputSchema,
|
|
509
|
-
execute: async (input) => {
|
|
510
|
-
const parsedInput = parseMemoryToolInput(removeMemoryInputSchema, input);
|
|
511
|
-
const runtimeContext = await memoryRuntimeContext(context);
|
|
512
|
-
const memory = await (async () => {
|
|
513
|
-
try {
|
|
514
|
-
return await memoryStore(context, runtimeContext).archiveMemory({
|
|
515
|
-
id: parsedInput.id,
|
|
516
|
-
reason: "tool_removed",
|
|
517
|
-
});
|
|
518
|
-
} catch (error) {
|
|
519
|
-
asToolInputError(error);
|
|
520
|
-
}
|
|
521
|
-
})();
|
|
522
|
-
return memoryToolResult("removeMemory", {
|
|
523
|
-
memory: compactMemory(memory),
|
|
524
|
-
});
|
|
525
|
-
},
|
|
526
|
-
});
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
/** Create a tool that lists visible active memories in the active context. */
|
|
530
|
-
export function createMemoryListTool(context: MemoryToolContext) {
|
|
531
|
-
return definePluginTool({
|
|
532
|
-
description:
|
|
533
|
-
"List active memories visible in the current context. Use when the user asks what Junior remembers or when memory ids are needed before removing a memory.",
|
|
534
|
-
annotations: {
|
|
535
|
-
destructiveHint: false,
|
|
536
|
-
idempotentHint: true,
|
|
537
|
-
openWorldHint: false,
|
|
538
|
-
readOnlyHint: true,
|
|
539
|
-
},
|
|
540
|
-
inputSchema: listMemoriesInputSchema,
|
|
541
|
-
outputSchema: memoryManyOutputSchema,
|
|
542
|
-
execute: async (input) => {
|
|
543
|
-
const parsedInput = parseMemoryToolInput(listMemoriesInputSchema, input);
|
|
544
|
-
const runtimeContext = await memoryRuntimeContext(context);
|
|
545
|
-
const memories = await memoryStore(context, runtimeContext).listMemories({
|
|
546
|
-
limit: boundedLimit(parsedInput.limit, DEFAULT_RESULT_LIMIT),
|
|
547
|
-
});
|
|
548
|
-
return memoryToolResult("listMemories", {
|
|
549
|
-
memories: memories.map(compactMemory),
|
|
550
|
-
});
|
|
551
|
-
},
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
/** Create a tool that searches visible active memories in the active context. */
|
|
556
|
-
export function createMemorySearchTool(context: MemoryToolContext) {
|
|
557
|
-
return definePluginTool({
|
|
558
|
-
description:
|
|
559
|
-
"Search active memories visible in the current context. Use when the model needs targeted memory recall. Public memories are visible everywhere. Private memories belong to the current User.",
|
|
560
|
-
annotations: {
|
|
561
|
-
destructiveHint: false,
|
|
562
|
-
idempotentHint: true,
|
|
563
|
-
openWorldHint: false,
|
|
564
|
-
readOnlyHint: true,
|
|
565
|
-
},
|
|
566
|
-
inputSchema: searchMemoriesInputSchema,
|
|
567
|
-
outputSchema: memoryManyOutputSchema,
|
|
568
|
-
execute: async (input) => {
|
|
569
|
-
const parsedInput = parseMemoryToolInput(
|
|
570
|
-
searchMemoriesInputSchema,
|
|
571
|
-
input,
|
|
572
|
-
);
|
|
573
|
-
const runtimeContext = await memoryRuntimeContext(context);
|
|
574
|
-
const memories = await memoryStore(
|
|
575
|
-
context,
|
|
576
|
-
runtimeContext,
|
|
577
|
-
).searchMemories({
|
|
578
|
-
query: parsedInput.query,
|
|
579
|
-
limit: boundedLimit(parsedInput.limit, DEFAULT_SEARCH_LIMIT),
|
|
580
|
-
});
|
|
581
|
-
return memoryToolResult("searchMemories", {
|
|
582
|
-
memories: memories.map(compactMemory),
|
|
583
|
-
});
|
|
584
|
-
},
|
|
585
|
-
});
|
|
586
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { actorSchema, sourceSchema } from "@sentry/junior-plugin-api";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
|
|
4
|
-
export const MEMORY_KINDS = ["preference", "procedure", "knowledge"] as const;
|
|
5
|
-
|
|
6
|
-
export const MEMORY_SCOPES = ["private", "public"] as const;
|
|
7
|
-
export const MEMORY_SUBJECT_TYPES = [
|
|
8
|
-
"user",
|
|
9
|
-
"conversation",
|
|
10
|
-
"general",
|
|
11
|
-
] as const;
|
|
12
|
-
// Durable attribution follows Source kind, including dashboard roots.
|
|
13
|
-
export const MEMORY_SOURCE_PLATFORMS = ["slack", "local", "web"] as const;
|
|
14
|
-
export const MEMORY_EMBEDDING_METRICS = ["cosine"] as const;
|
|
15
|
-
export const MEMORY_EMBEDDING_DIMENSIONS = 1536;
|
|
16
|
-
|
|
17
|
-
export type MemoryKind = (typeof MEMORY_KINDS)[number];
|
|
18
|
-
export type MemoryScope = (typeof MEMORY_SCOPES)[number];
|
|
19
|
-
export type MemorySubjectType = (typeof MEMORY_SUBJECT_TYPES)[number];
|
|
20
|
-
export type MemorySourcePlatform = (typeof MEMORY_SOURCE_PLATFORMS)[number];
|
|
21
|
-
export type MemoryEmbeddingMetric = (typeof MEMORY_EMBEDDING_METRICS)[number];
|
|
22
|
-
|
|
23
|
-
const nonEmptyStringSchema = z.string().min(1);
|
|
24
|
-
|
|
25
|
-
/** Host data used to set memory access, subject, and source. */
|
|
26
|
-
export const memoryRuntimeContextSchema = z
|
|
27
|
-
.object({
|
|
28
|
-
conversationId: nonEmptyStringSchema.optional(),
|
|
29
|
-
locationId: nonEmptyStringSchema.optional(),
|
|
30
|
-
actor: actorSchema.optional(),
|
|
31
|
-
source: sourceSchema,
|
|
32
|
-
/** User linked to the active Actor. */
|
|
33
|
-
userId: nonEmptyStringSchema.optional(),
|
|
34
|
-
})
|
|
35
|
-
.strict();
|
|
36
|
-
|
|
37
|
-
export type MemoryRuntimeContext = z.output<typeof memoryRuntimeContextSchema>;
|