@anuma/sdk 4.1.0 → 4.2.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.
@@ -7,6 +7,7 @@ import {
7
7
  EMBEDDINGS_DEGRADED_EMPTY,
8
8
  ENTITY_FANOUT,
9
9
  ENTITY_KINDS,
10
+ EncryptionKeyMissingError,
10
11
  LRUCache,
11
12
  MAX_HOPS,
12
13
  NODE_BUDGET,
@@ -95,6 +96,7 @@ import {
95
96
  prepareVaultCandidates,
96
97
  rankPreparedVaultCandidates,
97
98
  recall,
99
+ refreshEncryptionKeyIfMatches,
98
100
  relinkMemoryTopicsOp,
99
101
  replaceMemoryEntitiesGuardedOp,
100
102
  requestEncryptionKey,
@@ -116,6 +118,7 @@ import {
116
118
  searchChunksOp,
117
119
  searchMessagesOp,
118
120
  searchVaultMemories,
121
+ seedEncryptionKeys,
119
122
  setMemoryVisibilityOp,
120
123
  shouldChunkMessage,
121
124
  stampTopicsExtractedAtOp,
@@ -133,7 +136,7 @@ import {
133
136
  updateVaultMemoryOp,
134
137
  upsertMessageOp,
135
138
  vaultMemoryToStored
136
- } from "./chunk-WADHFDMA.mjs";
139
+ } from "./chunk-UQDYBQVF.mjs";
137
140
  import {
138
141
  createStreamingDeAnonymizer,
139
142
  notifyConsolidationFallback,
@@ -6886,21 +6889,63 @@ var DEFAULT_PROFILE_FACETS = [
6886
6889
  guidance: "Summarize what the person has been up to lately in one line, favoring the most recently reinforced facts. Frame it as current/ongoing (e.g. 'Lately: training for a first half-marathon and learning Portuguese'). Omit if nothing recent stands out."
6887
6890
  }
6888
6891
  ];
6892
+ var NEARBY_MAX_OCCUPATION_CODEPOINTS = 80;
6893
+ var NEARBY_MAX_INTERESTS = 12;
6894
+ var NEARBY_MAX_INTEREST_CODEPOINTS = 40;
6895
+ var MAX_RAW_INTERESTS = NEARBY_MAX_INTERESTS * 2;
6896
+ function codePointLength(value) {
6897
+ return [...value].length;
6898
+ }
6899
+ var FACET_BASE_PROPERTIES = {
6900
+ summary: {
6901
+ type: "string",
6902
+ description: "The synthesized section prose. Empty string if the memories don't cover it."
6903
+ },
6904
+ hasEvidence: {
6905
+ type: "boolean",
6906
+ description: "False when the supplied memories don't support any claim for this facet."
6907
+ }
6908
+ };
6889
6909
  var FACET_RESPONSE_SCHEMA = {
6910
+ type: "object",
6911
+ properties: FACET_BASE_PROPERTIES,
6912
+ required: ["summary", "hasEvidence"],
6913
+ additionalProperties: false
6914
+ };
6915
+ var WORK_ROLE_RESPONSE_SCHEMA = {
6890
6916
  type: "object",
6891
6917
  properties: {
6892
- summary: {
6918
+ ...FACET_BASE_PROPERTIES,
6919
+ occupation: {
6893
6920
  type: "string",
6894
- description: "The synthesized section prose. Empty string if the memories don't cover it."
6895
- },
6896
- hasEvidence: {
6897
- type: "boolean",
6898
- description: "False when the supplied memories don't support any claim for this facet."
6921
+ description: `The same role as a standalone phrase for a profile field, at most ${NEARBY_MAX_OCCUPATION_CODEPOINTS} characters (e.g. "Backend engineer, fintech"). Empty string when hasEvidence is false.`
6899
6922
  }
6900
6923
  },
6901
- required: ["summary", "hasEvidence"],
6924
+ required: ["summary", "hasEvidence", "occupation"],
6925
+ additionalProperties: false
6926
+ };
6927
+ var INTERESTS_RESPONSE_SCHEMA = {
6928
+ type: "object",
6929
+ properties: {
6930
+ ...FACET_BASE_PROPERTIES,
6931
+ interests: {
6932
+ type: "array",
6933
+ items: { type: "string" },
6934
+ description: `The same interests as discrete strings \u2014 at most ${NEARBY_MAX_INTERESTS} items, each at most ${NEARBY_MAX_INTEREST_CODEPOINTS} characters (e.g. ["trail running", "film photography"]). Empty array when hasEvidence is false.`
6935
+ }
6936
+ },
6937
+ required: ["summary", "hasEvidence", "interests"],
6902
6938
  additionalProperties: false
6903
6939
  };
6940
+ function facetResponseSchema(key) {
6941
+ if (key === "work_role") return WORK_ROLE_RESPONSE_SCHEMA;
6942
+ if (key === "interests") return INTERESTS_RESPONSE_SCHEMA;
6943
+ return FACET_RESPONSE_SCHEMA;
6944
+ }
6945
+ var FACET_STRUCTURED_RESPONSE_HINT = {
6946
+ work_role: `, "occupation": <the role as a standalone phrase of at most ${NEARBY_MAX_OCCUPATION_CODEPOINTS} characters, e.g. "Backend engineer, fintech", or "">`,
6947
+ interests: `, "interests": <the same interests as an array of at most ${NEARBY_MAX_INTERESTS} strings of at most ${NEARBY_MAX_INTEREST_CODEPOINTS} characters each, e.g. ["trail running", "film photography"], or []>`
6948
+ };
6904
6949
  async function synthesizeProfile(ctx, options = {}) {
6905
6950
  if (!ctx.vaultCtx) {
6906
6951
  throw new Error("synthesizeProfile requires ctx.vaultCtx (vault-backed facts).");
@@ -6996,7 +7041,7 @@ function reviewedMemoryIdsSignature(ids) {
6996
7041
  return [...new Set(ids)].sort().join("\n");
6997
7042
  }
6998
7043
  function facetsSignature(facets) {
6999
- return facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance])).sort().join("\n");
7044
+ return facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance, facetResponseSchema(f.key)])).sort().join("\n");
7000
7045
  }
