@anuma/sdk 10.7.0 → 10.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/expo/index.cjs +336 -167
- package/dist/expo/index.d.mts +193 -151
- package/dist/expo/index.d.ts +193 -151
- package/dist/expo/index.mjs +321 -159
- package/dist/index.cjs +165 -16
- package/dist/index.d.mts +377 -151
- package/dist/index.d.ts +377 -151
- package/dist/index.mjs +158 -16
- package/dist/react/index.cjs +339 -170
- package/dist/react/index.d.mts +193 -151
- package/dist/react/index.d.ts +193 -151
- package/dist/react/index.mjs +324 -162
- package/dist/server/index.d.mts +20 -0
- package/dist/server/index.d.ts +20 -0
- package/package.json +2 -2
package/dist/expo/index.mjs
CHANGED
|
@@ -9923,118 +9923,19 @@ var xhrTransport = (options) => {
|
|
|
9923
9923
|
return { stream: createStream() };
|
|
9924
9924
|
};
|
|
9925
9925
|
|
|
9926
|
-
// src/lib/
|
|
9927
|
-
|
|
9928
|
-
|
|
9929
|
-
|
|
9930
|
-
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
|
|
9934
|
-
}
|
|
9935
|
-
function modelToStored(record2, summary) {
|
|
9936
|
-
return {
|
|
9937
|
-
uniqueId: record2.id,
|
|
9938
|
-
conversationId: record2.conversationId,
|
|
9939
|
-
summary,
|
|
9940
|
-
summarizedUpTo: record2.summarizedUpTo,
|
|
9941
|
-
tokenCount: record2.tokenCount,
|
|
9942
|
-
createdAt: record2.createdAt,
|
|
9943
|
-
updatedAt: record2.updatedAt
|
|
9944
|
-
};
|
|
9945
|
-
}
|
|
9946
|
-
async function getConversationSummaryOp(ctx, conversationId) {
|
|
9947
|
-
const results = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
|
|
9948
|
-
if (results.length === 0) return null;
|
|
9949
|
-
const record2 = results[0];
|
|
9950
|
-
const stored2 = modelToStored(record2, record2.summary);
|
|
9951
|
-
if (ctx.walletAddress && isEncrypted(stored2.summary)) {
|
|
9952
|
-
if (ctx.signMessage) {
|
|
9953
|
-
try {
|
|
9954
|
-
await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
9955
|
-
} catch (error) {
|
|
9956
|
-
getLogger().warn("Failed to request the encryption key for the summary:", error);
|
|
9957
|
-
}
|
|
9958
|
-
}
|
|
9959
|
-
stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
|
|
9960
|
-
} else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
|
|
9961
|
-
try {
|
|
9962
|
-
const encryptedSummary = await encryptField(
|
|
9963
|
-
stored2.summary,
|
|
9964
|
-
ctx.walletAddress,
|
|
9965
|
-
ctx.signMessage,
|
|
9966
|
-
ctx.embeddedWalletSigner
|
|
9967
|
-
);
|
|
9968
|
-
await ctx.database.write(async () => {
|
|
9969
|
-
const current = await ctx.summariesCollection.query(Q3.where("id", record2.id)).fetch();
|
|
9970
|
-
if (current[0]?.summary === stored2.summary) {
|
|
9971
|
-
await current[0].update((rec) => {
|
|
9972
|
-
rec.summary = encryptedSummary;
|
|
9973
|
-
});
|
|
9974
|
-
}
|
|
9975
|
-
});
|
|
9976
|
-
} catch (error) {
|
|
9977
|
-
getLogger().warn("Failed to encrypt the legacy summary:", error);
|
|
9978
|
-
}
|
|
9926
|
+
// src/lib/chatStore/types.ts
|
|
9927
|
+
var ChatStoreError = class extends Error {
|
|
9928
|
+
constructor(message, status, code, retryAfterMs) {
|
|
9929
|
+
super(message);
|
|
9930
|
+
this.status = status;
|
|
9931
|
+
this.code = code;
|
|
9932
|
+
this.retryAfterMs = retryAfterMs;
|
|
9933
|
+
this.name = "ChatStoreError";
|
|
9979
9934
|
}
|
|
9980
|
-
return stored2;
|
|
9981
|
-
}
|
|
9982
|
-
async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
|
|
9983
|
-
const revision2 = getConversationRevision(ctx.database, conversationId);
|
|
9984
|
-
let record2;
|
|
9985
|
-
const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
|
|
9986
|
-
await ctx.database.write(async () => {
|
|
9987
|
-
assertConversationRevision(ctx.database, conversationId, revision2);
|
|
9988
|
-
const existing = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
|
|
9989
|
-
if (existing.length > 0) {
|
|
9990
|
-
record2 = await existing[0].update((rec) => {
|
|
9991
|
-
rec.summary = encryptedSummary;
|
|
9992
|
-
rec.summarizedUpTo = summarizedUpTo;
|
|
9993
|
-
rec.tokenCount = tokenCount;
|
|
9994
|
-
});
|
|
9995
|
-
} else {
|
|
9996
|
-
record2 = await ctx.summariesCollection.create((rec) => {
|
|
9997
|
-
rec.conversationId = conversationId;
|
|
9998
|
-
rec.summary = encryptedSummary;
|
|
9999
|
-
rec.summarizedUpTo = summarizedUpTo;
|
|
10000
|
-
rec.tokenCount = tokenCount;
|
|
10001
|
-
});
|
|
10002
|
-
}
|
|
10003
|
-
});
|
|
10004
|
-
return modelToStored(record2, summary);
|
|
10005
|
-
}
|
|
10006
|
-
async function deleteConversationSummaryOp(ctx, conversationId) {
|
|
10007
|
-
await ctx.database.write(async () => {
|
|
10008
|
-
const existing = await ctx.summariesCollection.query(Q3.where("conversation_id", conversationId)).fetch();
|
|
10009
|
-
for (const record2 of existing) {
|
|
10010
|
-
await record2.destroyPermanently();
|
|
10011
|
-
}
|
|
10012
|
-
});
|
|
10013
|
-
}
|
|
10014
|
-
|
|
10015
|
-
// src/lib/db/conversationMemory/models.ts
|
|
10016
|
-
import { Model as Model3 } from "@nozbe/watermelondb";
|
|
10017
|
-
import { date as date2, field as field2, readonly, text as text3 } from "@nozbe/watermelondb/decorators";
|
|
10018
|
-
var ConversationMemory = class extends Model3 {
|
|
10019
9935
|
};
|
|
10020
|
-
ConversationMemory.table = "conversation_memory";
|
|
10021
|
-
ConversationMemory.associations = {};
|
|
10022
|
-
__decorateClass([
|
|
10023
|
-
text3("conversation_id")
|
|
10024
|
-
], ConversationMemory.prototype, "conversationId", 2);
|
|
10025
|
-
__decorateClass([
|
|
10026
|
-
text3("memory_id")
|
|
10027
|
-
], ConversationMemory.prototype, "memoryId", 2);
|
|
10028
|
-
__decorateClass([
|
|
10029
|
-
field2("score")
|
|
10030
|
-
], ConversationMemory.prototype, "score", 2);
|
|
10031
|
-
__decorateClass([
|
|
10032
|
-
readonly,
|
|
10033
|
-
date2("created_at")
|
|
10034
|
-
], ConversationMemory.prototype, "createdAt", 2);
|
|
10035
9936
|
|
|
10036
9937
|
// src/lib/db/conversationMemory/operations.ts
|
|
10037
|
-
import { Q as
|
|
9938
|
+
import { Q as Q3 } from "@nozbe/watermelondb";
|
|
10038
9939
|
var MAX_PER_CONVERSATION = 200;
|
|
10039
9940
|
function conversationMemoryToStored(row) {
|
|
10040
9941
|
return {
|
|
@@ -10049,7 +9950,7 @@ async function addConversationMemoriesOp(ctx, conversationId, items) {
|
|
|
10049
9950
|
if (!conversationId || items.length === 0) return;
|
|
10050
9951
|
const now = Date.now();
|
|
10051
9952
|
await ctx.database.write(async () => {
|
|
10052
|
-
const existing = await ctx.conversationMemoryCollection.query(
|
|
9953
|
+
const existing = await ctx.conversationMemoryCollection.query(Q3.where("conversation_id", conversationId), Q3.sortBy("created_at", Q3.asc)).fetch();
|
|
10053
9954
|
const seen = new Set(existing.map((r) => r.memoryId));
|
|
10054
9955
|
const batchSeen = /* @__PURE__ */ new Set();
|
|
10055
9956
|
const deduped = [];
|
|
@@ -10086,7 +9987,7 @@ async function recordConversationMemoriesOp(ctx, conversationId, items, now = Da
|
|
|
10086
9987
|
if (!conversationId || turn.size === 0) return;
|
|
10087
9988
|
const kept = new Map([...turn].slice(-MAX_PER_CONVERSATION));
|
|
10088
9989
|
await ctx.database.write(async () => {
|
|
10089
|
-
const existing = await ctx.conversationMemoryCollection.query(
|
|
9990
|
+
const existing = await ctx.conversationMemoryCollection.query(Q3.where("conversation_id", conversationId), Q3.sortBy("created_at", Q3.asc)).fetch();
|
|
10090
9991
|
const earlier = existing.filter((r) => !turn.has(r.memoryId));
|
|
10091
9992
|
const linked = new Set(existing.map((r) => r.memoryId));
|
|
10092
9993
|
await ctx.database.batch(
|
|
@@ -10111,13 +10012,13 @@ async function recordConversationMemoriesOp(ctx, conversationId, items, now = Da
|
|
|
10111
10012
|
}
|
|
10112
10013
|
async function getConversationMemoriesOp(ctx, conversationId) {
|
|
10113
10014
|
if (!conversationId) return [];
|
|
10114
|
-
const rows = await ctx.conversationMemoryCollection.query(
|
|
10015
|
+
const rows = await ctx.conversationMemoryCollection.query(Q3.where("conversation_id", conversationId), Q3.sortBy("created_at", Q3.asc)).fetch();
|
|
10115
10016
|
return rows.map(conversationMemoryToStored);
|
|
10116
10017
|
}
|
|
10117
10018
|
async function clearConversationMemoriesOp(ctx, conversationId) {
|
|
10118
10019
|
if (!conversationId) return;
|
|
10119
10020
|
await ctx.database.write(async () => {
|
|
10120
|
-
const rows = await ctx.conversationMemoryCollection.query(
|
|
10021
|
+
const rows = await ctx.conversationMemoryCollection.query(Q3.where("conversation_id", conversationId)).fetch();
|
|
10121
10022
|
if (rows.length === 0) return;
|
|
10122
10023
|
await ctx.database.batch(...rows.map((r) => r.prepareDestroyPermanently()));
|
|
10123
10024
|
});
|
|
@@ -10132,46 +10033,93 @@ var maxChunks = 16;
|
|
|
10132
10033
|
var droppable = ["thoughtProcess", "thinking", "sources", "toolCallEvents"];
|
|
10133
10034
|
var messageMetadata = /* @__PURE__ */ new Set(["conversationId", "uniqueId", "vector", "chunks"]);
|
|
10134
10035
|
var alwaysStored = /* @__PURE__ */ new Set(["role", "content", "responseDuration"]);
|
|
10036
|
+
var maxBubbles = 3;
|
|
10037
|
+
var maxTurnIdBytes = 128;
|
|
10038
|
+
var maxBubbleBytes = 16384;
|
|
10039
|
+
var anumaOrigins = /* @__PURE__ */ new Set(["intro", "reply"]);
|
|
10135
10040
|
function plain(value) {
|
|
10136
10041
|
return JSON.parse(JSON.stringify(value ?? {}));
|
|
10137
10042
|
}
|
|
10138
|
-
function
|
|
10043
|
+
function text3(value) {
|
|
10139
10044
|
return typeof value === "string" ? value : void 0;
|
|
10140
10045
|
}
|
|
10141
10046
|
function number(value) {
|
|
10142
10047
|
return typeof value === "number" ? value : void 0;
|
|
10143
10048
|
}
|
|
10049
|
+
function readAnumaTurn(value) {
|
|
10050
|
+
if (!isObject(value)) return void 0;
|
|
10051
|
+
const { turnId, bubbles, origin } = value;
|
|
10052
|
+
if (typeof turnId !== "string" || turnId.length === 0 || new TextEncoder().encode(turnId).length > maxTurnIdBytes)
|
|
10053
|
+
return void 0;
|
|
10054
|
+
if (bubbles !== void 0 && (!Array.isArray(bubbles) || bubbles.length < 1 || bubbles.length > maxBubbles || !bubbles.every((b) => typeof b === "string") || bubbles.reduce((sum, b) => sum + new TextEncoder().encode(b).length, 0) > maxBubbleBytes))
|
|
10055
|
+
return void 0;
|
|
10056
|
+
if (origin !== void 0 && (typeof origin !== "string" || !anumaOrigins.has(origin)))
|
|
10057
|
+
return void 0;
|
|
10058
|
+
return {
|
|
10059
|
+
turnId,
|
|
10060
|
+
...bubbles !== void 0 ? { bubbles: [...bubbles] } : {},
|
|
10061
|
+
...origin !== void 0 ? { origin } : {}
|
|
10062
|
+
};
|
|
10063
|
+
}
|
|
10064
|
+
function isObject(value) {
|
|
10065
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
10066
|
+
}
|
|
10144
10067
|
function conversationSortKey(data, createdAt) {
|
|
10145
10068
|
const pinnedAt = number(data.pinnedAt);
|
|
10146
10069
|
if (pinnedAt) return PINNED_SORT_BASE + pinnedAt;
|
|
10147
10070
|
return number(data.lastActivityAt) ?? createdAt;
|
|
10148
10071
|
}
|
|
10072
|
+
var CONTEXT_FIELD_PREFIX = "context.";
|
|
10073
|
+
function contextField(key3) {
|
|
10074
|
+
return `${CONTEXT_FIELD_PREFIX}${key3}`;
|
|
10075
|
+
}
|
|
10076
|
+
function contextFields(context) {
|
|
10077
|
+
return plain(
|
|
10078
|
+
Object.fromEntries(Object.entries(context ?? {}).map(([k, value]) => [contextField(k), value]))
|
|
10079
|
+
);
|
|
10080
|
+
}
|
|
10081
|
+
function conversationContext(data) {
|
|
10082
|
+
const entries = Object.entries(data).filter(([field10]) => field10.startsWith(CONTEXT_FIELD_PREFIX)).map(([field10, value]) => [field10.slice(CONTEXT_FIELD_PREFIX.length), value]);
|
|
10083
|
+
return entries.length > 0 ? plain(Object.fromEntries(entries)) : void 0;
|
|
10084
|
+
}
|
|
10149
10085
|
function toConversation(record2) {
|
|
10150
10086
|
const pinnedAt = number(record2.data.pinnedAt);
|
|
10151
|
-
const projectId =
|
|
10087
|
+
const projectId = text3(record2.data.projectId);
|
|
10088
|
+
const context = conversationContext(record2.data);
|
|
10152
10089
|
return {
|
|
10153
10090
|
uniqueId: record2.id,
|
|
10154
10091
|
conversationId: record2.id,
|
|
10155
|
-
title:
|
|
10092
|
+
title: text3(record2.data.title) ?? "",
|
|
10156
10093
|
...projectId ? { projectId } : {},
|
|
10157
10094
|
createdAt: new Date(record2.createdAt),
|
|
10158
10095
|
updatedAt: new Date(record2.updatedAt),
|
|
10159
10096
|
isDeleted: record2.isDeleted,
|
|
10160
|
-
pinnedAt: pinnedAt ? new Date(pinnedAt) : null
|
|
10097
|
+
pinnedAt: pinnedAt ? new Date(pinnedAt) : null,
|
|
10098
|
+
...context ? { context } : {}
|
|
10161
10099
|
};
|
|
10162
10100
|
}
|
|
10101
|
+
function anumaTurnData(value) {
|
|
10102
|
+
if (value === void 0) return void 0;
|
|
10103
|
+
const turn = readAnumaTurn(value);
|
|
10104
|
+
if (!turn) throw new ChatStoreError("Invalid Anuma turn", 0, "invalid_record");
|
|
10105
|
+
return turn;
|
|
10106
|
+
}
|
|
10163
10107
|
function messageData(options) {
|
|
10164
|
-
|
|
10165
|
-
|
|
10108
|
+
const anuma = anumaTurnData(options.anuma);
|
|
10109
|
+
return plain({
|
|
10110
|
+
...Object.fromEntries(
|
|
10166
10111
|
Object.entries(options).filter(
|
|
10167
|
-
([key3, value]) => !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
|
|
10112
|
+
([key3, value]) => key3 !== "anuma" && !messageMetadata.has(key3) && (!!value || alwaysStored.has(key3))
|
|
10168
10113
|
)
|
|
10169
|
-
)
|
|
10170
|
-
|
|
10114
|
+
),
|
|
10115
|
+
...anuma ? { anuma } : {}
|
|
10116
|
+
});
|
|
10171
10117
|
}
|
|
10172
10118
|
function toMessage(record2) {
|
|
10173
|
-
const { chunkOffsets: _offsets, truncated: _truncated, ...fields } = record2.data;
|
|
10119
|
+
const { chunkOffsets: _offsets, truncated: _truncated, anuma: rawAnuma, ...fields } = record2.data;
|
|
10120
|
+
const anuma = readAnumaTurn(rawAnuma);
|
|
10174
10121
|
return {
|
|
10122
|
+
...anuma ? { anuma } : {},
|
|
10175
10123
|
...fields,
|
|
10176
10124
|
uniqueId: record2.id,
|
|
10177
10125
|
messageId: record2.sortKey,
|
|
@@ -10185,20 +10133,20 @@ function chunkOffsets(record2) {
|
|
|
10185
10133
|
return Array.isArray(offsets) ? offsets : void 0;
|
|
10186
10134
|
}
|
|
10187
10135
|
function toSkeletons(records) {
|
|
10188
|
-
const roleById = new Map(records.map((r) => [r.id,
|
|
10136
|
+
const roleById = new Map(records.map((r) => [r.id, text3(r.data.role)]));
|
|
10189
10137
|
return records.map((r) => {
|
|
10190
|
-
const parentMessageId =
|
|
10191
|
-
const model =
|
|
10138
|
+
const parentMessageId = text3(r.data.parentMessageId);
|
|
10139
|
+
const model = text3(r.data.model);
|
|
10192
10140
|
const artifact = r.data.role === "user" && !!parentMessageId && roleById.get(parentMessageId) === "user";
|
|
10193
10141
|
return {
|
|
10194
10142
|
uniqueId: r.id,
|
|
10195
10143
|
messageId: r.sortKey,
|
|
10196
10144
|
conversationId: r.conversationId,
|
|
10197
|
-
role:
|
|
10145
|
+
role: text3(r.data.role) ?? "",
|
|
10198
10146
|
createdAt: new Date(r.createdAt),
|
|
10199
10147
|
...parentMessageId ? { parentMessageId } : {},
|
|
10200
10148
|
...model ? { model } : {},
|
|
10201
|
-
...artifact ? { content:
|
|
10149
|
+
...artifact ? { content: text3(r.data.content) ?? "" } : {}
|
|
10202
10150
|
};
|
|
10203
10151
|
});
|
|
10204
10152
|
}
|
|
@@ -10206,8 +10154,8 @@ function toSummary(record2) {
|
|
|
10206
10154
|
return {
|
|
10207
10155
|
uniqueId: record2.id,
|
|
10208
10156
|
conversationId: record2.id,
|
|
10209
|
-
summary:
|
|
10210
|
-
summarizedUpTo:
|
|
10157
|
+
summary: text3(record2.data.summary) ?? "",
|
|
10158
|
+
summarizedUpTo: text3(record2.data.summarizedUpTo) ?? "",
|
|
10211
10159
|
tokenCount: number(record2.data.tokenCount) ?? 0,
|
|
10212
10160
|
createdAt: new Date(record2.createdAt),
|
|
10213
10161
|
updatedAt: new Date(record2.updatedAt)
|
|
@@ -10258,7 +10206,7 @@ function fitRecord(record2) {
|
|
|
10258
10206
|
delete data[field10];
|
|
10259
10207
|
truncated.push(field10);
|
|
10260
10208
|
}
|
|
10261
|
-
const content =
|
|
10209
|
+
const content = text3(data.content) ?? "";
|
|
10262
10210
|
const over = bytes({ ...record2, data }) - recordBudgetBytes;
|
|
10263
10211
|
if (over > 0) {
|
|
10264
10212
|
const encoded = new TextEncoder().encode(content);
|
|
@@ -10302,6 +10250,215 @@ function fitChunks(chunks3) {
|
|
|
10302
10250
|
return out;
|
|
10303
10251
|
}
|
|
10304
10252
|
|
|
10253
|
+
// src/lib/chatStore/anuma.ts
|
|
10254
|
+
var ANUMA_CONVERSATION_ID = "anuma-1on1";
|
|
10255
|
+
var maxAttempts = 3;
|
|
10256
|
+
function anumaTurnContent(bubbles) {
|
|
10257
|
+
return bubbles.join("\n\n");
|
|
10258
|
+
}
|
|
10259
|
+
function anumaLastReadSortKey(conversation) {
|
|
10260
|
+
const record2 = conversation && "record" in conversation ? conversation.record : conversation;
|
|
10261
|
+
const state = record2?.data.anuma;
|
|
10262
|
+
if (!isObject(state)) return 0;
|
|
10263
|
+
const sortKey = state.lastReadSortKey;
|
|
10264
|
+
return Number.isSafeInteger(sortKey) && sortKey > 0 ? sortKey : 0;
|
|
10265
|
+
}
|
|
10266
|
+
function conflict(error) {
|
|
10267
|
+
return error instanceof ChatStoreError && error.code === "version_conflict";
|
|
10268
|
+
}
|
|
10269
|
+
function live(snapshot) {
|
|
10270
|
+
if (snapshot?.record.isDeleted)
|
|
10271
|
+
throw new ChatStoreError("Anuma conversation was deleted", 409, "conversation_deleted");
|
|
10272
|
+
return snapshot;
|
|
10273
|
+
}
|
|
10274
|
+
async function ensureAnumaConversation(store, options = {}) {
|
|
10275
|
+
const existing = live(await store.get("conversation", ANUMA_CONVERSATION_ID, options.signal));
|
|
10276
|
+
if (existing) return existing;
|
|
10277
|
+
const at = (options.now ?? Date.now)();
|
|
10278
|
+
const data = plain({ title: "Anuma", lastActivityAt: at, anuma: { lastReadSortKey: 0 } });
|
|
10279
|
+
try {
|
|
10280
|
+
const [created] = await store.putMany(
|
|
10281
|
+
[
|
|
10282
|
+
{
|
|
10283
|
+
expectedVersion: 0,
|
|
10284
|
+
record: {
|
|
10285
|
+
kind: "conversation",
|
|
10286
|
+
id: ANUMA_CONVERSATION_ID,
|
|
10287
|
+
conversationId: "",
|
|
10288
|
+
sortKey: conversationSortKey(data, at),
|
|
10289
|
+
createdAt: at,
|
|
10290
|
+
updatedAt: at,
|
|
10291
|
+
isDeleted: false,
|
|
10292
|
+
data
|
|
10293
|
+
}
|
|
10294
|
+
}
|
|
10295
|
+
],
|
|
10296
|
+
options.signal
|
|
10297
|
+
);
|
|
10298
|
+
return created;
|
|
10299
|
+
} catch (error) {
|
|
10300
|
+
if (!conflict(error)) throw error;
|
|
10301
|
+
const winner = live(await store.get("conversation", ANUMA_CONVERSATION_ID, options.signal));
|
|
10302
|
+
if (!winner) throw error;
|
|
10303
|
+
return winner;
|
|
10304
|
+
}
|
|
10305
|
+
}
|
|
10306
|
+
async function markAnumaRead(store, sortKey, options = {}) {
|
|
10307
|
+
if (!Number.isSafeInteger(sortKey) || sortKey < 0)
|
|
10308
|
+
throw new ChatStoreError("Invalid Anuma read marker", 0, "invalid_record");
|
|
10309
|
+
const now = options.now ?? Date.now;
|
|
10310
|
+
for (let attempt = 1; ; attempt++) {
|
|
10311
|
+
const current = await ensureAnumaConversation(store, options);
|
|
10312
|
+
const read = anumaLastReadSortKey(current);
|
|
10313
|
+
if (sortKey <= read) return current;
|
|
10314
|
+
const record2 = current.record;
|
|
10315
|
+
const state = isObject(record2.data.anuma) ? record2.data.anuma : {};
|
|
10316
|
+
const data = plain({ ...record2.data, anuma: { ...state, lastReadSortKey: sortKey } });
|
|
10317
|
+
try {
|
|
10318
|
+
const [written] = await store.putMany(
|
|
10319
|
+
[
|
|
10320
|
+
{
|
|
10321
|
+
expectedVersion: current.version,
|
|
10322
|
+
record: {
|
|
10323
|
+
...record2,
|
|
10324
|
+
data,
|
|
10325
|
+
sortKey: conversationSortKey(data, record2.createdAt),
|
|
10326
|
+
updatedAt: Math.max(record2.updatedAt, now())
|
|
10327
|
+
}
|
|
10328
|
+
}
|
|
10329
|
+
],
|
|
10330
|
+
options.signal
|
|
10331
|
+
);
|
|
10332
|
+
return written;
|
|
10333
|
+
} catch (error) {
|
|
10334
|
+
if (!conflict(error) || attempt >= maxAttempts) throw error;
|
|
10335
|
+
}
|
|
10336
|
+
}
|
|
10337
|
+
}
|
|
10338
|
+
function countUnreadAnumaTurns(messages, lastReadSortKey) {
|
|
10339
|
+
const answered = Math.max(
|
|
10340
|
+
0,
|
|
10341
|
+
...messages.filter((m) => m.role === "user").map((m) => m.messageId)
|
|
10342
|
+
);
|
|
10343
|
+
const floor = Math.max(lastReadSortKey, answered);
|
|
10344
|
+
const turns = /* @__PURE__ */ new Set();
|
|
10345
|
+
for (const m of messages) {
|
|
10346
|
+
if (m.role !== "assistant" || m.messageId <= floor) continue;
|
|
10347
|
+
turns.add(m.anuma?.turnId ? `turn:${m.anuma.turnId}` : `message:${m.uniqueId}`);
|
|
10348
|
+
}
|
|
10349
|
+
return turns.size;
|
|
10350
|
+
}
|
|
10351
|
+
|
|
10352
|
+
// src/lib/db/chat/summaryOperations.ts
|
|
10353
|
+
import { Q as Q4 } from "@nozbe/watermelondb";
|
|
10354
|
+
function createSummaryContext(database, encryption = {}) {
|
|
10355
|
+
return {
|
|
10356
|
+
...encryption,
|
|
10357
|
+
database,
|
|
10358
|
+
summariesCollection: database.get("conversation_summaries")
|
|
10359
|
+
};
|
|
10360
|
+
}
|
|
10361
|
+
function modelToStored(record2, summary) {
|
|
10362
|
+
return {
|
|
10363
|
+
uniqueId: record2.id,
|
|
10364
|
+
conversationId: record2.conversationId,
|
|
10365
|
+
summary,
|
|
10366
|
+
summarizedUpTo: record2.summarizedUpTo,
|
|
10367
|
+
tokenCount: record2.tokenCount,
|
|
10368
|
+
createdAt: record2.createdAt,
|
|
10369
|
+
updatedAt: record2.updatedAt
|
|
10370
|
+
};
|
|
10371
|
+
}
|
|
10372
|
+
async function getConversationSummaryOp(ctx, conversationId) {
|
|
10373
|
+
const results = await ctx.summariesCollection.query(Q4.where("conversation_id", conversationId)).fetch();
|
|
10374
|
+
if (results.length === 0) return null;
|
|
10375
|
+
const record2 = results[0];
|
|
10376
|
+
const stored2 = modelToStored(record2, record2.summary);
|
|
10377
|
+
if (ctx.walletAddress && isEncrypted(stored2.summary)) {
|
|
10378
|
+
if (ctx.signMessage) {
|
|
10379
|
+
try {
|
|
10380
|
+
await requestEncryptionKey(ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner);
|
|
10381
|
+
} catch (error) {
|
|
10382
|
+
getLogger().warn("Failed to request the encryption key for the summary:", error);
|
|
10383
|
+
}
|
|
10384
|
+
}
|
|
10385
|
+
stored2.summary = await decryptField(stored2.summary, ctx.walletAddress);
|
|
10386
|
+
} else if (ctx.walletAddress && ctx.signMessage && stored2.summary) {
|
|
10387
|
+
try {
|
|
10388
|
+
const encryptedSummary = await encryptField(
|
|
10389
|
+
stored2.summary,
|
|
10390
|
+
ctx.walletAddress,
|
|
10391
|
+
ctx.signMessage,
|
|
10392
|
+
ctx.embeddedWalletSigner
|
|
10393
|
+
);
|
|
10394
|
+
await ctx.database.write(async () => {
|
|
10395
|
+
const current = await ctx.summariesCollection.query(Q4.where("id", record2.id)).fetch();
|
|
10396
|
+
if (current[0]?.summary === stored2.summary) {
|
|
10397
|
+
await current[0].update((rec) => {
|
|
10398
|
+
rec.summary = encryptedSummary;
|
|
10399
|
+
});
|
|
10400
|
+
}
|
|
10401
|
+
});
|
|
10402
|
+
} catch (error) {
|
|
10403
|
+
getLogger().warn("Failed to encrypt the legacy summary:", error);
|
|
10404
|
+
}
|
|
10405
|
+
}
|
|
10406
|
+
return stored2;
|
|
10407
|
+
}
|
|
10408
|
+
async function upsertConversationSummaryOp(ctx, conversationId, summary, summarizedUpTo, tokenCount) {
|
|
10409
|
+
const revision2 = getConversationRevision(ctx.database, conversationId);
|
|
10410
|
+
let record2;
|
|
10411
|
+
const encryptedSummary = ctx.walletAddress ? await encryptField(summary, ctx.walletAddress, ctx.signMessage, ctx.embeddedWalletSigner) : summary;
|
|
10412
|
+
await ctx.database.write(async () => {
|
|
10413
|
+
assertConversationRevision(ctx.database, conversationId, revision2);
|
|
10414
|
+
const existing = await ctx.summariesCollection.query(Q4.where("conversation_id", conversationId)).fetch();
|
|
10415
|
+
if (existing.length > 0) {
|
|
10416
|
+
record2 = await existing[0].update((rec) => {
|
|
10417
|
+
rec.summary = encryptedSummary;
|
|
10418
|
+
rec.summarizedUpTo = summarizedUpTo;
|
|
10419
|
+
rec.tokenCount = tokenCount;
|
|
10420
|
+
});
|
|
10421
|
+
} else {
|
|
10422
|
+
record2 = await ctx.summariesCollection.create((rec) => {
|
|
10423
|
+
rec.conversationId = conversationId;
|
|
10424
|
+
rec.summary = encryptedSummary;
|
|
10425
|
+
rec.summarizedUpTo = summarizedUpTo;
|
|
10426
|
+
rec.tokenCount = tokenCount;
|
|
10427
|
+
});
|
|
10428
|
+
}
|
|
10429
|
+
});
|
|
10430
|
+
return modelToStored(record2, summary);
|
|
10431
|
+
}
|
|
10432
|
+
async function deleteConversationSummaryOp(ctx, conversationId) {
|
|
10433
|
+
await ctx.database.write(async () => {
|
|
10434
|
+
const existing = await ctx.summariesCollection.query(Q4.where("conversation_id", conversationId)).fetch();
|
|
10435
|
+
for (const record2 of existing) {
|
|
10436
|
+
await record2.destroyPermanently();
|
|
10437
|
+
}
|
|
10438
|
+
});
|
|
10439
|
+
}
|
|
10440
|
+
|
|
10441
|
+
// src/lib/db/conversationMemory/models.ts
|
|
10442
|
+
import { Model as Model3 } from "@nozbe/watermelondb";
|
|
10443
|
+
import { date as date2, field as field2, readonly, text as text4 } from "@nozbe/watermelondb/decorators";
|
|
10444
|
+
var ConversationMemory = class extends Model3 {
|
|
10445
|
+
};
|
|
10446
|
+
ConversationMemory.table = "conversation_memory";
|
|
10447
|
+
ConversationMemory.associations = {};
|
|
10448
|
+
__decorateClass([
|
|
10449
|
+
text4("conversation_id")
|
|
10450
|
+
], ConversationMemory.prototype, "conversationId", 2);
|
|
10451
|
+
__decorateClass([
|
|
10452
|
+
text4("memory_id")
|
|
10453
|
+
], ConversationMemory.prototype, "memoryId", 2);
|
|
10454
|
+
__decorateClass([
|
|
10455
|
+
field2("score")
|
|
10456
|
+
], ConversationMemory.prototype, "score", 2);
|
|
10457
|
+
__decorateClass([
|
|
10458
|
+
readonly,
|
|
10459
|
+
date2("created_at")
|
|
10460
|
+
], ConversationMemory.prototype, "createdAt", 2);
|
|
10461
|
+
|
|
10305
10462
|
// src/lib/chatStore/chatImports.ts
|
|
10306
10463
|
var importBatch = 100;
|
|
10307
10464
|
var importChunks = 200;
|
|
@@ -10316,6 +10473,7 @@ function bytes2(value) {
|
|
|
10316
10473
|
function conversationRecord(conversation, messages) {
|
|
10317
10474
|
const createdAt = ms(conversation.createdAt);
|
|
10318
10475
|
const data = plain({
|
|
10476
|
+
...contextFields(conversation.context),
|
|
10319
10477
|
title: conversation.title,
|
|
10320
10478
|
projectId: conversation.projectId || void 0,
|
|
10321
10479
|
pinnedAt: conversation.pinnedAt ? ms(conversation.pinnedAt) : void 0,
|
|
@@ -10881,17 +11039,17 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
10881
11039
|
expectedVersion = typeof expectedVersion === "number" ? expectedVersion : snapshot.version;
|
|
10882
11040
|
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
|
10883
11041
|
throw new Error("expectedVersion must be a nonnegative integer");
|
|
10884
|
-
const
|
|
11042
|
+
const conflict2 = () => new RemoteMemoryError("The memory changed since it was read", 409, "version_conflict");
|
|
10885
11043
|
let existing;
|
|
10886
11044
|
if (expectedVersion !== 0 && !snapshot) {
|
|
10887
11045
|
try {
|
|
10888
11046
|
existing = memoryRecord(await request(path, {}, signal));
|
|
10889
11047
|
} catch (error) {
|
|
10890
|
-
if (error instanceof RemoteMemoryError && error.status === 404) throw
|
|
11048
|
+
if (error instanceof RemoteMemoryError && error.status === 404) throw conflict2();
|
|
10891
11049
|
throw error;
|
|
10892
11050
|
}
|
|
10893
11051
|
}
|
|
10894
|
-
if (existing && existing.version !== expectedVersion) throw
|
|
11052
|
+
if (existing && existing.version !== expectedVersion) throw conflict2();
|
|
10895
11053
|
const decoded = existing ? await decode(existing).catch(() => void 0) : void 0;
|
|
10896
11054
|
const reusableContent = snapshot?.encryptedContent ?? existing?.memory.content;
|
|
10897
11055
|
const content = reusableContent && (snapshot?.content ?? decoded?.memory.content) === memory.content ? reusableContent : await encryptField2(memory.content);
|
|
@@ -11116,17 +11274,6 @@ async function createRemoteMemoryPersistence(options) {
|
|
|
11116
11274
|
};
|
|
11117
11275
|
}
|
|
11118
11276
|
|
|
11119
|
-
// src/lib/chatStore/types.ts
|
|
11120
|
-
var ChatStoreError = class extends Error {
|
|
11121
|
-
constructor(message, status, code, retryAfterMs) {
|
|
11122
|
-
super(message);
|
|
11123
|
-
this.status = status;
|
|
11124
|
-
this.code = code;
|
|
11125
|
-
this.retryAfterMs = retryAfterMs;
|
|
11126
|
-
this.name = "ChatStoreError";
|
|
11127
|
-
}
|
|
11128
|
-
};
|
|
11129
|
-
|
|
11130
11277
|
// src/lib/chatStore/remote.ts
|
|
11131
11278
|
var kinds = /* @__PURE__ */ new Set(["conversation", "message", "summary", "project", "memory_links", "setting"]);
|
|
11132
11279
|
var cipherPattern = /^enc:v\d+:(?:[0-9a-f]{2}){28,}$/i;
|
|
@@ -11851,10 +11998,10 @@ async function deletedSinceUpload(store, journal, local, signal) {
|
|
|
11851
11998
|
const present = /* @__PURE__ */ new Set([...local.records.map((r) => key(r.record)), ...local.skipped.keys()]);
|
|
11852
11999
|
const gone = [...journal.keys].filter((k) => !present.has(k));
|
|
11853
12000
|
if (gone.length === 0) return [];
|
|
11854
|
-
const
|
|
11855
|
-
const tombstoning = new Set(
|
|
12001
|
+
const live2 = (await store.getMany(gone.map(ref2), signal)).filter((s) => !s.record.isDeleted);
|
|
12002
|
+
const tombstoning = new Set(live2.map((s) => key(s.record)));
|
|
11856
12003
|
await journal.drop(gone.filter((k) => !tombstoning.has(k)));
|
|
11857
|
-
return
|
|
12004
|
+
return live2.map(({ record: record2, version }) => {
|
|
11858
12005
|
const empty = emptied[record2.kind];
|
|
11859
12006
|
return {
|
|
11860
12007
|
record: {
|
|
@@ -12514,12 +12661,13 @@ var resumableFields = [
|
|
|
12514
12661
|
"error",
|
|
12515
12662
|
"thoughtProcess",
|
|
12516
12663
|
"thinking",
|
|
12517
|
-
"toolCallEvents"
|
|
12664
|
+
"toolCallEvents",
|
|
12665
|
+
"anuma"
|
|
12518
12666
|
];
|
|
12519
12667
|
function resumedFields(options) {
|
|
12520
12668
|
return plain(
|
|
12521
12669
|
Object.fromEntries(
|
|
12522
|
-
resumableFields.filter((f) => options[f] !== void 0).map((f) => [f, options[f]])
|
|
12670
|
+
resumableFields.filter((f) => options[f] !== void 0).map((f) => [f, f === "anuma" ? anumaTurnData(options.anuma) : options[f]])
|
|
12523
12671
|
)
|
|
12524
12672
|
);
|
|
12525
12673
|
}
|
|
@@ -13173,7 +13321,7 @@ function createVaultChatBackend(options) {
|
|
|
13173
13321
|
},
|
|
13174
13322
|
async getConversations(query) {
|
|
13175
13323
|
await available2();
|
|
13176
|
-
return all("conversation").map(toConversation).filter(
|
|
13324
|
+
return all("conversation").filter((record2) => record2.id !== ANUMA_CONVERSATION_ID).map(toConversation).filter(
|
|
13177
13325
|
(c) => query?.projectId === void 0 || (query.projectId === null ? !c.projectId : c.projectId === query.projectId)
|
|
13178
13326
|
).sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
13179
13327
|
},
|
|
@@ -13209,7 +13357,14 @@ function createVaultChatBackend(options) {
|
|
|
13209
13357
|
async updateConversationPinned(conversationId, pinned) {
|
|
13210
13358
|
return updateConversation(conversationId, { pinnedAt: pinned ? now() : null });
|
|
13211
13359
|
},
|
|
13360
|
+
async updateConversationContext(conversationId, context) {
|
|
13361
|
+
const set = contextFields(context);
|
|
13362
|
+
if (Object.keys(set).length > 0) return updateConversation(conversationId, set);
|
|
13363
|
+
const record2 = await conversation(conversationId);
|
|
13364
|
+
return !!record2 && !record2.isDeleted;
|
|
13365
|
+
},
|
|
13212
13366
|
async deleteConversation(conversationId) {
|
|
13367
|
+
if (conversationId === ANUMA_CONVERSATION_ID) return false;
|
|
13213
13368
|
const record2 = await conversation(conversationId);
|
|
13214
13369
|
if (!record2 || record2.isDeleted) return false;
|
|
13215
13370
|
for (const [k, patch] of pending)
|
|
@@ -16216,7 +16371,7 @@ async function countActiveVaultMemoriesOp(ctx) {
|
|
|
16216
16371
|
return ctx.vaultMemoryCollection.query(...baseVaultConditions(ctx)).fetchCount();
|
|
16217
16372
|
}
|
|
16218
16373
|
async function getVaultMemoryCountsOp(ctx) {
|
|
16219
|
-
const [
|
|
16374
|
+
const [live2, archived, quarantined] = await Promise.all([
|
|
16220
16375
|
countActiveVaultMemoriesOp(ctx),
|
|
16221
16376
|
ctx.vaultMemoryCollection.query(
|
|
16222
16377
|
...baseVaultConditions(ctx, { includeArchived: true }),
|
|
@@ -16227,7 +16382,7 @@ async function getVaultMemoryCountsOp(ctx) {
|
|
|
16227
16382
|
Q6.where("trust_tier", "quarantined")
|
|
16228
16383
|
).fetchCount()
|
|
16229
16384
|
]);
|
|
16230
|
-
return { live, archived, quarantined };
|
|
16385
|
+
return { live: live2, archived, quarantined };
|
|
16231
16386
|
}
|
|
16232
16387
|
async function getActiveVaultMemoryIdsOp(ctx, ids) {
|
|
16233
16388
|
if (ids.length === 0) return /* @__PURE__ */ new Set();
|
|
@@ -17512,12 +17667,12 @@ var WalletPoller = class {
|
|
|
17512
17667
|
* @param maxAttempts - Maximum polling attempts before giving up (default: 60)
|
|
17513
17668
|
* @returns Stop function to cancel polling
|
|
17514
17669
|
*/
|
|
17515
|
-
startPolling(checkWallet, onWalletReady, intervalMs = DEFAULT_INTERVAL_MS,
|
|
17670
|
+
startPolling(checkWallet, onWalletReady, intervalMs = DEFAULT_INTERVAL_MS, maxAttempts2 = DEFAULT_MAX_ATTEMPTS) {
|
|
17516
17671
|
this.stop();
|
|
17517
17672
|
this.attempts = 0;
|
|
17518
17673
|
const poll = async () => {
|
|
17519
17674
|
this.attempts++;
|
|
17520
|
-
if (this.attempts >
|
|
17675
|
+
if (this.attempts > maxAttempts2) {
|
|
17521
17676
|
this.stop();
|
|
17522
17677
|
return;
|
|
17523
17678
|
}
|
|
@@ -24878,13 +25033,13 @@ function createRemoteMemoryStore(options) {
|
|
|
24878
25033
|
});
|
|
24879
25034
|
return run;
|
|
24880
25035
|
};
|
|
24881
|
-
const
|
|
25036
|
+
const live2 = async (id2) => {
|
|
24882
25037
|
const record2 = await persistence.get(id2);
|
|
24883
25038
|
return record2 && !record2.memory.is_deleted ? record2 : null;
|
|
24884
25039
|
};
|
|
24885
25040
|
const mutateLocked = async (id2, change, edit, writeOptions) => {
|
|
24886
25041
|
writeOptions?.signal?.throwIfAborted();
|
|
24887
|
-
const record2 = writeOptions?.signal ? await persistence.get(id2, writeOptions.signal) : await
|
|
25042
|
+
const record2 = writeOptions?.signal ? await persistence.get(id2, writeOptions.signal) : await live2(id2);
|
|
24888
25043
|
if (!record2) return null;
|
|
24889
25044
|
if (record2.memory.is_deleted) return null;
|
|
24890
25045
|
if (writeOptions?.canWrite && !await writeOptions.canWrite())
|
|
@@ -25682,7 +25837,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25682
25837
|
}, clear);
|
|
25683
25838
|
return snapshot.then((topics) => structuredClone(topics));
|
|
25684
25839
|
},
|
|
25685
|
-
get: async (id2) => asStored(await
|
|
25840
|
+
get: async (id2) => asStored(await live2(id2)),
|
|
25686
25841
|
listArchived: async () => (await enumerate({ archived_only: true, order: "archived", include_embeddings: true })).map(
|
|
25687
25842
|
(record2) => stored(record2.memory)
|
|
25688
25843
|
),
|
|
@@ -25767,7 +25922,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25767
25922
|
return serialized(
|
|
25768
25923
|
first,
|
|
25769
25924
|
() => serialized(second, async () => {
|
|
25770
|
-
const [old, next] = await Promise.all([
|
|
25925
|
+
const [old, next] = await Promise.all([live2(id2), live2(supersededById)]);
|
|
25771
25926
|
if (!old || !next || old.memory.superseded_by || next.memory.superseded_by) return false;
|
|
25772
25927
|
if (old.memory.kind !== void 0 && old.memory.kind !== null) return false;
|
|
25773
25928
|
const saved = await persistence.putMany([
|
|
@@ -25788,7 +25943,7 @@ function createRemoteMemoryStore(options) {
|
|
|
25788
25943
|
(memory) => memory.archived_at === void 0 || memory.archived_at === null ? { ...memory, archived_at: Date.now() } : null
|
|
25789
25944
|
),
|
|
25790
25945
|
restore: (id2) => serialized(id2, async () => {
|
|
25791
|
-
const record2 = await
|
|
25946
|
+
const record2 = await live2(id2);
|
|
25792
25947
|
if (!record2) return false;
|
|
25793
25948
|
if (record2.memory.archived_at === void 0 || record2.memory.archived_at === null)
|
|
25794
25949
|
return true;
|
|
@@ -32934,6 +33089,7 @@ function useChatStorage(options) {
|
|
|
32934
33089
|
};
|
|
32935
33090
|
}
|
|
32936
33091
|
export {
|
|
33092
|
+
ANUMA_CONVERSATION_ID,
|
|
32937
33093
|
CHUNKS_DISCARDED_ORIGIN,
|
|
32938
33094
|
Conversation as ChatConversation,
|
|
32939
33095
|
Message as ChatMessage,
|
|
@@ -32993,6 +33149,8 @@ export {
|
|
|
32993
33149
|
WALLET_PAYMENT_TOOL_NAME,
|
|
32994
33150
|
WalletPoller,
|
|
32995
33151
|
addConversationMemoriesOp,
|
|
33152
|
+
anumaLastReadSortKey,
|
|
33153
|
+
anumaTurnContent,
|
|
32996
33154
|
archiveVaultMemoryOp,
|
|
32997
33155
|
assembleMemoryContext,
|
|
32998
33156
|
attachFileContextToLastUserMessage,
|
|
@@ -33026,6 +33184,7 @@ export {
|
|
|
33026
33184
|
consoleLogger,
|
|
33027
33185
|
conversationMemoryToStored,
|
|
33028
33186
|
cosineInt8,
|
|
33187
|
+
countUnreadAnumaTurns,
|
|
33029
33188
|
createAutoExtractor,
|
|
33030
33189
|
createChunkVectorCache,
|
|
33031
33190
|
createCryptoPricePreProcessor,
|
|
@@ -33074,6 +33233,7 @@ export {
|
|
|
33074
33233
|
embedMessage,
|
|
33075
33234
|
encodeChunkVector,
|
|
33076
33235
|
encryptToolCallEventsOp,
|
|
33236
|
+
ensureAnumaConversation,
|
|
33077
33237
|
ensureDefaultFoldersOp,
|
|
33078
33238
|
exchangeNotionCode,
|
|
33079
33239
|
extractAndLinkEntitiesForMemoriesOp,
|
|
@@ -33114,6 +33274,7 @@ export {
|
|
|
33114
33274
|
isRerankerAvailable,
|
|
33115
33275
|
loadSettings,
|
|
33116
33276
|
localChatBackend,
|
|
33277
|
+
markAnumaRead,
|
|
33117
33278
|
maskScopedEmbeddingCache,
|
|
33118
33279
|
maxVaultAttachmentBytes,
|
|
33119
33280
|
memoryCipher,
|
|
@@ -33129,6 +33290,7 @@ export {
|
|
|
33129
33290
|
quantizeEmbedding,
|
|
33130
33291
|
queueManager,
|
|
33131
33292
|
rankProfileCandidates,
|
|
33293
|
+
readAnumaTurn,
|
|
33132
33294
|
recall,
|
|
33133
33295
|
reencryptMemoryField,
|
|
33134
33296
|
reflect,
|