@standardagents/vue 0.10.1-dev.8f03957 → 0.10.1-dev.d2d335e

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/index.cjs CHANGED
@@ -35,6 +35,18 @@ function useStandardAgents() {
35
35
 
36
36
  // src/composables/useThreadSetup.ts
37
37
  var uploadManager = new client.FileUploadManager();
38
+ function fileToBase64(file) {
39
+ return new Promise((resolve, reject) => {
40
+ const reader = new FileReader();
41
+ reader.onload = () => {
42
+ const result = reader.result;
43
+ const base64 = result.split(",")[1];
44
+ resolve(base64);
45
+ };
46
+ reader.onerror = () => reject(new Error("Failed to read file"));
47
+ reader.readAsDataURL(file);
48
+ });
49
+ }
38
50
  function useThreadSetup(threadId, options = {}) {
39
51
  const {
40
52
  preload = true,
@@ -58,6 +70,7 @@ function useThreadSetup(threadId, options = {}) {
58
70
  const isLoading = vue.ref(preload);
59
71
  const error = vue.ref(null);
60
72
  const pendingFiles = vue.ref([]);
73
+ const attachments = vue.ref([]);
61
74
  const committedFiles = vue.computed(() => {
62
75
  return client.messagesToFiles(messages.value);
63
76
  });
@@ -129,9 +142,53 @@ function useThreadSetup(threadId, options = {}) {
129
142
  connectionManager.connect();
130
143
  }
131
144
  async function sendMessage(payload) {
145
+ const optimisticId = `optimistic-${crypto.randomUUID()}`;
146
+ const optimisticAttachments = attachments.value.map((a) => ({
147
+ id: a.id,
148
+ type: "file",
149
+ path: "",
150
+ // No path yet - will be assigned by server
151
+ name: a.name,
152
+ mimeType: a.mimeType,
153
+ size: a.size,
154
+ width: a.width,
155
+ height: a.height,
156
+ localPreviewUrl: a.previewUrl || void 0
157
+ }));
158
+ const optimisticMessage = {
159
+ id: optimisticId,
160
+ role: payload.role,
161
+ content: payload.content,
162
+ attachments: optimisticAttachments.length > 0 ? JSON.stringify(optimisticAttachments) : null,
163
+ created_at: Date.now() * 1e3,
164
+ // microseconds
165
+ status: "pending"
166
+ };
167
+ messages.value = [...messages.value, optimisticMessage];
168
+ const currentAttachments = [...attachments.value];
169
+ attachments.value = [];
132
170
  try {
133
- return await client$1.sendMessage(threadId, payload);
171
+ const attachmentPayloads = await Promise.all(
172
+ currentAttachments.map(async (a) => ({
173
+ name: a.name,
174
+ mimeType: a.mimeType,
175
+ data: await fileToBase64(a.file),
176
+ width: a.width,
177
+ height: a.height
178
+ }))
179
+ );
180
+ const result = await client$1.sendMessage(threadId, {
181
+ ...payload,
182
+ attachments: attachmentPayloads.length > 0 ? attachmentPayloads : void 0
183
+ });
184
+ messages.value = messages.value.filter((m) => m.id !== optimisticId);
185
+ currentAttachments.forEach((a) => {
186
+ if (a.previewUrl) URL.revokeObjectURL(a.previewUrl);
187
+ });
188
+ return result;
134
189
  } catch (err) {
190
+ attachments.value = currentAttachments;
191
+ messages.value = messages.value.filter((m) => m.id !== optimisticId);
135
192
  error.value = err instanceof Error ? err : new Error(String(err));
136
193
  throw err;
137
194
  }
@@ -183,6 +240,35 @@ function useThreadSetup(threadId, options = {}) {
183
240
  }
184
241
  return null;
185
242
  }
243
+ function addAttachment(input) {
244
+ const filesToAdd = input instanceof FileList ? Array.from(input) : Array.isArray(input) ? input : [input];
245
+ const newAttachments = filesToAdd.map((file) => {
246
+ const isImage = file.type.startsWith("image/");
247
+ return {
248
+ id: crypto.randomUUID(),
249
+ file,
250
+ name: file.name,
251
+ mimeType: file.type,
252
+ size: file.size,
253
+ isImage,
254
+ previewUrl: isImage ? URL.createObjectURL(file) : null
255
+ };
256
+ });
257
+ attachments.value = [...attachments.value, ...newAttachments];
258
+ }
259
+ function removeAttachment(id) {
260
+ const attachment = attachments.value.find((a) => a.id === id);
261
+ if (attachment?.previewUrl) {
262
+ URL.revokeObjectURL(attachment.previewUrl);
263
+ }
264
+ attachments.value = attachments.value.filter((a) => a.id !== id);
265
+ }
266
+ function clearAttachments() {
267
+ attachments.value.forEach((a) => {
268
+ if (a.previewUrl) URL.revokeObjectURL(a.previewUrl);
269
+ });
270
+ attachments.value = [];
271
+ }
186
272
  function onEvent(eventType, callback) {
187
273
  if (!eventHandlers.has(eventType)) {
188
274
  eventHandlers.set(eventType, /* @__PURE__ */ new Set());
@@ -207,6 +293,9 @@ function useThreadSetup(threadId, options = {}) {
207
293
  vue.onUnmounted(() => {
208
294
  connectionManager?.disconnect();
209
295
  eventHandlers.clear();
296
+ attachments.value.forEach((a) => {
297
+ if (a.previewUrl) URL.revokeObjectURL(a.previewUrl);
298
+ });
210
299
  });
211
300
  return {
212
301
  threadId,
@@ -225,13 +314,18 @@ function useThreadSetup(threadId, options = {}) {
225
314
  onEvent,
226
315
  subscribeToEvent: onEvent,
227
316
  // alias
228
- // File management
317
+ // File management (uploads to filesystem)
229
318
  files,
230
319
  addFiles,
231
320
  removeFile,
232
321
  getFileUrl,
233
322
  getThumbnailUrl,
234
- getPreviewUrl
323
+ getPreviewUrl,
324
+ // Attachment management (sent inline with messages)
325
+ attachments,
326
+ addAttachment,
327
+ removeAttachment,
328
+ clearAttachments
235
329
  };
236
330
  }
237
331
 
package/dist/index.d.cts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as vue from 'vue';
2
2
  import { Ref, ComputedRef, InjectionKey, Plugin, PropType } from 'vue';
3
3
  import * as _standardagents_client from '@standardagents/client';
4
- import { AgentBuilderClient, SendMessagePayload, Message, ThreadFile } from '@standardagents/client';
5
- export { AgentBuilderClient, AttachmentRef, ConnectionStatus, FileUploadManager, GetMessagesOptions, Message, SendMessagePayload, Thread, ThreadConnectionCallbacks, ThreadConnectionManager, ThreadConnectionOptions, ThreadFile, ThreadMessage, WorkItem, WorkMessage, generatePendingFileId, isImageMimeType, messagesToFiles, parseAttachments, readFileAsDataUrl, transformToWorkblocks } from '@standardagents/client';
4
+ import { AgentBuilderClient, SendMessagePayload, Message, ThreadFile, PendingAttachment } from '@standardagents/client';
5
+ export { AgentBuilderClient, AttachmentPayload, AttachmentRef, ConnectionStatus, FileUploadManager, GetMessagesOptions, Message, PendingAttachment, SendMessagePayload, Thread, ThreadConnectionCallbacks, ThreadConnectionManager, ThreadConnectionOptions, ThreadFile, ThreadMessage, WorkItem, WorkMessage, generatePendingFileId, isImageMimeType, messagesToFiles, parseAttachments, readFileAsDataUrl, transformToWorkblocks } from '@standardagents/client';
6
6
 
7
7
  /**
8
8
  * Configuration for the StandardAgents plugin
@@ -57,8 +57,8 @@ interface ThreadContext {
57
57
  loading: Ref<boolean>;
58
58
  /** Any error that occurred */
59
59
  error: Ref<Error | null>;
60
- /** Send a message to the thread */
61
- sendMessage: (payload: SendMessagePayload) => Promise<Message>;
60
+ /** Send a message to the thread (auto-includes pending attachments) */
61
+ sendMessage: (payload: Omit<SendMessagePayload, 'attachments'>) => Promise<Message>;
62
62
  /** Stop the current execution */
63
63
  stopExecution: () => Promise<void>;
64
64
  /** Subscribe to custom events */
@@ -67,7 +67,7 @@ interface ThreadContext {
67
67
  subscribeToEvent: <T = unknown>(eventType: string, callback: (data: T) => void) => () => void;
68
68
  /** All files in the thread (pending uploads + committed from messages) */
69
69
  files: ComputedRef<ThreadFile[]>;
70
- /** Add files and start uploading immediately */
70
+ /** Add files and start uploading immediately to filesystem */
71
71
  addFiles: (files: File[] | FileList) => void;
72
72
  /** Remove a pending file (cannot remove committed files) */
73
73
  removeFile: (id: string) => void;
@@ -77,6 +77,14 @@ interface ThreadContext {
77
77
  getThumbnailUrl: (file: ThreadFile) => string;
78
78
  /** Get preview URL - localPreviewUrl for pending images, thumbnail for committed */
79
79
  getPreviewUrl: (file: ThreadFile) => string | null;
80
+ /** Pending attachments to be sent with next message */
81
+ attachments: Ref<PendingAttachment[]>;
82
+ /** Add attachment(s) to be sent with next message (no upload, stored locally) */
83
+ addAttachment: (files: File | File[] | FileList) => void;
84
+ /** Remove a pending attachment */
85
+ removeAttachment: (id: string) => void;
86
+ /** Clear all pending attachments */
87
+ clearAttachments: () => void;
80
88
  }
81
89
  /**
82
90
  * Options for useThread composable
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as vue from 'vue';
2
2
  import { Ref, ComputedRef, InjectionKey, Plugin, PropType } from 'vue';
3
3
  import * as _standardagents_client from '@standardagents/client';
4
- import { AgentBuilderClient, SendMessagePayload, Message, ThreadFile } from '@standardagents/client';
5
- export { AgentBuilderClient, AttachmentRef, ConnectionStatus, FileUploadManager, GetMessagesOptions, Message, SendMessagePayload, Thread, ThreadConnectionCallbacks, ThreadConnectionManager, ThreadConnectionOptions, ThreadFile, ThreadMessage, WorkItem, WorkMessage, generatePendingFileId, isImageMimeType, messagesToFiles, parseAttachments, readFileAsDataUrl, transformToWorkblocks } from '@standardagents/client';
4
+ import { AgentBuilderClient, SendMessagePayload, Message, ThreadFile, PendingAttachment } from '@standardagents/client';
5
+ export { AgentBuilderClient, AttachmentPayload, AttachmentRef, ConnectionStatus, FileUploadManager, GetMessagesOptions, Message, PendingAttachment, SendMessagePayload, Thread, ThreadConnectionCallbacks, ThreadConnectionManager, ThreadConnectionOptions, ThreadFile, ThreadMessage, WorkItem, WorkMessage, generatePendingFileId, isImageMimeType, messagesToFiles, parseAttachments, readFileAsDataUrl, transformToWorkblocks } from '@standardagents/client';
6
6
 
7
7
  /**
8
8
  * Configuration for the StandardAgents plugin
@@ -57,8 +57,8 @@ interface ThreadContext {
57
57
  loading: Ref<boolean>;
58
58
  /** Any error that occurred */
59
59
  error: Ref<Error | null>;
60
- /** Send a message to the thread */
61
- sendMessage: (payload: SendMessagePayload) => Promise<Message>;
60
+ /** Send a message to the thread (auto-includes pending attachments) */
61
+ sendMessage: (payload: Omit<SendMessagePayload, 'attachments'>) => Promise<Message>;
62
62
  /** Stop the current execution */
63
63
  stopExecution: () => Promise<void>;
64
64
  /** Subscribe to custom events */
@@ -67,7 +67,7 @@ interface ThreadContext {
67
67
  subscribeToEvent: <T = unknown>(eventType: string, callback: (data: T) => void) => () => void;
68
68
  /** All files in the thread (pending uploads + committed from messages) */
69
69
  files: ComputedRef<ThreadFile[]>;
70
- /** Add files and start uploading immediately */
70
+ /** Add files and start uploading immediately to filesystem */
71
71
  addFiles: (files: File[] | FileList) => void;
72
72
  /** Remove a pending file (cannot remove committed files) */
73
73
  removeFile: (id: string) => void;
@@ -77,6 +77,14 @@ interface ThreadContext {
77
77
  getThumbnailUrl: (file: ThreadFile) => string;
78
78
  /** Get preview URL - localPreviewUrl for pending images, thumbnail for committed */
79
79
  getPreviewUrl: (file: ThreadFile) => string | null;
80
+ /** Pending attachments to be sent with next message */
81
+ attachments: Ref<PendingAttachment[]>;
82
+ /** Add attachment(s) to be sent with next message (no upload, stored locally) */
83
+ addAttachment: (files: File | File[] | FileList) => void;
84
+ /** Remove a pending attachment */
85
+ removeAttachment: (id: string) => void;
86
+ /** Clear all pending attachments */
87
+ clearAttachments: () => void;
80
88
  }
81
89
  /**
82
90
  * Options for useThread composable
package/dist/index.js CHANGED
@@ -34,6 +34,18 @@ function useStandardAgents() {
34
34
 
35
35
  // src/composables/useThreadSetup.ts
36
36
  var uploadManager = new FileUploadManager();
37
+ function fileToBase64(file) {
38
+ return new Promise((resolve, reject) => {
39
+ const reader = new FileReader();
40
+ reader.onload = () => {
41
+ const result = reader.result;
42
+ const base64 = result.split(",")[1];
43
+ resolve(base64);
44
+ };
45
+ reader.onerror = () => reject(new Error("Failed to read file"));
46
+ reader.readAsDataURL(file);
47
+ });
48
+ }
37
49
  function useThreadSetup(threadId, options = {}) {
38
50
  const {
39
51
  preload = true,
@@ -57,6 +69,7 @@ function useThreadSetup(threadId, options = {}) {
57
69
  const isLoading = ref(preload);
58
70
  const error = ref(null);
59
71
  const pendingFiles = ref([]);
72
+ const attachments = ref([]);
60
73
  const committedFiles = computed(() => {
61
74
  return messagesToFiles(messages.value);
62
75
  });
@@ -128,9 +141,53 @@ function useThreadSetup(threadId, options = {}) {
128
141
  connectionManager.connect();
129
142
  }
130
143
  async function sendMessage(payload) {
144
+ const optimisticId = `optimistic-${crypto.randomUUID()}`;
145
+ const optimisticAttachments = attachments.value.map((a) => ({
146
+ id: a.id,
147
+ type: "file",
148
+ path: "",
149
+ // No path yet - will be assigned by server
150
+ name: a.name,
151
+ mimeType: a.mimeType,
152
+ size: a.size,
153
+ width: a.width,
154
+ height: a.height,
155
+ localPreviewUrl: a.previewUrl || void 0
156
+ }));
157
+ const optimisticMessage = {
158
+ id: optimisticId,
159
+ role: payload.role,
160
+ content: payload.content,
161
+ attachments: optimisticAttachments.length > 0 ? JSON.stringify(optimisticAttachments) : null,
162
+ created_at: Date.now() * 1e3,
163
+ // microseconds
164
+ status: "pending"
165
+ };
166
+ messages.value = [...messages.value, optimisticMessage];
167
+ const currentAttachments = [...attachments.value];
168
+ attachments.value = [];
131
169
  try {
132
- return await client.sendMessage(threadId, payload);
170
+ const attachmentPayloads = await Promise.all(
171
+ currentAttachments.map(async (a) => ({
172
+ name: a.name,
173
+ mimeType: a.mimeType,
174
+ data: await fileToBase64(a.file),
175
+ width: a.width,
176
+ height: a.height
177
+ }))
178
+ );
179
+ const result = await client.sendMessage(threadId, {
180
+ ...payload,
181
+ attachments: attachmentPayloads.length > 0 ? attachmentPayloads : void 0
182
+ });
183
+ messages.value = messages.value.filter((m) => m.id !== optimisticId);
184
+ currentAttachments.forEach((a) => {
185
+ if (a.previewUrl) URL.revokeObjectURL(a.previewUrl);
186
+ });
187
+ return result;
133
188
  } catch (err) {
189
+ attachments.value = currentAttachments;
190
+ messages.value = messages.value.filter((m) => m.id !== optimisticId);
134
191
  error.value = err instanceof Error ? err : new Error(String(err));
135
192
  throw err;
136
193
  }
@@ -182,6 +239,35 @@ function useThreadSetup(threadId, options = {}) {
182
239
  }
183
240
  return null;
184
241
  }
242
+ function addAttachment(input) {
243
+ const filesToAdd = input instanceof FileList ? Array.from(input) : Array.isArray(input) ? input : [input];
244
+ const newAttachments = filesToAdd.map((file) => {
245
+ const isImage = file.type.startsWith("image/");
246
+ return {
247
+ id: crypto.randomUUID(),
248
+ file,
249
+ name: file.name,
250
+ mimeType: file.type,
251
+ size: file.size,
252
+ isImage,
253
+ previewUrl: isImage ? URL.createObjectURL(file) : null
254
+ };
255
+ });
256
+ attachments.value = [...attachments.value, ...newAttachments];
257
+ }
258
+ function removeAttachment(id) {
259
+ const attachment = attachments.value.find((a) => a.id === id);
260
+ if (attachment?.previewUrl) {
261
+ URL.revokeObjectURL(attachment.previewUrl);
262
+ }
263
+ attachments.value = attachments.value.filter((a) => a.id !== id);
264
+ }
265
+ function clearAttachments() {
266
+ attachments.value.forEach((a) => {
267
+ if (a.previewUrl) URL.revokeObjectURL(a.previewUrl);
268
+ });
269
+ attachments.value = [];
270
+ }
185
271
  function onEvent(eventType, callback) {
186
272
  if (!eventHandlers.has(eventType)) {
187
273
  eventHandlers.set(eventType, /* @__PURE__ */ new Set());
@@ -206,6 +292,9 @@ function useThreadSetup(threadId, options = {}) {
206
292
  onUnmounted(() => {
207
293
  connectionManager?.disconnect();
208
294
  eventHandlers.clear();
295
+ attachments.value.forEach((a) => {
296
+ if (a.previewUrl) URL.revokeObjectURL(a.previewUrl);
297
+ });
209
298
  });
210
299
  return {
211
300
  threadId,
@@ -224,13 +313,18 @@ function useThreadSetup(threadId, options = {}) {
224
313
  onEvent,
225
314
  subscribeToEvent: onEvent,
226
315
  // alias
227
- // File management
316
+ // File management (uploads to filesystem)
228
317
  files,
229
318
  addFiles,
230
319
  removeFile,
231
320
  getFileUrl,
232
321
  getThumbnailUrl,
233
- getPreviewUrl
322
+ getPreviewUrl,
323
+ // Attachment management (sent inline with messages)
324
+ attachments,
325
+ addAttachment,
326
+ removeAttachment,
327
+ clearAttachments
234
328
  };
235
329
  }
236
330
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@standardagents/vue",
3
- "version": "0.10.1-dev.8f03957",
3
+ "version": "0.10.1-dev.d2d335e",
4
4
  "description": "Vue SDK for Standard Agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -22,7 +22,7 @@
22
22
  "dist"
23
23
  ],
24
24
  "dependencies": {
25
- "@standardagents/client": "0.10.1-dev.8f03957"
25
+ "@standardagents/client": "0.10.1-dev.d2d335e"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "vue": "^3.3.0"