@jskit-ai/assistant-core 0.2.7 → 0.2.8
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/examples/conversation/package.json +5 -5
- package/package.json +18 -7
- package/src/client/browser.js +21 -0
- package/src/client/conversation/AssistantAttachmentQueue.vue +25 -108
- package/src/client/conversation/AssistantComposerActions.vue +1 -1
- package/src/client/conversation/AssistantConversationElement.vue +14 -52
- package/src/client/conversation/AssistantGoalControl.vue +13 -10
- package/src/client/conversation/AssistantPromptInput.vue +6 -91
- package/src/client/conversation/AssistantTranscript.css +505 -0
- package/src/client/conversation/AssistantTranscript.vue +24 -1197
- package/src/client/conversation/attachmentFiles.js +158 -0
- package/src/client/conversation/attachmentQueueItems.js +121 -0
- package/src/client/conversation/attachmentUploadRows.js +265 -0
- package/src/client/conversation/conversationDisplay.js +54 -0
- package/src/client/conversation/messageDelivery.js +13 -9
- package/src/client/conversation/retainedConversation.js +14 -3
- package/src/client/conversation/submitText.js +13 -2
- package/src/client/conversation/transcriptEntries.js +225 -0
- package/src/client/conversation/useAssistantAttachments.js +86 -388
- package/src/client/conversation/useAssistantQuestions.js +16 -3
- package/src/client/conversation/useAssistantSuggestions.js +16 -2
- package/src/client/conversation/useScrollToBottom.js +17 -19
- package/src/client/conversation/useTextareaAutoGrow.js +115 -0
- package/src/client/conversation/useTranscriptScrollFollow.js +525 -0
- package/src/client/lib/assistantApi.js +192 -161
- package/src/client/types.js +110 -0
- package/src/server/conversation/attachments.js +21 -6
- package/src/server/conversation/boundedToolLoop.js +1 -0
- package/src/server/conversation/claudeClient.js +71 -20
- package/src/server/conversation/claudeCommandRun.js +191 -0
- package/src/server/conversation/claudeHistory.js +7 -0
- package/src/server/conversation/claudeNativeTurn.js +708 -0
- package/src/server/conversation/claudeProcess.js +186 -112
- package/src/server/conversation/claudeProcessStart.js +214 -0
- package/src/server/conversation/claudePromptDelivery.js +183 -0
- package/src/server/conversation/claudeSessionCleanup.js +248 -0
- package/src/server/conversation/claudeTools.js +15 -3
- package/src/server/conversation/claudeTurn.js +212 -1388
- package/src/server/conversation/codexAccountReader.js +168 -0
- package/src/server/conversation/codexAuthPreflight.js +5 -4
- package/src/server/conversation/codexClient.js +18 -6
- package/src/server/conversation/codexConfiguration.js +8 -844
- package/src/server/conversation/codexConversationStops.js +377 -0
- package/src/server/conversation/codexConversationStore.js +119 -85
- package/src/server/conversation/codexConversationTurns.js +378 -0
- package/src/server/conversation/codexConversations.js +134 -866
- package/src/server/conversation/codexDetachedConversation.js +203 -0
- package/src/server/conversation/codexDetachedTurn.js +145 -104
- package/src/server/conversation/codexEvents.js +5 -200
- package/src/server/conversation/codexGoalCommands.js +14 -4
- package/src/server/conversation/codexHelperExecution.js +57 -57
- package/src/server/conversation/codexHelperThreadLedger.js +30 -288
- package/src/server/conversation/codexHelperThreadRecord.js +304 -0
- package/src/server/conversation/codexHelperThreadRecovery.js +54 -76
- package/src/server/conversation/codexHelperThreads.js +94 -93
- package/src/server/conversation/codexHistoryAdapter.js +13 -8
- package/src/server/conversation/codexIsolation.js +672 -0
- package/src/server/conversation/codexLiveItems.js +379 -0
- package/src/server/conversation/codexMessageCommands.js +68 -286
- package/src/server/conversation/codexMessageDelivery.js +46 -37
- package/src/server/conversation/codexModelCatalog.js +86 -7
- package/src/server/conversation/codexNotificationObserver.js +81 -88
- package/src/server/conversation/codexNotificationQueue.js +21 -10
- package/src/server/conversation/codexObservationControl.js +105 -89
- package/src/server/conversation/codexOutput.js +84 -419
- package/src/server/conversation/codexProcess.js +29 -1053
- package/src/server/conversation/codexProcessLeader.js +1 -0
- package/src/server/conversation/codexPromptDispatch.js +241 -0
- package/src/server/conversation/codexProvider.js +147 -1807
- package/src/server/conversation/codexProviderAuth.js +348 -0
- package/src/server/conversation/codexProviderInvalidation.js +371 -0
- package/src/server/conversation/codexProviderInventories.js +437 -0
- package/src/server/conversation/codexProviderOwner.js +149 -957
- package/src/server/conversation/codexProviderRelease.js +465 -0
- package/src/server/conversation/codexProviderSelection.js +26 -15
- package/src/server/conversation/codexProviderThreads.js +698 -0
- package/src/server/conversation/codexProviderTurns.js +453 -0
- package/src/server/conversation/codexReasoning.js +32 -23
- package/src/server/conversation/codexRenewalCommands.js +18 -6
- package/src/server/conversation/codexRenewalThreads.js +7 -22
- package/src/server/conversation/codexResultSettlement.js +70 -88
- package/src/server/conversation/codexRunJournal.js +91 -97
- package/src/server/conversation/codexRuntime.js +426 -0
- package/src/server/conversation/codexRuntimeInventory.js +113 -0
- package/src/server/conversation/codexRuntimeLifecycle.js +39 -13
- package/src/server/conversation/codexRuntimeStart.js +431 -0
- package/src/server/conversation/codexRuntimeStop.js +324 -0
- package/src/server/conversation/codexSessionCleanup.js +25 -10
- package/src/server/conversation/codexSessionReconciliation.js +21 -7
- package/src/server/conversation/codexThreadReadiness.js +49 -52
- package/src/server/conversation/codexThreadSnapshot.js +210 -0
- package/src/server/conversation/codexThreadStatus.js +48 -62
- package/src/server/conversation/codexTurn.js +171 -55
- package/src/server/conversation/codexTurnActivity.js +210 -0
- package/src/server/conversation/codexTurnControl.js +44 -48
- package/src/server/conversation/codexTurnEndings.js +610 -0
- package/src/server/conversation/codexTurnRecovery.js +97 -848
- package/src/server/conversation/codexTurnState.js +138 -111
- package/src/server/conversation/completedResponses.js +227 -0
- package/src/server/conversation/configuration.js +2 -2
- package/src/server/conversation/continuity.js +43 -6
- package/src/server/conversation/conversationDelivery.js +394 -0
- package/src/server/conversation/conversationEntries.js +365 -0
- package/src/server/conversation/conversationEvents.js +192 -0
- package/src/server/conversation/conversationGoals.js +187 -0
- package/src/server/conversation/conversationHandles.js +237 -0
- package/src/server/conversation/conversationReads.js +206 -0
- package/src/server/conversation/conversationRefusals.js +58 -0
- package/src/server/conversation/conversationReplacement.js +254 -0
- package/src/server/conversation/conversationSending.js +273 -0
- package/src/server/conversation/conversationStopping.js +121 -0
- package/src/server/conversation/conversationTurnDelivery.js +413 -0
- package/src/server/conversation/conversationTurns.js +511 -0
- package/src/server/conversation/deliveryTiming.js +25 -3
- package/src/server/conversation/fileStorage.js +11 -6
- package/src/server/conversation/hookBridge.js +14 -3
- package/src/server/conversation/index.js +1 -1
- package/src/server/conversation/localExecution.js +82 -625
- package/src/server/conversation/nativeCommandCallbacks.js +10 -0
- package/src/server/conversation/nativeConversationLifecycle.js +379 -0
- package/src/server/conversation/nativeHistoryExport.js +27 -18
- package/src/server/conversation/normalize.js +9 -0
- package/src/server/conversation/openCodeClient.js +295 -366
- package/src/server/conversation/openCodeNativeHistory.js +141 -0
- package/src/server/conversation/openCodeNativeSession.js +79 -0
- package/src/server/conversation/openCodeProcess.js +109 -53
- package/src/server/conversation/openCodeProcessOwner.js +565 -0
- package/src/server/conversation/openCodeRuntime.js +111 -1814
- package/src/server/conversation/openCodeSessionTurns.js +547 -0
- package/src/server/conversation/openCodeTemporaryConversations.js +394 -0
- package/src/server/conversation/openCodeTools.js +28 -14
- package/src/server/conversation/openCodeTurn.js +80 -74
- package/src/server/conversation/openCodeTurnMonitor.js +388 -0
- package/src/server/conversation/processIdentity.js +582 -0
- package/src/server/conversation/provider.js +21 -6
- package/src/server/conversation/providers/api.js +268 -107
- package/src/server/conversation/providers/claude.js +29 -6
- package/src/server/conversation/providers/claudeDriver.js +325 -250
- package/src/server/conversation/providers/codex.js +69 -33
- package/src/server/conversation/providers/codexDriver.js +503 -1081
- package/src/server/conversation/providers/codexDriverConnection.js +331 -0
- package/src/server/conversation/providers/codexDriverTurns.js +464 -0
- package/src/server/conversation/providers/opencode.js +30 -4
- package/src/server/conversation/providers/opencodeDriver.js +321 -659
- package/src/server/conversation/providers/opencodeStandalone.js +475 -0
- package/src/server/conversation/providers/scoped.js +64 -19
- package/src/server/conversation/runtime.js +171 -2863
- package/src/server/conversation/storage.js +91 -50
- package/src/server/conversation/streams.js +15 -2
- package/src/server/conversation/structuredOutput.js +7 -11
- package/src/server/conversation/systemPrompt.js +13 -1
- package/src/server/conversation/tools.js +47 -15
- package/src/server/conversation/transcript.js +49 -20
- package/src/server/hosts/claudeTurn.js +2 -4
- package/src/server/hosts/codexConfiguration.js +6 -8
- package/src/server/hosts/codexEvents.js +4 -2
- package/src/server/hosts/codexProcess.js +1 -1
- package/src/server/hosts/codexProvider.js +11 -9
- package/src/server/hosts/codexTurn.js +3 -3
- package/src/server/hosts/openCodeClient.js +4 -2
- package/src/server/index.js +0 -2
- package/src/server/lib/aiConnectionClient.js +35 -25
- package/src/server/lib/ndjson.js +1 -0
- package/src/server/lib/providers/anthropicClient.js +15 -6
- package/src/server/lib/providers/common.js +10 -6
- package/src/server/lib/providers/openAiCompatibleClient.js +40 -23
- package/src/server/lib/serviceToolCatalog.js +29 -283
- package/src/server/lib/serviceToolEntries.js +270 -0
- package/src/server/types.js +78 -0
- package/src/shared/assistantResource.js +0 -23
- package/src/shared/conversation/answerChoiceSugar.js +2 -14
- package/src/shared/conversation/messageInputSugar.js +18 -0
- package/src/shared/conversation/numberedQuestionSugar.js +6 -16
- package/src/shared/conversation/pagination.js +1 -1
- package/src/shared/conversation/questions.js +1 -0
- package/src/shared/conversation/streaming.js +1 -0
- package/src/shared/index.js +0 -1
- package/src/testing/conversationStorageContract.js +20 -0
- package/test/aiConnectionClient.test.js +42 -1
- package/test/apiConversationDriver.test.js +217 -38
- package/test/assistantBoundedToolLoop.test.js +1 -1
- package/test/claudeConversationSession.test.js +15 -11
- package/test/claudeInstructionResume.test.js +1 -1
- package/test/claudeProcess.test.js +9 -9
- package/test/claudeTurn.test.js +21 -8
- package/test/codexAccountChange.test.js +5 -3
- package/test/codexConversationSession.test.js +22 -21
- package/test/codexEvents.test.js +3 -1
- package/test/codexHelperDeletion.test.js +3 -7
- package/test/codexIsolation.test.js +6 -6
- package/test/codexModelCatalog.test.js +6 -7
- package/test/codexProcess.test.js +3 -3
- package/test/codexThreadSelection.test.js +4 -1
- package/test/codexTurn.test.js +29 -20
- package/test/conversationApiFacilities.test.js +11 -9
- package/test/conversationAttachments.test.js +3 -3
- package/test/conversationConfiguration.test.js +4 -4
- package/test/conversationNativeStorage.test.js +11 -10
- package/test/conversationReplacement.test.js +13 -13
- package/test/conversationRuntime.test.js +9 -5
- package/test/conversationSession.test.js +78 -22
- package/test/conversationTools.test.js +47 -26
- package/test/fileConversationStorage.test.js +10 -3
- package/test/fixtures/codexHelperThreadLedger.js +3 -3
- package/test/frameworkActions.test.js +33 -18
- package/test/localConversationExecution.test.js +4 -4
- package/test/localExecution.test.js +1 -1
- package/test/openCodeConnectionChange.test.js +3 -2
- package/test/openCodeRuntime.test.js +8 -7
- package/test/openCodeTools.test.js +1 -1
- package/test/opencodeConversationSession.test.js +4 -3
- package/test/serviceToolCatalog.test.js +3 -8
- package/src/server/lib/assistantCompletion.js +0 -190
- package/src/server/lib/assistantToolLoop.js +0 -259
|
@@ -2,7 +2,6 @@ import {
|
|
|
2
2
|
computed,
|
|
3
3
|
getCurrentScope,
|
|
4
4
|
onScopeDispose,
|
|
5
|
-
reactive,
|
|
6
5
|
ref,
|
|
7
6
|
toValue,
|
|
8
7
|
watch
|
|
@@ -10,6 +9,26 @@ import {
|
|
|
10
9
|
import { ASSISTANT_ATTACHMENT_MAX_ITEMS } from "../../shared/conversation/attachments.js";
|
|
11
10
|
import { useJskitText } from "../i18n.js";
|
|
12
11
|
import { attachmentLimitText } from "./attachmentSize.js";
|
|
12
|
+
import {
|
|
13
|
+
assistantAttachmentEventHasFiles,
|
|
14
|
+
assistantAttachmentFiles,
|
|
15
|
+
assistantAttachmentFilesFromDropEvent,
|
|
16
|
+
assistantAttachmentFilesFromPasteEvent,
|
|
17
|
+
assistantAttachmentFilesFromTransferItems,
|
|
18
|
+
useAttachmentDropTarget
|
|
19
|
+
} from "./attachmentFiles.js";
|
|
20
|
+
import {
|
|
21
|
+
attachmentFileName,
|
|
22
|
+
attachmentIdentity,
|
|
23
|
+
attachmentReceipt,
|
|
24
|
+
attachmentUploadError,
|
|
25
|
+
attachmentUploadResult,
|
|
26
|
+
buildQueueRow,
|
|
27
|
+
createReceiptCleanup,
|
|
28
|
+
createWaiter,
|
|
29
|
+
settleWaiter,
|
|
30
|
+
updateRowProgress
|
|
31
|
+
} from "./attachmentUploadRows.js";
|
|
13
32
|
|
|
14
33
|
const { serverMessage, t } = useJskitText();
|
|
15
34
|
|
|
@@ -27,91 +46,6 @@ function assistantAttachmentUploadAllowed(canUpload) {
|
|
|
27
46
|
return toValue(canUpload) !== false;
|
|
28
47
|
}
|
|
29
48
|
|
|
30
|
-
function assistantAttachmentFiles(fileList = []) {
|
|
31
|
-
return Array.from(fileList || []).filter((file) => file && file.size >= 0);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function assistantAttachmentFilesFromTransferItems(items = []) {
|
|
35
|
-
return assistantAttachmentFiles(Array.from(items || [])
|
|
36
|
-
.map((item) => {
|
|
37
|
-
if (item?.kind !== "file" || typeof item.getAsFile !== "function") {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
return item.getAsFile();
|
|
41
|
-
}));
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function assistantAttachmentFilesFromDropEvent(event) {
|
|
45
|
-
const dataTransfer = event?.dataTransfer;
|
|
46
|
-
const itemFiles = assistantAttachmentFilesFromTransferItems(dataTransfer?.items);
|
|
47
|
-
if (itemFiles.length > 0) {
|
|
48
|
-
return itemFiles;
|
|
49
|
-
}
|
|
50
|
-
return assistantAttachmentFiles(dataTransfer?.files);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function assistantAttachmentFilesFromPasteEvent(event) {
|
|
54
|
-
const clipboardData = event?.clipboardData;
|
|
55
|
-
const itemFiles = assistantAttachmentFilesFromTransferItems(clipboardData?.items);
|
|
56
|
-
if (itemFiles.length > 0) {
|
|
57
|
-
return itemFiles;
|
|
58
|
-
}
|
|
59
|
-
return assistantAttachmentFiles(clipboardData?.files);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function assistantAttachmentEventHasFiles(event) {
|
|
63
|
-
const dataTransfer = event?.dataTransfer;
|
|
64
|
-
return assistantAttachmentFilesFromDropEvent(event).length > 0 ||
|
|
65
|
-
Array.from(dataTransfer?.items || []).some((item) => item?.kind === "file") ||
|
|
66
|
-
Array.from(dataTransfer?.types || []).some((type) => (
|
|
67
|
-
type === "Files" ||
|
|
68
|
-
type === "application/x-moz-file"
|
|
69
|
-
));
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function assistantAttachmentClipboardText(event) {
|
|
73
|
-
if (typeof event?.clipboardData?.getData !== "function") {
|
|
74
|
-
return "";
|
|
75
|
-
}
|
|
76
|
-
return String(event.clipboardData.getData("text/plain") || "");
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function assistantAttachmentClipboardLocalFileReference(event) {
|
|
80
|
-
const clipboardData = event?.clipboardData;
|
|
81
|
-
if (!clipboardData || typeof clipboardData.getData !== "function") {
|
|
82
|
-
return "";
|
|
83
|
-
}
|
|
84
|
-
const types = Array.from(clipboardData.types || []);
|
|
85
|
-
const text = [
|
|
86
|
-
clipboardData.getData("x-special/gnome-copied-files"),
|
|
87
|
-
clipboardData.getData("text/uri-list"),
|
|
88
|
-
clipboardData.getData("text/plain")
|
|
89
|
-
].map((value) => String(value || "").trim()).filter(Boolean).join("\n");
|
|
90
|
-
if (
|
|
91
|
-
types.includes("Files") ||
|
|
92
|
-
types.includes("application/x-moz-file") ||
|
|
93
|
-
types.includes("x-special/gnome-copied-files") ||
|
|
94
|
-
/^file:/imu.test(text)
|
|
95
|
-
) {
|
|
96
|
-
return text || "file://";
|
|
97
|
-
}
|
|
98
|
-
return "";
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function attachmentUploadError(attachment = {}) {
|
|
102
|
-
return attachment?.error || attachment?.errors?.[0]?.message || "";
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function attachmentIdentity(attachment = {}) {
|
|
106
|
-
return String(
|
|
107
|
-
attachment?.clientId ||
|
|
108
|
-
attachment?.attachmentId ||
|
|
109
|
-
attachment?.path ||
|
|
110
|
-
attachment?.fileName ||
|
|
111
|
-
""
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
49
|
const ASSISTANT_ATTACHMENT_MAX_BYTES = 100_000_000;
|
|
116
50
|
const ASSISTANT_ATTACHMENT_UPLOAD_CONCURRENCY = 2;
|
|
117
51
|
const ASSISTANT_ATTACHMENT_UNRESOLVED_PHASES = new Set([
|
|
@@ -122,126 +56,53 @@ const ASSISTANT_ATTACHMENT_UNRESOLVED_PHASES = new Set([
|
|
|
122
56
|
"failed"
|
|
123
57
|
]);
|
|
124
58
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
function nextAttachmentClientId() {
|
|
128
|
-
attachmentClientSequence += 1;
|
|
129
|
-
return `attachment-${Date.now().toString(36)}-${attachmentClientSequence.toString(36)}`;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function attachmentFileName(file = {}) {
|
|
133
|
-
return String(file?.name || "attachment");
|
|
134
|
-
}
|
|
59
|
+
/** Without an onError, an attachment failure shows only in the queue's own status. */
|
|
60
|
+
function keepAttachmentErrorInStatus() {}
|
|
135
61
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
cancel: typeof upload.cancel === "function" ? () => upload.cancel() : null,
|
|
140
|
-
promise: upload
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
if (upload?.promise && typeof upload.promise.then === "function") {
|
|
144
|
-
const cancel = typeof upload.abort === "function"
|
|
145
|
-
? () => upload.abort()
|
|
146
|
-
: typeof upload.cancel === "function"
|
|
147
|
-
? () => upload.cancel()
|
|
148
|
-
: null;
|
|
149
|
-
return {
|
|
150
|
-
cancel,
|
|
151
|
-
promise: upload.promise
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
return {
|
|
155
|
-
cancel: null,
|
|
156
|
-
promise: Promise.resolve(upload)
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function attachmentProgress(progress = {}, possibleTotal, fallbackTotal = 0) {
|
|
161
|
-
const directNumericProgress = typeof progress === "number" ? progress : null;
|
|
162
|
-
const progressObject = progress && typeof progress === "object" ? progress : {};
|
|
163
|
-
const totalBytes = Math.max(0, Number(
|
|
164
|
-
progressObject.totalBytes ??
|
|
165
|
-
progressObject.total ??
|
|
166
|
-
possibleTotal ??
|
|
167
|
-
fallbackTotal
|
|
168
|
-
) || 0);
|
|
169
|
-
const bytesValue = progressObject.bytesSent ??
|
|
170
|
-
progressObject.loaded ??
|
|
171
|
-
progressObject.uploadedBytes ??
|
|
172
|
-
directNumericProgress;
|
|
173
|
-
const bytesKnown = bytesValue !== null && bytesValue !== undefined && bytesValue !== "";
|
|
174
|
-
let bytesSent = bytesKnown ? Number(bytesValue) || 0 : 0;
|
|
175
|
-
const directPercent = progressObject.percent;
|
|
176
|
-
let percent = directPercent !== null && directPercent !== undefined && directPercent !== ""
|
|
177
|
-
? Number(directPercent)
|
|
178
|
-
: null;
|
|
179
|
-
const progressValue = progressObject.progress;
|
|
180
|
-
if (!Number.isFinite(percent) && progressValue !== null && progressValue !== undefined && progressValue !== "") {
|
|
181
|
-
const numericProgressValue = Number(progressValue);
|
|
182
|
-
if (Number.isFinite(numericProgressValue)) {
|
|
183
|
-
percent = numericProgressValue <= 1 ? numericProgressValue * 100 : numericProgressValue;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
if (!Number.isFinite(percent)) {
|
|
187
|
-
percent = bytesKnown && totalBytes > 0 ? (bytesSent / totalBytes) * 100 : null;
|
|
188
|
-
}
|
|
189
|
-
if (percent !== null) {
|
|
190
|
-
percent = Math.max(0, Math.min(100, percent));
|
|
191
|
-
}
|
|
192
|
-
if (totalBytes > 0) {
|
|
193
|
-
const inferredBytes = percent === null ? 0 : totalBytes * percent / 100;
|
|
194
|
-
bytesSent = Math.max(0, Math.min(totalBytes, bytesSent || inferredBytes));
|
|
195
|
-
} else {
|
|
196
|
-
bytesSent = Math.max(0, bytesSent);
|
|
197
|
-
}
|
|
198
|
-
return {
|
|
199
|
-
bytesSent,
|
|
200
|
-
percent,
|
|
201
|
-
totalBytes
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function attachmentReceipt(row, uploaded = {}) {
|
|
206
|
-
return {
|
|
207
|
-
...uploaded,
|
|
208
|
-
attachmentId: String(uploaded?.attachmentId || ""),
|
|
209
|
-
clientId: row.clientId,
|
|
210
|
-
fileName: String(uploaded?.fileName || row.fileName),
|
|
211
|
-
sessionId: row.sessionId,
|
|
212
|
-
size: Number(uploaded?.size ?? row.size) || 0
|
|
213
|
-
};
|
|
62
|
+
/** Without an onUploaded, an uploaded file stays in the queue, ready to send with the next message. */
|
|
63
|
+
async function keepUploadedAttachmentsReady() {
|
|
64
|
+
return null;
|
|
214
65
|
}
|
|
215
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Attachment upload and selection state for one composer: a bounded queue that uploads files a few at a time, hands
|
|
69
|
+
* each receipt to `onUploaded`, and deletes uploaded files no message will send. The application owns storage and
|
|
70
|
+
* authorization through `uploadAttachment` and `deleteAttachment`.
|
|
71
|
+
* @param {{
|
|
72
|
+
* canUpload?: import("vue").MaybeRefOrGetter<boolean>,
|
|
73
|
+
* deleteAttachment?: import("../types.js").AssistantAttachmentDeletion,
|
|
74
|
+
* onError?: (error: unknown, fallbackMessage: string) => void,
|
|
75
|
+
* onUploaded?: (receipts: import("../types.js").AssistantAttachmentReceipt[]) => Promise<{ accepted?: boolean } | null>,
|
|
76
|
+
* sessionId: import("vue").MaybeRefOrGetter<string>,
|
|
77
|
+
* uploadAttachment: import("../types.js").AssistantAttachmentUpload,
|
|
78
|
+
* maxBytes?: number,
|
|
79
|
+
* maxItems?: number,
|
|
80
|
+
* uploadConcurrency?: number
|
|
81
|
+
* }} options
|
|
82
|
+
*/
|
|
216
83
|
function useAssistantAttachments({
|
|
217
84
|
canUpload = () => true,
|
|
218
|
-
deleteAttachment
|
|
219
|
-
onError =
|
|
220
|
-
onUploaded =
|
|
85
|
+
deleteAttachment,
|
|
86
|
+
onError = keepAttachmentErrorInStatus,
|
|
87
|
+
onUploaded = keepUploadedAttachmentsReady,
|
|
221
88
|
sessionId,
|
|
222
89
|
uploadAttachment,
|
|
223
90
|
maxBytes = ASSISTANT_ATTACHMENT_MAX_BYTES,
|
|
224
91
|
maxItems = ASSISTANT_ATTACHMENT_MAX_ITEMS,
|
|
225
92
|
uploadConcurrency = ASSISTANT_ATTACHMENT_UPLOAD_CONCURRENCY
|
|
226
|
-
}
|
|
93
|
+
}) {
|
|
227
94
|
if (![maxBytes, maxItems, uploadConcurrency].every(value => Number.isSafeInteger(value) && value > 0)) {
|
|
228
95
|
throw new TypeError("Attachment limits must be positive integers.");
|
|
229
96
|
}
|
|
230
97
|
const attachments = ref([]);
|
|
231
98
|
const queueItems = ref([]);
|
|
232
|
-
const dragDepth = ref(0);
|
|
233
99
|
const status = ref("");
|
|
234
100
|
const activeUploadCount = ref(0);
|
|
235
101
|
const uploadQueue = [];
|
|
236
102
|
const rowsById = new Map();
|
|
237
103
|
const activeAttempts = new Map();
|
|
238
|
-
const cleanupTasks = new Set();
|
|
239
|
-
const receiptCleanupById = new Map();
|
|
240
|
-
const cleanedReceiptIds = new Set();
|
|
241
104
|
let disposed = false;
|
|
242
|
-
let stopSessionWatch = null;
|
|
243
105
|
|
|
244
|
-
const dragActive = computed(() => dragDepth.value > 0);
|
|
245
106
|
const uploading = computed(() => (
|
|
246
107
|
activeUploadCount.value > 0 || queueItems.value.some((item) => (
|
|
247
108
|
["preparing", "uploading", "delivering"].includes(item.phase)
|
|
@@ -259,8 +120,7 @@ function useAssistantAttachments({
|
|
|
259
120
|
!disposed &&
|
|
260
121
|
assistantAttachmentSessionId(sessionId) &&
|
|
261
122
|
assistantAttachmentUploadAllowed(canUpload) &&
|
|
262
|
-
!atCapacity.value
|
|
263
|
-
typeof uploadAttachment === "function"
|
|
123
|
+
!atCapacity.value
|
|
264
124
|
));
|
|
265
125
|
const aggregateProgress = computed(() => {
|
|
266
126
|
const retainedItems = queueItems.value.filter((item) => item.phase !== "cancelled");
|
|
@@ -281,7 +141,7 @@ function useAssistantAttachments({
|
|
|
281
141
|
} = {}) {
|
|
282
142
|
const message = attachmentErrorText(error, fallbackMessage);
|
|
283
143
|
status.value = message;
|
|
284
|
-
if (notify
|
|
144
|
+
if (notify) {
|
|
285
145
|
try {
|
|
286
146
|
onError(error || new Error(message), fallbackMessage);
|
|
287
147
|
} catch {
|
|
@@ -291,33 +151,16 @@ function useAssistantAttachments({
|
|
|
291
151
|
return message;
|
|
292
152
|
}
|
|
293
153
|
|
|
294
|
-
function resetDragState() {
|
|
295
|
-
dragDepth.value = 0;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
154
|
function clearStatus() {
|
|
299
155
|
status.value = "";
|
|
300
156
|
}
|
|
301
157
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
promise,
|
|
309
|
-
resolve,
|
|
310
|
-
settled: false
|
|
311
|
-
};
|
|
312
|
-
return row.waiter;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function settleWaiter(row, value = null, waiter = row.waiter) {
|
|
316
|
-
if (!waiter || waiter.settled) {
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
waiter.settled = true;
|
|
320
|
-
waiter.resolve(value);
|
|
158
|
+
/** Marks a row failed at one stage with its error's text, which also becomes the queue's status. */
|
|
159
|
+
function failRow(row, failureStage, error, fallbackMessage) {
|
|
160
|
+
row.error = attachmentErrorText(error, fallbackMessage);
|
|
161
|
+
row.failureStage = failureStage;
|
|
162
|
+
row.phase = "failed";
|
|
163
|
+
reportAttachmentError(error, fallbackMessage, { notify: false });
|
|
321
164
|
}
|
|
322
165
|
|
|
323
166
|
function canonicalRow(attachment = {}) {
|
|
@@ -327,62 +170,18 @@ function useAssistantAttachments({
|
|
|
327
170
|
)) : null;
|
|
328
171
|
}
|
|
329
172
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
if (!attachmentId || typeof deleteAttachment !== "function") {
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
|
-
const response = await deleteAttachment(currentSessionId, attachmentId);
|
|
346
|
-
if (response?.ok === false) {
|
|
347
|
-
throw new Error(attachmentUploadError(response) || t("jskit.assistant.attachments.error.cleanupFailed"));
|
|
348
|
-
}
|
|
349
|
-
return true;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
function cleanupReceipt(currentSessionId, receipt = {}) {
|
|
353
|
-
const attachmentId = String(receipt?.attachmentId || "").trim();
|
|
354
|
-
const cleanupId = `${currentSessionId}:${attachmentId}`;
|
|
355
|
-
if (!attachmentId) {
|
|
356
|
-
return Promise.resolve(false);
|
|
357
|
-
}
|
|
358
|
-
if (cleanedReceiptIds.has(cleanupId)) {
|
|
359
|
-
return Promise.resolve(false);
|
|
360
|
-
}
|
|
361
|
-
if (receiptCleanupById.has(cleanupId)) {
|
|
362
|
-
return receiptCleanupById.get(cleanupId);
|
|
363
|
-
}
|
|
364
|
-
const cleanup = trackCleanup(deleteUploadedAttachment(currentSessionId, receipt)).then((deleted) => {
|
|
365
|
-
if (deleted) {
|
|
366
|
-
cleanedReceiptIds.add(cleanupId);
|
|
367
|
-
}
|
|
368
|
-
return deleted;
|
|
369
|
-
});
|
|
370
|
-
receiptCleanupById.set(cleanupId, cleanup);
|
|
371
|
-
cleanup.finally(() => receiptCleanupById.delete(cleanupId));
|
|
372
|
-
return cleanup;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
function updateProgress(row, progress, total) {
|
|
376
|
-
if (!row.retained || row.phase !== "uploading") {
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
const next = attachmentProgress(progress, total, row.totalBytes);
|
|
380
|
-
row.bytesSent = Math.max(row.bytesSent, next.bytesSent);
|
|
381
|
-
row.totalBytes = next.totalBytes || row.totalBytes;
|
|
382
|
-
if (next.percent !== null) {
|
|
383
|
-
row.progress = Math.max(Number(row.progress) || 0, next.percent);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
173
|
+
// readable-check: allow method-probe - optional operation: a queue whose uploaded files are kept passes no deleteAttachment, so an upload no message sends stays stored
|
|
174
|
+
const deletesUnsentUploads = typeof deleteAttachment === "function";
|
|
175
|
+
const { cleanupReceipt, waitForAttachmentCleanup } = createReceiptCleanup({ deleteAttachment, deletesUnsentUploads, reportAttachmentError });
|
|
176
|
+
const {
|
|
177
|
+
dragActive,
|
|
178
|
+
handleDragEnter,
|
|
179
|
+
handleDragLeave,
|
|
180
|
+
handleDragOver,
|
|
181
|
+
handleDrop,
|
|
182
|
+
handlePaste,
|
|
183
|
+
resetDragState
|
|
184
|
+
} = useAttachmentDropTarget({ uploadFiles, reportAttachmentError });
|
|
386
185
|
|
|
387
186
|
function removeReadyReceipt(row) {
|
|
388
187
|
const removed = attachments.value.filter((attachment) => (
|
|
@@ -434,11 +233,8 @@ function useAssistantAttachments({
|
|
|
434
233
|
}
|
|
435
234
|
row.activeHandoffToken = null;
|
|
436
235
|
removeReadyReceipt(row);
|
|
437
|
-
row
|
|
438
|
-
row.failureStage = "handoff";
|
|
439
|
-
row.phase = "failed";
|
|
236
|
+
failRow(row, "handoff", error, t("jskit.assistant.attachments.error.unusable"));
|
|
440
237
|
settleWaiter(row, null, waiter);
|
|
441
|
-
reportAttachmentError(error, t("jskit.assistant.attachments.error.unusable"), { notify: false });
|
|
442
238
|
return null;
|
|
443
239
|
}
|
|
444
240
|
}
|
|
@@ -480,20 +276,15 @@ function useAssistantAttachments({
|
|
|
480
276
|
const error = uploadError || new Error(
|
|
481
277
|
attachmentUploadError(uploaded) || t("jskit.assistant.attachments.error.uploadFailed")
|
|
482
278
|
);
|
|
483
|
-
row
|
|
484
|
-
row.failureStage = "upload";
|
|
485
|
-
row.phase = "failed";
|
|
279
|
+
failRow(row, "upload", error, t("jskit.assistant.attachments.error.uploadFailed"));
|
|
486
280
|
settleWaiter(row, null, attempt.waiter);
|
|
487
|
-
reportAttachmentError(error, t("jskit.assistant.attachments.error.uploadFailed"), { notify: false });
|
|
488
281
|
}
|
|
489
282
|
pumpQueue();
|
|
490
283
|
}
|
|
491
284
|
|
|
492
285
|
function startUpload(row) {
|
|
493
286
|
const token = Symbol(row.clientId);
|
|
494
|
-
const abortController =
|
|
495
|
-
? new AbortController()
|
|
496
|
-
: null;
|
|
287
|
+
const abortController = new AbortController();
|
|
497
288
|
const attempt = {
|
|
498
289
|
abortController,
|
|
499
290
|
cancel: null,
|
|
@@ -511,8 +302,8 @@ function useAssistantAttachments({
|
|
|
511
302
|
|
|
512
303
|
try {
|
|
513
304
|
const transport = attachmentUploadResult(uploadAttachment(row.sessionId, row.file, {
|
|
514
|
-
onProgress: (progress, total) =>
|
|
515
|
-
signal: abortController
|
|
305
|
+
onProgress: (progress, total) => updateRowProgress(row, progress, total),
|
|
306
|
+
signal: abortController.signal
|
|
516
307
|
}));
|
|
517
308
|
attempt.cancel = transport.cancel;
|
|
518
309
|
attempt.settled = transport.promise.then(
|
|
@@ -558,7 +349,8 @@ function useAssistantAttachments({
|
|
|
558
349
|
const attempt = token ? activeAttempts.get(token) : null;
|
|
559
350
|
try {
|
|
560
351
|
row.producerAbortController?.abort();
|
|
561
|
-
attempt?.abortController
|
|
352
|
+
attempt?.abortController.abort();
|
|
353
|
+
// readable-check: allow optional-call - optional operation: an upload that returns a bare promise has no cancel
|
|
562
354
|
attempt?.cancel?.();
|
|
563
355
|
} catch {
|
|
564
356
|
// A cancelled transport is already detached; late success is still cleaned up.
|
|
@@ -576,8 +368,7 @@ function useAssistantAttachments({
|
|
|
576
368
|
!row.retained ||
|
|
577
369
|
!["failed", "cancelled"].includes(row.phase) ||
|
|
578
370
|
row.sessionId !== assistantAttachmentSessionId(sessionId) ||
|
|
579
|
-
!assistantAttachmentUploadAllowed(canUpload)
|
|
580
|
-
typeof uploadAttachment !== "function"
|
|
371
|
+
!assistantAttachmentUploadAllowed(canUpload)
|
|
581
372
|
) {
|
|
582
373
|
return Promise.resolve(null);
|
|
583
374
|
}
|
|
@@ -598,10 +389,7 @@ function useAssistantAttachments({
|
|
|
598
389
|
return waiter.promise;
|
|
599
390
|
}
|
|
600
391
|
if (row.size > maxBytes) {
|
|
601
|
-
row
|
|
602
|
-
row.failureStage = "validation";
|
|
603
|
-
row.phase = "failed";
|
|
604
|
-
reportAttachmentError(row.error, t("jskit.assistant.attachments.error.uploadFailed"), { notify: false });
|
|
392
|
+
failRow(row, "validation", tooLarge(row), t("jskit.assistant.attachments.error.uploadFailed"));
|
|
605
393
|
return Promise.resolve(null);
|
|
606
394
|
}
|
|
607
395
|
row.bytesSent = 0;
|
|
@@ -695,75 +483,18 @@ function useAssistantAttachments({
|
|
|
695
483
|
return rows;
|
|
696
484
|
}
|
|
697
485
|
|
|
698
|
-
async function waitForAttachmentCleanup() {
|
|
699
|
-
while (cleanupTasks.size > 0) {
|
|
700
|
-
await Promise.allSettled([...cleanupTasks]);
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
|
|
704
486
|
async function disposeAttachments() {
|
|
705
487
|
if (disposed) {
|
|
706
488
|
await waitForAttachmentCleanup();
|
|
707
489
|
return [];
|
|
708
490
|
}
|
|
709
491
|
disposed = true;
|
|
710
|
-
stopSessionWatch
|
|
711
|
-
stopSessionWatch = null;
|
|
492
|
+
stopSessionWatch();
|
|
712
493
|
return abandonAttachments();
|
|
713
494
|
}
|
|
714
495
|
|
|
715
|
-
function
|
|
716
|
-
|
|
717
|
-
return;
|
|
718
|
-
}
|
|
719
|
-
dragDepth.value += 1;
|
|
720
|
-
if (event?.dataTransfer) {
|
|
721
|
-
event.dataTransfer.dropEffect = "copy";
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
function handleDragOver(event) {
|
|
726
|
-
if (event?.dataTransfer) {
|
|
727
|
-
event.dataTransfer.dropEffect = "copy";
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
function handleDragLeave() {
|
|
732
|
-
dragDepth.value = Math.max(0, dragDepth.value - 1);
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
function createQueueRow({
|
|
736
|
-
currentSessionId,
|
|
737
|
-
file = null,
|
|
738
|
-
fileName = "attachment",
|
|
739
|
-
phase = "queued",
|
|
740
|
-
producer = null,
|
|
741
|
-
size = 0
|
|
742
|
-
} = {}) {
|
|
743
|
-
const normalizedSize = Number(file?.size ?? size) || 0;
|
|
744
|
-
const row = reactive({
|
|
745
|
-
activeHandoffToken: null,
|
|
746
|
-
activeToken: null,
|
|
747
|
-
attachmentId: "",
|
|
748
|
-
bytesSent: 0,
|
|
749
|
-
clientId: nextAttachmentClientId(),
|
|
750
|
-
error: "",
|
|
751
|
-
failureStage: "",
|
|
752
|
-
file,
|
|
753
|
-
fileName: file ? attachmentFileName(file) : String(fileName || "attachment"),
|
|
754
|
-
path: "",
|
|
755
|
-
phase,
|
|
756
|
-
producer,
|
|
757
|
-
producerAbortController: null,
|
|
758
|
-
producerToken: null,
|
|
759
|
-
progress: null,
|
|
760
|
-
receipt: null,
|
|
761
|
-
retained: true,
|
|
762
|
-
sessionId: currentSessionId,
|
|
763
|
-
size: normalizedSize,
|
|
764
|
-
totalBytes: normalizedSize,
|
|
765
|
-
waiter: null
|
|
766
|
-
});
|
|
496
|
+
function createQueueRow(options) {
|
|
497
|
+
const row = buildQueueRow(options);
|
|
767
498
|
rowsById.set(row.clientId, row);
|
|
768
499
|
queueItems.value.push(row);
|
|
769
500
|
createWaiter(row);
|
|
@@ -782,11 +513,8 @@ function useAssistantAttachments({
|
|
|
782
513
|
row.size = Number(preparedFile.size) || 0;
|
|
783
514
|
row.totalBytes = row.size;
|
|
784
515
|
if (row.size > maxBytes) {
|
|
785
|
-
row
|
|
786
|
-
row.failureStage = "validation";
|
|
787
|
-
row.phase = "failed";
|
|
516
|
+
failRow(row, "validation", tooLarge(row), t("jskit.assistant.attachments.error.uploadFailed"));
|
|
788
517
|
settleWaiter(row, null, waiter);
|
|
789
|
-
reportAttachmentError(row.error, t("jskit.assistant.attachments.error.uploadFailed"), { notify: false });
|
|
790
518
|
return false;
|
|
791
519
|
}
|
|
792
520
|
row.phase = "queued";
|
|
@@ -798,9 +526,7 @@ function useAssistantAttachments({
|
|
|
798
526
|
function startAttachmentProducer(row) {
|
|
799
527
|
const token = Symbol(`${row.clientId}-producer`);
|
|
800
528
|
const waiter = row.waiter;
|
|
801
|
-
const abortController =
|
|
802
|
-
? new AbortController()
|
|
803
|
-
: null;
|
|
529
|
+
const abortController = new AbortController();
|
|
804
530
|
row.file = null;
|
|
805
531
|
row.producerAbortController = abortController;
|
|
806
532
|
row.producerToken = token;
|
|
@@ -808,7 +534,7 @@ function useAssistantAttachments({
|
|
|
808
534
|
row.error = "";
|
|
809
535
|
row.failureStage = "";
|
|
810
536
|
row.producerSettled = Promise.resolve().then(() => row.producer({
|
|
811
|
-
signal: abortController
|
|
537
|
+
signal: abortController.signal
|
|
812
538
|
})).then((file) => {
|
|
813
539
|
if (row.producerToken !== token || !row.retained || disposed) {
|
|
814
540
|
settleWaiter(row, null, waiter);
|
|
@@ -819,11 +545,8 @@ function useAssistantAttachments({
|
|
|
819
545
|
try {
|
|
820
546
|
queuePreparedFile(row, file, waiter);
|
|
821
547
|
} catch (error) {
|
|
822
|
-
row
|
|
823
|
-
row.failureStage = "preparing";
|
|
824
|
-
row.phase = "failed";
|
|
548
|
+
failRow(row, "preparing", error, t("jskit.assistant.attachments.error.preparationFailed"));
|
|
825
549
|
settleWaiter(row, null, waiter);
|
|
826
|
-
reportAttachmentError(error, t("jskit.assistant.attachments.error.preparationFailed"), { notify: false });
|
|
827
550
|
}
|
|
828
551
|
return file;
|
|
829
552
|
}, (error) => {
|
|
@@ -837,10 +560,7 @@ function useAssistantAttachments({
|
|
|
837
560
|
row.phase = "cancelled";
|
|
838
561
|
row.error = "";
|
|
839
562
|
} else {
|
|
840
|
-
row
|
|
841
|
-
row.failureStage = "preparing";
|
|
842
|
-
row.phase = "failed";
|
|
843
|
-
reportAttachmentError(error, t("jskit.assistant.attachments.error.preparationFailed"), { notify: false });
|
|
563
|
+
failRow(row, "preparing", error, t("jskit.assistant.attachments.error.preparationFailed"));
|
|
844
564
|
}
|
|
845
565
|
settleWaiter(row, null, waiter);
|
|
846
566
|
return null;
|
|
@@ -852,6 +572,7 @@ function useAssistantAttachments({
|
|
|
852
572
|
produce
|
|
853
573
|
} = {}) {
|
|
854
574
|
const currentSessionId = assistantAttachmentSessionId(sessionId);
|
|
575
|
+
// readable-check: allow method-probe - input validation: an application hands each call its file producer
|
|
855
576
|
if (!canAddFiles.value || typeof produce !== "function") {
|
|
856
577
|
if (atCapacity.value) {
|
|
857
578
|
reportAttachmentError(tooMany());
|
|
@@ -877,8 +598,7 @@ function useAssistantAttachments({
|
|
|
877
598
|
uploadableFiles.length < 1 ||
|
|
878
599
|
!currentSessionId ||
|
|
879
600
|
disposed ||
|
|
880
|
-
!assistantAttachmentUploadAllowed(canUpload)
|
|
881
|
-
typeof uploadAttachment !== "function"
|
|
601
|
+
!assistantAttachmentUploadAllowed(canUpload)
|
|
882
602
|
) {
|
|
883
603
|
return [];
|
|
884
604
|
}
|
|
@@ -896,11 +616,8 @@ function useAssistantAttachments({
|
|
|
896
616
|
const waiter = row.waiter;
|
|
897
617
|
waiters.push(waiter.promise);
|
|
898
618
|
if (row.size > maxBytes) {
|
|
899
|
-
row
|
|
900
|
-
row.failureStage = "validation";
|
|
901
|
-
row.phase = "failed";
|
|
619
|
+
failRow(row, "validation", tooLarge(row), t("jskit.assistant.attachments.error.uploadFailed"));
|
|
902
620
|
settleWaiter(row, null);
|
|
903
|
-
reportAttachmentError(row.error, t("jskit.assistant.attachments.error.uploadFailed"), { notify: false });
|
|
904
621
|
} else {
|
|
905
622
|
uploadQueue.push(row);
|
|
906
623
|
}
|
|
@@ -913,26 +630,7 @@ function useAssistantAttachments({
|
|
|
913
630
|
));
|
|
914
631
|
}
|
|
915
632
|
|
|
916
|
-
|
|
917
|
-
resetDragState();
|
|
918
|
-
return uploadFiles(assistantAttachmentFilesFromDropEvent(event));
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
async function handlePaste(event) {
|
|
922
|
-
const files = assistantAttachmentFilesFromPasteEvent(event);
|
|
923
|
-
if (files.length < 1) {
|
|
924
|
-
if (assistantAttachmentClipboardLocalFileReference(event)) {
|
|
925
|
-
reportAttachmentError(t("jskit.assistant.attachments.error.localFilePaste"));
|
|
926
|
-
}
|
|
927
|
-
return [];
|
|
928
|
-
}
|
|
929
|
-
if (!assistantAttachmentClipboardText(event)) {
|
|
930
|
-
event?.preventDefault?.();
|
|
931
|
-
}
|
|
932
|
-
return uploadFiles(files);
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
stopSessionWatch = watch(
|
|
633
|
+
const stopSessionWatch = watch(
|
|
936
634
|
() => assistantAttachmentSessionId(sessionId),
|
|
937
635
|
(nextSessionId, previousSessionId) => {
|
|
938
636
|
if (nextSessionId !== previousSessionId && previousSessionId) {
|