@sentry/junior-memory 0.124.1 → 0.124.2

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/api.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  /**
2
- * Authenticated REST resources for personal memories.
2
+ * Authenticated REST resources for viewer-visible memories.
3
3
  *
4
4
  * HTTP identity is one verified viewer. Linked platform actors are resolved
5
- * behind the route boundary and used only to authorize personal scopes.
5
+ * behind the route boundary and used only to authorize personal and public
6
+ * workspace scopes.
6
7
  */
7
8
  import { z } from "zod";
8
9
  import { type PluginRouteApp, type PluginUserPageActor } from "@sentry/junior-plugin-api";
@@ -18,6 +19,10 @@ export declare const memoryApiSchema: z.ZodObject<{
18
19
  knowledge: "knowledge";
19
20
  }>;
20
21
  observedAt: z.ZodISODateTime;
22
+ visibility: z.ZodEnum<{
23
+ public: "public";
24
+ private: "private";
25
+ }>;
21
26
  }, z.core.$strict>;
22
27
  export declare const memoryListResponseSchema: z.ZodObject<{
23
28
  memories: z.ZodArray<z.ZodObject<{
@@ -31,15 +36,18 @@ export declare const memoryListResponseSchema: z.ZodObject<{
31
36
  knowledge: "knowledge";
32
37
  }>;
33
38
  observedAt: z.ZodISODateTime;
39
+ visibility: z.ZodEnum<{
40
+ public: "public";
41
+ private: "private";
42
+ }>;
34
43
  }, z.core.$strict>>;
35
44
  nextCursor: z.ZodOptional<z.ZodString>;
36
45
  }, z.core.$strict>;
37
46
  export declare const memoryDashboardResponseSchema: z.ZodObject<{
38
47
  days: z.ZodArray<z.ZodObject<{
39
48
  date: z.ZodISODate;
40
- knowledge: z.ZodNumber;
41
- preference: z.ZodNumber;
42
- procedure: z.ZodNumber;
49
+ personal: z.ZodNumber;
50
+ public: z.ZodNumber;
43
51
  }, z.core.$strict>>;
44
52
  generatedAt: z.ZodISODateTime;
45
53
  stats: z.ZodObject<{
@@ -49,8 +57,10 @@ export declare const memoryDashboardResponseSchema: z.ZodObject<{
49
57
  embedded: z.ZodNumber;
50
58
  explicit: z.ZodNumber;
51
59
  knowledge: z.ZodNumber;
60
+ personal: z.ZodNumber;
52
61
  preference: z.ZodNumber;
53
62
  procedure: z.ZodNumber;
63
+ public: z.ZodNumber;
54
64
  }, z.core.$strict>;
55
65
  }, z.core.$strict>;
56
66
  export type MemoryApi = z.output<typeof memoryApiSchema>;
@@ -60,6 +70,6 @@ interface MemoryApiOptions {
60
70
  actors(email: string): Promise<PluginUserPageActor[]>;
61
71
  db: MemoryDb;
62
72
  }
63
- /** Create the authenticated personal-memory REST app. */
73
+ /** Create the authenticated viewer-memory REST app. */
64
74
  export declare function createMemoryApi(options: MemoryApiOptions): PluginRouteApp;
65
75
  export {};
package/dist/index.js CHANGED
@@ -496,12 +496,12 @@ function visibleScopePredicate(scopes) {
496
496
  );
497
497
  }