7001
7046
  function trendsEqual(a, b) {
7002
7047
  if (!a) return false;
@@ -7144,7 +7189,7 @@ async function synthesizeFacet(facet, ctx, options, prior) {
7144
7189
  types: ["fact"],
7145
7190
  maxTokens: DEFAULT_FACET_MAX_TOKENS,
7146
7191
  systemPrompt: buildFacetSystemPrompt(facet),
7147
- responseSchema: FACET_RESPONSE_SCHEMA,
7192
+ responseSchema: facetResponseSchema(facet.key),
7148
7193
  memories
7149
7194
  });
7150
7195
  const noEvidence = result.basedOn.memoryIds.length === 0;
@@ -7167,6 +7212,25 @@ async function synthesizeFacet(facet, ctx, options, prior) {
7167
7212
  const redacted = await options.redactor.redactTextAsync(text12);
7168
7213
  section.text = redacted.text;
7169
7214
  }
7215
+ if (!legitimateEmpty && !noEvidence) {
7216
+ const values = extractStructuredValues(facet.key, result.structuredOutput);
7217
+ if (options.redactor) {
7218
+ if (values.occupation) {
7219
+ values.occupation = (await options.redactor.redactTextAsync(values.occupation)).text;
7220
+ }
7221
+ if (values.interests) {
7222
+ const gated = [];
7223
+ for (const interest of values.interests) {
7224
+ gated.push((await options.redactor.redactTextAsync(interest)).text);
7225
+ }
7226
+ values.interests = gated;
7227
+ }
7228
+ }
7229
+ const occupation = normalizeOccupation(values.occupation);
7230
+ if (occupation !== void 0) section.occupation = occupation;
7231
+ const interests = normalizeInterests(values.interests);
7232
+ if (interests !== void 0) section.interests = interests;
7233
+ }
7170
7234
  return section;
7171
7235
  }
7172
7236
  function fallbackSection(facet, prior) {
@@ -7183,6 +7247,7 @@ function fallbackSection(facet, prior) {
7183
7247
  };
7184
7248
  }
