@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.
@@ -8,6 +8,7 @@ import {
8
8
  EMBEDDINGS_DEGRADED_EMPTY,
9
9
  ENTITY_FANOUT,
10
10
  ENTITY_KINDS,
11
+ EncryptionKeyMissingError,
11
12
  LRUCache,
12
13
  MAX_HOPS,
13
14
  NODE_BUDGET,
@@ -132,6 +133,7 @@ import {
132
133
  prepareVaultCandidates,
133
134
  rankPreparedVaultCandidates,
134
135
  recall,
136
+ refreshEncryptionKeyIfMatches,
135
137
  relinkMemoryTopicsOp,
136
138
  replaceMemoryEntitiesGuardedOp,
137
139
  requestEncryptionKey,
@@ -141,6 +143,7 @@ import {
141
143
  searchChunksOp,
142
144
  searchMessagesOp,
143
145
  searchVaultMemories,
146
+ seedEncryptionKeys,
144
147
  setMemoryEntitiesOp,
145
148
  setMemoryVisibilityOp,
146
149
  shouldChunkMessage,
@@ -161,7 +164,7 @@ import {
161
164
  updateVaultMemoryOp,
162
165
  useEncryption,
163
166
  vaultMemoryToStored
164
- } from "./chunk-BS7C4CUW.mjs";
167
+ } from "./chunk-CUJDSH55.mjs";
165
168
  import {
166
169
  PiiRedactor,
167
170
  createStreamingDeAnonymizer,
@@ -8931,21 +8934,63 @@ var DEFAULT_PROFILE_FACETS = [
8931
8934
  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."
8932
8935
  }
8933
8936
  ];
8937
+ var NEARBY_MAX_OCCUPATION_CODEPOINTS = 80;
8938
+ var NEARBY_MAX_INTERESTS = 12;
8939
+ var NEARBY_MAX_INTEREST_CODEPOINTS = 40;
8940
+ var MAX_RAW_INTERESTS = NEARBY_MAX_INTERESTS * 2;
8941
+ function codePointLength(value) {
8942
+ return [...value].length;
8943
+ }
8944
+ var FACET_BASE_PROPERTIES = {
8945
+ summary: {
8946
+ type: "string",
8947
+ description: "The synthesized section prose. Empty string if the memories don't cover it."
8948
+ },
8949
+ hasEvidence: {
8950
+ type: "boolean",
8951
+ description: "False when the supplied memories don't support any claim for this facet."
8952
+ }
8953
+ };
8934
8954
  var FACET_RESPONSE_SCHEMA = {
8955
+ type: "object",
8956
+ properties: FACET_BASE_PROPERTIES,
8957
+ required: ["summary", "hasEvidence"],
8958
+ additionalProperties: false
8959
+ };
8960
+ var WORK_ROLE_RESPONSE_SCHEMA = {
8935
8961
  type: "object",
8936
8962
  properties: {
8937
- summary: {
8963
+ ...FACET_BASE_PROPERTIES,
8964
+ occupation: {
8938
8965
  type: "string",
8939
- description: "The synthesized section prose. Empty string if the memories don't cover it."
8940
- },
8941
- hasEvidence: {
8942
- type: "boolean",
8943
- description: "False when the supplied memories don't support any claim for this facet."
8966
+ 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.`
8944
8967
  }
8945
8968
  },
8946
- required: ["summary", "hasEvidence"],
8969
+ required: ["summary", "hasEvidence", "occupation"],
8970
+ additionalProperties: false
8971
+ };
8972
+ var INTERESTS_RESPONSE_SCHEMA = {
8973
+ type: "object",
8974
+ properties: {
8975
+ ...FACET_BASE_PROPERTIES,
8976
+ interests: {
8977
+ type: "array",
8978
+ items: { type: "string" },
8979
+ 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.`
8980
+ }
8981
+ },
8982
+ required: ["summary", "hasEvidence", "interests"],
8947
8983
  additionalProperties: false
8948
8984
  };
8985
+ function facetResponseSchema(key) {
8986
+ if (key === "work_role") return WORK_ROLE_RESPONSE_SCHEMA;
8987
+ if (key === "interests") return INTERESTS_RESPONSE_SCHEMA;
8988
+ return FACET_RESPONSE_SCHEMA;
8989
+ }
8990
+ var FACET_STRUCTURED_RESPONSE_HINT = {
8991
+ work_role: `, "occupation": <the role as a standalone phrase of at most ${NEARBY_MAX_OCCUPATION_CODEPOINTS} characters, e.g. "Backend engineer, fintech", or "">`,
8992
+ 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 []>`
8993
+ };
8949
8994
  async function synthesizeProfile(ctx, options = {}) {
8950
8995
  if (!ctx.vaultCtx) {
8951
8996
  throw new Error("synthesizeProfile requires ctx.vaultCtx (vault-backed facts).");
@@ -9041,7 +9086,7 @@ function reviewedMemoryIdsSignature(ids) {
9041
9086
  return [...new Set(ids)].sort().join("\n");
9042
9087
  }
9043
9088
  function facetsSignature(facets) {
9044
- return facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance])).sort().join("\n");
9089
+ return facets.map((f) => JSON.stringify([f.key, f.label, f.query, f.guidance, facetResponseSchema(f.key)])).sort().join("\n");
9045
9090
  }
9046
9091
  function trendsEqual(a, b) {
9047
9092
  if (!a) return false;
@@ -9189,7 +9234,7 @@ async function synthesizeFacet(facet, ctx, options, prior) {
9189
9234
  types: ["fact"],
9190
9235
  maxTokens: DEFAULT_FACET_MAX_TOKENS,
9191
9236
  systemPrompt: buildFacetSystemPrompt(facet),
9192
- responseSchema: FACET_RESPONSE_SCHEMA,
9237
+ responseSchema: facetResponseSchema(facet.key),
9193
9238
  memories
9194
9239
  });
9195
9240
  const noEvidence = result.basedOn.memoryIds.length === 0;
@@ -9212,6 +9257,25 @@ async function synthesizeFacet(facet, ctx, options, prior) {
9212
9257
  const redacted = await options.redactor.redactTextAsync(text12);
9213
9258
  section.text = redacted.text;
9214
9259
  }
9260
+ if (!legitimateEmpty && !noEvidence) {
9261
+ const values = extractStructuredValues(facet.key, result.structuredOutput);
9262
+ if (options.redactor) {
9263
+ if (values.occupation) {
9264
+ values.occupation = (await options.redactor.redactTextAsync(values.occupation)).text;
9265
+ }
9266
+ if (values.interests) {
9267
+ const gated = [];
9268
+ for (const interest of values.interests) {
9269
+ gated.push((await options.redactor.redactTextAsync(interest)).text);
9270
+ }
9271
+ values.interests = gated;
9272
+ }
9273
+ }
9274
+ const occupation = normalizeOccupation(values.occupation);
9275
+ if (occupation !== void 0) section.occupation = occupation;
9276
+ const interests = normalizeInterests(values.interests);
9277
+ if (interests !== void 0) section.interests = interests;
9278
+ }
9215
9279
  return section;
9216
9280
  }
9217
9281
  function fallbackSection(facet, prior) {
@@ -9228,6 +9292,7 @@ function fallbackSection(facet, prior) {
9228
9292
  };
9229
9293
  }
9230
9294
  function buildFacetSystemPrompt(facet) {
9295
+ const structuredField = FACET_STRUCTURED_RESPONSE_HINT[facet.key] ?? "";
9231
9296
  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.
9232
9297
 
9233
9298
  Task for this section:
@@ -9238,7 +9303,7 @@ Rules:
9238
9303
  - If the memories don't cover this section, return an empty summary with hasEvidence=false. Do not pad or guess.
9239
9304
  - Write in third person about the person, in a natural voice suitable for a public profile (no "I"/"you", no name repetition).
9240
9305
  - Be concise and specific; no preamble, hedging, or meta-commentary.
9241
- - Respond as JSON: { "summary": <the section text, or "">, "hasEvidence": <true|false> }.`;
9306
+ - Respond as JSON: { "summary": <the section text, or "">, "hasEvidence": <true|false>${structuredField} }.`;
9242
9307
  }
9243
9308
  function extractFacetText(structured) {
9244
9309
  if (structured && typeof structured === "object") {
@@ -9249,6 +9314,73 @@ function extractFacetText(structured) {
9249
9314
  }
9250
9315
  return { text: "", legitimateEmpty: false };
9251
9316
  }
9317
+ function extractStructuredValues(key, structured) {
9318
+ if (!structured || typeof structured !== "object") return {};
9319
+ const obj = structured;
9320
+ if (key === "work_role") {
9321
+ return typeof obj.occupation === "string" ? { occupation: obj.occupation } : {};
9322
+ }
9323
+ if (key === "interests") {
9324
+ const list = coerceInterestList(obj.interests);
9325
+ if (list) return { interests: list.slice(0, MAX_RAW_INTERESTS) };
9326
+ }
9327
+ return {};
9328
+ }
9329
+ function coerceInterestList(value) {
9330
+ if (Array.isArray(value)) return value.filter((i) => typeof i === "string");
9331
+ if (typeof value !== "string") return void 0;
9332
+ const trimmed = value.trim();
9333
+ if (trimmed.startsWith("[")) {
9334
+ try {
9335
+ const parsed = JSON.parse(trimmed);
9336
+ if (Array.isArray(parsed)) return parsed.filter((i) => typeof i === "string");
9337
+ } catch {
9338
+ if (trimmed.endsWith("]")) return splitInterestFragments(trimmed.slice(1, -1));
9339
+ }
9340
+ }
9341
+ return splitInterestFragments(trimmed);
9342
+ }
9343
+ function splitInterestFragments(source) {
9344
+ return source.split(",").map((fragment) => {
9345
+ let entry = fragment.trim();
9346
+ if (entry.startsWith("[")) entry = entry.slice(1);
9347
+ if (entry.endsWith("]")) entry = entry.slice(0, -1);
9348
+ entry = entry.trim();
9349
+ const quote = entry[0];
9350
+ if ((quote === '"' || quote === "'") && entry.endsWith(quote)) entry = entry.slice(1, -1);
9351
+ return entry;
9352
+ });
9353
+ }
9354
+ function normalizeOccupation(value) {
9355
+ if (value === void 0) return void 0;
9356
+ const trimmed = value.trim();
9357
+ if (!trimmed) return void 0;
9358
+ const length = codePointLength(trimmed);
9359
+ if (length > NEARBY_MAX_OCCUPATION_CODEPOINTS) {
9360
+ getLogger().warn(
9361
+ "[memory/synthesizeProfile] occupation exceeded the publishable length; dropping it",
9362
+ { length, max: NEARBY_MAX_OCCUPATION_CODEPOINTS }
9363
+ );
9364
+ return void 0;
9365
+ }
9366
+ return trimmed;
9367
+ }
9368
+ function normalizeInterests(values) {
9369
+ if (values === void 0) return void 0;
9370
+ const seen = /* @__PURE__ */ new Set();
9371
+ const out = [];
9372
+ for (const value of values) {
9373
+ const trimmed = value.trim();
9374
+ if (!trimmed) continue;
9375
+ if (codePointLength(trimmed) > NEARBY_MAX_INTEREST_CODEPOINTS) continue;
9376
+ const key = trimmed.toLowerCase();
9377
+ if (seen.has(key)) continue;
9378
+ seen.add(key);
9379
+ out.push(trimmed);
9380
+ if (out.length === NEARBY_MAX_INTERESTS) break;
9381
+ }
9382
+ return out.length > 0 ? out : void 0;
9383
+ }
9252
9384
 
9253
9385
  // src/lib/memory/topicExtract.ts
9254
9386
  var TOPIC_EXTRACTION_BATCH_SIZE = 10;
@@ -24460,6 +24592,7 @@ export {
24460
24592
  DropboxAuthProvider,
24461
24593
  ENTITY_FANOUT,
24462
24594
  ENTITY_KINDS,
24595
+ EncryptionKeyMissingError,
24463
24596
  Entity as EntityModel,
24464
24597
  ExcelProcessor,
24465
24598
  FILE_PLACEHOLDER_PREFIX,
@@ -24750,6 +24883,7 @@ export {
24750
24883
  reflect,
24751
24884
  refreshCalendarToken,
24752
24885
  refreshDriveToken,
24886
+ refreshEncryptionKeyIfMatches,
24753
24887
  refreshGithubToken,
24754
24888
  refreshNotionToken,
24755
24889
  relinkMemoryTopicsOp,
@@ -24781,6 +24915,7 @@ export {
24781
24915
  searchMediaOp,
24782
24916
  searchMessagesOp,
24783
24917
  searchVaultMemories,
24918
+ seedEncryptionKeys,
24784
24919
  selectServerToolsForPrompt,
24785
24920
  serializeJsx,
24786
24921
  setLogger,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-BS7C4CUW.mjs";
3
+ } from "./chunk-CUJDSH55.mjs";
4
4
  import "./chunk-ILAWDQDE.mjs";
5
5
  import "./chunk-GYKJOWEO.mjs";
6
6
  export {