498
498
  function activeVisiblePredicate(args) {
499
- const scopePredicate = visibleScopePredicate(args.scopes);
500
- if (!scopePredicate) {
499
+ const scopePredicate2 = visibleScopePredicate(args.scopes);
500
+ if (!scopePredicate2) {
501
501
  return void 0;
502
502
  }
503
503
  return and(
504
- scopePredicate,
504
+ scopePredicate2,
505
505
  isNull(juniorMemoryMemories.archivedAtMs),
506
506
  isNull(juniorMemoryMemories.supersededAtMs),
507
507
  isNull(juniorMemoryMemories.supersededById),
@@ -571,12 +571,12 @@ async function findByIdempotencyKey(args) {
571
571
  return void 0;
572
572
  }
573
573
  async function archiveExpiredMemoryBatch(args) {
574
- const scopePredicate = visibleScopePredicate(args.scopes);
575
- if (!scopePredicate) {
574
+ const scopePredicate2 = visibleScopePredicate(args.scopes);
575
+ if (!scopePredicate2) {
576
576
  return { archivedCount: 0 };
577
577
  }
578
578
  const predicates = [
579
- scopePredicate,
579
+ scopePredicate2,
580
580
  isNull(juniorMemoryMemories.archivedAtMs),
581
581
  isNull(juniorMemoryMemories.supersededAtMs),
582
582
  isNull(juniorMemoryMemories.supersededById),
@@ -1765,6 +1765,7 @@ import { z as z5 } from "zod";
1765
1765
  import { and as and2, asc as asc2, desc as desc2, eq as eq2, gt as gt2, ilike, like as like2, lt, or as or2, sql as sql3 } from "drizzle-orm";
1766
1766
  import { z as z4 } from "zod";
1767
1767
  var nonEmptyStringSchema3 = z4.string().min(1);
1768
+ var memoryVisibilitySchema = z4.enum(["private", "public"]);
1768
1769
  var personalMemoryCursorSchema = z4.object({
1769
1770
  createdAtMs: z4.number().finite(),
1770
1771
  id: nonEmptyStringSchema3
@@ -1774,7 +1775,8 @@ var personalMemoryPageInputSchema = z4.object({
1774
1775
  kind: z4.enum(MEMORY_KINDS).optional(),
1775
1776
  limit: z4.number().int().min(1).max(50),
1776
1777
  origin: z4.enum(["automatic", "explicit"]).optional(),
1777
- query: z4.string().max(200).optional()
1778
+ query: z4.string().max(200).optional(),
1779
+ visibility: memoryVisibilitySchema.optional()
1778
1780
  }).strict();
1779
1781
  var personalMemoryTimelineInputSchema = z4.object({
1780
1782
  days: z4.number().int().min(1).max(365)
@@ -1796,7 +1798,26 @@ function personalScopes(runtimeContexts) {
1796
1798
  ).values()
1797
1799
  ];
1798
1800
  }
1799
- function personalScopePredicate(scopes) {
1801
+ function publicWorkspaceScopes(runtimeContexts) {
1802
+ return [
1803
+ ...new Map(
1804
+ runtimeContexts.flatMap((context) => {
1805
+ if (context.source.platform !== "slack" || !context.actor) {
1806
+ return [];
1807
+ }
1808
+ if (context.actor.platform !== "slack") {
1809
+ return [];
1810
+ }
1811
+ const scope = {
1812
+ scope: "conversation",
1813
+ scopeKey: `slack:${context.actor.teamId}`
1814
+ };
1815
+ return [[`${scope.scope}:${scope.scopeKey}`, scope]];
1816
+ })
1817
+ ).values()
1818
+ ];
1819
+ }
1820
+ function scopePredicate(scopes) {
1800
1821
  if (scopes.length === 0) return void 0;
1801
1822
  return or2(
1802
1823
  ...scopes.map(
@@ -1822,21 +1843,50 @@ function memoryOrigin(idempotencyKey) {
1822
1843
  if (idempotencyKey?.startsWith("tool:")) return "explicit";
1823
1844
  return "other";
1824
1845
  }
1846
+ function memoryVisibility(scope) {
1847
+ return scope === "personal" ? "private" : "public";
1848
+ }
1825
1849
  function personalMemoryRecord(row) {
1850
+ const memory = parseMemoryRow(row);
1826
1851
  return {
1827
- ...parseMemoryRow(row),
1852
+ ...memory,
1828
1853
  origin: memoryOrigin(row.idempotencyKey),
1829
- sourcePlatform: row.sourcePlatform
1854
+ sourcePlatform: row.sourcePlatform,
1855
+ visibility: memoryVisibility(memory.scope)
1856
+ };
1857
+ }
1858
+ function emptyStats() {
1859
+ return {
1860
+ active: 0,
1861
+ automatic: 0,
1862
+ createdThirtyDays: 0,
1863
+ embedded: 0,
1864
+ explicit: 0,
1865
+ knowledge: 0,
1866
+ personal: 0,
1867
+ preference: 0,
1868
+ procedure: 0,
1869
+ public: 0
1830
1870
  };
1831
1871
  }
1832
1872
  function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1833
- const scopes = personalScopes(runtimeContexts);
1873
+ const privateScopes = personalScopes(runtimeContexts);
1874
+ const publicScopes = publicWorkspaceScopes(runtimeContexts);
1875
+ const allScopes = [...privateScopes, ...publicScopes];
1834
1876
  const getNowMs = () => options.now?.() ?? Date.now();
1877
+ function scopesForVisibility(visibility) {
1878
+ if (visibility === "private") return privateScopes;
1879
+ if (visibility === "public") return publicScopes;
1880
+ return allScopes;
1881
+ }
1835
1882
  return {
1836
1883
  async archive(id) {
1837
1884
  const memoryId = nonEmptyStringSchema3.parse(id);
1838
1885
  const nowMs = getNowMs();
1839
- const predicate = activeVisiblePredicate({ nowMs, scopes });
1886
+ const predicate = activeVisiblePredicate({
1887
+ nowMs,
1888
+ scopes: privateScopes
1889
+ });
1840
1890
  if (!predicate) {
1841
1891
  throw new PersonalMemoryNotFoundError();
1842
1892
  }
@@ -1853,7 +1903,7 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1853
1903
  async get(id) {
1854
1904
  const memoryId = nonEmptyStringSchema3.parse(id);
1855
1905
  const nowMs = getNowMs();
1856
- const predicate = activeVisiblePredicate({ nowMs, scopes });
1906
+ const predicate = activeVisiblePredicate({ nowMs, scopes: allScopes });
1857
1907
  if (!predicate) {
1858
1908
  throw new PersonalMemoryNotFoundError();
1859
1909
  }
@@ -1861,11 +1911,12 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1861
1911
  if (!rows[0]) {
1862
1912
  throw new PersonalMemoryNotFoundError();
1863
1913
  }
1864
- return parseMemoryRow(rows[0]);
1914
+ return personalMemoryRecord(rows[0]);
1865
1915
  },
1866
1916
  async list(input) {
1867
1917
  input = personalMemoryPageInputSchema.parse(input);
1868
1918
  const nowMs = getNowMs();
1919
+ const scopes = scopesForVisibility(input.visibility);
1869
1920
  await archiveExpiredMemoryBatch({ db, nowMs, scopes });
1870
1921
  const active = activeVisiblePredicate({ nowMs, scopes });
1871
1922
  if (!active) {
@@ -1905,19 +1956,10 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1905
1956
  },
1906
1957
  async stats() {
1907
1958
  const nowMs = getNowMs();
1908
- await archiveExpiredMemoryBatch({ db, nowMs, scopes });
1909
- const active = activeVisiblePredicate({ nowMs, scopes });
1959
+ await archiveExpiredMemoryBatch({ db, nowMs, scopes: allScopes });
1960
+ const active = activeVisiblePredicate({ nowMs, scopes: allScopes });
1910
1961
  if (!active) {
1911
- return {
1912
- active: 0,
1913
- automatic: 0,
1914
- createdThirtyDays: 0,
1915
- embedded: 0,
1916
- explicit: 0,
1917
- knowledge: 0,
1918
- preference: 0,
1919
- procedure: 0
1920
- };
1962
+ return emptyStats();
1921
1963
  }
1922
1964
  const [counts] = await db.select({
1923
1965
  active: sql3`count(*)`.mapWith(Number),
@@ -1936,11 +1978,17 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1936
1978
  knowledge: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'knowledge')`.mapWith(
1937
1979
  Number
1938
1980
  ),
1981
+ personal: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'personal')`.mapWith(
1982
+ Number
1983
+ ),
1939
1984
  preference: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'preference')`.mapWith(
1940
1985
  Number
1941
1986
  ),
1942
1987
  procedure: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'procedure')`.mapWith(
1943
1988
  Number
1989
+ ),
1990
+ public: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'conversation')`.mapWith(
1991
+ Number
1944
1992
  )
1945
1993
  }).from(juniorMemoryMemories).leftJoin(
1946
1994
  juniorMemoryEmbeddings,
@@ -1953,34 +2001,32 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1953
2001
  embedded: counts?.embedded ?? 0,
1954
2002
  explicit: counts?.explicit ?? 0,
1955
2003
  knowledge: counts?.knowledge ?? 0,
2004
+ personal: counts?.personal ?? 0,
1956
2005
  preference: counts?.preference ?? 0,
1957
- procedure: counts?.procedure ?? 0
2006
+ procedure: counts?.procedure ?? 0,
2007
+ public: counts?.public ?? 0
1958
2008
  };
1959
2009
  },
1960
2010
  async timeline(input) {
1961
2011
  input = personalMemoryTimelineInputSchema.parse(input);
1962
2012
  const todayMs = Date.parse(`${utcDate(getNowMs())}T00:00:00.000Z`);
1963
2013
  const startMs = todayMs - (input.days - 1) * DAY_MS;
1964
- const ownership = personalScopePredicate(scopes);
2014
+ const ownership = scopePredicate(allScopes);
1965
2015
  if (!ownership) {
1966
2016
  return Array.from({ length: input.days }, (_, index2) => ({
1967
2017
  date: utcDate(startMs + index2 * DAY_MS),
1968
- knowledge: 0,
1969
- preference: 0,
1970
- procedure: 0
2018
+ personal: 0,
2019
+ public: 0
1971
2020
  }));
1972
2021
  }
1973
2022
  const rows = await db.select({
1974
2023
  date: sql3`to_char(to_timestamp(${juniorMemoryMemories.createdAtMs} / 1000.0) AT TIME ZONE 'UTC', 'YYYY-MM-DD')`.as(
1975
2024
  "date"
1976
2025
  ),
1977
- knowledge: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'knowledge')`.mapWith(
1978
- Number
1979
- ),
1980
- preference: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'preference')`.mapWith(
2026
+ personal: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'personal')`.mapWith(
1981
2027
  Number
1982
2028
  ),
1983
- procedure: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'procedure')`.mapWith(
2029
+ public: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'conversation')`.mapWith(
1984
2030
  Number
1985
2031
  )
1986
2032
  }).from(juniorMemoryMemories).where(
@@ -1994,9 +2040,8 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1994
2040
  const row = byDate.get(date);
1995
2041
  return {
1996
2042
  date,
1997
- knowledge: row?.knowledge ?? 0,
1998
- preference: row?.preference ?? 0,
1999
- procedure: row?.procedure ?? 0
2043
+ personal: row?.personal ?? 0,
2044
+ public: row?.public ?? 0
2000
2045
  };
2001
2046
  });
2002
2047
  }
@@ -2010,7 +2055,8 @@ var cursorSchema = z5.object({
2010
2055
  kind: z5.enum(["preference", "procedure", "knowledge"]).optional(),
2011
2056
  origin: z5.enum(["automatic", "explicit"]).optional(),
2012
2057
  query: z5.string().max(200).optional(),
2013
- version: z5.literal(1)
2058
+ version: z5.literal(1),
2059
+ visibility: z5.enum(["private", "public"]).optional()
2014
2060
  }).strict();
2015
2061
  var InvalidMemoryCursorError = class extends Error {
2016
2062
  constructor() {
@@ -2045,7 +2091,7 @@ function decodeCursor(value, input) {
2045
2091
  const parsed = cursorSchema.parse(
2046
2092
  JSON.parse(Buffer.from(value, "base64url").toString("utf8"))
2047
2093
  );
2048
- if (parsed.query !== input.query || parsed.kind !== input.kind || parsed.origin !== input.origin) {
2094
+ if (parsed.query !== input.query || parsed.kind !== input.kind || parsed.origin !== input.origin || parsed.visibility !== input.visibility) {
2049
2095
  throw new InvalidMemoryCursorError();
2050
2096
  }
2051
2097
  return { createdAtMs: parsed.createdAtMs, id: parsed.id };
@@ -2060,6 +2106,7 @@ function encodeCursor(cursor, input) {
2060
2106
  ...input.query ? { query: input.query } : {},
2061
2107
  ...input.kind ? { kind: input.kind } : {},
2062
2108
  ...input.origin ? { origin: input.origin } : {},
2109
+ ...input.visibility ? { visibility: input.visibility } : {},
2063
2110
  version: 1
2064
2111
  }),
2065
2112
  "utf8"
@@ -2082,7 +2129,8 @@ function createViewerMemories(db, actors) {
2082
2129
  const filters = {
2083
2130
  ...input.kind ? { kind: input.kind } : {},
2084
2131
  ...input.origin ? { origin: input.origin } : {},
2085
- ...query ? { query } : {}
2132
+ ...query ? { query } : {},
2133
+ ...input.visibility ? { visibility: input.visibility } : {}
2086
2134
  };
2087
2135
  const page = await collection.list({
2088
2136
  cursor: decodeCursor(input.cursor, filters),
@@ -2110,7 +2158,8 @@ var memoryApiSchema = z6.object({
2110
2158
  expiresAt: z6.iso.datetime().optional(),
2111
2159
  id: z6.string().min(1),
2112
2160
  kind: z6.enum(["preference", "procedure", "knowledge"]),
2113
- observedAt: z6.iso.datetime()
2161
+ observedAt: z6.iso.datetime(),
2162
+ visibility: z6.enum(["private", "public"])
2114
2163
  }).strict();
2115
2164
  var memoryListResponseSchema = z6.object({
2116
2165
  memories: z6.array(memoryApiSchema),
@@ -2118,9 +2167,8 @@ var memoryListResponseSchema = z6.object({
2118
2167
  }).strict();
2119
2168
  var memoryDashboardDaySchema = z6.object({
2120
2169
  date: z6.iso.date(),
2121
- knowledge: z6.number().int().min(0),
2122
- preference: z6.number().int().min(0),
2123
- procedure: z6.number().int().min(0)
2170
+ personal: z6.number().int().min(0),
2171
+ public: z6.number().int().min(0)
2124
2172
  }).strict();
2125
2173
  var memoryDashboardResponseSchema = z6.object({
2126
2174
  days: z6.array(memoryDashboardDaySchema).length(90),
@@ -2132,8 +2180,10 @@ var memoryDashboardResponseSchema = z6.object({
2132
2180
  embedded: z6.number().int().min(0),
2133
2181
  explicit: z6.number().int().min(0),
2134
2182
  knowledge: z6.number().int().min(0),
2183
+ personal: z6.number().int().min(0),
2135
2184
  preference: z6.number().int().min(0),
2136
- procedure: z6.number().int().min(0)
2185
+ procedure: z6.number().int().min(0),
2186
+ public: z6.number().int().min(0)
2137
2187
  }).strict()
2138
2188
  }).strict();
2139
2189
  var memoryListQuerySchema = z6.object({
@@ -2154,7 +2204,8 @@ function apiMemory(memory) {
2154
2204
  ...memory.expiresAtMs !== void 0 ? { expiresAt: new Date(memory.expiresAtMs).toISOString() } : {},
2155
2205
  id: memory.id,
2156
2206
  kind: memory.kind,
2157
- observedAt: new Date(memory.observedAtMs).toISOString()
2207
+ observedAt: new Date(memory.observedAtMs).toISOString(),
2208
+ visibility: memory.visibility
2158
2209
  };
2159
2210
  }
2160
2211
  function viewerEmail(context) {
@@ -3281,25 +3332,26 @@ function originLabel(origin) {
3281
3332
  if (origin === "explicit") return "Explicit";
3282
3333
  return "Other";
3283
3334
  }
3335
+ function visibilityLabel(visibility) {
3336
+ return visibility === "public" ? "Public" : "Private";
3337
+ }
3284
3338
  function pageFilter(filter) {
3285
- if (filter === "preferences") return { kind: "preference" };
3286
- if (filter === "automatic") return { origin: "automatic" };
3287
- if (filter === "explicit") return { origin: "explicit" };
3339
+ if (filter === "private") return { visibility: "private" };
3340
+ if (filter === "public") return { visibility: "public" };
3288
3341
  return {};
3289
3342
  }
3290
3343
  function pageEmptyText(input) {
3291
3344
  if (input.query) return "No memories matched your search.";
3292
- if (input.filter === "preferences") return "No preferences yet.";
3293
- if (input.filter === "automatic") return "No learned memories yet.";
3294
- if (input.filter === "explicit") return "No saved memories yet.";
3295
- return "No personal memories yet.";
3345
+ if (input.filter === "private") return "No private memories yet.";
3346
+ if (input.filter === "public") return "No public memories yet.";
3347
+ return "No memories yet.";
3296
3348
  }
3297
3349
  function createMemoryUserPage() {
3298
3350
  return {
3299
3351
  id: "memories",
3300
3352
  label: "Memories",
3301
3353
  navigation: "primary",
3302
- description: "Personal facts and preferences Junior remembers about you.",
3354
+ description: "Personal and public memories Junior can use across conversations.",
3303
3355
  async read(ctx, input) {
3304
3356
  const memories = createViewerMemories(
3305
3357
  ctx.db,
@@ -3317,7 +3369,7 @@ function createMemoryUserPage() {
3317
3369
  ...page.nextCursor ? { nextCursor: page.nextCursor } : {},
3318
3370
  searchPlaceholder: "Search memories",
3319
3371
  records: page.memories.map((memory) => ({
3320
- actions: [
3372
+ actions: memory.visibility === "private" ? [
3321
3373
  {
3322
3374
  confirmation: "Forget this memory?",
3323
3375
  href: `/api/plugins/memory/memories/${encodeURIComponent(memory.id)}`,
@@ -3325,14 +3377,17 @@ function createMemoryUserPage() {
3325
3377
  method: "DELETE",
3326
3378
  tone: "danger"
3327
3379
  }
3328
- ],
3380
+ ] : [],
3329
3381
  id: memory.id,
3330
3382
  title: memory.content,
3331
3383
  metadata: [
3332
3384
  { label: "Type", value: titleCase(memory.kind) },
3333
3385
  { label: "Learned", value: originLabel(memory.origin) },
3334
3386
  { label: "Source", value: titleCase(memory.sourcePlatform) },
3335
- { label: "Visibility", value: "Only you" },
3387
+ {
3388
+ label: "Visibility",
3389
+ value: visibilityLabel(memory.visibility)
3390
+ },
3336
3391
  { label: "Remembered", value: rememberedDate(memory.createdAtMs) },
3337
3392
  { label: "Observed", value: rememberedDate(memory.observedAtMs) },
3338
3393
  {