@sentry/junior-memory 0.180.0 → 0.181.1

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.
@@ -2,9 +2,8 @@ import { type PluginTaskContext } from "@sentry/junior-plugin-api";
2
2
  /**
3
3
  * Extract and store memories from a completed session plugin task.
4
4
  *
5
- * Memory owns post-session extraction and consumes only the bounded plugin task
6
- * projection. Explicit memory tools and private non-local sources remain hard
7
- * boundaries so background retries cannot reinterpret user-directed mutations
8
- * or private conversations.
5
+ * Memory owns learning after a run and reads only the plugin run data.
6
+ * Explicit memory tools stay separate so retries do not reinterpret user
7
+ * requests.
9
8
  */
10
9
  export declare function processMemorySession(context: PluginTaskContext): Promise<void>;
package/dist/ranking.d.ts CHANGED
@@ -4,14 +4,12 @@ export interface MemoryMatch {
4
4
  rank: number;
5
5
  };
6
6
  memory: MemoryRecord;
7
- sourceKey: string;
8
7
  vector?: {
9
8
  rank: number;
10
9
  };
11
10
  }
12
11
  /** Fuse lexical and vector ranks without comparing provider raw scores. */
13
12
  export declare function rankMemoryMatches(matches: MemoryMatch[], options: {
14
- channelPrefix?: string;
15
13
  /** Optional RRF weight for the lexical leg. Defaults to 1. */
16
14
  lexicalWeight?: number;
17
15
  nowMs: number;
package/dist/recall.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type UserPromptContribution, type Actor, type PluginConversationEvents, type PluginLogger, type Source } from "@sentry/junior-plugin-api";
1
+ import { type UserPromptContribution, type Actor, type Identity, type PluginConversationEvents, type PluginLogger, type Source, type User } from "@sentry/junior-plugin-api";
2
2
  import { z } from "zod";
3
3
  import type { MemoryAgent } from "./agent";
4
4
  import { type MemoryDb, type MemoryEmbeddingProvider } from "./store";
@@ -9,9 +9,16 @@ export interface MemoryRecallContext {
9
9
  embedder?: MemoryEmbeddingProvider;
10
10
  events?: PluginConversationEvents;
11
11
  log: PluginLogger;
12
+ locationId?: string;
12
13
  actor?: Actor;
13
14
  source: Source;
14
15
  text: string;
16
+ users: {
17
+ resolveActor(): Promise<{
18
+ identity: Identity;
19
+ user?: User;
20
+ } | undefined>;
21
+ };
15
22
  }
16
23
  /** Structured snapshot retained for one automatic memory recall. */
17
24
  export declare const memoryRecallContextSchema: z.ZodObject<{
@@ -20,8 +27,8 @@ export declare const memoryRecallContextSchema: z.ZodObject<{
20
27
  content: z.ZodString;
21
28
  observedAtMs: z.ZodNumber;
22
29
  scope: z.ZodEnum<{
23
- personal: "personal";
24
30
  conversation: "conversation";
31
+ personal: "personal";
25
32
  }>;
26
33
  kind: z.ZodEnum<{
27
34
  preference: "preference";
package/dist/scope.d.ts CHANGED
@@ -1,23 +1,19 @@
1
- import { type Identity } from "@sentry/junior-plugin-api";
2
1
  import type { MemoryRuntimeContext, MemoryScope, MemorySubjectType } from "./types";
3
- /** Runtime-derived visibility scope used for memory authorization checks. */
2
+ /** Stored memory access rule. */
4
3
  export interface ResolvedMemoryScope {
5
4
  scope: MemoryScope;
6
5
  scopeKey: string;
7
6
  }
8
- /** Runtime-derived subject classification stored for filtering and rendering. */
7
+ /** What a stored memory is about. */
9
8
  export interface ResolvedMemorySubject {
10
- subjectKey?: string;
11
- subjectType: MemorySubjectType;
9
+ subjectKey: string;
10
+ subjectType: Extract<MemorySubjectType, "user" | "conversation">;
12
11
  }
13
- /** Derive viewer-visible memory scopes from canonical provider identities. */
14
- export declare function deriveViewerMemoryScopes(identities: Identity[]): {
15
- privateScopes: ResolvedMemoryScope[];
16
- publicScopes: ResolvedMemoryScope[];
17
- };
18
- /** Derive the authority-bearing key for a requested memory scope. */
19
- export declare function deriveMemoryScope(ctx: MemoryRuntimeContext, scope: MemoryScope): ResolvedMemoryScope;
20
- /** Derive the memory subject from the already-authorized write scope. */
21
- export declare function deriveMemorySubject(ctx: MemoryRuntimeContext, scope: ResolvedMemoryScope): ResolvedMemorySubject;
22
- /** Return every visible scope for memory retrieval in the current context. */
12
+ /** Public memories are visible everywhere. */
13
+ export declare const publicMemoryScope: ResolvedMemoryScope;
14
+ /** Set memory access from the Source. */
15
+ export declare function deriveMemoryScope(ctx: MemoryRuntimeContext): ResolvedMemoryScope;
16
+ /** Set what a memory is about. Access is set separately. */
17
+ export declare function deriveMemorySubject(ctx: MemoryRuntimeContext, subjectType: Extract<MemorySubjectType, "user" | "conversation">): ResolvedMemorySubject;
18
+ /** Return the memory scopes that the current User can access. */
23
19
  export declare function deriveVisibleMemoryScopes(ctx: MemoryRuntimeContext): ResolvedMemoryScope[];
package/dist/store.d.ts CHANGED
@@ -39,8 +39,8 @@ declare const memoryRecordSchema: z.ZodObject<{
39
39
  id: z.ZodString;
40
40
  observedAtMs: z.ZodNumber;
41
41
  scope: z.ZodEnum<{
42
- personal: "personal";
43
- conversation: "conversation";
42
+ public: "public";
43
+ private: "private";
44
44
  }>;
45
45
  subjectType: z.ZodEnum<{
46
46
  user: "user";
@@ -67,6 +67,7 @@ export declare const memorySupersessionInputSchema: z.ZodObject<{
67
67
  }, z.core.$strict>>;
68
68
  runtimeContext: z.ZodObject<{
69
69
  conversationId: z.ZodOptional<z.ZodString>;
70
+ locationId: z.ZodOptional<z.ZodString>;
70
71
  actor: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
71
72
  platform: z.ZodLiteral<"slack">;
72
73
  teamId: z.ZodString;
@@ -112,6 +113,7 @@ export declare const memorySupersessionInputSchema: z.ZodObject<{
112
113
  }>;
113
114
  conversationId: z.ZodString;
114
115
  }, z.core.$strict>], "platform">;
116
+ userId: z.ZodOptional<z.ZodString>;
115
117
  }, z.core.$strict>;
116
118
  }, z.core.$strict>;
117
119
  /**
@@ -177,14 +179,12 @@ export interface MemoryStore {
177
179
  archiveExpiredMemories(input?: ArchiveExpiredMemoriesInput): Promise<ArchiveExpiredMemoriesResult>;
178
180
  /** Archive a visible memory in the current runtime context. */
179
181
  archiveMemory(input: ArchiveMemoryInput): Promise<MemoryRecord>;
180
- /** Store a personal memory for the current actor. */
182
+ /** Store a memory about the current User. The Source sets access. */
181
183
  createMemory(input: CreateMemoryInput): Promise<CreateMemoryResult>;
182
- /** Store a conversation memory for the current source conversation. */
184
+ /** Store a memory about the current Conversation. The Source sets access. */
183
185
  createConversationMemory(input: CreateMemoryInput): Promise<CreateMemoryResult>;
184
186
  /** List active memories visible in the current runtime context. */
185
187
  listMemories(input: ListMemoriesInput): Promise<MemoryRecord[]>;
186
- /** List active personal memories owned by the current actor. */
187
- listPersonalMemories(input: ListMemoriesInput): Promise<MemoryRecord[]>;
188
188
  /**
189
189
  * Retrieve a broad relevance-ranked candidate window for automatic recall.
190
190
  * Prompt admission remains owned by the recall boundary.
@@ -193,7 +193,6 @@ export interface MemoryStore {
193
193
  /** Search active memories visible in the current runtime context. */
194
194
  searchMemories(input: SearchMemoriesInput): Promise<MemoryRecord[]>;
195
195
  }
196
- /** Parse one SQL row into the public memory record projection. */
197
196
  /** Parse one SQL row into the public memory projection. */
198
197
  export declare function parseMemoryRow(row: unknown): MemoryRecord;
199
198
  /** Build the active-row predicate for already-authorized memory scopes. */
package/dist/tools.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type Source, type Actor } from "@sentry/junior-plugin-api";
1
+ import { type Source, type Actor, type Identity, type User } from "@sentry/junior-plugin-api";
2
2
  import { type MemoryEmbeddingProvider, type MemoryDb, type MemorySupersessionDecider } from "./store";
3
3
  import { type MemoryAgent } from "./agent";
4
4
  export type MemoryReviewer = Pick<MemoryAgent, "reviewCreateRequest">;
@@ -8,8 +8,15 @@ export interface MemoryToolContext {
8
8
  conversationId?: string;
9
9
  db: MemoryDb;
10
10
  embedder?: MemoryEmbeddingProvider;
11
+ locationId?: string;
11
12
  actor?: Actor;
12
13
  source: Source;
14
+ users: {
15
+ resolveActor(): Promise<{
16
+ identity: Identity;
17
+ user?: User;
18
+ } | undefined>;
19
+ };
13
20
  userText?: string;
14
21
  }
15
22
  export interface MemoryCreateToolContext extends MemoryToolContext {
package/dist/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  export declare const MEMORY_KINDS: readonly ["preference", "procedure", "knowledge"];
3
- export declare const MEMORY_SCOPES: readonly ["personal", "conversation"];
3
+ export declare const MEMORY_SCOPES: readonly ["private", "public"];
4
4
  export declare const MEMORY_SUBJECT_TYPES: readonly ["user", "conversation", "general"];
5
5
  export declare const MEMORY_SOURCE_PLATFORMS: readonly ["slack", "local", "web"];
6
6
  export declare const MEMORY_EMBEDDING_METRICS: readonly ["cosine"];
@@ -10,9 +10,10 @@ export type MemoryScope = (typeof MEMORY_SCOPES)[number];
10
10
  export type MemorySubjectType = (typeof MEMORY_SUBJECT_TYPES)[number];
11
11
  export type MemorySourcePlatform = (typeof MEMORY_SOURCE_PLATFORMS)[number];
12
12
  export type MemoryEmbeddingMetric = (typeof MEMORY_EMBEDDING_METRICS)[number];
13
- /** Runtime-owned memory invocation fields used for scope and source authority. */
13
+ /** Host data used to set memory access, subject, and source. */
14
14
  export declare const memoryRuntimeContextSchema: z.ZodObject<{
15
15
  conversationId: z.ZodOptional<z.ZodString>;
16
+ locationId: z.ZodOptional<z.ZodString>;
16
17
  actor: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
17
18
  platform: z.ZodLiteral<"slack">;
18
19
  teamId: z.ZodString;
@@ -58,5 +59,6 @@ export declare const memoryRuntimeContextSchema: z.ZodObject<{
58
59
  }>;
59
60
  conversationId: z.ZodString;
60
61
  }, z.core.$strict>], "platform">;
62
+ userId: z.ZodOptional<z.ZodString>;
61
63
  }, z.core.$strict>;