7185
7249
  function buildFacetSystemPrompt(facet) {
7250
+ const structuredField = FACET_STRUCTURED_RESPONSE_HINT[facet.key] ?? "";
7186
7251
  return `You are writing the "${facet.label}" section of a person's shareable profile, using their private memories (supplied as evidence) as the only source of truth.
7187
7252
 
7188
7253
  Task for this section:
@@ -7193,7 +7258,7 @@ Rules:
7193
7258
  - If the memories don't cover this section, return an empty summary with hasEvidence=false. Do not pad or guess.
7194
7259
  - Write in third person about the person, in a natural voice suitable for a public profile (no "I"/"you", no name repetition).
7195
7260
  - Be concise and specific; no preamble, hedging, or meta-commentary.
7196
- - Respond as JSON: { "summary": <the section text, or "">, "hasEvidence": <true|false> }.`;
7261
+ - Respond as JSON: { "summary": <the section text, or "">, "hasEvidence": <true|false>${structuredField} }.`;
7197
7262
  }
7198
7263
  function extractFacetText(structured) {
7199
7264
  if (structured && typeof structured === "object") {
@@ -7204,6 +7269,73 @@ function extractFacetText(structured) {
7204
7269
  }
7205
7270
  return { text: "", legitimateEmpty: false };
7206
7271
  }
7272
+ function extractStructuredValues(key, structured) {
7273
+ if (!structured || typeof structured !== "object") return {};
7274
+ const obj = structured;
7275
+ if (key === "work_role") {
7276
+ return typeof obj.occupation === "string" ? { occupation: obj.occupation } : {};
7277
+ }
7278
+ if (key === "interests") {
7279
+ const list = coerceInterestList(obj.interests);
7280
+ if (list) return { interests: list.slice(0, MAX_RAW_INTERESTS) };
7281
+ }
7282
+ return {};
7283
+ }
7284
+ function coerceInterestList(value) {
7285
+ if (Array.isArray(value)) return value.filter((i) => typeof i === "string");
7286
+ if (typeof value !== "string") return void 0;
7287
+ const trimmed = value.trim();
7288
+ if (trimmed.startsWith("[")) {
7289
+ try {
7290
+ const parsed = JSON.parse(trimmed);
7291
+ if (Array.isArray(parsed)) return parsed.filter((i) => typeof i === "string");
7292
+ } catch {
7293
+ if (trimmed.endsWith("]")) return splitInterestFragments(trimmed.slice(1, -1));
7294
+ }
7295
+ }
7296
+ return splitInterestFragments(trimmed);
7297
+ }
7298
+ function splitInterestFragments(source) {
7299
+ return source.split(",").map((fragment) => {
7300
+ let entry = fragment.trim();
7301
+ if (entry.startsWith("[")) entry = entry.slice(1);
7302
+ if (entry.endsWith("]")) entry = entry.slice(0, -1);
7303
+ entry = entry.trim();
7304
+ const quote = entry[0];
7305
+ if ((quote === '"' || quote === "'") && entry.endsWith(quote)) entry = entry.slice(1, -1);
7306
+ return entry;
7307
+ });
7308
+ }
7309
+ function normalizeOccupation(value) {
7310
+ if (value === void 0) return void 0;
7311
+ const trimmed = value.trim();
7312
+ if (!trimmed) return void 0;
7313
+ const length = codePointLength(trimmed);
7314
+ if (length > NEARBY_MAX_OCCUPATION_CODEPOINTS) {
7315
+ getLogger().warn(
7316
+ "[memory/synthesizeProfile] occupation exceeded the publishable length; dropping it",
7317
+ { length, max: NEARBY_MAX_OCCUPATION_CODEPOINTS }
7318
+ );
7319
+ return void 0;
7320
+ }
7321
+ return trimmed;
7322
+ }
7323
+ function normalizeInterests(values) {
7324
+ if (values === void 0) return void 0;
7325
+ const seen = /* @__PURE__ */ new Set();
7326
+ const out = [];
7327
+ for (const value of values) {
7328
+ const trimmed = value.trim();
7329
+ if (!trimmed) continue;
7330
+ if (codePointLength(trimmed) > NEARBY_MAX_INTEREST_CODEPOINTS) continue;
7331
+ const key = trimmed.toLowerCase();
7332
+ if (seen.has(key)) continue;
7333
+ seen.add(key);
7334
+ out.push(trimmed);
7335
+ if (out.length === NEARBY_MAX_INTERESTS) break;
7336
+ }
7337
+ return out.length > 0 ? out : void 0;
7338
+ }
7207
7339
 
7208
7340
  // src/lib/memory/topicExtract.ts
7209
7341
  var TOPIC_EXTRACTION_BATCH_SIZE = 10;
@@ -12983,6 +13115,7 @@ export {
12983
13115
  DEFAULT_VAULT_CACHE_SIZE,
12984
13116
  DatabaseManager,
12985
13117
  ENTITY_FANOUT,
13118
+ EncryptionKeyMissingError,
12986
13119
  ExcelProcessor,
12987
13120
  HARD_DELETE_WINDOW_MS,
12988
13121
  INFERENCE_ID_HEADER,
@@ -13183,6 +13316,7 @@ export {
13183
13316
  rankProfileCandidates,
13184
13317
  recall,
13185
13318
  reflect,
13319
+ refreshEncryptionKeyIfMatches,
13186
13320
  relinkMemoryTopicsOp,
13187
13321
  relinkMisclassifiedVideosOp,
13188
13322
  renderTemplate,
@@ -13203,6 +13337,7 @@ export {
13203
13337
  searchMediaOp,
13204
13338
  searchMessagesOp,
13205
13339
  searchVaultMemories,
13340
+ seedEncryptionKeys,
13206
13341
  selectServerToolsForPrompt,
13207
13342
  serverPlatformStorage,
13208
13343
  setMemoryVisibilityOp,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-WADHFDMA.mjs";
3
+ } from "./chunk-UQDYBQVF.mjs";
4
4
  import "./chunk-OBDRKQQI.mjs";
5
5
  import "./chunk-3RPGXXPZ.mjs";
6
6
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anuma/sdk",
3
- "version": "4.1.0",
3
+ "version": "4.2.1",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",