@anuma/sdk 6.8.1 → 6.9.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.
@@ -3642,8 +3642,26 @@ interface StoredConversationSummary {
3642
3642
  * A chunk of a message with its own embedding for fine-grained search
3643
3643
  */
3644
3644
  interface MessageChunk {
3645
- /** The chunk text */
3646
- text: string;
3645
+ /**
3646
+ * The chunk text — IN MEMORY ONLY. Not persisted (sdk#880).
3647
+ *
3648
+ * `chunkText` covers a message end to end with a 50-character overlap, so the
3649
+ * chunk set of any message over 400 characters reconstructs the whole thing.
3650
+ * Storing it put a fully readable copy of the message next to its own
3651
+ * ciphertext `content` on devices with at-rest encryption enabled.
3652
+ *
3653
+ * `updateMessageChunksOp` now strips this before writing and readers rebuild
3654
+ * the snippet from {@link startOffset}/{@link endOffset} against the message's
3655
+ * own (decrypted) `content` — so the text exists exactly once, under the
3656
+ * protection `content` already has. Encrypting the column instead was
3657
+ * rejected: the client reads this column raw and `JSON.parse`s it in four
3658
+ * places, each swallowing the throw and silently scoring 0.
3659
+ *
3660
+ * Optional because rows written before that change still carry it, and
3661
+ * readers prefer a stored value when present. It is populated in memory by
3662
+ * `chunkText()` and on the way out of a search.
3663
+ */
3664
+ text?: string;
3647
3665
  /**
3648
3666
  * Embedding vector for this chunk.
3649
3667
  *
@@ -6597,6 +6615,14 @@ declare function relinkMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryI
6597
6615
  * row has: a curated memory's topics are recorded as `user`, everything else as
6598
6616
  * `auto`. Skips deleted, foreign-user, unlinked rows, and rows that already have
6599
6617
  * a record. Returns the ids filled.
6618
+ *
6619
+ * Runs as ONE writer over the whole (caller-bounded) list, in two phases:
6620
+ * resolve every row's write — all the awaits — and only then prepare and batch,
6621
+ * synchronously. Resolving and preparing per row inside its own writer is what
6622
+ * fired WatermelonDB's "wasn't sent to batch() synchronously" diagnostic once
6623
+ * per memory (~107 on a single dev launch, sdk#891); it also cost N writes.
6624
+ * Same treatment as {@link stampTopicsExtractedAtOp}, including its
6625
+ * transpilation hazard — the prepare pass MUST stay a `.map()`.
6600
6626
  */
6601
6627
  declare function backfillMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryIds: readonly string[]): Promise<string[]>;
6602
6628
  declare function deleteAllVaultMemoriesForUserOp(ctx: VaultMemoryOperationsContext, userId: string): Promise<number>;
@@ -7789,6 +7815,22 @@ interface TurnCompleteEvent {
7789
7815
  * previously indistinguishable (both surfaced as zero candidates).
7790
7816
  */
7791
7817
  outcome: ExtractOutcome;
7818
+ /**
7819
+ * Present only alongside `outcome: "empty-after-retry"` — WHICH failure ended
7820
+ * the turn (#888).
7821
+ *
7822
+ * `outcome` says extraction gave up; this says why, from a stable enum. The
7823
+ * distinction is the whole point: a 2026-08-11 audit measured ~63% of
7824
+ * production extraction turns ending in `empty-after-retry` and could not tell
7825
+ * from telemetry whether the cause was the freeloader 403 everyone assumed or
7826
+ * something else. It took a Prometheus cross-check to find the real one — the
7827
+ * portal returning HTTP 200 with an empty body, which it counts as a success.
7828
+ *
7829
+ * Forward `failure.reason` into your extraction analytics event; all three
7830
+ * fields are bounded (an enum, an HTTP status, a small attempt count) and none
7831
+ * carries content.
7832
+ */
7833
+ failure?: PortalLlmFailure;
7792
7834
  }
7793
7835
  /** @public */
7794
7836
  /**
@@ -3642,8 +3642,26 @@ interface StoredConversationSummary {
3642
3642
  * A chunk of a message with its own embedding for fine-grained search
3643
3643
  */
3644
3644
  interface MessageChunk {
3645
- /** The chunk text */
3646
- text: string;
3645
+ /**
3646
+ * The chunk text — IN MEMORY ONLY. Not persisted (sdk#880).
3647
+ *
3648
+ * `chunkText` covers a message end to end with a 50-character overlap, so the
3649
+ * chunk set of any message over 400 characters reconstructs the whole thing.
3650
+ * Storing it put a fully readable copy of the message next to its own
3651
+ * ciphertext `content` on devices with at-rest encryption enabled.
3652
+ *
3653
+ * `updateMessageChunksOp` now strips this before writing and readers rebuild
3654
+ * the snippet from {@link startOffset}/{@link endOffset} against the message's
3655
+ * own (decrypted) `content` — so the text exists exactly once, under the
3656
+ * protection `content` already has. Encrypting the column instead was
3657
+ * rejected: the client reads this column raw and `JSON.parse`s it in four
3658
+ * places, each swallowing the throw and silently scoring 0.
3659
+ *
3660
+ * Optional because rows written before that change still carry it, and
3661
+ * readers prefer a stored value when present. It is populated in memory by
3662
+ * `chunkText()` and on the way out of a search.
3663
+ */
3664
+ text?: string;
3647
3665
  /**
3648
3666
  * Embedding vector for this chunk.
3649
3667
  *
@@ -6597,6 +6615,14 @@ declare function relinkMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryI
6597
6615
  * row has: a curated memory's topics are recorded as `user`, everything else as
6598
6616
  * `auto`. Skips deleted, foreign-user, unlinked rows, and rows that already have
6599
6617
  * a record. Returns the ids filled.
6618
+ *
6619
+ * Runs as ONE writer over the whole (caller-bounded) list, in two phases:
6620
+ * resolve every row's write — all the awaits — and only then prepare and batch,
6621
+ * synchronously. Resolving and preparing per row inside its own writer is what
6622
+ * fired WatermelonDB's "wasn't sent to batch() synchronously" diagnostic once
6623
+ * per memory (~107 on a single dev launch, sdk#891); it also cost N writes.
6624
+ * Same treatment as {@link stampTopicsExtractedAtOp}, including its
6625
+ * transpilation hazard — the prepare pass MUST stay a `.map()`.
6600
6626
  */
6601
6627
  declare function backfillMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryIds: readonly string[]): Promise<string[]>;
6602
6628
  declare function deleteAllVaultMemoriesForUserOp(ctx: VaultMemoryOperationsContext, userId: string): Promise<number>;
@@ -7789,6 +7815,22 @@ interface TurnCompleteEvent {
7789
7815
  * previously indistinguishable (both surfaced as zero candidates).
7790
7816
  */
7791
7817
  outcome: ExtractOutcome;
7818
+ /**
7819
+ * Present only alongside `outcome: "empty-after-retry"` — WHICH failure ended
7820
+ * the turn (#888).
7821
+ *
7822
+ * `outcome` says extraction gave up; this says why, from a stable enum. The
7823
+ * distinction is the whole point: a 2026-08-11 audit measured ~63% of
7824
+ * production extraction turns ending in `empty-after-retry` and could not tell
7825
+ * from telemetry whether the cause was the freeloader 403 everyone assumed or
7826
+ * something else. It took a Prometheus cross-check to find the real one — the
7827
+ * portal returning HTTP 200 with an empty body, which it counts as a success.
7828
+ *
7829
+ * Forward `failure.reason` into your extraction analytics event; all three
7830
+ * fields are bounded (an enum, an HTTP status, a small attempt count) and none
7831
+ * carries content.
7832
+ */
7833
+ failure?: PortalLlmFailure;
7792
7834
  }
7793
7835
  /** @public */
7794
7836
  /**
@@ -141,7 +141,7 @@ import {
141
141
  updateVaultMemoryOp,
142
142
  upsertMessageOp,
143
143
  vaultMemoryToStored
144
- } from "./chunk-FS6DNUNT.mjs";
144
+ } from "./chunk-I56324FR.mjs";
145
145
  import {
146
146
  createStreamingDeAnonymizer,
147
147
  notifyConsolidationFallback,
@@ -6371,7 +6371,7 @@ function createAutoExtractor(options) {
6371
6371
  const t0 = Date.now();
6372
6372
  void (async () => {
6373
6373
  try {
6374
- const { candidates, results, failedCount, outcome } = await extractAndRetain(
6374
+ const { candidates, results, failedCount, outcome, failure } = await extractAndRetain(
6375
6375
  window2,
6376
6376
  retainCtx,
6377
6377
  {
@@ -6411,7 +6411,11 @@ function createAutoExtractor(options) {
6411
6411
  failedCount,
6412
6412
  durationMs: Date.now() - t0,
6413
6413
  conversationId,
6414
- outcome
6414
+ outcome,
6415
+ // Only set alongside `outcome: "empty-after-retry"`. Spread so the key
6416
+ // is absent rather than explicitly undefined on a healthy turn —
6417
+ // analytics backends store an explicit undefined as a real value.
6418
+ ...failure !== void 0 && { failure }
6415
6419
  });
6416
6420
  } catch (err) {
6417
6421
  options.onError?.(err instanceof Error ? err : new Error(String(err)), conversationId);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  recall
3
- } from "./chunk-FS6DNUNT.mjs";
3
+ } from "./chunk-I56324FR.mjs";
4
4
  import "./chunk-KF5OU4IN.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": "6.8.1",
3
+ "version": "6.9.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -160,7 +160,7 @@
160
160
  "homepage": "https://github.com/anuma-ai/sdk#readme",
161
161
  "packageManager": "pnpm@10.23.0",
162
162
  "dependencies": {
163
- "@anuma/portal": "1.0.0-next.20260806040449",
163
+ "@anuma/portal": "1.0.0-next.20260811055217",
164
164
  "@babel/parser": "^7.29.2",
165
165
  "@babel/types": "^7.29.0",
166
166
  "ai": "6.0.202",