@anuma/sdk 6.31.3 → 6.31.4-next.20261007055054
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/react/index.cjs +230 -66
- package/dist/react/index.d.mts +57 -1
- package/dist/react/index.d.ts +57 -1
- package/dist/react/index.mjs +228 -66
- package/package.json +1 -1
package/dist/react/index.cjs
CHANGED
|
@@ -1653,6 +1653,7 @@ __export(index_exports, {
|
|
|
1653
1653
|
extractEntitiesForMemories: () => extractEntitiesForMemories,
|
|
1654
1654
|
extractFacts: () => extractFacts,
|
|
1655
1655
|
extractFileIds: () => extractFileIds,
|
|
1656
|
+
extractMCPImageUrls: () => extractMCPImageUrls,
|
|
1656
1657
|
fileExists: () => fileExists,
|
|
1657
1658
|
findById: () => findById,
|
|
1658
1659
|
findMatchingTools: () => findMatchingTools,
|
|
@@ -10603,6 +10604,7 @@ async function resumeStream(options) {
|
|
|
10603
10604
|
// src/react/useChat.ts
|
|
10604
10605
|
var import_react = require("react");
|
|
10605
10606
|
init_clientConfig();
|
|
10607
|
+
init_logger();
|
|
10606
10608
|
init_redactor();
|
|
10607
10609
|
function useChat(options) {
|
|
10608
10610
|
const {
|
|
@@ -10616,6 +10618,8 @@ function useChat(options) {
|
|
|
10616
10618
|
onServerToolCall,
|
|
10617
10619
|
onToolCallArgumentsDelta,
|
|
10618
10620
|
onStepFinish,
|
|
10621
|
+
resumable,
|
|
10622
|
+
onStreamMeta,
|
|
10619
10623
|
apiType: defaultApiType = "auto",
|
|
10620
10624
|
smoothing,
|
|
10621
10625
|
preProcessors,
|
|
@@ -10625,25 +10629,39 @@ function useChat(options) {
|
|
|
10625
10629
|
const [isLoading, setIsLoading] = (0, import_react.useState)(false);
|
|
10626
10630
|
const abortControllerRef = (0, import_react.useRef)(null);
|
|
10627
10631
|
const requestIdRef = (0, import_react.useRef)(0);
|
|
10632
|
+
const pendingInferenceRef = (0, import_react.useRef)(
|
|
10633
|
+
null
|
|
10634
|
+
);
|
|
10635
|
+
const cancelInference = (0, import_react.useCallback)(
|
|
10636
|
+
(inferenceId, requestToken) => {
|
|
10637
|
+
void (async () => {
|
|
10638
|
+
const token = requestToken ?? (getToken ? await getToken() : null);
|
|
10639
|
+
const response = await fetch(`${baseUrl}${streamCancelPath(inferenceId)}`, {
|
|
10640
|
+
method: "POST",
|
|
10641
|
+
headers: token ? { Authorization: `Bearer ${token}` } : void 0
|
|
10642
|
+
});
|
|
10643
|
+
if (!response.ok) throw new Error(`Stream cancellation failed: ${response.status}`);
|
|
10644
|
+
})().catch((error) => getLogger().warn("[useChat] stream cancel POST failed:", error));
|
|
10645
|
+
},
|
|
10646
|
+
[getToken, baseUrl]
|
|
10647
|
+
);
|
|
10628
10648
|
const piiRedactorRef = (0, import_react.useRef)(null);
|
|
10629
10649
|
if (piiRedaction === true && !piiRedactorRef.current) {
|
|
10630
10650
|
piiRedactorRef.current = new PiiRedactor();
|
|
10631
10651
|
}
|
|
10632
10652
|
const resolvedPiiRedaction = piiRedaction === true ? piiRedactorRef.current : piiRedaction;
|
|
10633
10653
|
const stop = (0, import_react.useCallback)(() => {
|
|
10654
|
+
const pending = pendingInferenceRef.current;
|
|
10655
|
+
pendingInferenceRef.current = null;
|
|
10656
|
+
pending?.cancel();
|
|
10634
10657
|
if (abortControllerRef.current) {
|
|
10635
10658
|
abortControllerRef.current.abort();
|
|
10636
10659
|
abortControllerRef.current = null;
|
|
10637
10660
|
}
|
|
10638
10661
|
}, []);
|
|
10639
|
-
(0, import_react.
|
|
10640
|
-
|
|
10641
|
-
|
|
10642
|
-
abortControllerRef.current.abort();
|
|
10643
|
-
abortControllerRef.current = null;
|
|
10644
|
-
}
|
|
10645
|
-
};
|
|
10646
|
-
}, []);
|
|
10662
|
+
const stopRef = (0, import_react.useRef)(stop);
|
|
10663
|
+
stopRef.current = stop;
|
|
10664
|
+
(0, import_react.useEffect)(() => () => stopRef.current(), []);
|
|
10647
10665
|
const sendMessage = (0, import_react.useCallback)(
|
|
10648
10666
|
async ({
|
|
10649
10667
|
messages,
|
|
@@ -10669,13 +10687,12 @@ function useChat(options) {
|
|
|
10669
10687
|
endpointOverride,
|
|
10670
10688
|
piiRedaction: requestPiiRedaction
|
|
10671
10689
|
}) => {
|
|
10672
|
-
|
|
10673
|
-
abortControllerRef.current.abort();
|
|
10674
|
-
}
|
|
10690
|
+
stop();
|
|
10675
10691
|
const abortController = new AbortController();
|
|
10676
10692
|
abortControllerRef.current = abortController;
|
|
10677
10693
|
const requestId = ++requestIdRef.current;
|
|
10678
10694
|
setIsLoading(true);
|
|
10695
|
+
let succeeded = false;
|
|
10679
10696
|
try {
|
|
10680
10697
|
const tokenGetterValidation = validateTokenGetter(getToken);
|
|
10681
10698
|
if (!tokenGetterValidation.valid) {
|
|
@@ -10738,6 +10755,22 @@ function useChat(options) {
|
|
|
10738
10755
|
headers,
|
|
10739
10756
|
apiType: requestApiType ?? defaultApiType,
|
|
10740
10757
|
endpointOverride,
|
|
10758
|
+
resumable,
|
|
10759
|
+
onStreamMeta: resumable || onStreamMeta ? (meta) => {
|
|
10760
|
+
if (requestId !== requestIdRef.current || abortController.signal.aborted) {
|
|
10761
|
+
if (resumable) cancelInference(meta.inferenceId, token);
|
|
10762
|
+
return;
|
|
10763
|
+
}
|
|
10764
|
+
const previous = pendingInferenceRef.current;
|
|
10765
|
+
if (previous && previous.round === meta.round && previous.id !== meta.inferenceId)
|
|
10766
|
+
previous.cancel();
|
|
10767
|
+
pendingInferenceRef.current = {
|
|
10768
|
+
id: meta.inferenceId,
|
|
10769
|
+
round: meta.round,
|
|
10770
|
+
cancel: resumable ? () => cancelInference(meta.inferenceId, token) : () => void 0
|
|
10771
|
+
};
|
|
10772
|
+
onStreamMeta?.(meta);
|
|
10773
|
+
} : void 0,
|
|
10741
10774
|
temperature,
|
|
10742
10775
|
maxOutputTokens,
|
|
10743
10776
|
tools,
|
|
@@ -10767,6 +10800,7 @@ function useChat(options) {
|
|
|
10767
10800
|
piiRedaction: requestPiiRedaction ?? resolvedPiiRedaction,
|
|
10768
10801
|
onPiiRedacted
|
|
10769
10802
|
});
|
|
10803
|
+
succeeded = result.error === null;
|
|
10770
10804
|
return result;
|
|
10771
10805
|
} catch (err) {
|
|
10772
10806
|
return createErrorResult(
|
|
@@ -10777,12 +10811,16 @@ function useChat(options) {
|
|
|
10777
10811
|
if (requestIdRef.current === requestId) {
|
|
10778
10812
|
setIsLoading(false);
|
|
10779
10813
|
abortControllerRef.current = null;
|
|
10814
|
+
if (!succeeded) pendingInferenceRef.current?.cancel();
|
|
10815
|
+
pendingInferenceRef.current = null;
|
|
10780
10816
|
}
|
|
10781
10817
|
}
|
|
10782
10818
|
},
|
|
10783
10819
|
[
|
|
10784
10820
|
getToken,
|
|
10785
10821
|
baseUrl,
|
|
10822
|
+
stop,
|
|
10823
|
+
cancelInference,
|
|
10786
10824
|
globalOnData,
|
|
10787
10825
|
globalOnThinking,
|
|
10788
10826
|
onFinish,
|
|
@@ -10791,6 +10829,8 @@ function useChat(options) {
|
|
|
10791
10829
|
onServerToolCall,
|
|
10792
10830
|
onToolCallArgumentsDelta,
|
|
10793
10831
|
onStepFinish,
|
|
10832
|
+
resumable,
|
|
10833
|
+
onStreamMeta,
|
|
10794
10834
|
defaultApiType,
|
|
10795
10835
|
smoothing,
|
|
10796
10836
|
preProcessors,
|
|
@@ -24690,6 +24730,8 @@ function useChatStorage(options) {
|
|
|
24690
24730
|
onError,
|
|
24691
24731
|
onServerToolCall,
|
|
24692
24732
|
onToolCallArgumentsDelta,
|
|
24733
|
+
resumable,
|
|
24734
|
+
onStreamMeta,
|
|
24693
24735
|
apiType,
|
|
24694
24736
|
walletAddress,
|
|
24695
24737
|
signMessage,
|
|
@@ -25254,6 +25296,8 @@ function useChatStorage(options) {
|
|
|
25254
25296
|
onError,
|
|
25255
25297
|
onServerToolCall,
|
|
25256
25298
|
onToolCallArgumentsDelta,
|
|
25299
|
+
resumable,
|
|
25300
|
+
onStreamMeta,
|
|
25257
25301
|
apiType,
|
|
25258
25302
|
preProcessors,
|
|
25259
25303
|
smoothing,
|
|
@@ -25676,6 +25720,7 @@ function useChatStorage(options) {
|
|
|
25676
25720
|
return {
|
|
25677
25721
|
data: result2.data,
|
|
25678
25722
|
error: null,
|
|
25723
|
+
autoExecutedToolResults: "autoExecutedToolResults" in result2 ? result2.autoExecutedToolResults : void 0,
|
|
25679
25724
|
skipped: true
|
|
25680
25725
|
};
|
|
25681
25726
|
}
|
|
@@ -32167,6 +32212,22 @@ async function uploadFileToDropbox(accessToken, filename, content, folder = DEFA
|
|
|
32167
32212
|
}
|
|
32168
32213
|
return response.json();
|
|
32169
32214
|
}
|
|
32215
|
+
async function getDropboxFileMetadata(accessToken, filename, folder = DEFAULT_BACKUP_FOLDER) {
|
|
32216
|
+
const response = await fetch(`${DROPBOX_API_URL}/files/get_metadata`, {
|
|
32217
|
+
method: "POST",
|
|
32218
|
+
headers: {
|
|
32219
|
+
Authorization: `Bearer ${accessToken}`,
|
|
32220
|
+
"Content-Type": "application/json"
|
|
32221
|
+
},
|
|
32222
|
+
body: JSON.stringify({ path: `${folder}/${filename}` })
|
|
32223
|
+
});
|
|
32224
|
+
if (response.status === 409) return null;
|
|
32225
|
+
if (!response.ok) {
|
|
32226
|
+
const errorText = await response.text();
|
|
32227
|
+
throw new Error(`Dropbox get metadata failed: ${response.status} - ${errorText}`);
|
|
32228
|
+
}
|
|
32229
|
+
return response.json();
|
|
32230
|
+
}
|
|
32170
32231
|
async function listDropboxFiles(accessToken, folder = DEFAULT_BACKUP_FOLDER) {
|
|
32171
32232
|
await ensureBackupFolder(accessToken, folder);
|
|
32172
32233
|
const response = await fetch(`${DROPBOX_API_URL}/files/list_folder`, {
|
|
@@ -32232,27 +32293,61 @@ async function downloadDropboxFile(accessToken, path) {
|
|
|
32232
32293
|
}
|
|
32233
32294
|
return response.blob();
|
|
32234
32295
|
}
|
|
32235
|
-
async function findDropboxFile(accessToken, filename, folder = DEFAULT_BACKUP_FOLDER) {
|
|
32236
|
-
const files = await listDropboxFiles(accessToken, folder);
|
|
32237
|
-
return files.find((f) => f.name === filename) || null;
|
|
32238
|
-
}
|
|
32239
32296
|
|
|
32240
32297
|
// src/lib/backup/dropbox/backup.ts
|
|
32241
32298
|
var isAuthError = (err) => err instanceof Error && (err.message.includes("401") || err.message.includes("invalid_access_token"));
|
|
32242
|
-
|
|
32299
|
+
var MAX_LISTING_FAILURES = 3;
|
|
32300
|
+
function createDropboxFileIndex(backupFolder) {
|
|
32301
|
+
let pending;
|
|
32302
|
+
let failures = 0;
|
|
32303
|
+
return {
|
|
32304
|
+
get(token) {
|
|
32305
|
+
if (!pending) {
|
|
32306
|
+
if (failures >= MAX_LISTING_FAILURES) {
|
|
32307
|
+
return Promise.reject(
|
|
32308
|
+
new Error("The backup folder listing failed repeatedly; skipped for this run")
|
|
32309
|
+
);
|
|
32310
|
+
}
|
|
32311
|
+
pending = listDropboxFiles(token, backupFolder).then((files) => {
|
|
32312
|
+
const byName = /* @__PURE__ */ new Map();
|
|
32313
|
+
for (const file of files) {
|
|
32314
|
+
if (!byName.has(file.name)) byName.set(file.name, file);
|
|
32315
|
+
}
|
|
32316
|
+
return byName;
|
|
32317
|
+
}).catch((err) => {
|
|
32318
|
+
pending = void 0;
|
|
32319
|
+
failures++;
|
|
32320
|
+
throw err;
|
|
32321
|
+
});
|
|
32322
|
+
}
|
|
32323
|
+
return pending;
|
|
32324
|
+
}
|
|
32325
|
+
};
|
|
32326
|
+
}
|
|
32327
|
+
async function readLocalUpdatedAt(database, conversationId) {
|
|
32328
|
+
const { Q: Q19 } = await import("@nozbe/watermelondb");
|
|
32329
|
+
const records = await database.get("conversations").query(Q19.where("conversation_id", conversationId)).fetch();
|
|
32330
|
+
const match = records.map(conversationToStoredRaw).find((c) => c.conversationId === conversationId);
|
|
32331
|
+
return match ? match.updatedAt : null;
|
|
32332
|
+
}
|
|
32333
|
+
async function pushConversationToDropbox(database, conversationId, userAddress, token, fileIndex, deps, backupFolder = DEFAULT_BACKUP_FOLDER, _retried = false) {
|
|
32243
32334
|
try {
|
|
32244
32335
|
await deps.requestEncryptionKey(userAddress);
|
|
32245
32336
|
const filename = `${conversationId}.json`;
|
|
32246
|
-
const
|
|
32337
|
+
const index = await fileIndex.get(token);
|
|
32338
|
+
const existingFile = index.get(filename);
|
|
32247
32339
|
if (existingFile) {
|
|
32248
|
-
const
|
|
32249
|
-
const
|
|
32250
|
-
|
|
32251
|
-
|
|
32252
|
-
|
|
32253
|
-
|
|
32254
|
-
|
|
32255
|
-
|
|
32340
|
+
const localUpdatedAt = await readLocalUpdatedAt(database, conversationId);
|
|
32341
|
+
const localUpdated = localUpdatedAt ? localUpdatedAt.getTime() : null;
|
|
32342
|
+
if (localUpdated !== null && localUpdated <= new Date(existingFile.server_modified).getTime()) {
|
|
32343
|
+
return "skipped";
|
|
32344
|
+
}
|
|
32345
|
+
const current = await getDropboxFileMetadata(token, filename, backupFolder);
|
|
32346
|
+
if (!current) {
|
|
32347
|
+
index.delete(filename);
|
|
32348
|
+
} else {
|
|
32349
|
+
index.set(filename, current);
|
|
32350
|
+
if (localUpdated !== null && localUpdated <= new Date(current.server_modified).getTime()) {
|
|
32256
32351
|
return "skipped";
|
|
32257
32352
|
}
|
|
32258
32353
|
}
|
|
@@ -32261,7 +32356,8 @@ async function pushConversationToDropbox(database, conversationId, userAddress,
|
|
|
32261
32356
|
if (!exportResult.success || !exportResult.blob) {
|
|
32262
32357
|
return "failed";
|
|
32263
32358
|
}
|
|
32264
|
-
await uploadFileToDropbox(token, filename, exportResult.blob, backupFolder);
|
|
32359
|
+
const uploaded = await uploadFileToDropbox(token, filename, exportResult.blob, backupFolder);
|
|
32360
|
+
index.set(filename, uploaded);
|
|
32265
32361
|
return "uploaded";
|
|
32266
32362
|
} catch (err) {
|
|
32267
32363
|
if (isAuthError(err) && !_retried) {
|
|
@@ -32272,6 +32368,7 @@ async function pushConversationToDropbox(database, conversationId, userAddress,
|
|
|
32272
32368
|
conversationId,
|
|
32273
32369
|
userAddress,
|
|
32274
32370
|
newToken,
|
|
32371
|
+
fileIndex,
|
|
32275
32372
|
deps,
|
|
32276
32373
|
backupFolder,
|
|
32277
32374
|
true
|
|
@@ -32295,6 +32392,7 @@ async function performDropboxExport(database, userAddress, token, deps, onProgre
|
|
|
32295
32392
|
}
|
|
32296
32393
|
let uploaded = 0;
|
|
32297
32394
|
let skipped = 0;
|
|
32395
|
+
const fileIndex = createDropboxFileIndex(backupFolder);
|
|
32298
32396
|
for (let i = 0; i < conversations.length; i++) {
|
|
32299
32397
|
const conv = conversations[i];
|
|
32300
32398
|
onProgress?.(i + 1, total);
|
|
@@ -32303,6 +32401,7 @@ async function performDropboxExport(database, userAddress, token, deps, onProgre
|
|
|
32303
32401
|
conv.conversationId,
|
|
32304
32402
|
userAddress,
|
|
32305
32403
|
token,
|
|
32404
|
+
fileIndex,
|
|
32306
32405
|
deps,
|
|
32307
32406
|
backupFolder
|
|
32308
32407
|
);
|
|
@@ -32866,29 +32965,52 @@ async function listDriveFiles(accessToken, folderId) {
|
|
|
32866
32965
|
const data = await response.json();
|
|
32867
32966
|
return data.files ?? [];
|
|
32868
32967
|
}
|
|
32869
|
-
|
|
32870
|
-
|
|
32871
|
-
|
|
32872
|
-
|
|
32873
|
-
|
|
32874
|
-
|
|
32875
|
-
|
|
32876
|
-
|
|
32968
|
+
var DRIVE_MAX_PAGE_SIZE = 1e3;
|
|
32969
|
+
async function listAllDriveFiles(accessToken, folderId) {
|
|
32970
|
+
const query = `'${escapeQueryValue(folderId)}' in parents and trashed=false`;
|
|
32971
|
+
const fields = encodeURIComponent("nextPageToken,files(id,name,createdTime,modifiedTime,size)");
|
|
32972
|
+
const files = [];
|
|
32973
|
+
let pageToken;
|
|
32974
|
+
do {
|
|
32975
|
+
const tokenParam = pageToken ? `&pageToken=${encodeURIComponent(pageToken)}` : "";
|
|
32976
|
+
const response = await fetch(
|
|
32977
|
+
`${DRIVE_API_URL}/files?q=${encodeURIComponent(query)}&fields=${fields}&pageSize=${DRIVE_MAX_PAGE_SIZE}${tokenParam}`,
|
|
32978
|
+
{
|
|
32979
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
32980
|
+
}
|
|
32981
|
+
);
|
|
32982
|
+
if (!response.ok) {
|
|
32983
|
+
throw new Error(`Failed to list files: ${response.status}`);
|
|
32984
|
+
}
|
|
32985
|
+
const data = await response.json();
|
|
32986
|
+
files.push(...data.files ?? []);
|
|
32987
|
+
pageToken = data.nextPageToken;
|
|
32988
|
+
} while (pageToken);
|
|
32989
|
+
return files;
|
|
32877
32990
|
}
|
|
32878
|
-
async function
|
|
32879
|
-
const
|
|
32880
|
-
const fields = "files(id,name,createdTime,modifiedTime,size)";
|
|
32991
|
+
async function getDriveFileMetadata(accessToken, fileId) {
|
|
32992
|
+
const fields = encodeURIComponent("id,name,createdTime,modifiedTime,size,trashed");
|
|
32881
32993
|
const response = await fetch(
|
|
32882
|
-
`${DRIVE_API_URL}/files
|
|
32994
|
+
`${DRIVE_API_URL}/files/${encodeURIComponent(fileId)}?fields=${fields}`,
|
|
32883
32995
|
{
|
|
32884
32996
|
headers: { Authorization: `Bearer ${accessToken}` }
|
|
32885
32997
|
}
|
|
32886
32998
|
);
|
|
32999
|
+
if (response.status === 404) return null;
|
|
32887
33000
|
if (!response.ok) {
|
|
32888
|
-
throw new Error(`Failed to
|
|
33001
|
+
throw new Error(`Failed to read file: ${response.status}`);
|
|
32889
33002
|
}
|
|
32890
33003
|
const data = await response.json();
|
|
32891
|
-
return data.
|
|
33004
|
+
return data.trashed ? null : data;
|
|
33005
|
+
}
|
|
33006
|
+
async function downloadDriveFile(accessToken, fileId) {
|
|
33007
|
+
const response = await fetch(`${DRIVE_API_URL}/files/${fileId}?alt=media`, {
|
|
33008
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
33009
|
+
});
|
|
33010
|
+
if (!response.ok) {
|
|
33011
|
+
throw new Error(`Failed to download file: ${response.status}`);
|
|
33012
|
+
}
|
|
33013
|
+
return response.blob();
|
|
32892
33014
|
}
|
|
32893
33015
|
|
|
32894
33016
|
// src/lib/backup/google/backup.ts
|
|
@@ -32910,28 +33032,59 @@ async function getConversationsFolder(token, requestDriveAccess, rootFolder, sub
|
|
|
32910
33032
|
throw err;
|
|
32911
33033
|
}
|
|
32912
33034
|
}
|
|
32913
|
-
|
|
33035
|
+
var MAX_LISTING_FAILURES2 = 3;
|
|
33036
|
+
function createDriveFileIndex(folderId) {
|
|
33037
|
+
let pending;
|
|
33038
|
+
let failures = 0;
|
|
33039
|
+
return {
|
|
33040
|
+
get(token) {
|
|
33041
|
+
if (!pending) {
|
|
33042
|
+
if (failures >= MAX_LISTING_FAILURES2) {
|
|
33043
|
+
return Promise.reject(
|
|
33044
|
+
new Error("The backup folder listing failed repeatedly; skipped for this run")
|
|
33045
|
+
);
|
|
33046
|
+
}
|
|
33047
|
+
pending = listAllDriveFiles(token, folderId).then((files) => {
|
|
33048
|
+
const byName = /* @__PURE__ */ new Map();
|
|
33049
|
+
for (const file of files) {
|
|
33050
|
+
if (!byName.has(file.name)) byName.set(file.name, file);
|
|
33051
|
+
}
|
|
33052
|
+
return byName;
|
|
33053
|
+
}).catch((err) => {
|
|
33054
|
+
pending = void 0;
|
|
33055
|
+
failures++;
|
|
33056
|
+
throw err;
|
|
33057
|
+
});
|
|
33058
|
+
}
|
|
33059
|
+
return pending;
|
|
33060
|
+
}
|
|
33061
|
+
};
|
|
33062
|
+
}
|
|
33063
|
+
async function readLocalUpdatedAt2(database, conversationId) {
|
|
33064
|
+
const { Q: Q19 } = await import("@nozbe/watermelondb");
|
|
33065
|
+
const records = await database.get("conversations").query(Q19.where("conversation_id", conversationId)).fetch();
|
|
33066
|
+
const match = records.map(conversationToStoredRaw).find((c) => c.conversationId === conversationId);
|
|
33067
|
+
return match ? match.updatedAt : null;
|
|
33068
|
+
}
|
|
33069
|
+
async function pushConversationToDrive(database, conversationId, userAddress, token, folderId, fileIndex, deps, _retried = false) {
|
|
32914
33070
|
try {
|
|
32915
33071
|
await deps.requestEncryptionKey(userAddress);
|
|
32916
|
-
const folderResult = await getConversationsFolder(
|
|
32917
|
-
token,
|
|
32918
|
-
deps.requestDriveAccess,
|
|
32919
|
-
rootFolder,
|
|
32920
|
-
subfolder
|
|
32921
|
-
);
|
|
32922
|
-
if (!folderResult) return "failed";
|
|
32923
|
-
const { folderId, token: activeToken } = folderResult;
|
|
32924
33072
|
const filename = `${conversationId}.json`;
|
|
32925
|
-
const
|
|
33073
|
+
const index = await fileIndex.get(token);
|
|
33074
|
+
let existingFile = index.get(filename);
|
|
32926
33075
|
if (existingFile) {
|
|
32927
|
-
const
|
|
32928
|
-
const
|
|
32929
|
-
|
|
32930
|
-
|
|
32931
|
-
|
|
32932
|
-
|
|
32933
|
-
|
|
32934
|
-
|
|
33076
|
+
const localUpdatedAt = await readLocalUpdatedAt2(database, conversationId);
|
|
33077
|
+
const localUpdated = localUpdatedAt ? localUpdatedAt.getTime() : null;
|
|
33078
|
+
if (localUpdated !== null && localUpdated <= new Date(existingFile.modifiedTime).getTime()) {
|
|
33079
|
+
return "skipped";
|
|
33080
|
+
}
|
|
33081
|
+
const current = await getDriveFileMetadata(token, existingFile.id);
|
|
33082
|
+
if (!current) {
|
|
33083
|
+
index.delete(filename);
|
|
33084
|
+
existingFile = void 0;
|
|
33085
|
+
} else {
|
|
33086
|
+
index.set(filename, current);
|
|
33087
|
+
if (localUpdated !== null && localUpdated <= new Date(current.modifiedTime).getTime()) {
|
|
32935
33088
|
return "skipped";
|
|
32936
33089
|
}
|
|
32937
33090
|
}
|
|
@@ -32940,10 +33093,19 @@ async function pushConversationToDrive(database, conversationId, userAddress, to
|
|
|
32940
33093
|
if (!exportResult.success || !exportResult.blob) {
|
|
32941
33094
|
return "failed";
|
|
32942
33095
|
}
|
|
33096
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
32943
33097
|
if (existingFile) {
|
|
32944
|
-
await updateDriveFile(
|
|
33098
|
+
await updateDriveFile(token, existingFile.id, exportResult.blob);
|
|
33099
|
+
index.set(filename, { ...existingFile, modifiedTime: now });
|
|
32945
33100
|
} else {
|
|
32946
|
-
await uploadFileToDrive(
|
|
33101
|
+
const created = await uploadFileToDrive(token, folderId, exportResult.blob, filename);
|
|
33102
|
+
index.set(filename, {
|
|
33103
|
+
id: created.id,
|
|
33104
|
+
name: created.name,
|
|
33105
|
+
createdTime: now,
|
|
33106
|
+
modifiedTime: now,
|
|
33107
|
+
size: String(exportResult.blob.size)
|
|
33108
|
+
});
|
|
32947
33109
|
}
|
|
32948
33110
|
return "uploaded";
|
|
32949
33111
|
} catch (err) {
|
|
@@ -32955,9 +33117,9 @@ async function pushConversationToDrive(database, conversationId, userAddress, to
|
|
|
32955
33117
|
conversationId,
|
|
32956
33118
|
userAddress,
|
|
32957
33119
|
newToken,
|
|
33120
|
+
folderId,
|
|
33121
|
+
fileIndex,
|
|
32958
33122
|
deps,
|
|
32959
|
-
rootFolder,
|
|
32960
|
-
subfolder,
|
|
32961
33123
|
true
|
|
32962
33124
|
);
|
|
32963
33125
|
} catch {
|
|
@@ -32978,7 +33140,8 @@ async function performGoogleDriveExport(database, userAddress, token, deps, onPr
|
|
|
32978
33140
|
if (!folderResult) {
|
|
32979
33141
|
return { success: false, uploaded: 0, skipped: 0, total: 0 };
|
|
32980
33142
|
}
|
|
32981
|
-
const { token: activeToken } = folderResult;
|
|
33143
|
+
const { folderId, token: activeToken } = folderResult;
|
|
33144
|
+
const fileIndex = createDriveFileIndex(folderId);
|
|
32982
33145
|
const { Q: Q19 } = await import("@nozbe/watermelondb");
|
|
32983
33146
|
const conversationsCollection = database.get("conversations");
|
|
32984
33147
|
const records = await conversationsCollection.query(Q19.where("is_deleted", false)).fetch();
|
|
@@ -32997,9 +33160,9 @@ async function performGoogleDriveExport(database, userAddress, token, deps, onPr
|
|
|
32997
33160
|
conv.conversationId,
|
|
32998
33161
|
userAddress,
|
|
32999
33162
|
activeToken,
|
|
33000
|
-
|
|
33001
|
-
|
|
33002
|
-
|
|
33163
|
+
folderId,
|
|
33164
|
+
fileIndex,
|
|
33165
|
+
deps
|
|
33003
33166
|
);
|
|
33004
33167
|
if (result === "uploaded") uploaded++;
|
|
33005
33168
|
if (result === "skipped") skipped++;
|
|
@@ -37628,6 +37791,7 @@ function renderAnumaJsx(jsx3) {
|
|
|
37628
37791
|
extractEntitiesForMemories,
|
|
37629
37792
|
extractFacts,
|
|
37630
37793
|
extractFileIds,
|
|
37794
|
+
extractMCPImageUrls,
|
|
37631
37795
|
fileExists,
|
|
37632
37796
|
findById,
|
|
37633
37797
|
findMatchingTools,
|