@anuma/sdk 6.29.2 → 6.30.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.
@@ -20021,6 +20021,11 @@ function formatEventTime(start, end, kind) {
20021
20021
  if (kind === "ongoing") return `, event: since ${startDate}`;
20022
20022
  return `, event: ${startDate}`;
20023
20023
  }
20024
+ function formatSavedTime(createdAt) {
20025
+ const ms = createdAt?.getTime();
20026
+ if (ms === void 0 || !Number.isFinite(ms) || ms <= 0) return "";
20027
+ return `, saved: ${new Date(ms).toISOString().slice(0, 10)}`;
20028
+ }
20024
20029
  function generateFenceNonce() {
20025
20030
  const bytes = new Uint8Array(9);
20026
20031
  crypto.getRandomValues(bytes);
@@ -20039,8 +20044,9 @@ function formatRecallResult(memories) {
20039
20044
  const lines = memories.map((m, i) => {
20040
20045
  let body;
20041
20046
  if (m.kind === "fact") {
20047
+ const savedSuffix = formatSavedTime(m.createdAt);
20042
20048
  const eventSuffix = formatEventTime(m.eventTimeStart, m.eventTimeEnd, m.eventTimeKind);
20043
- body = `[${i + 1}] fact (id: ${m.id}${eventSuffix})
20049
+ body = `[${i + 1}] fact (id: ${m.id}${savedSuffix}${eventSuffix})
20044
20050
  ${m.content}`;
20045
20051
  } else {
20046
20052
  const date10 = m.createdAt.toISOString().slice(0, 10);
@@ -20090,6 +20096,40 @@ function isDumpQuery(query) {
20090
20096
  if (EVERYTHING_YOU_KNOW_RE.test(q)) return true;
20091
20097
  return false;
20092
20098
  }
20099
+ async function listRecentFacts(ctx, limit, toolOptions) {
20100
+ const vaultCtx = ctx.vaultCtx;
20101
+ if (!vaultCtx) return [];
20102
+ const ordered = await getVaultRankingProjectionsOp(vaultCtx, {
20103
+ ...toolOptions?.scopes && { scopes: toolOptions.scopes },
20104
+ ...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds },
20105
+ ...toolOptions?.folderId !== void 0 && { folderId: toolOptions.folderId }
20106
+ });
20107
+ const readable = [];
20108
+ for (let i = 0; i < ordered.length && readable.length < limit; i += limit) {
20109
+ const batch = ordered.slice(i, i + limit).map((p) => p.uniqueId);
20110
+ const byId = new Map(
20111
+ (await getVaultMemoriesByIdsOp(vaultCtx, batch)).map((m) => [m.uniqueId, m])
20112
+ );
20113
+ for (const id of batch) {
20114
+ const m = byId.get(id);
20115
+ if (m && !isEncrypted(m.content)) readable.push(m);
20116
+ if (readable.length >= limit) break;
20117
+ }
20118
+ }
20119
+ return readable.map((m) => ({
20120
+ id: m.uniqueId,
20121
+ kind: "fact",
20122
+ content: m.content,
20123
+ score: 0,
20124
+ folderId: m.folderId,
20125
+ eventTimeStart: m.eventTimeStart,
20126
+ eventTimeEnd: m.eventTimeEnd,
20127
+ eventTimeKind: m.eventTimeKind,
20128
+ factType: m.factType,
20129
+ createdAt: m.createdAt,
20130
+ updatedAt: m.updatedAt
20131
+ }));
20132
+ }
20093
20133
  function createRecallTool(ctx, toolOptions, callbacks) {
20094
20134
  const defaultTypes = toolOptions?.types ?? ["fact", "chunk"];
20095
20135
  const defaultLimit = toolOptions?.limit ?? DEFAULT_LIMIT2;
@@ -20102,7 +20142,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
20102
20142
  type: "function",
20103
20143
  function: {
20104
20144
  name: RECALL_TOOL_NAME,
20105
- description: `Search the user's memory across stored facts/preferences and past conversation excerpts. Returns a unified ranked list \u2014 facts carry an \`id\` you can reference; conversation excerpts carry a date and role. Use this whenever the user's question may relate to anything previously discussed or saved (preferences, prior decisions, past topics). Phrase the query naturally. For multi-faceted / overview questions ("tell me about the user", "what's my tech stack"), prefer several targeted searches \u2014 one facet each (e.g. name, work, hobbies) \u2014 over a single broad query; fuse the results yourself.`,
20145
+ description: 'Search the user\'s memory across stored facts/preferences and past conversation excerpts. Returns a unified ranked list \u2014 facts carry an `id` you can reference and the date they were saved; conversation excerpts carry a date and role. Use this whenever the user\'s question may relate to anything previously discussed or saved (preferences, prior decisions, past topics). Phrase the query naturally. For multi-faceted / overview questions ("tell me about the user", "what\'s my tech stack"), prefer several targeted searches \u2014 one facet each (e.g. name, work, hobbies) \u2014 over a single broad query; fuse the results yourself. For "what did I save recently / latest memories" questions, set `sort` to "recent" to get the newest saved facts, newest first, instead of a relevance search.',
20106
20146
  arguments: {
20107
20147
  type: "object",
20108
20148
  properties: {
@@ -20113,6 +20153,11 @@ function createRecallTool(ctx, toolOptions, callbacks) {
20113
20153
  limit: {
20114
20154
  type: "integer",
20115
20155
  description: `Max number of results. Default: ${defaultLimit}.`
20156
+ },
20157
+ sort: {
20158
+ type: "string",
20159
+ enum: ["relevance", "recent"],
20160
+ description: `"relevance" (default) ranks by match to the query. "recent" returns the newest saved facts, newest first, and ignores the query's topic.`
20116
20161
  }
20117
20162
  },
20118
20163
  required: ["query"]
@@ -20157,35 +20202,41 @@ function createRecallTool(ctx, toolOptions, callbacks) {
20157
20202
  let surfaced = 0;
20158
20203
  try {
20159
20204
  let recallDegraded = [];
20160
- let subQueries;
20161
- if (defaultBudget === "high" && toolOptions?.decomposeOptions) {
20162
- const decomp = await decomposeQuery(query, toolOptions.decomposeOptions);
20163
- if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
20164
- subQueries = decomp.subQueries;
20205
+ const wantsRecent = args.sort === "recent" && defaultTypes.includes("fact") && ctx.vaultCtx !== void 0;
20206
+ let result;
20207
+ if (wantsRecent) {
20208
+ result = { memories: await listRecentFacts(ctx, effectiveLimit, toolOptions) };
20209
+ } else {
20210
+ let subQueries;
20211
+ if (defaultBudget === "high" && toolOptions?.decomposeOptions) {
20212
+ const decomp = await decomposeQuery(query, toolOptions.decomposeOptions);
20213
+ if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
20214
+ subQueries = decomp.subQueries;
20215
+ }
20165
20216
  }
20217
+ const recallOpts = {
20218
+ onDiagnostics: (d) => {
20219
+ recallDegraded = d.degraded;
20220
+ },
20221
+ types: defaultTypes,
20222
+ limit: effectiveLimit,
20223
+ budget: defaultBudget,
20224
+ ...toolOptions?.minScore !== void 0 && { minScore: toolOptions.minScore },
20225
+ ...toolOptions?.scopes && { scopes: toolOptions.scopes },
20226
+ ...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds },
20227
+ ...toolOptions?.folderId !== void 0 && { folderId: toolOptions.folderId },
20228
+ ...toolOptions?.excludeConversationId && {
20229
+ excludeConversationId: toolOptions.excludeConversationId
20230
+ },
20231
+ // Do NOT forward decomposeOptions into recall() — rewrite already
20232
+ // ran above, and forwarding would falsely trip `decompose-moved`
20233
+ // on every specific-mode high-budget call. graphRefine auth can
20234
+ // be threaded later when the tool opts into that path.
20235
+ ...toolOptions?.now !== void 0 && { now: toolOptions.now },
20236
+ ...subQueries && { subQueries }
20237
+ };
20238
+ result = await recall(query, ctx, recallOpts);
20166
20239
  }
20167
- const recallOpts = {
20168
- onDiagnostics: (d) => {
20169
- recallDegraded = d.degraded;
20170
- },
20171
- types: defaultTypes,
20172
- limit: effectiveLimit,
20173
- budget: defaultBudget,
20174
- ...toolOptions?.minScore !== void 0 && { minScore: toolOptions.minScore },
20175
- ...toolOptions?.scopes && { scopes: toolOptions.scopes },
20176
- ...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds },
20177
- ...toolOptions?.folderId !== void 0 && { folderId: toolOptions.folderId },
20178
- ...toolOptions?.excludeConversationId && {
20179
- excludeConversationId: toolOptions.excludeConversationId
20180
- },
20181
- // Do NOT forward decomposeOptions into recall() — rewrite already
20182
- // ran above, and forwarding would falsely trip `decompose-moved`
20183
- // on every specific-mode high-budget call. graphRefine auth can
20184
- // be threaded later when the tool opts into that path.
20185
- ...toolOptions?.now !== void 0 && { now: toolOptions.now },
20186
- ...subQueries && { subQueries }
20187
- };
20188
- const result = await recall(query, ctx, recallOpts);
20189
20240
  if (callbacks?.onChunksRetrieved) {
20190
20241
  const convIds = Array.from(
20191
20242
  new Set(
@@ -20198,7 +20249,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
20198
20249
  const facts = result.memories.filter((m) => m.kind === "fact").map((m) => ({ id: m.id, score: m.score }));
20199
20250
  if (facts.length > 0) {
20200
20251
  callbacks.onFactsRetrieved?.(facts.map((f) => f.id));
20201
- callbacks.onFactsRanked?.(facts);
20252
+ if (!wantsRecent) callbacks.onFactsRanked?.(facts);
20202
20253
  }
20203
20254
  }
20204
20255
  surfaced = result.memories.length;
@@ -21379,6 +21430,10 @@ function createMessageSourceResolver(ctx) {
21379
21430
  }
21380
21431
 
21381
21432
  // src/lib/memory/context.ts
21433
+ function savedAt(createdAt) {
21434
+ const ms = createdAt?.getTime();
21435
+ return ms !== void 0 && Number.isFinite(ms) && ms > 0 ? { createdAt } : {};
21436
+ }
21382
21437
  function shouldRecallMemory(query) {
21383
21438
  const normalized = query.trim().toLowerCase().replace(/[.!?。!?¡¿]+$/u, "").replace(/^[¡¿]+/u, "");
21384
21439
  return normalized.length > 0 && !/^(hi|hi there|hello|hey|yes|no|yep|nope|sure|k|ok|okay|thanks|thank you|thank you very much|thanks a lot|cool|great|got it|sounds good|hola|buenos días|buenas|sí|si|gracias|muchas gracias|vale|bonjour|salut|oui|non|merci|merci beaucoup|d'accord|hallo|guten tag|ja|nein|danke|danke schön|alles klar|olá|obrigado|obrigada|ciao|grazie|sì|你好|谢谢|好的|こんにちは|ありがとう|안녕하세요|감사합니다)$/u.test(
@@ -21416,7 +21471,8 @@ async function assembleMemoryContext(options) {
21416
21471
  content: m.content,
21417
21472
  score,
21418
21473
  lane,
21419
- sourceIds: m.sourceChunkIds ?? []
21474
+ sourceIds: m.sourceChunkIds ?? [],
21475
+ ...savedAt(m.createdAt)
21420
21476
  });
21421
21477
  const empty = {
21422
21478
  memories: [],
@@ -21481,7 +21537,8 @@ async function assembleMemoryContext(options) {
21481
21537
  score: m.score,
21482
21538
  lane,
21483
21539
  ...lane === "fact" && { recalled: true },
21484
- sourceIds: m.sourceChunkIds ?? (m.messageId ? [m.messageId] : [])
21540
+ sourceIds: m.sourceChunkIds ?? (m.messageId ? [m.messageId] : []),
21541
+ ...savedAt(m.createdAt)
21485
21542
  }));
21486
21543
  const recalledFacts = toItems(facts, "fact");
21487
21544
  const recalledScores = /* @__PURE__ */ new Map();
@@ -36307,7 +36364,8 @@ var DEFAULT_THEME = {
36307
36364
  textPrimary: "#ffffff",
36308
36365
  textSecondary: "#ffffff",
36309
36366
  textMuted: "#9a9592",
36310
- accent: "#e67519",
36367
+ // White on the dark default deck — the brand orange is retired (#8419).
36368
+ accent: "#ffffff",
36311
36369
  card: "#1a1a21",
36312
36370
  border: "#434242"
36313
36371
  }
@@ -8433,6 +8433,7 @@ declare function getVaultRankingProjectionsOp(ctx: VaultMemoryOperationsContext,
8433
8433
  since?: Date;
8434
8434
  limit?: number;
8435
8435
  folderId?: string | null;
8436
+ memoryIds?: string[];
8436
8437
  }): Promise<RankableVaultMemory[]>;
8437
8438
  interface VaultCandidateKey {
8438
8439
  uniqueId: string;
@@ -10845,6 +10846,9 @@ interface MemoryContextItem {
10845
10846
  sourceIds: string[];
10846
10847
  /** Ranked fact evidence, retained when profile deduplication wins placement. */
10847
10848
  recalled?: boolean;
10849
+ /** When the memory was written — lets the prompt show a saved date so the
10850
+ * model can answer "what did I save recently". */
10851
+ createdAt?: Date;
10848
10852
  }
10849
10853
  interface MemoryContextOptions {
10850
10854
  query: string;
@@ -8433,6 +8433,7 @@ declare function getVaultRankingProjectionsOp(ctx: VaultMemoryOperationsContext,
8433
8433
  since?: Date;
8434
8434
  limit?: number;
8435
8435
  folderId?: string | null;
8436
+ memoryIds?: string[];
8436
8437
  }): Promise<RankableVaultMemory[]>;
8437
8438
  interface VaultCandidateKey {
8438
8439
  uniqueId: string;
@@ -10845,6 +10846,9 @@ interface MemoryContextItem {
10845
10846
  sourceIds: string[];
10846
10847
  /** Ranked fact evidence, retained when profile deduplication wins placement. */
10847
10848
  recalled?: boolean;
10849
+ /** When the memory was written — lets the prompt show a saved date so the
10850
+ * model can answer "what did I save recently". */
10851
+ createdAt?: Date;
10848
10852
  }
10849
10853
  interface MemoryContextOptions {
10850
10854
  query: string;
@@ -18118,6 +18118,11 @@ function formatEventTime(start, end, kind) {
18118
18118
  if (kind === "ongoing") return `, event: since ${startDate}`;
18119
18119
  return `, event: ${startDate}`;
18120
18120
  }
18121
+ function formatSavedTime(createdAt) {
18122
+ const ms = createdAt?.getTime();
18123
+ if (ms === void 0 || !Number.isFinite(ms) || ms <= 0) return "";
18124
+ return `, saved: ${new Date(ms).toISOString().slice(0, 10)}`;
18125
+ }
18121
18126
  function generateFenceNonce() {
18122
18127
  const bytes = new Uint8Array(9);
18123
18128
  crypto.getRandomValues(bytes);
@@ -18136,8 +18141,9 @@ function formatRecallResult(memories) {
18136
18141
  const lines = memories.map((m, i) => {
18137
18142
  let body;
18138
18143
  if (m.kind === "fact") {
18144
+ const savedSuffix = formatSavedTime(m.createdAt);
18139
18145
  const eventSuffix = formatEventTime(m.eventTimeStart, m.eventTimeEnd, m.eventTimeKind);
18140
- body = `[${i + 1}] fact (id: ${m.id}${eventSuffix})
18146
+ body = `[${i + 1}] fact (id: ${m.id}${savedSuffix}${eventSuffix})
18141
18147
  ${m.content}`;
18142
18148
  } else {
18143
18149
  const date10 = m.createdAt.toISOString().slice(0, 10);
@@ -18187,6 +18193,40 @@ function isDumpQuery(query) {
18187
18193
  if (EVERYTHING_YOU_KNOW_RE.test(q)) return true;
18188
18194
  return false;
18189
18195
  }
18196
+ async function listRecentFacts(ctx, limit, toolOptions) {
18197
+ const vaultCtx = ctx.vaultCtx;
18198
+ if (!vaultCtx) return [];
18199
+ const ordered = await getVaultRankingProjectionsOp(vaultCtx, {
18200
+ ...toolOptions?.scopes && { scopes: toolOptions.scopes },
18201
+ ...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds },
18202
+ ...toolOptions?.folderId !== void 0 && { folderId: toolOptions.folderId }
18203
+ });
18204
+ const readable = [];
18205
+ for (let i = 0; i < ordered.length && readable.length < limit; i += limit) {
18206
+ const batch = ordered.slice(i, i + limit).map((p) => p.uniqueId);
18207
+ const byId = new Map(
18208
+ (await getVaultMemoriesByIdsOp(vaultCtx, batch)).map((m) => [m.uniqueId, m])
18209
+ );
18210
+ for (const id of batch) {
18211
+ const m = byId.get(id);
18212
+ if (m && !isEncrypted(m.content)) readable.push(m);
18213
+ if (readable.length >= limit) break;
18214
+ }
18215
+ }
18216
+ return readable.map((m) => ({
18217
+ id: m.uniqueId,
18218
+ kind: "fact",
18219
+ content: m.content,
18220
+ score: 0,
18221
+ folderId: m.folderId,
18222
+ eventTimeStart: m.eventTimeStart,
18223
+ eventTimeEnd: m.eventTimeEnd,
18224
+ eventTimeKind: m.eventTimeKind,
18225
+ factType: m.factType,
18226
+ createdAt: m.createdAt,
18227
+ updatedAt: m.updatedAt
18228
+ }));
18229
+ }
18190
18230
  function createRecallTool(ctx, toolOptions, callbacks) {
18191
18231
  const defaultTypes = toolOptions?.types ?? ["fact", "chunk"];
18192
18232
  const defaultLimit = toolOptions?.limit ?? DEFAULT_LIMIT2;
@@ -18199,7 +18239,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
18199
18239
  type: "function",
18200
18240
  function: {
18201
18241
  name: RECALL_TOOL_NAME,
18202
- description: `Search the user's memory across stored facts/preferences and past conversation excerpts. Returns a unified ranked list \u2014 facts carry an \`id\` you can reference; conversation excerpts carry a date and role. Use this whenever the user's question may relate to anything previously discussed or saved (preferences, prior decisions, past topics). Phrase the query naturally. For multi-faceted / overview questions ("tell me about the user", "what's my tech stack"), prefer several targeted searches \u2014 one facet each (e.g. name, work, hobbies) \u2014 over a single broad query; fuse the results yourself.`,
18242
+ description: 'Search the user\'s memory across stored facts/preferences and past conversation excerpts. Returns a unified ranked list \u2014 facts carry an `id` you can reference and the date they were saved; conversation excerpts carry a date and role. Use this whenever the user\'s question may relate to anything previously discussed or saved (preferences, prior decisions, past topics). Phrase the query naturally. For multi-faceted / overview questions ("tell me about the user", "what\'s my tech stack"), prefer several targeted searches \u2014 one facet each (e.g. name, work, hobbies) \u2014 over a single broad query; fuse the results yourself. For "what did I save recently / latest memories" questions, set `sort` to "recent" to get the newest saved facts, newest first, instead of a relevance search.',
18203
18243
  arguments: {
18204
18244
  type: "object",
18205
18245
  properties: {
@@ -18210,6 +18250,11 @@ function createRecallTool(ctx, toolOptions, callbacks) {
18210
18250
  limit: {
18211
18251
  type: "integer",
18212
18252
  description: `Max number of results. Default: ${defaultLimit}.`
18253
+ },
18254
+ sort: {
18255
+ type: "string",
18256
+ enum: ["relevance", "recent"],
18257
+ description: `"relevance" (default) ranks by match to the query. "recent" returns the newest saved facts, newest first, and ignores the query's topic.`
18213
18258
  }
18214
18259
  },
18215
18260
  required: ["query"]
@@ -18254,35 +18299,41 @@ function createRecallTool(ctx, toolOptions, callbacks) {
18254
18299
  let surfaced = 0;
18255
18300
  try {
18256
18301
  let recallDegraded = [];
18257
- let subQueries;
18258
- if (defaultBudget === "high" && toolOptions?.decomposeOptions) {
18259
- const decomp = await decomposeQuery(query, toolOptions.decomposeOptions);
18260
- if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
18261
- subQueries = decomp.subQueries;
18302
+ const wantsRecent = args.sort === "recent" && defaultTypes.includes("fact") && ctx.vaultCtx !== void 0;
18303
+ let result;
18304
+ if (wantsRecent) {
18305
+ result = { memories: await listRecentFacts(ctx, effectiveLimit, toolOptions) };
18306
+ } else {
18307
+ let subQueries;
18308
+ if (defaultBudget === "high" && toolOptions?.decomposeOptions) {
18309
+ const decomp = await decomposeQuery(query, toolOptions.decomposeOptions);
18310
+ if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
18311
+ subQueries = decomp.subQueries;
18312
+ }
18262
18313
  }
18314
+ const recallOpts = {
18315
+ onDiagnostics: (d) => {
18316
+ recallDegraded = d.degraded;
18317
+ },
18318
+ types: defaultTypes,
18319
+ limit: effectiveLimit,
18320
+ budget: defaultBudget,
18321
+ ...toolOptions?.minScore !== void 0 && { minScore: toolOptions.minScore },
18322
+ ...toolOptions?.scopes && { scopes: toolOptions.scopes },
18323
+ ...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds },
18324
+ ...toolOptions?.folderId !== void 0 && { folderId: toolOptions.folderId },
18325
+ ...toolOptions?.excludeConversationId && {
18326
+ excludeConversationId: toolOptions.excludeConversationId
18327
+ },
18328
+ // Do NOT forward decomposeOptions into recall() — rewrite already
18329
+ // ran above, and forwarding would falsely trip `decompose-moved`
18330
+ // on every specific-mode high-budget call. graphRefine auth can
18331
+ // be threaded later when the tool opts into that path.
18332
+ ...toolOptions?.now !== void 0 && { now: toolOptions.now },
18333
+ ...subQueries && { subQueries }
18334
+ };
18335
+ result = await recall(query, ctx, recallOpts);
18263
18336
  }
18264
- const recallOpts = {
18265
- onDiagnostics: (d) => {
18266
- recallDegraded = d.degraded;
18267
- },
18268
- types: defaultTypes,
18269
- limit: effectiveLimit,
18270
- budget: defaultBudget,
18271
- ...toolOptions?.minScore !== void 0 && { minScore: toolOptions.minScore },
18272
- ...toolOptions?.scopes && { scopes: toolOptions.scopes },
18273
- ...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds },
18274
- ...toolOptions?.folderId !== void 0 && { folderId: toolOptions.folderId },
18275
- ...toolOptions?.excludeConversationId && {
18276
- excludeConversationId: toolOptions.excludeConversationId
18277
- },
18278
- // Do NOT forward decomposeOptions into recall() — rewrite already
18279
- // ran above, and forwarding would falsely trip `decompose-moved`
18280
- // on every specific-mode high-budget call. graphRefine auth can
18281
- // be threaded later when the tool opts into that path.
18282
- ...toolOptions?.now !== void 0 && { now: toolOptions.now },
18283
- ...subQueries && { subQueries }
18284
- };
18285
- const result = await recall(query, ctx, recallOpts);
18286
18337
  if (callbacks?.onChunksRetrieved) {
18287
18338
  const convIds = Array.from(
18288
18339
  new Set(
@@ -18295,7 +18346,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
18295
18346
  const facts = result.memories.filter((m) => m.kind === "fact").map((m) => ({ id: m.id, score: m.score }));
18296
18347
  if (facts.length > 0) {
18297
18348
  callbacks.onFactsRetrieved?.(facts.map((f) => f.id));
18298
- callbacks.onFactsRanked?.(facts);
18349
+ if (!wantsRecent) callbacks.onFactsRanked?.(facts);
18299
18350
  }
18300
18351
  }
18301
18352
  surfaced = result.memories.length;
@@ -19464,6 +19515,10 @@ function createMessageSourceResolver(ctx) {
19464
19515
  }
19465
19516
 
19466
19517
  // src/lib/memory/context.ts
19518
+ function savedAt(createdAt) {
19519
+ const ms = createdAt?.getTime();
19520
+ return ms !== void 0 && Number.isFinite(ms) && ms > 0 ? { createdAt } : {};
19521
+ }
19467
19522
  function shouldRecallMemory(query) {
19468
19523
  const normalized = query.trim().toLowerCase().replace(/[.!?。!?¡¿]+$/u, "").replace(/^[¡¿]+/u, "");
19469
19524
  return normalized.length > 0 && !/^(hi|hi there|hello|hey|yes|no|yep|nope|sure|k|ok|okay|thanks|thank you|thank you very much|thanks a lot|cool|great|got it|sounds good|hola|buenos días|buenas|sí|si|gracias|muchas gracias|vale|bonjour|salut|oui|non|merci|merci beaucoup|d'accord|hallo|guten tag|ja|nein|danke|danke schön|alles klar|olá|obrigado|obrigada|ciao|grazie|sì|你好|谢谢|好的|こんにちは|ありがとう|안녕하세요|감사합니다)$/u.test(
@@ -19501,7 +19556,8 @@ async function assembleMemoryContext(options) {
19501
19556
  content: m.content,
19502
19557
  score,
19503
19558
  lane,
19504
- sourceIds: m.sourceChunkIds ?? []
19559
+ sourceIds: m.sourceChunkIds ?? [],
19560
+ ...savedAt(m.createdAt)
19505
19561
  });
19506
19562
  const empty = {
19507
19563
  memories: [],
@@ -19566,7 +19622,8 @@ async function assembleMemoryContext(options) {
19566
19622
  score: m.score,
19567
19623
  lane,
19568
19624
  ...lane === "fact" && { recalled: true },
19569
- sourceIds: m.sourceChunkIds ?? (m.messageId ? [m.messageId] : [])
19625
+ sourceIds: m.sourceChunkIds ?? (m.messageId ? [m.messageId] : []),
19626
+ ...savedAt(m.createdAt)
19570
19627
  }));
19571
19628
  const recalledFacts = toItems(facts, "fact");
19572
19629
  const recalledScores = /* @__PURE__ */ new Map();
@@ -34389,7 +34446,8 @@ var DEFAULT_THEME = {
34389
34446
  textPrimary: "#ffffff",
34390
34447
  textSecondary: "#ffffff",
34391
34448
  textMuted: "#9a9592",
34392
- accent: "#e67519",
34449
+ // White on the dark default deck — the brand orange is retired (#8419).
34450
+ accent: "#ffffff",
34393
34451
  card: "#1a1a21",
34394
34452
  border: "#434242"
34395
34453
  }