@anuma/sdk 9.1.5 → 9.1.6
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/expo/{chunk-XW3LYSDA.mjs → chunk-WRZTH4OS.mjs} +38 -13
- package/dist/expo/{consolidate-4CQJYKRK.mjs → consolidate-HKL5EGZT.mjs} +1 -1
- package/dist/expo/index.cjs +69 -28
- package/dist/expo/index.d.mts +9 -5
- package/dist/expo/index.d.ts +9 -5
- package/dist/expo/index.mjs +32 -16
- package/dist/react/{chunk-7QX4J7KV.mjs → chunk-RSA3S6OA.mjs} +38 -13
- package/dist/react/{consolidate-WLDYJF6J.mjs → consolidate-WFTPBHDV.mjs} +1 -1
- package/dist/react/index.cjs +80 -38
- package/dist/react/index.d.mts +9 -5
- package/dist/react/index.d.ts +9 -5
- package/dist/react/index.mjs +48 -31
- package/dist/server/{chunk-AU3Z7NBC.mjs → chunk-QEROZ4VH.mjs} +38 -13
- package/dist/server/{consolidate-B6OSCZU4.mjs → consolidate-PYED62LW.mjs} +1 -1
- package/dist/server/index.cjs +66 -25
- package/dist/server/index.d.mts +9 -5
- package/dist/server/index.d.ts +9 -5
- package/dist/server/index.mjs +29 -13
- package/package.json +1 -1
|
@@ -723,6 +723,12 @@ function assertTransportMatchesEndpoint(transport, endpoint) {
|
|
|
723
723
|
`endpointOverride "${endpoint}" is the other transport's endpoint, but transport is "${transport}". The request body is built for the transport, so this sends the wrong shape and 400s without retry.`
|
|
724
724
|
);
|
|
725
725
|
}
|
|
726
|
+
var TIME_BUDGET_EXHAUSTED = {
|
|
727
|
+
kind: "terminal",
|
|
728
|
+
code: "time-budget-exhausted",
|
|
729
|
+
reason: "time budget exhausted"
|
|
730
|
+
};
|
|
731
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
726
732
|
var RETRYABLE_HTTP = /* @__PURE__ */ new Set([408, 409, 425, 429]);
|
|
727
733
|
function isRetryableStatus(status) {
|
|
728
734
|
return status >= 500 || RETRYABLE_HTTP.has(status);
|
|
@@ -778,7 +784,8 @@ async function callPortalJsonCompletion(req) {
|
|
|
778
784
|
}
|
|
779
785
|
const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
|
|
780
786
|
const startedAt = Date.now();
|
|
781
|
-
const
|
|
787
|
+
const deadlineAt = req.totalTimeoutMs === void 0 ? void 0 : startedAt + req.totalTimeoutMs;
|
|
788
|
+
const overBudget = () => deadlineAt !== void 0 && Date.now() >= deadlineAt;
|
|
782
789
|
let lastFailure;
|
|
783
790
|
let reinforce = false;
|
|
784
791
|
const giveUp = () => {
|
|
@@ -791,17 +798,11 @@ async function callPortalJsonCompletion(req) {
|
|
|
791
798
|
lastFailure = { reason: "time-budget-exhausted", attempts: attempt - 1 };
|
|
792
799
|
break;
|
|
793
800
|
}
|
|
794
|
-
const attemptReq = req
|
|
795
|
-
...req,
|
|
796
|
-
timeoutMs: Math.max(
|
|
797
|
-
1,
|
|
798
|
-
Math.min(req.timeoutMs ?? 6e4, req.totalTimeoutMs - (Date.now() - startedAt))
|
|
799
|
-
),
|
|
800
|
-
...reinforce && { reinforceJsonContract: true }
|
|
801
|
-
} : reinforce ? { ...req, reinforceJsonContract: true } : req;
|
|
801
|
+
const attemptReq = reinforce ? { ...req, reinforceJsonContract: true } : req;
|
|
802
802
|
const outcome = await attemptPortalJson(
|
|
803
803
|
{ ...attemptReq, transport },
|
|
804
|
-
endpoint
|
|
804
|
+
endpoint,
|
|
805
|
+
deadlineAt
|
|
805
806
|
);
|
|
806
807
|
if (outcome.kind === "ok") {
|
|
807
808
|
req.onAttempt?.({ attempt, ok: true });
|
|
@@ -841,13 +842,38 @@ async function callPortalJsonCompletion(req) {
|
|
|
841
842
|
}
|
|
842
843
|
return giveUp();
|
|
843
844
|
}
|
|
844
|
-
async function attemptPortalJson(req, endpoint) {
|
|
845
|
+
async function attemptPortalJson(req, endpoint, deadlineAt) {
|
|
846
|
+
const controller = new AbortController();
|
|
847
|
+
if (deadlineAt === void 0 || deadlineAt - Date.now() > MAX_TIMER_DELAY_MS) {
|
|
848
|
+
return requestPortalJson(req, endpoint, controller);
|
|
849
|
+
}
|
|
850
|
+
const remainingMs = deadlineAt - Date.now();
|
|
851
|
+
if (remainingMs <= 0) return TIME_BUDGET_EXHAUSTED;
|
|
852
|
+
let timer;
|
|
853
|
+
try {
|
|
854
|
+
const outcome = await Promise.race([
|
|
855
|
+
new Promise((resolve) => {
|
|
856
|
+
timer = setTimeout(() => {
|
|
857
|
+
resolve(TIME_BUDGET_EXHAUSTED);
|
|
858
|
+
controller.abort();
|
|
859
|
+
}, remainingMs);
|
|
860
|
+
}),
|
|
861
|
+
requestPortalJson(req, endpoint, controller, deadlineAt)
|
|
862
|
+
]);
|
|
863
|
+
return Date.now() >= deadlineAt ? TIME_BUDGET_EXHAUSTED : outcome;
|
|
864
|
+
} finally {
|
|
865
|
+
clearTimeout(timer);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
async function requestPortalJson(req, endpoint, controller, deadlineAt) {
|
|
845
869
|
const baseUrl = req.baseUrl ?? defaultBaseUrl();
|
|
846
870
|
const fetchImpl = req.fetchFn ?? fetch;
|
|
847
|
-
const timeoutMs = req.timeoutMs ?? 6e4;
|
|
848
871
|
const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
|
|
872
|
+
const remainingMs = deadlineAt === void 0 ? Infinity : deadlineAt - Date.now();
|
|
873
|
+
if (controller.signal.aborted || remainingMs <= 0) return TIME_BUDGET_EXHAUSTED;
|
|
849
874
|
if (authHeaders === null)
|
|
850
875
|
return { kind: "terminal", code: "auth-unavailable", reason: "auth unavailable (no token)" };
|
|
876
|
+
const timeoutMs = Math.min(req.timeoutMs ?? 6e4, remainingMs);
|
|
851
877
|
const usesPrefill = req.transport !== "responses" && req.model.startsWith("anthropic/");
|
|
852
878
|
const prefill = usesPrefill ? "{" : "";
|
|
853
879
|
const messages = [
|
|
@@ -857,7 +883,6 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
857
883
|
];
|
|
858
884
|
if (prefill) messages.push({ role: "assistant", content: prefill });
|
|
859
885
|
const supportsJsonObjectFormat = supportsResponseFormat(req.model);
|
|
860
|
-
const controller = new AbortController();
|
|
861
886
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
862
887
|
const requestBody = req.transport === "responses" ? {
|
|
863
888
|
model: req.model,
|
package/dist/expo/index.cjs
CHANGED
|
@@ -875,7 +875,8 @@ async function callPortalJsonCompletion(req) {
|
|
|
875
875
|
}
|
|
876
876
|
const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
|
|
877
877
|
const startedAt = Date.now();
|
|
878
|
-
const
|
|
878
|
+
const deadlineAt = req.totalTimeoutMs === void 0 ? void 0 : startedAt + req.totalTimeoutMs;
|
|
879
|
+
const overBudget = () => deadlineAt !== void 0 && Date.now() >= deadlineAt;
|
|
879
880
|
let lastFailure;
|
|
880
881
|
let reinforce = false;
|
|
881
882
|
const giveUp = () => {
|
|
@@ -888,17 +889,11 @@ async function callPortalJsonCompletion(req) {
|
|
|
888
889
|
lastFailure = { reason: "time-budget-exhausted", attempts: attempt - 1 };
|
|
889
890
|
break;
|
|
890
891
|
}
|
|
891
|
-
const attemptReq = req
|
|
892
|
-
...req,
|
|
893
|
-
timeoutMs: Math.max(
|
|
894
|
-
1,
|
|
895
|
-
Math.min(req.timeoutMs ?? 6e4, req.totalTimeoutMs - (Date.now() - startedAt))
|
|
896
|
-
),
|
|
897
|
-
...reinforce && { reinforceJsonContract: true }
|
|
898
|
-
} : reinforce ? { ...req, reinforceJsonContract: true } : req;
|
|
892
|
+
const attemptReq = reinforce ? { ...req, reinforceJsonContract: true } : req;
|
|
899
893
|
const outcome2 = await attemptPortalJson(
|
|
900
894
|
{ ...attemptReq, transport },
|
|
901
|
-
endpoint
|
|
895
|
+
endpoint,
|
|
896
|
+
deadlineAt
|
|
902
897
|
);
|
|
903
898
|
if (outcome2.kind === "ok") {
|
|
904
899
|
req.onAttempt?.({ attempt, ok: true });
|
|
@@ -938,13 +933,38 @@ async function callPortalJsonCompletion(req) {
|
|
|
938
933
|
}
|
|
939
934
|
return giveUp();
|
|
940
935
|
}
|
|
941
|
-
async function attemptPortalJson(req, endpoint) {
|
|
936
|
+
async function attemptPortalJson(req, endpoint, deadlineAt) {
|
|
937
|
+
const controller = new AbortController();
|
|
938
|
+
if (deadlineAt === void 0 || deadlineAt - Date.now() > MAX_TIMER_DELAY_MS) {
|
|
939
|
+
return requestPortalJson(req, endpoint, controller);
|
|
940
|
+
}
|
|
941
|
+
const remainingMs = deadlineAt - Date.now();
|
|
942
|
+
if (remainingMs <= 0) return TIME_BUDGET_EXHAUSTED;
|
|
943
|
+
let timer;
|
|
944
|
+
try {
|
|
945
|
+
const outcome2 = await Promise.race([
|
|
946
|
+
new Promise((resolve) => {
|
|
947
|
+
timer = setTimeout(() => {
|
|
948
|
+
resolve(TIME_BUDGET_EXHAUSTED);
|
|
949
|
+
controller.abort();
|
|
950
|
+
}, remainingMs);
|
|
951
|
+
}),
|
|
952
|
+
requestPortalJson(req, endpoint, controller, deadlineAt)
|
|
953
|
+
]);
|
|
954
|
+
return Date.now() >= deadlineAt ? TIME_BUDGET_EXHAUSTED : outcome2;
|
|
955
|
+
} finally {
|
|
956
|
+
clearTimeout(timer);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
async function requestPortalJson(req, endpoint, controller, deadlineAt) {
|
|
942
960
|
const baseUrl = req.baseUrl ?? defaultBaseUrl();
|
|
943
961
|
const fetchImpl = req.fetchFn ?? fetch;
|
|
944
|
-
const timeoutMs = req.timeoutMs ?? 6e4;
|
|
945
962
|
const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
|
|
963
|
+
const remainingMs = deadlineAt === void 0 ? Infinity : deadlineAt - Date.now();
|
|
964
|
+
if (controller.signal.aborted || remainingMs <= 0) return TIME_BUDGET_EXHAUSTED;
|
|
946
965
|
if (authHeaders === null)
|
|
947
966
|
return { kind: "terminal", code: "auth-unavailable", reason: "auth unavailable (no token)" };
|
|
967
|
+
const timeoutMs = Math.min(req.timeoutMs ?? 6e4, remainingMs);
|
|
948
968
|
const usesPrefill = req.transport !== "responses" && req.model.startsWith("anthropic/");
|
|
949
969
|
const prefill = usesPrefill ? "{" : "";
|
|
950
970
|
const messages = [
|
|
@@ -954,7 +974,6 @@ async function attemptPortalJson(req, endpoint) {
|
|
|
954
974
|
];
|
|
955
975
|
if (prefill) messages.push({ role: "assistant", content: prefill });
|
|
956
976
|
const supportsJsonObjectFormat = supportsResponseFormat(req.model);
|
|
957
|
-
const controller = new AbortController();
|
|
958
977
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
959
978
|
const requestBody = req.transport === "responses" ? {
|
|
960
979
|
model: req.model,
|
|
@@ -1139,7 +1158,7 @@ function extractResponsesContent(body) {
|
|
|
1139
1158
|
const text14 = root.output.filter((item) => asRecord(item)?.type === "message").flatMap((item) => Array.isArray(item.content) ? item.content : []).map((part) => asRecord(part)?.text).filter((t) => typeof t === "string").join("");
|
|
1140
1159
|
return text14;
|
|
1141
1160
|
}
|
|
1142
|
-
var RESPONSE_FORMAT_OK, RESPONSE_SCHEMA_OK, JSON_CONTRACT_REMINDER, RESPONSES_ONLY_MODEL_PREFIXES, CHAT_TO_RESPONSES_FIELDS, FOREIGN_ENDPOINT_SUFFIX, RETRYABLE_HTTP;
|
|
1161
|
+
var RESPONSE_FORMAT_OK, RESPONSE_SCHEMA_OK, JSON_CONTRACT_REMINDER, RESPONSES_ONLY_MODEL_PREFIXES, CHAT_TO_RESPONSES_FIELDS, FOREIGN_ENDPOINT_SUFFIX, TIME_BUDGET_EXHAUSTED, MAX_TIMER_DELAY_MS, RETRYABLE_HTTP;
|
|
1143
1162
|
var init_portalLlm = __esm({
|
|
1144
1163
|
"src/lib/memory/portalLlm.ts"() {
|
|
1145
1164
|
"use strict";
|
|
@@ -1159,6 +1178,12 @@ var init_portalLlm = __esm({
|
|
|
1159
1178
|
chat: "/responses",
|
|
1160
1179
|
responses: "/chat/completions"
|
|
1161
1180
|
};
|
|
1181
|
+
TIME_BUDGET_EXHAUSTED = {
|
|
1182
|
+
kind: "terminal",
|
|
1183
|
+
code: "time-budget-exhausted",
|
|
1184
|
+
reason: "time budget exhausted"
|
|
1185
|
+
};
|
|
1186
|
+
MAX_TIMER_DELAY_MS = 2147483647;
|
|
1162
1187
|
RETRYABLE_HTTP = /* @__PURE__ */ new Set([408, 409, 425, 429]);
|
|
1163
1188
|
}
|
|
1164
1189
|
});
|
|
@@ -14971,6 +14996,16 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
14971
14996
|
const probe = await ctx.vaultMemoryCollection.find(id2);
|
|
14972
14997
|
if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
|
|
14973
14998
|
if (opts.freeFormOnly && isKinded(probe)) return null;
|
|
14999
|
+
const readStoredContent = probe._getRaw("content");
|
|
15000
|
+
if (opts.expectedContent !== void 0) {
|
|
15001
|
+
const current = await vaultMemoryToStored(
|
|
15002
|
+
probe,
|
|
15003
|
+
ctx.walletAddress,
|
|
15004
|
+
ctx.signMessage,
|
|
15005
|
+
ctx.embeddedWalletSigner
|
|
15006
|
+
);
|
|
15007
|
+
if (current.content !== opts.expectedContent) return null;
|
|
15008
|
+
}
|
|
14974
15009
|
const levelAfter = (current) => {
|
|
14975
15010
|
if (opts.level !== void 0) return opts.level;
|
|
14976
15011
|
if (opts.scope === void 0) return resolveMemoryLevel(current.level, current.scope);
|
|
@@ -14978,7 +15013,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
14978
15013
|
};
|
|
14979
15014
|
assertValidKindLevel(opts.kind !== void 0 ? opts.kind : probe.kind, levelAfter(probe));
|
|
14980
15015
|
const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
|
|
14981
|
-
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
15016
|
+
const encryptedContent = opts.content !== void 0 && ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
14982
15017
|
opts.content,
|
|
14983
15018
|
ctx.walletAddress,
|
|
14984
15019
|
ctx.signMessage,
|
|
@@ -14986,13 +15021,13 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
14986
15021
|
) : opts.content;
|
|
14987
15022
|
let stale = false;
|
|
14988
15023
|
const record2 = probe;
|
|
14989
|
-
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
14990
15024
|
await ctx.database.write(async () => {
|
|
14991
15025
|
await assertCanWrite2(ctx);
|
|
14992
|
-
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
|
|
15026
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2) || opts.expectedContent !== void 0 && record2._getRaw("content") !== readStoredContent) {
|
|
14993
15027
|
stale = true;
|
|
14994
15028
|
return;
|
|
14995
15029
|
}
|
|
15030
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
14996
15031
|
const nextKind = opts.kind !== void 0 ? opts.kind : record2.kind;
|
|
14997
15032
|
const nextLevel = levelAfter(record2);
|
|
14998
15033
|
assertValidKindLevel(nextKind, nextLevel);
|
|
@@ -15008,7 +15043,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
15008
15043
|
replayedObservation = opts.observationSourceIds.every((id3) => observedSources.includes(id3));
|
|
15009
15044
|
}
|
|
15010
15045
|
await record2.update((r) => {
|
|
15011
|
-
r._setRaw("content", encryptedContent);
|
|
15046
|
+
if (encryptedContent !== void 0) r._setRaw("content", encryptedContent);
|
|
15012
15047
|
if (opts.level !== void 0) {
|
|
15013
15048
|
r._setRaw("level", nextLevel);
|
|
15014
15049
|
r._setRaw("scope", scopeForLevel(nextLevel));
|
|
@@ -15776,7 +15811,7 @@ function classifyDecay(m, now, policy) {
|
|
|
15776
15811
|
if (m.source === "manual" || m.source === SOURCE_PHOTO) return "keep";
|
|
15777
15812
|
if (isTimeSensitiveType(m.factType) && m.eventTimeEnd !== null) {
|
|
15778
15813
|
if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
|
|
15779
|
-
|
|
15814
|
+
return "keep";
|
|
15780
15815
|
}
|
|
15781
15816
|
if (now - lastActivityAt(m) > ttlForType(m.factType, resolved)) return "archive";
|
|
15782
15817
|
return "keep";
|
|
@@ -18832,7 +18867,6 @@ async function retainWithPersistence(content, ctx, options = {}) {
|
|
|
18832
18867
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
18833
18868
|
const resurrect = resurrectFields(existing);
|
|
18834
18869
|
const updated = await ctx.persistence.update(targetId, {
|
|
18835
|
-
content: existing.content,
|
|
18836
18870
|
freeFormOnly: true,
|
|
18837
18871
|
proofCountIncrement: 1,
|
|
18838
18872
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -19071,7 +19105,6 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
19071
19105
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
19072
19106
|
const resurrect = resurrectFields(existing);
|
|
19073
19107
|
const updated = await ctx.persistence.update(decision.targetId, {
|
|
19074
|
-
content: existing.content,
|
|
19075
19108
|
freeFormOnly: true,
|
|
19076
19109
|
proofCountIncrement: 1,
|
|
19077
19110
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -19099,6 +19132,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
19099
19132
|
};
|
|
19100
19133
|
}
|
|
19101
19134
|
if (decision.action === "update" && decision.targetId && decision.content) {
|
|
19135
|
+
const expectedContent = candidates.find(
|
|
19136
|
+
(candidate) => candidate.id === decision.targetId
|
|
19137
|
+
)?.content;
|
|
19138
|
+
if (expectedContent === void 0) return null;
|
|
19102
19139
|
const existing = await ctx.persistence.get(decision.targetId);
|
|
19103
19140
|
if (!existing || existing.supersededBy) {
|
|
19104
19141
|
return abandonToRace(
|
|
@@ -19106,6 +19143,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
19106
19143
|
`update: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
|
|
19107
19144
|
);
|
|
19108
19145
|
}
|
|
19146
|
+
if (existing.content !== expectedContent) {
|
|
19147
|
+
return abandonToRace(options, `update: target ${decision.targetId} edited before the write`);
|
|
19148
|
+
}
|
|
19109
19149
|
const mergedSourceIds = unionStrings(
|
|
19110
19150
|
existing.sourceChunkIds ?? [],
|
|
19111
19151
|
options.sourceChunkIds ?? []
|
|
@@ -19118,6 +19158,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
19118
19158
|
const resurrect = resurrectFields(existing);
|
|
19119
19159
|
const updated = await ctx.persistence.update(decision.targetId, {
|
|
19120
19160
|
content: decision.content,
|
|
19161
|
+
expectedContent,
|
|
19121
19162
|
freeFormOnly: true,
|
|
19122
19163
|
proofCountIncrement: 1,
|
|
19123
19164
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -19130,10 +19171,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
19130
19171
|
...factTypeUpdate !== void 0 && { factType: factTypeUpdate }
|
|
19131
19172
|
});
|
|
19132
19173
|
if (!updated) {
|
|
19133
|
-
await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
|
|
19174
|
+
await assertMergeTargetGoneOrThrow(ctx, decision.targetId, expectedContent);
|
|
19134
19175
|
return abandonToRace(
|
|
19135
19176
|
options,
|
|
19136
|
-
`update: target ${decision.targetId}
|
|
19177
|
+
`update: target ${decision.targetId} changed mid-write (consolidated rewrite lost)`
|
|
19137
19178
|
);
|
|
19138
19179
|
}
|
|
19139
19180
|
cacheRowVector(
|
|
@@ -19160,9 +19201,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
19160
19201
|
);
|
|
19161
19202
|
return null;
|
|
19162
19203
|
}
|
|
19163
|
-
async function assertMergeTargetGoneOrThrow(ctx, targetId) {
|
|
19204
|
+
async function assertMergeTargetGoneOrThrow(ctx, targetId, expectedContent) {
|
|
19164
19205
|
const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
|
|
19165
|
-
if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
|
|
19206
|
+
if (stillExists && (stillExists.kind === null || stillExists.kind === void 0) && (expectedContent === void 0 || stillExists.content === expectedContent)) {
|
|
19166
19207
|
throw new RetainError(
|
|
19167
19208
|
"merge-not-persisted",
|
|
19168
19209
|
`retain: merge into memory ${targetId} failed to persist`
|
|
@@ -22574,16 +22615,16 @@ function createRemoteMemoryPipeline(options) {
|
|
|
22574
22615
|
create: (input) => write(createRow(input), 0),
|
|
22575
22616
|
update: async (id2, patch) => {
|
|
22576
22617
|
const existing = await get(id2);
|
|
22577
|
-
if (!existing || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
|
|
22618
|
+
if (!existing || patch.expectedContent !== void 0 && existing.content !== patch.expectedContent || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
|
|
22578
22619
|
return null;
|
|
22579
22620
|
const snapshot = snapshots.get(id2);
|
|
22580
22621
|
const memory = {
|
|
22581
22622
|
...snapshot.memory,
|
|
22582
|
-
content: patch.content,
|
|
22623
|
+
content: patch.content ?? snapshot.memory.content,
|
|
22583
22624
|
updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Math.max(Date.now(), (snapshot.memory.topics_extracted_at ?? 0) + 1)
|
|
22584
22625
|
};
|
|
22585
22626
|
if (patch.scope !== void 0) memory.scope = patch.scope;
|
|
22586
|
-
if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
|
|
22627
|
+
if (patch.embedding === void 0 && patch.content !== void 0 && patch.content !== snapshot.memory.content) {
|
|
22587
22628
|
delete memory.embedding;
|
|
22588
22629
|
delete memory.embedding_model;
|
|
22589
22630
|
}
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -5669,7 +5669,8 @@ interface CreateVaultMemoryOptions {
|
|
|
5669
5669
|
geohash?: string;
|
|
5670
5670
|
}
|
|
5671
5671
|
interface UpdateVaultMemoryOptions {
|
|
5672
|
-
content
|
|
5672
|
+
content?: string;
|
|
5673
|
+
expectedContent?: string;
|
|
5673
5674
|
/** When true, the write is skipped (returns null) if the row carries a profile kind. */
|
|
5674
5675
|
freeFormOnly?: boolean;
|
|
5675
5676
|
/**
|
|
@@ -6273,9 +6274,10 @@ declare function ttlForType(factType: string | null, policy?: Partial<DecayPolic
|
|
|
6273
6274
|
* null `eventTimeEnd` is still ongoing, so this rule does not fire for it.
|
|
6274
6275
|
* 4. Age fallback — `now - updatedAt > TTL(factType)` → archive. Durable types
|
|
6275
6276
|
* have Infinity TTL, so this never fires for them; null/unknown use medium.
|
|
6276
|
-
* EXCEPTION: a `plan
|
|
6277
|
-
* (`eventTimeEnd >= now
|
|
6278
|
-
*
|
|
6277
|
+
* EXCEPTION: a `plan` / `ongoing_context` with an upcoming event or an event
|
|
6278
|
+
* within the grace period (`eventTimeEnd >= now - pastEventGraceMs`) stays
|
|
6279
|
+
* active, even after its activity TTL expires. Rule 3 archives it after the
|
|
6280
|
+
* grace period ends.
|
|
6279
6281
|
* 5. Otherwise → keep.
|
|
6280
6282
|
*
|
|
6281
6283
|
* @param m Plaintext decay inputs for one row.
|
|
@@ -6606,7 +6608,9 @@ type MemoryCreate = Pick<CreateVaultMemoryOptions, "content" | "scope" | "factTy
|
|
|
6606
6608
|
* `embedding` (with `embeddingModel`) only when you already have the new one.
|
|
6607
6609
|
* @public
|
|
6608
6610
|
*/
|
|
6609
|
-
type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "
|
|
6611
|
+
type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "scope" | "factType" | "eventTime" | "embedding" | "embeddingModel" | "kind" | "kindValue" | "level"> & {
|
|
6612
|
+
content: string;
|
|
6613
|
+
};
|
|
6610
6614
|
/**
|
|
6611
6615
|
* Fact-only recall. Conversation chunks are message storage, not memory, so
|
|
6612
6616
|
* the chunk-lane knobs are not part of this surface; nor is `folderId` (see
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -5669,7 +5669,8 @@ interface CreateVaultMemoryOptions {
|
|
|
5669
5669
|
geohash?: string;
|
|
5670
5670
|
}
|
|
5671
5671
|
interface UpdateVaultMemoryOptions {
|
|
5672
|
-
content
|
|
5672
|
+
content?: string;
|
|
5673
|
+
expectedContent?: string;
|
|
5673
5674
|
/** When true, the write is skipped (returns null) if the row carries a profile kind. */
|
|
5674
5675
|
freeFormOnly?: boolean;
|
|
5675
5676
|
/**
|
|
@@ -6273,9 +6274,10 @@ declare function ttlForType(factType: string | null, policy?: Partial<DecayPolic
|
|
|
6273
6274
|
* null `eventTimeEnd` is still ongoing, so this rule does not fire for it.
|
|
6274
6275
|
* 4. Age fallback — `now - updatedAt > TTL(factType)` → archive. Durable types
|
|
6275
6276
|
* have Infinity TTL, so this never fires for them; null/unknown use medium.
|
|
6276
|
-
* EXCEPTION: a `plan
|
|
6277
|
-
* (`eventTimeEnd >= now
|
|
6278
|
-
*
|
|
6277
|
+
* EXCEPTION: a `plan` / `ongoing_context` with an upcoming event or an event
|
|
6278
|
+
* within the grace period (`eventTimeEnd >= now - pastEventGraceMs`) stays
|
|
6279
|
+
* active, even after its activity TTL expires. Rule 3 archives it after the
|
|
6280
|
+
* grace period ends.
|
|
6279
6281
|
* 5. Otherwise → keep.
|
|
6280
6282
|
*
|
|
6281
6283
|
* @param m Plaintext decay inputs for one row.
|
|
@@ -6606,7 +6608,9 @@ type MemoryCreate = Pick<CreateVaultMemoryOptions, "content" | "scope" | "factTy
|
|
|
6606
6608
|
* `embedding` (with `embeddingModel`) only when you already have the new one.
|
|
6607
6609
|
* @public
|
|
6608
6610
|
*/
|
|
6609
|
-
type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "
|
|
6611
|
+
type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "scope" | "factType" | "eventTime" | "embedding" | "embeddingModel" | "kind" | "kindValue" | "level"> & {
|
|
6612
|
+
content: string;
|
|
6613
|
+
};
|
|
6610
6614
|
/**
|
|
6611
6615
|
* Fact-only recall. Conversation chunks are message storage, not memory, so
|
|
6612
6616
|
* the chunk-lane knobs are not part of this surface; nor is `folderId` (see
|
package/dist/expo/index.mjs
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
taskTypeHeader,
|
|
21
21
|
validateEndpointOverride,
|
|
22
22
|
withInternalFlowMarker
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-WRZTH4OS.mjs";
|
|
24
24
|
import {
|
|
25
25
|
BASE_URL,
|
|
26
26
|
MCP_R2_DOMAIN,
|
|
@@ -13345,6 +13345,16 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
13345
13345
|
const probe = await ctx.vaultMemoryCollection.find(id2);
|
|
13346
13346
|
if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
|
|
13347
13347
|
if (opts.freeFormOnly && isKinded(probe)) return null;
|
|
13348
|
+
const readStoredContent = probe._getRaw("content");
|
|
13349
|
+
if (opts.expectedContent !== void 0) {
|
|
13350
|
+
const current = await vaultMemoryToStored(
|
|
13351
|
+
probe,
|
|
13352
|
+
ctx.walletAddress,
|
|
13353
|
+
ctx.signMessage,
|
|
13354
|
+
ctx.embeddedWalletSigner
|
|
13355
|
+
);
|
|
13356
|
+
if (current.content !== opts.expectedContent) return null;
|
|
13357
|
+
}
|
|
13348
13358
|
const levelAfter = (current) => {
|
|
13349
13359
|
if (opts.level !== void 0) return opts.level;
|
|
13350
13360
|
if (opts.scope === void 0) return resolveMemoryLevel(current.level, current.scope);
|
|
@@ -13352,7 +13362,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
13352
13362
|
};
|
|
13353
13363
|
assertValidKindLevel(opts.kind !== void 0 ? opts.kind : probe.kind, levelAfter(probe));
|
|
13354
13364
|
const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
|
|
13355
|
-
const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
13365
|
+
const encryptedContent = opts.content !== void 0 && ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
|
|
13356
13366
|
opts.content,
|
|
13357
13367
|
ctx.walletAddress,
|
|
13358
13368
|
ctx.signMessage,
|
|
@@ -13360,13 +13370,13 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
13360
13370
|
) : opts.content;
|
|
13361
13371
|
let stale = false;
|
|
13362
13372
|
const record2 = probe;
|
|
13363
|
-
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
13364
13373
|
await ctx.database.write(async () => {
|
|
13365
13374
|
await assertCanWrite2(ctx);
|
|
13366
|
-
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
|
|
13375
|
+
if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2) || opts.expectedContent !== void 0 && record2._getRaw("content") !== readStoredContent) {
|
|
13367
13376
|
stale = true;
|
|
13368
13377
|
return;
|
|
13369
13378
|
}
|
|
13379
|
+
const originalUpdatedAt = record2.updatedAt.getTime();
|
|
13370
13380
|
const nextKind = opts.kind !== void 0 ? opts.kind : record2.kind;
|
|
13371
13381
|
const nextLevel = levelAfter(record2);
|
|
13372
13382
|
assertValidKindLevel(nextKind, nextLevel);
|
|
@@ -13382,7 +13392,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
|
|
|
13382
13392
|
replayedObservation = opts.observationSourceIds.every((id3) => observedSources.includes(id3));
|
|
13383
13393
|
}
|
|
13384
13394
|
await record2.update((r) => {
|
|
13385
|
-
r._setRaw("content", encryptedContent);
|
|
13395
|
+
if (encryptedContent !== void 0) r._setRaw("content", encryptedContent);
|
|
13386
13396
|
if (opts.level !== void 0) {
|
|
13387
13397
|
r._setRaw("level", nextLevel);
|
|
13388
13398
|
r._setRaw("scope", scopeForLevel(nextLevel));
|
|
@@ -14149,7 +14159,7 @@ function classifyDecay(m, now, policy) {
|
|
|
14149
14159
|
if (m.source === "manual" || m.source === SOURCE_PHOTO) return "keep";
|
|
14150
14160
|
if (isTimeSensitiveType(m.factType) && m.eventTimeEnd !== null) {
|
|
14151
14161
|
if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
|
|
14152
|
-
|
|
14162
|
+
return "keep";
|
|
14153
14163
|
}
|
|
14154
14164
|
if (now - lastActivityAt(m) > ttlForType(m.factType, resolved)) return "archive";
|
|
14155
14165
|
return "keep";
|
|
@@ -17182,7 +17192,6 @@ async function retainWithPersistence(content, ctx, options = {}) {
|
|
|
17182
17192
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
17183
17193
|
const resurrect = resurrectFields(existing);
|
|
17184
17194
|
const updated = await ctx.persistence.update(targetId, {
|
|
17185
|
-
content: existing.content,
|
|
17186
17195
|
freeFormOnly: true,
|
|
17187
17196
|
proofCountIncrement: 1,
|
|
17188
17197
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -17386,7 +17395,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
17386
17395
|
content: m.content,
|
|
17387
17396
|
similarity: m.similarity
|
|
17388
17397
|
}));
|
|
17389
|
-
const { consolidateMemory: doConsolidate } = await import("./consolidate-
|
|
17398
|
+
const { consolidateMemory: doConsolidate } = await import("./consolidate-HKL5EGZT.mjs");
|
|
17390
17399
|
const decision = await doConsolidate(trimmed, candidates, consolidateOptions);
|
|
17391
17400
|
if (decision.action === "create") return decision.fallbackReason ? null : { create: true };
|
|
17392
17401
|
if (decision.action === "supersede" && decision.content) {
|
|
@@ -17421,7 +17430,6 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
17421
17430
|
const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
|
|
17422
17431
|
const resurrect = resurrectFields(existing);
|
|
17423
17432
|
const updated = await ctx.persistence.update(decision.targetId, {
|
|
17424
|
-
content: existing.content,
|
|
17425
17433
|
freeFormOnly: true,
|
|
17426
17434
|
proofCountIncrement: 1,
|
|
17427
17435
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -17449,6 +17457,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
17449
17457
|
};
|
|
17450
17458
|
}
|
|
17451
17459
|
if (decision.action === "update" && decision.targetId && decision.content) {
|
|
17460
|
+
const expectedContent = candidates.find(
|
|
17461
|
+
(candidate) => candidate.id === decision.targetId
|
|
17462
|
+
)?.content;
|
|
17463
|
+
if (expectedContent === void 0) return null;
|
|
17452
17464
|
const existing = await ctx.persistence.get(decision.targetId);
|
|
17453
17465
|
if (!existing || existing.supersededBy) {
|
|
17454
17466
|
return abandonToRace(
|
|
@@ -17456,6 +17468,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
17456
17468
|
`update: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
|
|
17457
17469
|
);
|
|
17458
17470
|
}
|
|
17471
|
+
if (existing.content !== expectedContent) {
|
|
17472
|
+
return abandonToRace(options, `update: target ${decision.targetId} edited before the write`);
|
|
17473
|
+
}
|
|
17459
17474
|
const mergedSourceIds = unionStrings(
|
|
17460
17475
|
existing.sourceChunkIds ?? [],
|
|
17461
17476
|
options.sourceChunkIds ?? []
|
|
@@ -17468,6 +17483,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
17468
17483
|
const resurrect = resurrectFields(existing);
|
|
17469
17484
|
const updated = await ctx.persistence.update(decision.targetId, {
|
|
17470
17485
|
content: decision.content,
|
|
17486
|
+
expectedContent,
|
|
17471
17487
|
freeFormOnly: true,
|
|
17472
17488
|
proofCountIncrement: 1,
|
|
17473
17489
|
observationSourceIds: options.sourceChunkIds,
|
|
@@ -17480,10 +17496,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
17480
17496
|
...factTypeUpdate !== void 0 && { factType: factTypeUpdate }
|
|
17481
17497
|
});
|
|
17482
17498
|
if (!updated) {
|
|
17483
|
-
await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
|
|
17499
|
+
await assertMergeTargetGoneOrThrow(ctx, decision.targetId, expectedContent);
|
|
17484
17500
|
return abandonToRace(
|
|
17485
17501
|
options,
|
|
17486
|
-
`update: target ${decision.targetId}
|
|
17502
|
+
`update: target ${decision.targetId} changed mid-write (consolidated rewrite lost)`
|
|
17487
17503
|
);
|
|
17488
17504
|
}
|
|
17489
17505
|
cacheRowVector(
|
|
@@ -17510,9 +17526,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
|
|
|
17510
17526
|
);
|
|
17511
17527
|
return null;
|
|
17512
17528
|
}
|
|
17513
|
-
async function assertMergeTargetGoneOrThrow(ctx, targetId) {
|
|
17529
|
+
async function assertMergeTargetGoneOrThrow(ctx, targetId, expectedContent) {
|
|
17514
17530
|
const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
|
|
17515
|
-
if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
|
|
17531
|
+
if (stillExists && (stillExists.kind === null || stillExists.kind === void 0) && (expectedContent === void 0 || stillExists.content === expectedContent)) {
|
|
17516
17532
|
throw new RetainError(
|
|
17517
17533
|
"merge-not-persisted",
|
|
17518
17534
|
`retain: merge into memory ${targetId} failed to persist`
|
|
@@ -20899,16 +20915,16 @@ function createRemoteMemoryPipeline(options) {
|
|
|
20899
20915
|
create: (input) => write(createRow(input), 0),
|
|
20900
20916
|
update: async (id2, patch) => {
|
|
20901
20917
|
const existing = await get(id2);
|
|
20902
|
-
if (!existing || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
|
|
20918
|
+
if (!existing || patch.expectedContent !== void 0 && existing.content !== patch.expectedContent || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
|
|
20903
20919
|
return null;
|
|
20904
20920
|
const snapshot = snapshots.get(id2);
|
|
20905
20921
|
const memory = {
|
|
20906
20922
|
...snapshot.memory,
|
|
20907
|
-
content: patch.content,
|
|
20923
|
+
content: patch.content ?? snapshot.memory.content,
|
|
20908
20924
|
updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Math.max(Date.now(), (snapshot.memory.topics_extracted_at ?? 0) + 1)
|
|
20909
20925
|
};
|
|
20910
20926
|
if (patch.scope !== void 0) memory.scope = patch.scope;
|
|
20911
|
-
if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
|
|
20927
|
+
if (patch.embedding === void 0 && patch.content !== void 0 && patch.content !== snapshot.memory.content) {
|
|
20912
20928
|
delete memory.embedding;
|
|
20913
20929
|
delete memory.embedding_model;
|
|
20914
20930
|
}
|