62
64
  export type MemoryRuntimeContext = z.output<typeof memoryRuntimeContextSchema>;
@@ -1,4 +1,4 @@
1
- /** Project viewer-visible memories into Junior's core-rendered user page. */
1
+ /** Render memory in Junior's User page format. */
2
2
  import type { PluginUserPageDefinition } from "@sentry/junior-plugin-api";
3
3
  /** Create the interactive Memories dashboard page. */
4
4
  export declare function createMemoryUserPage(): PluginUserPageDefinition;
@@ -0,0 +1,85 @@
1
+ import { z } from "zod";
2
+ import { type MemoryDb, type MemoryRecord } from "./store";
3
+ import { type MemorySourcePlatform } from "./types";
4
+ declare const memoryVisibilitySchema: z.ZodEnum<{
5
+ public: "public";
6
+ private: "private";
7
+ }>;
8
+ declare const pageInputSchema: z.ZodObject<{
9
+ cursor: z.ZodOptional<z.ZodString>;
10
+ kind: z.ZodOptional<z.ZodEnum<{
11
+ preference: "preference";
12
+ procedure: "procedure";
13
+ knowledge: "knowledge";
14
+ }>>;
15
+ limit: z.ZodNumber;
16
+ origin: z.ZodOptional<z.ZodEnum<{
17
+ automatic: "automatic";
18
+ explicit: "explicit";
19
+ }>>;
20
+ query: z.ZodOptional<z.ZodString>;
21
+ visibility: z.ZodOptional<z.ZodEnum<{
22
+ public: "public";
23
+ private: "private";
24
+ }>>;
25
+ }, z.core.$strict>;
26
+ /** Access label returned by dashboard and REST memory views. */
27
+ export type MemoryVisibility = z.output<typeof memoryVisibilitySchema>;
28
+ /** Memory fields returned to an authenticated User. */
29
+ export type MemoryView = MemoryRecord & {
30
+ origin: "automatic" | "explicit" | "other";
31
+ sourcePlatform: MemorySourcePlatform;
32
+ visibility: MemoryVisibility;
33
+ };
34
+ interface MemoryPage {
35
+ memories: MemoryView[];
36
+ nextCursor?: string;
37
+ }
38
+ type MemoryPageInput = z.output<typeof pageInputSchema>;
39
+ /** Expected error for a malformed or mismatched page cursor. */
40
+ export declare class InvalidMemoryCursorError extends Error {
41
+ constructor();
42
+ }
43
+ /** Expected error when the current User cannot access a memory. */
44
+ export declare class MemoryNotFoundError extends Error {
45
+ constructor();
46
+ }
47
+ /** Archive one active private memory owned by the authenticated User. */
48
+ export declare function archiveMemory(db: MemoryDb, userId: string, id: string): Promise<{
49
+ content: string;
50
+ createdAtMs: number;
51
+ id: string;
52
+ observedAtMs: number;
53
+ scope: "public" | "private";
54
+ subjectType: "user" | "conversation" | "general";
55
+ kind: "preference" | "procedure" | "knowledge";
56
+ archivedAtMs?: number | undefined;
57
+ archiveReason?: string | undefined;
58
+ expiresAtMs?: number | undefined;
59
+ supersededAtMs?: number | undefined;
60
+ supersededById?: string | undefined;
61
+ }>;
62
+ /** Read one active memory visible to the authenticated User. */
63
+ export declare function getMemory(db: MemoryDb, userId: string, id: string): Promise<MemoryView>;
64
+ /** List one stable page of active memory visible to the authenticated User. */
65
+ export declare function listMemories(db: MemoryDb, userId: string, input: MemoryPageInput): Promise<MemoryPage>;
66
+ /** Summarize active memory visible to the authenticated User. */
67
+ export declare function getMemoryStats(db: MemoryDb, userId: string): Promise<{
68
+ active: number;
69
+ automatic: number;
70
+ createdThirtyDays: number;
71
+ embedded: number;
72
+ explicit: number;
73
+ knowledge: number;
74
+ private: number;
75
+ preference: number;
76
+ procedure: number;
77
+ public: number;
78
+ }>;
79
+ /** Read daily memory creation totals visible to the authenticated User in UTC. */
80
+ export declare function getMemoryTimeline(db: MemoryDb, userId: string, days: number): Promise<{
81
+ date: string;
82
+ private: number;
83
+ public: number;
84
+ }[]>;
85
+ export {};
@@ -0,0 +1,114 @@
1
+ ALTER TABLE "junior_memory_memories" DROP CONSTRAINT "junior_memory_memories_scope_check";--> statement-breakpoint
2
+ ALTER TABLE "junior_memory_memories" ADD COLUMN "location_id" text;--> statement-breakpoint
3
+ CREATE TEMP TABLE junior_memory_legacy_owners (
4
+ id text PRIMARY KEY,
5
+ user_id text NOT NULL
6
+ ) ON COMMIT DROP;--> statement-breakpoint
7
+ DO $$
8
+ BEGIN
9
+ IF to_regclass('junior_identities') IS NOT NULL THEN
10
+ EXECUTE $migration$
11
+ INSERT INTO junior_memory_legacy_owners (id, user_id)
12
+ SELECT memory.id, owner.user_id
13
+ FROM junior_memory_memories AS memory
14
+ INNER JOIN LATERAL (
15
+ SELECT identity.user_id
16
+ FROM junior_identities AS identity
17
+ WHERE identity.user_id IS NOT NULL
18
+ AND (
19
+ (
20
+ memory.scope_key LIKE 'slack:%'
21
+ AND identity.provider = 'slack'
22
+ AND identity.provider_tenant_id = split_part(memory.scope_key, ':', 2)
23
+ AND identity.provider_subject_id = split_part(memory.scope_key, ':', 3)
24
+ )
25
+ OR (
26
+ memory.scope_key LIKE 'local:%'
27
+ AND identity.provider = 'local'
28
+ AND identity.provider_subject_id = substring(memory.scope_key FROM 7)
29
+ )
30
+ OR (
31
+ memory.scope_key LIKE 'junior:%'
32
+ AND identity.provider = 'junior'
33
+ AND identity.provider_subject_id = substring(memory.scope_key FROM 8)
34
+ )
35
+ )
36
+ ORDER BY identity.id
37
+ LIMIT 1
38
+ ) AS owner ON memory.scope = 'personal'
39
+ $migration$;
40
+ END IF;
41
+ END
42
+ $$;--> statement-breakpoint
43
+ CREATE TEMP TABLE junior_memory_scope_targets ON COMMIT DROP AS
44
+ SELECT
45
+ memory.id,
46
+ CASE
47
+ WHEN memory.scope = 'conversation'
48
+ AND memory.source_platform = 'slack'
49
+ AND memory.scope_key = 'slack:' || split_part(memory.source_key, ':', 2)
50
+ THEN 'public'
51
+ ELSE 'private'
52
+ END AS target_scope,
53
+ CASE
54
+ WHEN memory.scope = 'conversation'
55
+ AND memory.source_platform = 'slack'
56
+ AND memory.scope_key = 'slack:' || split_part(memory.source_key, ':', 2)
57
+ THEN 'public'
58
+ WHEN memory.scope = 'personal' AND owner.user_id IS NOT NULL
59
+ THEN owner.user_id
60
+ ELSE 'legacy-unowned:' || memory.id
61
+ END AS target_scope_key,
62
+ (
63
+ memory.scope <> 'personal' AND NOT (
64
+ memory.scope = 'conversation'
65
+ AND memory.source_platform = 'slack'
66
+ AND memory.scope_key = 'slack:' || split_part(memory.source_key, ':', 2)
67
+ )
68
+ ) OR (memory.scope = 'personal' AND owner.user_id IS NULL) AS archive_unowned
69
+ FROM junior_memory_memories AS memory
70
+ LEFT JOIN junior_memory_legacy_owners AS owner ON owner.id = memory.id;--> statement-breakpoint
71
+ WITH duplicate_targets AS (
72
+ SELECT
73
+ memory.id,
74
+ row_number() OVER (
75
+ PARTITION BY target.target_scope, target.target_scope_key, memory.idempotency_key
76
+ ORDER BY memory.id
77
+ ) AS duplicate_rank
78
+ FROM junior_memory_memories AS memory
79
+ INNER JOIN junior_memory_scope_targets AS target ON target.id = memory.id
80
+ WHERE memory.idempotency_key IS NOT NULL
81
+ AND memory.archived_at_ms IS NULL
82
+ AND memory.superseded_at_ms IS NULL
83
+ AND memory.superseded_by_id IS NULL
84
+ AND NOT target.archive_unowned
85
+ )
86
+ UPDATE junior_memory_memories AS memory
87
+ SET idempotency_key = 'legacy-scope:' || memory.id
88
+ FROM duplicate_targets
89
+ WHERE memory.id = duplicate_targets.id
90
+ AND duplicate_targets.duplicate_rank > 1;--> statement-breakpoint
91
+ UPDATE junior_memory_memories AS memory
92
+ SET
93
+ scope = target.target_scope,
94
+ scope_key = target.target_scope_key,
95
+ subject_key = CASE
96
+ WHEN memory.subject_type = 'user' AND target.target_scope = 'private'
97
+ THEN target.target_scope_key
98
+ ELSE memory.subject_key
99
+ END,
100
+ archived_at_ms = CASE
101
+ WHEN target.archive_unowned
102
+ THEN coalesce(memory.archived_at_ms, floor(extract(epoch FROM clock_timestamp()) * 1000)::bigint)
103
+ ELSE memory.archived_at_ms
104
+ END,
105
+ archive_reason = CASE
106
+ WHEN target.archive_unowned
107
+ THEN coalesce(memory.archive_reason, 'legacy_unowned_scope')
108
+ ELSE memory.archive_reason
109
+ END
110
+ FROM junior_memory_scope_targets AS target
111
+ WHERE memory.id = target.id;--> statement-breakpoint
112
+ DROP TABLE junior_memory_scope_targets;--> statement-breakpoint
113
+ DROP TABLE junior_memory_legacy_owners;--> statement-breakpoint
114
+ ALTER TABLE "junior_memory_memories" ADD CONSTRAINT "junior_memory_memories_scope_check" CHECK ("junior_memory_memories"."scope" IN ('private', 'public'));
@@ -0,0 +1,50 @@
1
+ -- Rewrite pre-rename memories_captured v2 scope labels in conversation history.
2
+ -- personal -> private, conversation -> public. Leaves v1 rows alone.
3
+ -- No-op when core events are absent.
4
+ DO $$
5
+ BEGIN
6
+ IF to_regclass('public.junior_conversation_events') IS NULL THEN
7
+ RETURN;
8
+ END IF;
9
+
10
+ UPDATE junior_conversation_events AS event
11
+ SET payload = jsonb_set(
12
+ event.payload,
13
+ '{content,memories}',
14
+ (
15
+ SELECT coalesce(
16
+ jsonb_agg(
17
+ CASE
18
+ WHEN jsonb_typeof(memory.value) = 'object'
19
+ AND memory.value->>'scope' = 'personal'
20
+ THEN jsonb_set(memory.value, '{scope}', '"private"'::jsonb)
21
+ WHEN jsonb_typeof(memory.value) = 'object'
22
+ AND memory.value->>'scope' = 'conversation'
23
+ THEN jsonb_set(memory.value, '{scope}', '"public"'::jsonb)
24
+ ELSE memory.value
25
+ END
26
+ ORDER BY memory.ordinality
27
+ ),
28
+ '[]'::jsonb
29
+ )
30
+ FROM jsonb_array_elements(
31
+ CASE
32
+ WHEN jsonb_typeof(event.payload->'content'->'memories') = 'array'
33
+ THEN event.payload->'content'->'memories'
34
+ ELSE '[]'::jsonb
35
+ END
36
+ ) WITH ORDINALITY AS memory(value, ordinality)
37
+ )
38
+ )
39
+ WHERE event.type = 'structured_event'
40
+ AND event.payload->>'namespace' = 'memory'
41
+ AND event.payload->>'name' = 'memories_captured'
42
+ AND (event.payload->>'version') = '2'
43
+ AND jsonb_typeof(event.payload->'content'->'memories') = 'array'
44
+ AND EXISTS (
45
+ SELECT 1
46
+ FROM jsonb_array_elements(event.payload->'content'->'memories') AS memory(value)
47
+ WHERE memory.value->>'scope' IN ('personal', 'conversation')
48
+ );
49
+ END
50
+ $$;