@sentry/junior-memory 0.124.1 → 0.125.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.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,
@@ -496,12 +497,12 @@ function visibleScopePredicate(scopes) {
496
497
  );
497
498
  }
498
499
  function activeVisiblePredicate(args) {
499
- const scopePredicate = visibleScopePredicate(args.scopes);
500
- if (!scopePredicate) {
500
+ const scopePredicate2 = visibleScopePredicate(args.scopes);
501
+ if (!scopePredicate2) {
501
502
  return void 0;
502
503
  }
503
504
  return and(
504
- scopePredicate,
505
+ scopePredicate2,
505
506
  isNull(juniorMemoryMemories.archivedAtMs),
506
507
  isNull(juniorMemoryMemories.supersededAtMs),
507
508
  isNull(juniorMemoryMemories.supersededById),
@@ -571,12 +572,12 @@ async function findByIdempotencyKey(args) {
571
572
  return void 0;
572
573
  }
573
574
  async function archiveExpiredMemoryBatch(args) {
574
- const scopePredicate = visibleScopePredicate(args.scopes);
575
- if (!scopePredicate) {
575
+ const scopePredicate2 = visibleScopePredicate(args.scopes);
576
+ if (!scopePredicate2) {
576
577
  return { archivedCount: 0 };
577
578
  }
578
579
  const predicates = [
579
- scopePredicate,
580
+ scopePredicate2,
580
581
  isNull(juniorMemoryMemories.archivedAtMs),
581
582
  isNull(juniorMemoryMemories.supersededAtMs),
582
583
  isNull(juniorMemoryMemories.supersededById),
@@ -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 [...new Set(decision.relevantIds)].filter(
1684
- (id) => candidateIds.has(id)
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 extractedMemoriesFromResponse(
1706
- extractMemoriesResponseSchema.parse(result.object)
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);
@@ -1765,6 +1772,7 @@ import { z as z5 } from "zod";
1765
1772
  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
1773
  import { z as z4 } from "zod";
1767
1774
  var nonEmptyStringSchema3 = z4.string().min(1);
1775
+ var memoryVisibilitySchema = z4.enum(["private", "public"]);
1768
1776
  var personalMemoryCursorSchema = z4.object({
1769
1777
  createdAtMs: z4.number().finite(),
1770
1778
  id: nonEmptyStringSchema3
@@ -1774,7 +1782,8 @@ var personalMemoryPageInputSchema = z4.object({
1774
1782
  kind: z4.enum(MEMORY_KINDS).optional(),
1775
1783
  limit: z4.number().int().min(1).max(50),
1776
1784
  origin: z4.enum(["automatic", "explicit"]).optional(),
1777
- query: z4.string().max(200).optional()
1785
+ query: z4.string().max(200).optional(),
1786
+ visibility: memoryVisibilitySchema.optional()
1778
1787
  }).strict();
1779
1788
  var personalMemoryTimelineInputSchema = z4.object({
1780
1789
  days: z4.number().int().min(1).max(365)
@@ -1796,7 +1805,26 @@ function personalScopes(runtimeContexts) {
1796
1805
  ).values()
1797
1806
  ];
1798
1807
  }
1799
- function personalScopePredicate(scopes) {
1808
+ function publicWorkspaceScopes(runtimeContexts) {
1809
+ return [
1810
+ ...new Map(
1811
+ runtimeContexts.flatMap((context) => {
1812
+ if (context.source.platform !== "slack" || !context.actor) {
1813
+ return [];
1814
+ }
1815
+ if (context.actor.platform !== "slack") {
1816
+ return [];
1817
+ }
1818
+ const scope = {
1819
+ scope: "conversation",
1820
+ scopeKey: `slack:${context.actor.teamId}`
1821
+ };
1822
+ return [[`${scope.scope}:${scope.scopeKey}`, scope]];
1823
+ })
1824
+ ).values()
1825
+ ];
1826
+ }
1827
+ function scopePredicate(scopes) {
1800
1828
  if (scopes.length === 0) return void 0;
1801
1829
  return or2(
1802
1830
  ...scopes.map(
@@ -1822,21 +1850,50 @@ function memoryOrigin(idempotencyKey) {
1822
1850
  if (idempotencyKey?.startsWith("tool:")) return "explicit";
1823
1851
  return "other";
1824
1852
  }
1853
+ function memoryVisibility(scope) {
1854
+ return scope === "personal" ? "private" : "public";
1855
+ }
1825
1856
  function personalMemoryRecord(row) {
1857
+ const memory = parseMemoryRow(row);
1826
1858
  return {
1827
- ...parseMemoryRow(row),
1859
+ ...memory,
1828
1860
  origin: memoryOrigin(row.idempotencyKey),
1829
- sourcePlatform: row.sourcePlatform
1861
+ sourcePlatform: row.sourcePlatform,
1862
+ visibility: memoryVisibility(memory.scope)
1863
+ };
1864
+ }
1865
+ function emptyStats() {
1866
+ return {
1867
+ active: 0,
1868
+ automatic: 0,
1869
+ createdThirtyDays: 0,
1870
+ embedded: 0,
1871
+ explicit: 0,
1872
+ knowledge: 0,
1873
+ personal: 0,
1874
+ preference: 0,
1875
+ procedure: 0,
1876
+ public: 0
1830
1877
  };
1831
1878
  }
1832
1879
  function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1833
- const scopes = personalScopes(runtimeContexts);
1880
+ const privateScopes = personalScopes(runtimeContexts);
1881
+ const publicScopes = publicWorkspaceScopes(runtimeContexts);
1882
+ const allScopes = [...privateScopes, ...publicScopes];
1834
1883
  const getNowMs = () => options.now?.() ?? Date.now();
1884
+ function scopesForVisibility(visibility) {
1885
+ if (visibility === "private") return privateScopes;
1886
+ if (visibility === "public") return publicScopes;
1887
+ return allScopes;
1888
+ }
1835
1889
  return {
1836
1890
  async archive(id) {
1837
1891
  const memoryId = nonEmptyStringSchema3.parse(id);
1838
1892
  const nowMs = getNowMs();
1839
- const predicate = activeVisiblePredicate({ nowMs, scopes });
1893
+ const predicate = activeVisiblePredicate({
1894
+ nowMs,
1895
+ scopes: privateScopes
1896
+ });
1840
1897
  if (!predicate) {
1841
1898
  throw new PersonalMemoryNotFoundError();
1842
1899
  }
@@ -1853,7 +1910,7 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1853
1910
  async get(id) {
1854
1911
  const memoryId = nonEmptyStringSchema3.parse(id);
1855
1912
  const nowMs = getNowMs();
1856
- const predicate = activeVisiblePredicate({ nowMs, scopes });
1913
+ const predicate = activeVisiblePredicate({ nowMs, scopes: allScopes });
1857
1914
  if (!predicate) {
1858
1915
  throw new PersonalMemoryNotFoundError();
1859
1916
  }
@@ -1861,11 +1918,12 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1861
1918
  if (!rows[0]) {
1862
1919
  throw new PersonalMemoryNotFoundError();
1863
1920
  }
1864
- return parseMemoryRow(rows[0]);
1921
+ return personalMemoryRecord(rows[0]);
1865
1922
  },
1866
1923
  async list(input) {
1867
1924
  input = personalMemoryPageInputSchema.parse(input);
1868
1925
  const nowMs = getNowMs();
1926
+ const scopes = scopesForVisibility(input.visibility);
1869
1927
  await archiveExpiredMemoryBatch({ db, nowMs, scopes });
1870
1928
  const active = activeVisiblePredicate({ nowMs, scopes });
1871
1929
  if (!active) {
@@ -1905,19 +1963,10 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1905
1963
  },
1906
1964
  async stats() {
1907
1965
  const nowMs = getNowMs();
1908
- await archiveExpiredMemoryBatch({ db, nowMs, scopes });
1909
- const active = activeVisiblePredicate({ nowMs, scopes });
1966
+ await archiveExpiredMemoryBatch({ db, nowMs, scopes: allScopes });
1967
+ const active = activeVisiblePredicate({ nowMs, scopes: allScopes });
1910
1968
  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
- };
1969
+ return emptyStats();
1921
1970
  }
1922
1971
  const [counts] = await db.select({
1923
1972
  active: sql3`count(*)`.mapWith(Number),
@@ -1936,11 +1985,17 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1936
1985
  knowledge: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'knowledge')`.mapWith(
1937
1986
  Number
1938
1987
  ),
1988
+ personal: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'personal')`.mapWith(
1989
+ Number
1990
+ ),
1939
1991
  preference: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'preference')`.mapWith(
1940
1992
  Number
1941
1993
  ),
1942
1994
  procedure: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'procedure')`.mapWith(
1943
1995
  Number
1996
+ ),
1997
+ public: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'conversation')`.mapWith(
1998
+ Number
1944
1999
  )
1945
2000
  }).from(juniorMemoryMemories).leftJoin(
1946
2001
  juniorMemoryEmbeddings,
@@ -1953,34 +2008,32 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1953
2008
  embedded: counts?.embedded ?? 0,
1954
2009
  explicit: counts?.explicit ?? 0,
1955
2010
  knowledge: counts?.knowledge ?? 0,
2011
+ personal: counts?.personal ?? 0,
1956
2012
  preference: counts?.preference ?? 0,
1957
- procedure: counts?.procedure ?? 0
2013
+ procedure: counts?.procedure ?? 0,
2014
+ public: counts?.public ?? 0
1958
2015
  };
1959
2016
  },
1960
2017
  async timeline(input) {
1961
2018
  input = personalMemoryTimelineInputSchema.parse(input);
1962
2019
  const todayMs = Date.parse(`${utcDate(getNowMs())}T00:00:00.000Z`);
1963
2020
  const startMs = todayMs - (input.days - 1) * DAY_MS;
1964
- const ownership = personalScopePredicate(scopes);
2021
+ const ownership = scopePredicate(allScopes);
1965
2022
  if (!ownership) {
1966
2023
  return Array.from({ length: input.days }, (_, index2) => ({
1967
2024
  date: utcDate(startMs + index2 * DAY_MS),
1968
- knowledge: 0,
1969
- preference: 0,
1970
- procedure: 0
2025
+ personal: 0,
2026
+ public: 0
1971
2027
  }));
1972
2028
  }
1973
2029
  const rows = await db.select({
1974
2030
  date: sql3`to_char(to_timestamp(${juniorMemoryMemories.createdAtMs} / 1000.0) AT TIME ZONE 'UTC', 'YYYY-MM-DD')`.as(
1975
2031
  "date"
1976
2032
  ),
1977
- knowledge: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'knowledge')`.mapWith(
2033
+ personal: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'personal')`.mapWith(
1978
2034
  Number
1979
2035
  ),
1980
- preference: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'preference')`.mapWith(
1981
- Number
1982
- ),
1983
- procedure: sql3`count(*) filter (where ${juniorMemoryMemories.kind} = 'procedure')`.mapWith(
2036
+ public: sql3`count(*) filter (where ${juniorMemoryMemories.scope} = 'conversation')`.mapWith(
1984
2037
  Number
1985
2038
  )
1986
2039
  }).from(juniorMemoryMemories).where(
@@ -1994,9 +2047,8 @@ function createPersonalMemoryCollection(db, runtimeContexts, options = {}) {
1994
2047
  const row = byDate.get(date);
1995
2048
  return {
1996
2049
  date,
1997
- knowledge: row?.knowledge ?? 0,
1998
- preference: row?.preference ?? 0,
1999
- procedure: row?.procedure ?? 0
2050
+ personal: row?.personal ?? 0,
2051
+ public: row?.public ?? 0
2000
2052
  };
2001
2053
  });
2002
2054
  }
@@ -2010,7 +2062,8 @@ var cursorSchema = z5.object({
2010
2062
  kind: z5.enum(["preference", "procedure", "knowledge"]).optional(),
2011
2063
  origin: z5.enum(["automatic", "explicit"]).optional(),
2012
2064
  query: z5.string().max(200).optional(),
2013
- version: z5.literal(1)
2065
+ version: z5.literal(1),
2066
+ visibility: z5.enum(["private", "public"]).optional()
2014
2067
  }).strict();
2015
2068
  var InvalidMemoryCursorError = class extends Error {
2016
2069
  constructor() {
@@ -2045,7 +2098,7 @@ function decodeCursor(value, input) {
2045
2098
  const parsed = cursorSchema.parse(
2046
2099
  JSON.parse(Buffer.from(value, "base64url").toString("utf8"))
2047
2100
  );
2048
- if (parsed.query !== input.query || parsed.kind !== input.kind || parsed.origin !== input.origin) {
2101
+ if (parsed.query !== input.query || parsed.kind !== input.kind || parsed.origin !== input.origin || parsed.visibility !== input.visibility) {
2049
2102
  throw new InvalidMemoryCursorError();
2050
2103
  }
2051
2104
  return { createdAtMs: parsed.createdAtMs, id: parsed.id };
@@ -2060,6 +2113,7 @@ function encodeCursor(cursor, input) {
2060
2113
  ...input.query ? { query: input.query } : {},
2061
2114
  ...input.kind ? { kind: input.kind } : {},
2062
2115
  ...input.origin ? { origin: input.origin } : {},
2116
+ ...input.visibility ? { visibility: input.visibility } : {},
2063
2117
  version: 1
2064
2118
  }),
2065
2119
  "utf8"
@@ -2082,7 +2136,8 @@ function createViewerMemories(db, actors) {
2082
2136
  const filters = {
2083
2137
  ...input.kind ? { kind: input.kind } : {},
2084
2138
  ...input.origin ? { origin: input.origin } : {},
2085
- ...query ? { query } : {}
2139
+ ...query ? { query } : {},
2140
+ ...input.visibility ? { visibility: input.visibility } : {}
2086
2141
  };
2087
2142
  const page = await collection.list({
2088
2143
  cursor: decodeCursor(input.cursor, filters),
@@ -2110,7 +2165,8 @@ var memoryApiSchema = z6.object({
2110
2165
  expiresAt: z6.iso.datetime().optional(),
2111
2166
  id: z6.string().min(1),
2112
2167
  kind: z6.enum(["preference", "procedure", "knowledge"]),
2113
- observedAt: z6.iso.datetime()
2168
+ observedAt: z6.iso.datetime(),
2169
+ visibility: z6.enum(["private", "public"])
2114
2170
  }).strict();
2115
2171
  var memoryListResponseSchema = z6.object({
2116
2172
  memories: z6.array(memoryApiSchema),
@@ -2118,12 +2174,17 @@ var memoryListResponseSchema = z6.object({
2118
2174
  }).strict();
2119
2175
  var memoryDashboardDaySchema = z6.object({
2120
2176
  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)
2177
+ personal: z6.number().int().min(0),
2178
+ public: z6.number().int().min(0)
2179
+ }).strict();
2180
+ var memoryExtractionDaySchema = z6.object({
2181
+ costUsd: z6.number().finite().nonnegative(),
2182
+ date: z6.iso.date(),
2183
+ events: z6.number().int().min(0)
2124
2184
  }).strict();
2125
2185
  var memoryDashboardResponseSchema = z6.object({
2126
2186
  days: z6.array(memoryDashboardDaySchema).length(90),
2187
+ extractionDays: z6.array(memoryExtractionDaySchema).length(90),
2127
2188
  generatedAt: z6.iso.datetime(),
2128
2189
  stats: z6.object({
2129
2190
  active: z6.number().int().min(0),
@@ -2132,8 +2193,10 @@ var memoryDashboardResponseSchema = z6.object({
2132
2193
  embedded: z6.number().int().min(0),
2133
2194
  explicit: z6.number().int().min(0),
2134
2195
  knowledge: z6.number().int().min(0),
2196
+ personal: z6.number().int().min(0),
2135
2197
  preference: z6.number().int().min(0),
2136
- procedure: z6.number().int().min(0)
2198
+ procedure: z6.number().int().min(0),
2199
+ public: z6.number().int().min(0)
2137
2200
  }).strict()
2138
2201
  }).strict();
2139
2202
  var memoryListQuerySchema = z6.object({
@@ -2154,7 +2217,8 @@ function apiMemory(memory) {
2154
2217
  ...memory.expiresAtMs !== void 0 ? { expiresAt: new Date(memory.expiresAtMs).toISOString() } : {},
2155
2218
  id: memory.id,
2156
2219
  kind: memory.kind,
2157
- observedAt: new Date(memory.observedAtMs).toISOString()
2220
+ observedAt: new Date(memory.observedAtMs).toISOString(),
2221
+ visibility: memory.visibility
2158
2222
  };
2159
2223
  }
2160
2224
  function viewerEmail(context) {
@@ -2182,12 +2246,17 @@ function createMemoryApi(options) {
2182
2246
  const memories = createViewerMemories(options.db, actors);
2183
2247
  try {
2184
2248
  if (isDashboard && (request.method === "GET" || request.method === "HEAD")) {
2185
- const [stats, days] = await Promise.all([
2249
+ const [stats, days, extractionDays] = await Promise.all([
2186
2250
  memories.stats(),
2187
- memories.timeline({ days: 90 })
2251
+ memories.timeline({ days: 90 }),
2252
+ options.eventStats.costsByDay({
2253
+ days: 90,
2254
+ eventName: "memories_captured"
2255
+ })
2188
2256
  ]);
2189
2257
  const body = memoryDashboardResponseSchema.parse({
2190
2258
  days,
2259
+ extractionDays,
2191
2260
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2192
2261
  stats
2193
2262
  });
@@ -2628,6 +2697,7 @@ function memoryToolResult(target, data) {
2628
2697
  }
2629
2698
  function createMemoryCreateTool(context) {
2630
2699
  return definePluginTool({
2700
+ approvalMode: "approve",
2631
2701
  annotations: {
2632
2702
  destructiveHint: false,
2633
2703
  idempotentHint: true,
@@ -2807,23 +2877,47 @@ function eventPreview(content) {
2807
2877
  if (trimmed.length <= MAX_EVENT_PREVIEW_CHARS) return trimmed;
2808
2878
  return `${trimmed.slice(0, MAX_EVENT_PREVIEW_CHARS - 3).trimEnd()}...`;
2809
2879
  }
2810
- var memoriesCapturedEvent = defineConversationEvent({
2880
+ var capturedMemoriesSchema = z8.object({
2881
+ memories: z8.array(capturedMemorySchema).max(100),
2882
+ costUsd: z8.number().finite().nonnegative().optional()
2883
+ }).strict();
2884
+ var recalledMemoriesSchema = z8.object({
2885
+ memories: z8.array(z8.string().min(1)).max(5),
2886
+ costUsd: z8.number().finite().nonnegative().optional()
2887
+ }).strict();
2888
+ function renderCapturedMemories(event) {
2889
+ const count = event.memories.length;
2890
+ if (count === 0) return void 0;
2891
+ return {
2892
+ icon: "brain",
2893
+ title: count === 1 ? "Memory captured" : "Memories captured",
2894
+ preview: count === 1 ? eventPreview(event.memories[0].content) : `${count} memories`,
2895
+ details: event.memories.map((memory) => ({
2896
+ title: memory.content,
2897
+ metadata: [memory.kind, memory.scope]
2898
+ }))
2899
+ };
2900
+ }
2901
+ var memoriesCapturedEventV1 = defineConversationEvent({
2811
2902
  name: "memories_captured",
2812
2903
  version: 1,
2813
2904
  schema: z8.object({
2814
2905
  memories: z8.array(capturedMemorySchema).min(1).max(100)
2815
2906
  }).strict(),
2816
- renderEvent(event) {
2817
- const count = event.memories.length;
2818
- return {
2819
- icon: "brain",
2820
- title: count === 1 ? "Memory captured" : "Memories captured",
2821
- preview: count === 1 ? eventPreview(event.memories[0].content) : `${count} memories`,
2822
- details: event.memories.map((memory) => ({
2823
- title: memory.content,
2824
- metadata: [memory.kind, memory.scope]
2825
- }))
2826
- };
2907
+ renderEvent: renderCapturedMemories
2908
+ });
2909
+ var memoriesCapturedEvent = defineConversationEvent({
2910
+ name: "memories_captured",
2911
+ version: 2,
2912
+ schema: capturedMemoriesSchema,
2913
+ renderEvent: renderCapturedMemories
2914
+ });
2915
+ var memoriesRecalledEvent = defineConversationEvent({
2916
+ name: "memories_recalled",
2917
+ version: 1,
2918
+ schema: recalledMemoriesSchema,
2919
+ renderEvent() {
2920
+ return void 0;
2827
2921
  }
2828
2922
  });
2829
2923
  function capturedMemory(memory) {
@@ -2844,14 +2938,19 @@ var MEMORY_TOOL_NAMES = /* @__PURE__ */ new Set([
2844
2938
  "searchMemories"
2845
2939
  ]);
2846
2940
  var MEMORY_TASK_STATE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
2847
- var extractedMemoryCacheSchema = z9.array(
2941
+ var extractedMemorySchema2 = z9.object({
2942
+ content: z9.string().min(1),
2943
+ expiresAtMs: z9.number().finite().nullable(),
2944
+ kind: z9.enum(MEMORY_KINDS),
2945
+ evidenceMessageIndices: z9.array(z9.number().int().nonnegative()).min(1).max(10)
2946
+ }).strict().transform(parseExtractedMemory);
2947
+ var extractedMemoryCacheSchema = z9.union([
2848
2948
  z9.object({
2849
- content: z9.string().min(1),
2850
- expiresAtMs: z9.number().finite().nullable(),
2851
- kind: z9.enum(MEMORY_KINDS),
2852
- evidenceMessageIndices: z9.array(z9.number().int().nonnegative()).min(1).max(10)
2853
- }).strict().transform(parseExtractedMemory)
2854
- );
2949
+ costUsd: z9.number().finite().nonnegative().optional(),
2950
+ memories: z9.array(extractedMemorySchema2).max(5)
2951
+ }).strict(),
2952
+ z9.array(extractedMemorySchema2).max(5).transform((memories) => ({ memories }))
2953
+ ]);
2855
2954
  function recordCapturedMemory(captured, result) {
2856
2955
  const supersededIds = new Set(result.supersededIds ?? []);
2857
2956
  for (let index2 = captured.length - 1; index2 >= 0; index2 -= 1) {
@@ -2918,7 +3017,7 @@ function passiveInput(sessionId, memory, sourceKey2, target) {
2918
3017
  ...memory.expiresAtMs !== null ? { expiresAtMs: memory.expiresAtMs } : {}
2919
3018
  };
2920
3019
  }
2921
- async function getTaskMemories(context, extract) {
3020
+ async function getTaskExtraction(context, extract) {
2922
3021
  const cacheKey = `memory-extraction:${context.id}`;
2923
3022
  const cached = await context.state.get(cacheKey);
2924
3023
  if (cached !== void 0) {
@@ -2928,11 +3027,9 @@ async function getTaskMemories(context, extract) {
2928
3027
  }
2929
3028
  await context.state.delete(cacheKey);
2930
3029
  }
2931
- const memories = await extract();
2932
- if (memories.length > 0) {
2933
- await context.state.set(cacheKey, memories, MEMORY_TASK_STATE_TTL_MS);
2934
- }
2935
- return memories;
3030
+ const extraction = await extract();
3031
+ await context.state.set(cacheKey, extraction, MEMORY_TASK_STATE_TTL_MS);
3032
+ return extraction;
2936
3033
  }
2937
3034
  async function processMemorySession(context) {
2938
3035
  const run = await context.run.load();
@@ -2964,7 +3061,7 @@ async function processMemorySession(context) {
2964
3061
  supersessionDecider: agent
2965
3062
  });
2966
3063
  await store.archiveExpiredMemories();
2967
- const memories = await getTaskMemories(context, async () => {
3064
+ const extraction = await getTaskExtraction(context, async () => {
2968
3065
  const existingMemories = await store.searchMemories({
2969
3066
  limit: 10,
2970
3067
  query: evidenceText
@@ -2978,11 +3075,8 @@ async function processMemorySession(context) {
2978
3075
  runtimeContext: runtimeContext2
2979
3076
  });
2980
3077
  });
2981
- if (memories.length === 0) {
2982
- return;
2983
- }
2984
3078
  const captured = [];
2985
- for (const memory of memories) {
3079
+ for (const memory of extraction.memories) {
2986
3080
  const target = routeExtractedMemory(memory, transcript, run);
2987
3081
  if (target === "drop") {
2988
3082
  continue;
@@ -2996,9 +3090,12 @@ async function processMemorySession(context) {
2996
3090
  const result = await store.createMemory(input);
2997
3091
  recordCapturedMemory(captured, result);
2998
3092
  }
2999
- if (captured.length > 0) {
3000
- await context.events.emit(memoriesCapturedEvent({ memories: captured }));
3001
- }
3093
+ await context.events.emit(
3094
+ memoriesCapturedEvent({
3095
+ memories: captured,
3096
+ ...extraction.costUsd !== void 0 ? { costUsd: extraction.costUsd } : {}
3097
+ })
3098
+ );
3002
3099
  }
3003
3100
 
3004
3101
  // src/recall.ts
@@ -3062,6 +3159,19 @@ function renderMemoryPrompt(memories) {
3062
3159
  "Treat these as possibly stale context. Current user instructions and repository evidence take priority."
3063
3160
  ].join("\n");
3064
3161
  }
3162
+ function addUsd(left, right) {
3163
+ if (left === void 0) return right;
3164
+ if (right === void 0) return left;
3165
+ return Math.round((left + right) * 1e12) / 1e12;
3166
+ }
3167
+ async function emitRecallOutcome(args) {
3168
+ await args.events?.emit(
3169
+ memoriesRecalledEvent({
3170
+ memories: args.memories,
3171
+ ...args.costUsd !== void 0 ? { costUsd: args.costUsd } : {}
3172
+ })
3173
+ );
3174
+ }
3065
3175
  var memoryRecallContext = definePromptContext({
3066
3176
  kind: "recall",
3067
3177
  version: 1,
@@ -3077,19 +3187,33 @@ async function createMemoryPromptContributions(context) {
3077
3187
  ...context.actor ? { actor: context.actor } : {},
3078
3188
  source: context.source
3079
3189
  });
3190
+ let embeddingCostUsd;
3191
+ const sourceEmbedder = context.embedder;
3192
+ const embedder = sourceEmbedder ? {
3193
+ async embedTexts(input) {
3194
+ const result = await sourceEmbedder.embedTexts(input);
3195
+ embeddingCostUsd = addUsd(embeddingCostUsd, result.costUsd);
3196
+ return result;
3197
+ }
3198
+ } : void 0;
3080
3199
  const candidates = await createMemoryStore(context.db, runtimeContext2, {
3081
- ...context.embedder ? { embedder: context.embedder } : {},
3200
+ ...embedder ? { embedder } : {},
3082
3201
  ...context.maxVectorDistance !== void 0 ? { maxVectorDistance: context.maxVectorDistance } : {}
3083
3202
  }).recallMemories({
3084
3203
  query: context.text,
3085
3204
  limit: RECALL_CANDIDATE_LIMIT
3086
3205
  });
3087
3206
  if (candidates.length === 0) {
3207
+ await emitRecallOutcome({
3208
+ ...embeddingCostUsd !== void 0 ? { costUsd: embeddingCostUsd } : {},
3209
+ events: context.events,
3210
+ memories: []
3211
+ });
3088
3212
  return void 0;
3089
3213
  }
3090
- let relevantIds;
3214
+ let recall;
3091
3215
  try {
3092
- relevantIds = await context.agent.selectRelevantMemories({
3216
+ recall = await context.agent.selectRelevantMemories({
3093
3217
  candidates: candidates.map(({ content, id }) => ({ content, id })),
3094
3218
  userRequest: context.text
3095
3219
  });
@@ -3100,8 +3224,14 @@ async function createMemoryPromptContributions(context) {
3100
3224
  const candidatesById = new Map(
3101
3225
  candidates.map((memory) => [memory.id, memory])
3102
3226
  );
3103
- const relevant = relevantIds.map((id) => candidatesById.get(id)).filter((memory) => memory !== void 0).slice(0, DEFAULT_RECALL_LIMIT);
3227
+ const relevant = recall.relevantIds.map((id) => candidatesById.get(id)).filter((memory) => memory !== void 0).slice(0, DEFAULT_RECALL_LIMIT);
3104
3228
  const selected = selectPromptMemories(relevant);
3229
+ const costUsd = addUsd(embeddingCostUsd, recall.costUsd);
3230
+ await emitRecallOutcome({
3231
+ ...costUsd !== void 0 ? { costUsd } : {},
3232
+ events: context.events,
3233
+ memories: selected.map(({ id }) => id)
3234
+ });
3105
3235
  if (selected.length === 0) {
3106
3236
  return void 0;
3107
3237
  }
@@ -3180,6 +3310,15 @@ function formatPercent(value) {
3180
3310
  style: "percent"
3181
3311
  }).format(value);
3182
3312
  }
3313
+ function formatUsd(value) {
3314
+ const maximumFractionDigits = value > 0 && value < 0.01 ? 4 : 2;
3315
+ return new Intl.NumberFormat("en-US", {
3316
+ currency: "USD",
3317
+ maximumFractionDigits,
3318
+ minimumFractionDigits: 2,
3319
+ style: "currency"
3320
+ }).format(value);
3321
+ }
3183
3322
  async function buildMemoryOperationalReport(args) {
3184
3323
  const active = and4(
3185
3324
  isNull3(juniorMemoryMemories.archivedAtMs),
@@ -3214,6 +3353,11 @@ async function buildMemoryOperationalReport(args) {
3214
3353
  const activeCount = counts?.active ?? 0;
3215
3354
  const embeddedCount = counts?.embedded ?? 0;
3216
3355
  const embeddingCoverage = activeCount === 0 ? 0 : embeddedCount / activeCount;
3356
+ const extractionThirtyDays = args.extractionDays.slice(-30);
3357
+ const extractionCostThirtyDays = extractionThirtyDays.reduce(
3358
+ (total, day) => total + day.costUsd,
3359
+ 0
3360
+ );
3217
3361
  return {
3218
3362
  generatedAt: new Date(args.nowMs).toISOString(),
3219
3363
  title: "Memory",
@@ -3223,6 +3367,10 @@ async function buildMemoryOperationalReport(args) {
3223
3367
  tone: activeCount > 0 ? "good" : "neutral",
3224
3368
  value: formatCount(activeCount)
3225
3369
  },
3370
+ {
3371
+ label: "extraction cost \xB7 30d",
3372
+ value: formatUsd(extractionCostThirtyDays)
3373
+ },
3226
3374
  {
3227
3375
  label: "created \xB7 30d",
3228
3376
  value: formatCount(counts?.createdThirtyDays ?? 0)
@@ -3242,6 +3390,19 @@ async function buildMemoryOperationalReport(args) {
3242
3390
  }
3243
3391
  ],
3244
3392
  widgets: [
3393
+ {
3394
+ categories: args.extractionDays.map((day) => ({
3395
+ id: day.date,
3396
+ label: day.date,
3397
+ values: { costUsd: day.costUsd }
3398
+ })),
3399
+ description: "Estimated model cost of passive memory extraction",
3400
+ id: "extraction-cost",
3401
+ series: [{ format: "usd", key: "costUsd", label: "Cost" }],
3402
+ timeRangeDays: [...WINDOWS],
3403
+ title: "Extraction cost",
3404
+ type: "bar_chart"
3405
+ },
3245
3406
  {
3246
3407
  categories: memoryDays.map((day) => ({
3247
3408
  id: day.date,
@@ -3281,25 +3442,26 @@ function originLabel(origin) {
3281
3442
  if (origin === "explicit") return "Explicit";
3282
3443
  return "Other";
3283
3444
  }
3445
+ function visibilityLabel(visibility) {
3446
+ return visibility === "public" ? "Public" : "Private";
3447
+ }
3284
3448
  function pageFilter(filter) {
3285
- if (filter === "preferences") return { kind: "preference" };
3286
- if (filter === "automatic") return { origin: "automatic" };
3287
- if (filter === "explicit") return { origin: "explicit" };
3449
+ if (filter === "private") return { visibility: "private" };
3450
+ if (filter === "public") return { visibility: "public" };
3288
3451
  return {};
3289
3452
  }
3290
3453
  function pageEmptyText(input) {
3291
3454
  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.";
3455
+ if (input.filter === "private") return "No private memories yet.";
3456
+ if (input.filter === "public") return "No public memories yet.";
3457
+ return "No memories yet.";
3296
3458
  }
3297
3459
  function createMemoryUserPage() {
3298
3460
  return {
3299
3461
  id: "memories",
3300
3462
  label: "Memories",
3301
3463
  navigation: "primary",
3302
- description: "Personal facts and preferences Junior remembers about you.",
3464
+ description: "Personal and public memories Junior can use across conversations.",
3303
3465
  async read(ctx, input) {
3304
3466
  const memories = createViewerMemories(
3305
3467
  ctx.db,
@@ -3317,7 +3479,7 @@ function createMemoryUserPage() {
3317
3479
  ...page.nextCursor ? { nextCursor: page.nextCursor } : {},
3318
3480
  searchPlaceholder: "Search memories",
3319
3481
  records: page.memories.map((memory) => ({
3320
- actions: [
3482
+ actions: memory.visibility === "private" ? [
3321
3483
  {
3322
3484
  confirmation: "Forget this memory?",
3323
3485
  href: `/api/plugins/memory/memories/${encodeURIComponent(memory.id)}`,
@@ -3325,14 +3487,17 @@ function createMemoryUserPage() {
3325
3487
  method: "DELETE",
3326
3488
  tone: "danger"
3327
3489
  }
3328
- ],
3490
+ ] : [],
3329
3491
  id: memory.id,
3330
3492
  title: memory.content,
3331
3493
  metadata: [
3332
3494
  { label: "Type", value: titleCase(memory.kind) },
3333
3495
  { label: "Learned", value: originLabel(memory.origin) },
3334
3496
  { label: "Source", value: titleCase(memory.sourcePlatform) },
3335
- { label: "Visibility", value: "Only you" },
3497
+ {
3498
+ label: "Visibility",
3499
+ value: visibilityLabel(memory.visibility)
3500
+ },
3336
3501
  { label: "Remembered", value: rememberedDate(memory.createdAtMs) },
3337
3502
  { label: "Observed", value: rememberedDate(memory.observedAtMs) },
3338
3503
  {
@@ -3398,7 +3563,11 @@ function memoryPlugin(options = {}) {
3398
3563
  },
3399
3564
  model: modelId ? { structuredModelId: modelId } : { structuredModel: "default" },
3400
3565
  packageName: "@sentry/junior-memory",
3401
- conversationEvents: [memoriesCapturedEvent],
3566
+ conversationEvents: [
3567
+ memoriesCapturedEventV1,
3568
+ memoriesCapturedEvent,
3569
+ memoriesRecalledEvent
3570
+ ],
3402
3571
  cli: {
3403
3572
  commands: [createMemoryCliCommand()]
3404
3573
  },
@@ -3412,15 +3581,21 @@ function memoryPlugin(options = {}) {
3412
3581
  userPages: [createMemoryUserPage()],
3413
3582
  hooks: {
3414
3583
  async operationalReport(ctx) {
3584
+ const extractionDays = await ctx.eventStats.costsByDay({
3585
+ days: 90,
3586
+ eventName: "memories_captured"
3587
+ });
3415
3588
  return await buildMemoryOperationalReport({
3416
3589
  db: ctx.db,
3590
+ extractionDays,
3417
3591
  nowMs: ctx.nowMs
3418
3592
  });
3419
3593
  },
3420
3594
  apiRoutes(ctx) {
3421
3595
  return createMemoryApi({
3422
3596
  actors: ctx.viewer.actors,
3423
- db: ctx.db
3597
+ db: ctx.db,
3598
+ eventStats: ctx.eventStats
3424
3599
  });
3425
3600
  },
3426
3601
  tools(ctx) {
@@ -3453,6 +3628,7 @@ function memoryPlugin(options = {}) {
3453
3628
  ...ctx.actor ? { actor: ctx.actor } : {},
3454
3629
  db: ctx.db,
3455
3630
  embedder: ctx.embedder,
3631
+ events: ctx.events,
3456
3632
  log: ctx.log,
3457
3633
  maxVectorDistance: recallMaxVectorDistance(options),
3458
3634
  source: ctx.source,