@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.
- package/dist/client/index.cjs +10 -0
- package/dist/client/index.d.mts +79 -1
- package/dist/client/index.d.ts +79 -1
- package/dist/client/index.mjs +9 -0
- package/dist/expo/{chunk-YO5UXOC4.mjs → chunk-4M56MKBV.mjs} +81 -48
- package/dist/expo/index.cjs +86 -49
- package/dist/expo/index.d.mts +44 -2
- package/dist/expo/index.d.ts +44 -2
- package/dist/expo/index.mjs +7 -3
- package/dist/expo/{recall-IEKVX4JL.mjs → recall-WIB7RQQZ.mjs} +1 -1
- package/dist/index.d.mts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/react/{chunk-POCLKALT.mjs → chunk-EJ65X4GI.mjs} +89 -50
- package/dist/react/index.cjs +94 -51
- package/dist/react/index.d.mts +44 -2
- package/dist/react/index.d.ts +44 -2
- package/dist/react/index.mjs +7 -3
- package/dist/react/{recall-B2AIAPCM.mjs → recall-FWILZSFH.mjs} +1 -1
- package/dist/server/{chunk-FS6DNUNT.mjs → chunk-I56324FR.mjs} +81 -48
- package/dist/server/index.cjs +86 -49
- package/dist/server/index.d.mts +44 -2
- package/dist/server/index.d.ts +44 -2
- package/dist/server/index.mjs +7 -3
- package/dist/server/{recall-2GAPE2XH.mjs → recall-T7CNXTQ3.mjs} +1 -1
- package/package.json +2 -2
package/dist/expo/index.cjs
CHANGED
|
@@ -2107,9 +2107,10 @@ async function updateMessageChunksOp(ctx, uniqueId, chunks, embeddingModel) {
|
|
|
2107
2107
|
} catch {
|
|
2108
2108
|
return null;
|
|
2109
2109
|
}
|
|
2110
|
+
const storedChunks = chunks.map(({ text: _text, ...rest }) => rest);
|
|
2110
2111
|
await ctx.database.write(async () => {
|
|
2111
2112
|
await message.update((msg) => {
|
|
2112
|
-
msg._setRaw("chunks", JSON.stringify(
|
|
2113
|
+
msg._setRaw("chunks", JSON.stringify(storedChunks));
|
|
2113
2114
|
msg._setRaw("embedding_model", embeddingModel);
|
|
2114
2115
|
});
|
|
2115
2116
|
});
|
|
@@ -2190,6 +2191,16 @@ async function _updateMessageOp(ctx, uniqueId, opts) {
|
|
|
2190
2191
|
});
|
|
2191
2192
|
return messageToStored(message, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
2192
2193
|
}
|
|
2194
|
+
function resolveChunkText(content, chunk, chunksInRow) {
|
|
2195
|
+
if (!chunk) return content;
|
|
2196
|
+
if (typeof chunk.text === "string" && chunk.text.length > 0) return chunk.text;
|
|
2197
|
+
const { startOffset: start, endOffset: end } = chunk;
|
|
2198
|
+
if (!Number.isInteger(start) || !Number.isInteger(end)) return content;
|
|
2199
|
+
if (start < 0 || end <= start || end > content.length) return content;
|
|
2200
|
+
const covered = chunksInRow?.reduce((max, c) => Math.max(max, c.endOffset ?? 0), 0) ?? 0;
|
|
2201
|
+
if (covered !== content.length) return content;
|
|
2202
|
+
return content.slice(start, end);
|
|
2203
|
+
}
|
|
2193
2204
|
async function readJsonField(model, column, walletAddress) {
|
|
2194
2205
|
const raw = model._getRaw(column);
|
|
2195
2206
|
if (!raw) return void 0;
|
|
@@ -2270,7 +2281,7 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2270
2281
|
candidates.push({
|
|
2271
2282
|
message,
|
|
2272
2283
|
similarity,
|
|
2273
|
-
chunkTextSource: { kind: "chunk",
|
|
2284
|
+
chunkTextSource: { kind: "chunk", chunk: chunks[ci], siblings: chunks }
|
|
2274
2285
|
});
|
|
2275
2286
|
}
|
|
2276
2287
|
}
|
|
@@ -2328,11 +2339,11 @@ async function searchChunksOp(ctx, queryVector, options) {
|
|
|
2328
2339
|
const stored = { ...storedById.get(message.id) };
|
|
2329
2340
|
let chunkText2;
|
|
2330
2341
|
if (chunkTextSource.kind === "chunk") {
|
|
2331
|
-
chunkText2 = chunkTextSource.
|
|
2342
|
+
chunkText2 = resolveChunkText(stored.content, chunkTextSource.chunk, chunkTextSource.siblings);
|
|
2332
2343
|
} else if (chunkTextSource.kind === "chunk-cached") {
|
|
2333
2344
|
const state = chunkStateByMsgId.get(message.id);
|
|
2334
2345
|
const chunk = state && state.version === chunkTextSource.version ? state.chunks[chunkTextSource.chunkIndex] : void 0;
|
|
2335
|
-
chunkText2 =
|
|
2346
|
+
chunkText2 = resolveChunkText(stored.content, chunk, state?.chunks);
|
|
2336
2347
|
} else {
|
|
2337
2348
|
chunkText2 = stored.content;
|
|
2338
2349
|
}
|
|
@@ -4660,13 +4671,13 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
4660
4671
|
}
|
|
4661
4672
|
const unique = Array.from(kindByName.keys());
|
|
4662
4673
|
const out = /* @__PURE__ */ new Map();
|
|
4663
|
-
if (unique.length === 0) return { entities: out, operations: [] };
|
|
4674
|
+
if (unique.length === 0) return { entities: out, operations: [], kindBackfills: [] };
|
|
4664
4675
|
const existing = await ctx.entityCollection.query(import_watermelondb8.Q.where("canonical_name", import_watermelondb8.Q.oneOf(unique))).fetch();
|
|
4665
4676
|
const existingNames = new Set(existing.map((e) => e.canonicalName));
|
|
4666
|
-
const
|
|
4677
|
+
const kindBackfills = existing.filter((e) => {
|
|
4667
4678
|
const incoming = kindByName.get(e.canonicalName);
|
|
4668
4679
|
return incoming !== void 0 && (e.kind === null || e.kind === void 0 || e.kind === "");
|
|
4669
|
-
});
|
|
4680
|
+
}).map((record) => ({ record, kind: kindByName.get(record.canonicalName) }));
|
|
4670
4681
|
const missing = unique.filter((n) => !existingNames.has(n));
|
|
4671
4682
|
const created = missing.map(
|
|
4672
4683
|
(name) => ctx.entityCollection.prepareCreate((record) => {
|
|
@@ -4675,14 +4686,19 @@ async function upsertEntitiesInWrite(ctx, entities) {
|
|
|
4675
4686
|
if (kind !== void 0) record._setRaw("kind", kind);
|
|
4676
4687
|
})
|
|
4677
4688
|
);
|
|
4678
|
-
const updated = updates.map(
|
|
4679
|
-
(e) => e.prepareUpdate((record) => {
|
|
4680
|
-
record._setRaw("kind", kindByName.get(e.canonicalName));
|
|
4681
|
-
})
|
|
4682
|
-
);
|
|
4683
4689
|
for (const e of existing) out.set(e.canonicalName, entityToStored(e));
|
|
4684
4690
|
for (const record of created) out.set(record.canonicalName, entityToStored(record));
|
|
4685
|
-
|
|
4691
|
+
for (const { record, kind } of kindBackfills) {
|
|
4692
|
+
out.set(record.canonicalName, { ...entityToStored(record), kind });
|
|
4693
|
+
}
|
|
4694
|
+
return { entities: out, operations: created, kindBackfills };
|
|
4695
|
+
}
|
|
4696
|
+
function prepareKindBackfills(backfills) {
|
|
4697
|
+
return backfills.map(
|
|
4698
|
+
({ record, kind }) => record.prepareUpdate((r) => {
|
|
4699
|
+
r._setRaw("kind", kind);
|
|
4700
|
+
})
|
|
4701
|
+
);
|
|
4686
4702
|
}
|
|
4687
4703
|
async function findVaultRowInWrite(ctx, memoryId) {
|
|
4688
4704
|
try {
|
|
@@ -4732,10 +4748,12 @@ function topicsForEntities(entities, displayNames, source) {
|
|
|
4732
4748
|
function toEntityObjects(entityInputs) {
|
|
4733
4749
|
return entityInputs.map((e) => typeof e === "string" ? { name: e } : e);
|
|
4734
4750
|
}
|
|
4735
|
-
async function
|
|
4751
|
+
async function resolveMemoryTopicsWrite(ctx, memoryId, linked, inputs, source) {
|
|
4736
4752
|
const row = await findVaultRowInWrite(ctx, memoryId);
|
|
4737
|
-
|
|
4738
|
-
|
|
4753
|
+
return resolveTopicsWrite(row, linked, displayNamesOf(toEntityObjects(inputs)), source);
|
|
4754
|
+
}
|
|
4755
|
+
function prepareMemoryTopicsUpdate(write) {
|
|
4756
|
+
return prepareTopicsUpdate(write.row, write.topics, Date.now());
|
|
4739
4757
|
}
|
|
4740
4758
|
async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
4741
4759
|
if (entityInputs.length === 0) return [];
|
|
@@ -4744,15 +4762,16 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
4744
4762
|
let skipped = false;
|
|
4745
4763
|
let entities = [];
|
|
4746
4764
|
await ctx.database.write(async () => {
|
|
4747
|
-
const {
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4765
|
+
const {
|
|
4766
|
+
entities: byName,
|
|
4767
|
+
operations: entityOps,
|
|
4768
|
+
kindBackfills
|
|
4769
|
+
} = await upsertEntitiesInWrite(ctx, normalized);
|
|
4751
4770
|
entities = Array.from(byName.values());
|
|
4752
4771
|
const vaultRow = await findVaultRowInWrite(ctx, memoryId);
|
|
4753
4772
|
if (options?.unlessTopicsUserManaged && autoLinkBlocked(vaultRow)) {
|
|
4754
|
-
if (entityOps.length > 0) {
|
|
4755
|
-
await ctx.database.batch(...entityOps);
|
|
4773
|
+
if (entityOps.length > 0 || kindBackfills.length > 0) {
|
|
4774
|
+
await ctx.database.batch(...entityOps, ...prepareKindBackfills(kindBackfills));
|
|
4756
4775
|
}
|
|
4757
4776
|
skipped = true;
|
|
4758
4777
|
return;
|
|
@@ -4772,7 +4791,9 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
4772
4791
|
displayNamesOf(normalized),
|
|
4773
4792
|
options?.topicsSource ?? "auto"
|
|
4774
4793
|
);
|
|
4775
|
-
if (entityOps.length === 0 && toCreate.length === 0 && topicsWrite === null)
|
|
4794
|
+
if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && topicsWrite === null) {
|
|
4795
|
+
return;
|
|
4796
|
+
}
|
|
4776
4797
|
const linkOps = toCreate.map(
|
|
4777
4798
|
(e) => ctx.memoryEntityCollection.prepareCreate((record) => {
|
|
4778
4799
|
record._setRaw("memory_id", memoryId);
|
|
@@ -4782,6 +4803,7 @@ async function linkMemoryEntitiesOp(ctx, memoryId, entityInputs, options) {
|
|
|
4782
4803
|
);
|
|
4783
4804
|
await ctx.database.batch(
|
|
4784
4805
|
...entityOps,
|
|
4806
|
+
...prepareKindBackfills(kindBackfills),
|
|
4785
4807
|
...linkOps,
|
|
4786
4808
|
...topicsWrite ? [prepareTopicsUpdate(topicsWrite.row, topicsWrite.topics, Date.now())] : []
|
|
4787
4809
|
);
|
|
@@ -4819,10 +4841,11 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
4819
4841
|
skipped = true;
|
|
4820
4842
|
return;
|
|
4821
4843
|
}
|
|
4822
|
-
const {
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4844
|
+
const {
|
|
4845
|
+
entities: byName,
|
|
4846
|
+
operations: entityOps,
|
|
4847
|
+
kindBackfills
|
|
4848
|
+
} = await upsertEntitiesInWrite(ctx, normalized);
|
|
4826
4849
|
entities = Array.from(byName.values());
|
|
4827
4850
|
const existingLinks = await ctx.memoryEntityCollection.query(import_watermelondb8.Q.where("memory_id", memoryId)).fetch();
|
|
4828
4851
|
const keep = new Set(entities.map((e) => e.uniqueId));
|
|
@@ -4835,12 +4858,13 @@ async function replaceMemoryEntities(ctx, memoryId, entityInputs, options) {
|
|
|
4835
4858
|
displayNamesOf(normalized),
|
|
4836
4859
|
options.topicsSource
|
|
4837
4860
|
);
|
|
4838
|
-
if (entityOps.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
|
|
4861
|
+
if (entityOps.length === 0 && kindBackfills.length === 0 && toCreate.length === 0 && toDestroy.length === 0 && topicsWrite === null) {
|
|
4839
4862
|
return;
|
|
4840
4863
|
}
|
|
4841
4864
|
const orphans = await findOrphanedEntities(ctx, memoryId, toDestroy);
|
|
4842
4865
|
await ctx.database.batch(
|
|
4843
4866
|
...entityOps,
|
|
4867
|
+
...prepareKindBackfills(kindBackfills),
|
|
4844
4868
|
...toCreate.map(
|
|
4845
4869
|
(e) => ctx.memoryEntityCollection.prepareCreate((record) => {
|
|
4846
4870
|
record._setRaw("memory_id", memoryId);
|
|
@@ -5929,27 +5953,36 @@ async function backfillMemoryTopicsOp(ctx, memoryIds) {
|
|
|
5929
5953
|
if (!entityCtx) {
|
|
5930
5954
|
throw new Error("backfillMemoryTopicsOp requires ctx.entityCtx");
|
|
5931
5955
|
}
|
|
5956
|
+
const uniqueIds = Array.from(new Set(memoryIds));
|
|
5957
|
+
if (uniqueIds.length === 0) return [];
|
|
5932
5958
|
const filled = [];
|
|
5933
|
-
|
|
5934
|
-
|
|
5935
|
-
|
|
5936
|
-
record = await ctx.vaultMemoryCollection.find(id);
|
|
5937
|
-
} catch {
|
|
5938
|
-
continue;
|
|
5939
|
-
}
|
|
5940
|
-
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
|
|
5941
|
-
if (parseTopics(record.topics) !== null) continue;
|
|
5942
|
-
const links = await entityCtx.memoryEntityCollection.query(import_watermelondb9.Q.where("memory_id", id)).unsafeFetchRaw();
|
|
5943
|
-
const entityIds = links.map((l) => String(l.entity_id));
|
|
5944
|
-
if (entityIds.length === 0) continue;
|
|
5945
|
-
const entities = await entityCtx.entityCollection.query(import_watermelondb9.Q.where("id", import_watermelondb9.Q.oneOf(entityIds))).fetch();
|
|
5946
|
-
if (entities.length === 0) continue;
|
|
5947
|
-
const source = record.topicsUserManaged ? "user" : "auto";
|
|
5959
|
+
const CHUNK = 500;
|
|
5960
|
+
for (let i = 0; i < uniqueIds.length; i += CHUNK) {
|
|
5961
|
+
const chunkIds = uniqueIds.slice(i, i + CHUNK);
|
|
5948
5962
|
await ctx.database.write(async () => {
|
|
5949
|
-
const
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5963
|
+
const writes = [];
|
|
5964
|
+
for (const id of chunkIds) {
|
|
5965
|
+
let record;
|
|
5966
|
+
try {
|
|
5967
|
+
record = await ctx.vaultMemoryCollection.find(id);
|
|
5968
|
+
} catch {
|
|
5969
|
+
continue;
|
|
5970
|
+
}
|
|
5971
|
+
if (record.isDeleted || !isOwnedByCtxUser(ctx, record)) continue;
|
|
5972
|
+
if (parseTopics(record.topics) !== null) continue;
|
|
5973
|
+
const links = await entityCtx.memoryEntityCollection.query(import_watermelondb9.Q.where("memory_id", id)).unsafeFetchRaw();
|
|
5974
|
+
const entityIds = links.map((l) => String(l.entity_id));
|
|
5975
|
+
if (entityIds.length === 0) continue;
|
|
5976
|
+
const entities = await entityCtx.entityCollection.query(import_watermelondb9.Q.where("id", import_watermelondb9.Q.oneOf(entityIds))).fetch();
|
|
5977
|
+
if (entities.length === 0) continue;
|
|
5978
|
+
const source = record.topicsUserManaged ? "user" : "auto";
|
|
5979
|
+
const write = await resolveMemoryTopicsWrite(entityCtx, id, entities, [], source);
|
|
5980
|
+
if (write) writes.push(write);
|
|
5981
|
+
}
|
|
5982
|
+
if (writes.length === 0) return;
|
|
5983
|
+
const prepared = writes.map(prepareMemoryTopicsUpdate);
|
|
5984
|
+
await ctx.database.batch(...prepared);
|
|
5985
|
+
for (const write of writes) filled.push(write.row.id);
|
|
5953
5986
|
});
|
|
5954
5987
|
}
|
|
5955
5988
|
return filled;
|
|
@@ -17084,7 +17117,7 @@ function createAutoExtractor(options) {
|
|
|
17084
17117
|
const t0 = Date.now();
|
|
17085
17118
|
void (async () => {
|
|
17086
17119
|
try {
|
|
17087
|
-
const { candidates, results, failedCount, outcome } = await extractAndRetain(
|
|
17120
|
+
const { candidates, results, failedCount, outcome, failure } = await extractAndRetain(
|
|
17088
17121
|
window2,
|
|
17089
17122
|
retainCtx,
|
|
17090
17123
|
{
|
|
@@ -17124,7 +17157,11 @@ function createAutoExtractor(options) {
|
|
|
17124
17157
|
failedCount,
|
|
17125
17158
|
durationMs: Date.now() - t0,
|
|
17126
17159
|
conversationId,
|
|
17127
|
-
outcome
|
|
17160
|
+
outcome,
|
|
17161
|
+
// Only set alongside `outcome: "empty-after-retry"`. Spread so the key
|
|
17162
|
+
// is absent rather than explicitly undefined on a healthy turn —
|
|
17163
|
+
// analytics backends store an explicit undefined as a real value.
|
|
17164
|
+
...failure !== void 0 && { failure }
|
|
17128
17165
|
});
|
|
17129
17166
|
} catch (err) {
|
|
17130
17167
|
options.onError?.(err instanceof Error ? err : new Error(String(err)), conversationId);
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -3635,8 +3635,26 @@ interface StoredMessageWithSimilarity extends StoredMessage {
|
|
|
3635
3635
|
* A chunk of a message with its own embedding for fine-grained search
|
|
3636
3636
|
*/
|
|
3637
3637
|
interface MessageChunk {
|
|
3638
|
-
/**
|
|
3639
|
-
|
|
3638
|
+
/**
|
|
3639
|
+
* The chunk text — IN MEMORY ONLY. Not persisted (sdk#880).
|
|
3640
|
+
*
|
|
3641
|
+
* `chunkText` covers a message end to end with a 50-character overlap, so the
|
|
3642
|
+
* chunk set of any message over 400 characters reconstructs the whole thing.
|
|
3643
|
+
* Storing it put a fully readable copy of the message next to its own
|
|
3644
|
+
* ciphertext `content` on devices with at-rest encryption enabled.
|
|
3645
|
+
*
|
|
3646
|
+
* `updateMessageChunksOp` now strips this before writing and readers rebuild
|
|
3647
|
+
* the snippet from {@link startOffset}/{@link endOffset} against the message's
|
|
3648
|
+
* own (decrypted) `content` — so the text exists exactly once, under the
|
|
3649
|
+
* protection `content` already has. Encrypting the column instead was
|
|
3650
|
+
* rejected: the client reads this column raw and `JSON.parse`s it in four
|
|
3651
|
+
* places, each swallowing the throw and silently scoring 0.
|
|
3652
|
+
*
|
|
3653
|
+
* Optional because rows written before that change still carry it, and
|
|
3654
|
+
* readers prefer a stored value when present. It is populated in memory by
|
|
3655
|
+
* `chunkText()` and on the way out of a search.
|
|
3656
|
+
*/
|
|
3657
|
+
text?: string;
|
|
3640
3658
|
/**
|
|
3641
3659
|
* Embedding vector for this chunk.
|
|
3642
3660
|
*
|
|
@@ -6750,6 +6768,14 @@ declare function relinkMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryI
|
|
|
6750
6768
|
* row has: a curated memory's topics are recorded as `user`, everything else as
|
|
6751
6769
|
* `auto`. Skips deleted, foreign-user, unlinked rows, and rows that already have
|
|
6752
6770
|
* a record. Returns the ids filled.
|
|
6771
|
+
*
|
|
6772
|
+
* Runs as ONE writer over the whole (caller-bounded) list, in two phases:
|
|
6773
|
+
* resolve every row's write — all the awaits — and only then prepare and batch,
|
|
6774
|
+
* synchronously. Resolving and preparing per row inside its own writer is what
|
|
6775
|
+
* fired WatermelonDB's "wasn't sent to batch() synchronously" diagnostic once
|
|
6776
|
+
* per memory (~107 on a single dev launch, sdk#891); it also cost N writes.
|
|
6777
|
+
* Same treatment as {@link stampTopicsExtractedAtOp}, including its
|
|
6778
|
+
* transpilation hazard — the prepare pass MUST stay a `.map()`.
|
|
6753
6779
|
*/
|
|
6754
6780
|
declare function backfillMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryIds: readonly string[]): Promise<string[]>;
|
|
6755
6781
|
declare function deleteAllVaultMemoriesForUserOp(ctx: VaultMemoryOperationsContext, userId: string): Promise<number>;
|
|
@@ -7212,6 +7238,22 @@ interface TurnCompleteEvent {
|
|
|
7212
7238
|
* previously indistinguishable (both surfaced as zero candidates).
|
|
7213
7239
|
*/
|
|
7214
7240
|
outcome: ExtractOutcome;
|
|
7241
|
+
/**
|
|
7242
|
+
* Present only alongside `outcome: "empty-after-retry"` — WHICH failure ended
|
|
7243
|
+
* the turn (#888).
|
|
7244
|
+
*
|
|
7245
|
+
* `outcome` says extraction gave up; this says why, from a stable enum. The
|
|
7246
|
+
* distinction is the whole point: a 2026-08-11 audit measured ~63% of
|
|
7247
|
+
* production extraction turns ending in `empty-after-retry` and could not tell
|
|
7248
|
+
* from telemetry whether the cause was the freeloader 403 everyone assumed or
|
|
7249
|
+
* something else. It took a Prometheus cross-check to find the real one — the
|
|
7250
|
+
* portal returning HTTP 200 with an empty body, which it counts as a success.
|
|
7251
|
+
*
|
|
7252
|
+
* Forward `failure.reason` into your extraction analytics event; all three
|
|
7253
|
+
* fields are bounded (an enum, an HTTP status, a small attempt count) and none
|
|
7254
|
+
* carries content.
|
|
7255
|
+
*/
|
|
7256
|
+
failure?: PortalLlmFailure;
|
|
7215
7257
|
}
|
|
7216
7258
|
/** @public */
|
|
7217
7259
|
/**
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -3635,8 +3635,26 @@ interface StoredMessageWithSimilarity extends StoredMessage {
|
|
|
3635
3635
|
* A chunk of a message with its own embedding for fine-grained search
|
|
3636
3636
|
*/
|
|
3637
3637
|
interface MessageChunk {
|
|
3638
|
-
/**
|
|
3639
|
-
|
|
3638
|
+
/**
|
|
3639
|
+
* The chunk text — IN MEMORY ONLY. Not persisted (sdk#880).
|
|
3640
|
+
*
|
|
3641
|
+
* `chunkText` covers a message end to end with a 50-character overlap, so the
|
|
3642
|
+
* chunk set of any message over 400 characters reconstructs the whole thing.
|
|
3643
|
+
* Storing it put a fully readable copy of the message next to its own
|
|
3644
|
+
* ciphertext `content` on devices with at-rest encryption enabled.
|
|
3645
|
+
*
|
|
3646
|
+
* `updateMessageChunksOp` now strips this before writing and readers rebuild
|
|
3647
|
+
* the snippet from {@link startOffset}/{@link endOffset} against the message's
|
|
3648
|
+
* own (decrypted) `content` — so the text exists exactly once, under the
|
|
3649
|
+
* protection `content` already has. Encrypting the column instead was
|
|
3650
|
+
* rejected: the client reads this column raw and `JSON.parse`s it in four
|
|
3651
|
+
* places, each swallowing the throw and silently scoring 0.
|
|
3652
|
+
*
|
|
3653
|
+
* Optional because rows written before that change still carry it, and
|
|
3654
|
+
* readers prefer a stored value when present. It is populated in memory by
|
|
3655
|
+
* `chunkText()` and on the way out of a search.
|
|
3656
|
+
*/
|
|
3657
|
+
text?: string;
|
|
3640
3658
|
/**
|
|
3641
3659
|
* Embedding vector for this chunk.
|
|
3642
3660
|
*
|
|
@@ -6750,6 +6768,14 @@ declare function relinkMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryI
|
|
|
6750
6768
|
* row has: a curated memory's topics are recorded as `user`, everything else as
|
|
6751
6769
|
* `auto`. Skips deleted, foreign-user, unlinked rows, and rows that already have
|
|
6752
6770
|
* a record. Returns the ids filled.
|
|
6771
|
+
*
|
|
6772
|
+
* Runs as ONE writer over the whole (caller-bounded) list, in two phases:
|
|
6773
|
+
* resolve every row's write — all the awaits — and only then prepare and batch,
|
|
6774
|
+
* synchronously. Resolving and preparing per row inside its own writer is what
|
|
6775
|
+
* fired WatermelonDB's "wasn't sent to batch() synchronously" diagnostic once
|
|
6776
|
+
* per memory (~107 on a single dev launch, sdk#891); it also cost N writes.
|
|
6777
|
+
* Same treatment as {@link stampTopicsExtractedAtOp}, including its
|
|
6778
|
+
* transpilation hazard — the prepare pass MUST stay a `.map()`.
|
|
6753
6779
|
*/
|
|
6754
6780
|
declare function backfillMemoryTopicsOp(ctx: VaultMemoryOperationsContext, memoryIds: readonly string[]): Promise<string[]>;
|
|
6755
6781
|
declare function deleteAllVaultMemoriesForUserOp(ctx: VaultMemoryOperationsContext, userId: string): Promise<number>;
|
|
@@ -7212,6 +7238,22 @@ interface TurnCompleteEvent {
|
|
|
7212
7238
|
* previously indistinguishable (both surfaced as zero candidates).
|
|
7213
7239
|
*/
|
|
7214
7240
|
outcome: ExtractOutcome;
|
|
7241
|
+
/**
|
|
7242
|
+
* Present only alongside `outcome: "empty-after-retry"` — WHICH failure ended
|
|
7243
|
+
* the turn (#888).
|
|
7244
|
+
*
|
|
7245
|
+
* `outcome` says extraction gave up; this says why, from a stable enum. The
|
|
7246
|
+
* distinction is the whole point: a 2026-08-11 audit measured ~63% of
|
|
7247
|
+
* production extraction turns ending in `empty-after-retry` and could not tell
|
|
7248
|
+
* from telemetry whether the cause was the freeloader 403 everyone assumed or
|
|
7249
|
+
* something else. It took a Prometheus cross-check to find the real one — the
|
|
7250
|
+
* portal returning HTTP 200 with an empty body, which it counts as a success.
|
|
7251
|
+
*
|
|
7252
|
+
* Forward `failure.reason` into your extraction analytics event; all three
|
|
7253
|
+
* fields are bounded (an enum, an HTTP status, a small attempt count) and none
|
|
7254
|
+
* carries content.
|
|
7255
|
+
*/
|
|
7256
|
+
failure?: PortalLlmFailure;
|
|
7215
7257
|
}
|
|
7216
7258
|
/** @public */
|
|
7217
7259
|
/**
|
package/dist/expo/index.mjs
CHANGED
|
@@ -132,7 +132,7 @@ import {
|
|
|
132
132
|
upsertMessageOp,
|
|
133
133
|
useEncryption,
|
|
134
134
|
vaultMemoryToStored
|
|
135
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-4M56MKBV.mjs";
|
|
136
136
|
import {
|
|
137
137
|
PII_PATTERNS,
|
|
138
138
|
PiiRedactor,
|
|
@@ -7539,7 +7539,7 @@ function createAutoExtractor(options) {
|
|
|
7539
7539
|
const t0 = Date.now();
|
|
7540
7540
|
void (async () => {
|
|
7541
7541
|
try {
|
|
7542
|
-
const { candidates, results, failedCount, outcome } = await extractAndRetain(
|
|
7542
|
+
const { candidates, results, failedCount, outcome, failure } = await extractAndRetain(
|
|
7543
7543
|
window,
|
|
7544
7544
|
retainCtx,
|
|
7545
7545
|
{
|
|
@@ -7579,7 +7579,11 @@ function createAutoExtractor(options) {
|
|
|
7579
7579
|
failedCount,
|
|
7580
7580
|
durationMs: Date.now() - t0,
|
|
7581
7581
|
conversationId,
|
|
7582
|
-
outcome
|
|
7582
|
+
outcome,
|
|
7583
|
+
// Only set alongside `outcome: "empty-after-retry"`. Spread so the key
|
|
7584
|
+
// is absent rather than explicitly undefined on a healthy turn —
|
|
7585
|
+
// analytics backends store an explicit undefined as a real value.
|
|
7586
|
+
...failure !== void 0 && { failure }
|
|
7583
7587
|
});
|
|
7584
7588
|
} catch (err) {
|
|
7585
7589
|
options.onError?.(err instanceof Error ? err : new Error(String(err)), conversationId);
|
package/dist/index.d.mts
CHANGED
|
@@ -2462,6 +2462,14 @@ type HandlersUserLookupAccount = {
|
|
|
2462
2462
|
fraud_notes?: string;
|
|
2463
2463
|
id?: number;
|
|
2464
2464
|
identifier?: string;
|
|
2465
|
+
/**
|
|
2466
|
+
* InternalTester and InternalTesterAt report the People Nearby internal-tester grant (#1578), so
|
|
2467
|
+
* the console renders the toggle's CURRENT state instead of guessing. Always emitted (no omitempty)
|
|
2468
|
+
* because false is meaningful here — an absent field would be indistinguishable from an older
|
|
2469
|
+
* portal build, on a security-relevant flag.
|
|
2470
|
+
*/
|
|
2471
|
+
internal_tester?: boolean;
|
|
2472
|
+
internal_tester_at?: string;
|
|
2465
2473
|
stripe_customer_id?: string;
|
|
2466
2474
|
type?: string;
|
|
2467
2475
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -2462,6 +2462,14 @@ type HandlersUserLookupAccount = {
|
|
|
2462
2462
|
fraud_notes?: string;
|
|
2463
2463
|
id?: number;
|
|
2464
2464
|
identifier?: string;
|
|
2465
|
+
/**
|
|
2466
|
+
* InternalTester and InternalTesterAt report the People Nearby internal-tester grant (#1578), so
|
|
2467
|
+
* the console renders the toggle's CURRENT state instead of guessing. Always emitted (no omitempty)
|
|
2468
|
+
* because false is meaningful here — an absent field would be indistinguishable from an older
|
|
2469
|
+
* portal build, on a security-relevant flag.
|
|
2470
|
+
*/
|
|
2471
|
+
internal_tester?: boolean;
|
|
2472
|
+
internal_tester_at?: string;
|
|
2465
2473
|
stripe_customer_id?: string;
|
|
2466
2474
|
type?: string;
|
|
2467
2475
|
};
|