@standardagents/vue 0.14.1 → 0.15.1

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
@@ -33,6 +33,29 @@ function useStandardAgents() {
33
33
  return context;
34
34
  }
35
35
 
36
+ // src/utils/id.ts
37
+ function createClientId() {
38
+ const cryptoRef = globalThis.crypto;
39
+ if (typeof cryptoRef?.randomUUID === "function") {
40
+ return cryptoRef.randomUUID();
41
+ }
42
+ if (typeof cryptoRef?.getRandomValues === "function") {
43
+ const bytes = new Uint8Array(16);
44
+ cryptoRef.getRandomValues(bytes);
45
+ bytes[6] = bytes[6] & 15 | 64;
46
+ bytes[8] = bytes[8] & 63 | 128;
47
+ const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
48
+ return [
49
+ hex.slice(0, 4).join(""),
50
+ hex.slice(4, 6).join(""),
51
+ hex.slice(6, 8).join(""),
52
+ hex.slice(8, 10).join(""),
53
+ hex.slice(10, 16).join("")
54
+ ].join("-");
55
+ }
56
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
57
+ }
58
+
36
59
  // src/composables/useThreadSetup.ts
37
60
  var uploadManager = new client.FileUploadManager();
38
61
  function fileToBase64(file) {
@@ -69,6 +92,9 @@ function useThreadSetup(threadIdInput, options = {}) {
69
92
  includeSilent
70
93
  };
71
94
  const messages = vue.ref([]);
95
+ const paginatedMessagesLoaded = vue.ref(0);
96
+ const hasMoreMessages = vue.ref(false);
97
+ const isLoadingOlderMessages = vue.ref(false);
72
98
  const status = vue.ref("disconnected");
73
99
  const isLoading = vue.ref(preload);
74
100
  const error = vue.ref(null);
@@ -105,18 +131,104 @@ function useThreadSetup(threadIdInput, options = {}) {
105
131
  }
106
132
  return messages.value;
107
133
  });
134
+ const MESSAGE_PAGE_SIZE = 100;
135
+ const mergeMessages = (olderMessages, newerMessages) => {
136
+ const messageMap = /* @__PURE__ */ new Map();
137
+ for (const message of olderMessages) {
138
+ messageMap.set(message.id, message);
139
+ }
140
+ for (const message of newerMessages) {
141
+ messageMap.set(message.id, message);
142
+ }
143
+ return Array.from(messageMap.values()).sort((a, b) => {
144
+ if (a.created_at !== b.created_at) return a.created_at - b.created_at;
145
+ return a.id.localeCompare(b.id);
146
+ });
147
+ };
148
+ const hasCompleteOldestWorkblockBoundary = () => {
149
+ const firstMessage = messages.value[0];
150
+ if (!firstMessage) return true;
151
+ if (firstMessage.role === "tool") return false;
152
+ if (firstMessage.role === "assistant" && firstMessage.tool_calls) return false;
153
+ return true;
154
+ };
108
155
  async function loadMessages() {
109
156
  isLoading.value = true;
110
157
  error.value = null;
111
158
  try {
112
- const loadedMessages = await client$1.getMessages(threadId.value, { depth, includeSilent });
113
- messages.value = loadedMessages;
159
+ const page = await client$1.getMessagesPage(threadId.value, {
160
+ limit: MESSAGE_PAGE_SIZE,
161
+ offset: 0,
162
+ depth,
163
+ includeSilent
164
+ });
165
+ messages.value = page.messages;
166
+ paginatedMessagesLoaded.value = page.messages.length;
167
+ hasMoreMessages.value = page.hasMore;
114
168
  } catch (err) {
115
169
  error.value = err instanceof Error ? err : new Error(String(err));
116
170
  } finally {
117
171
  isLoading.value = false;
118
172
  }
119
173
  }
174
+ async function loadOlderMessages() {
175
+ if (isLoadingOlderMessages.value || isLoading.value || !hasMoreMessages.value) {
176
+ return false;
177
+ }
178
+ isLoadingOlderMessages.value = true;
179
+ error.value = null;
180
+ try {
181
+ let loadedAny = false;
182
+ let keepLoading = true;
183
+ while (keepLoading && hasMoreMessages.value) {
184
+ const page = await client$1.getMessagesPage(threadId.value, {
185
+ limit: MESSAGE_PAGE_SIZE,
186
+ offset: paginatedMessagesLoaded.value,
187
+ depth,
188
+ includeSilent
189
+ });
190
+ if (page.messages.length === 0) {
191
+ hasMoreMessages.value = false;
192
+ break;
193
+ }
194
+ messages.value = mergeMessages(page.messages, messages.value);
195
+ paginatedMessagesLoaded.value += page.messages.length;
196
+ hasMoreMessages.value = page.hasMore;
197
+ loadedAny = true;
198
+ keepLoading = !hasCompleteOldestWorkblockBoundary();
199
+ }
200
+ return loadedAny;
201
+ } catch (err) {
202
+ error.value = err instanceof Error ? err : new Error(String(err));
203
+ return false;
204
+ } finally {
205
+ isLoadingOlderMessages.value = false;
206
+ }
207
+ }
208
+ async function loadMessagesByIds(ids, options2 = {}) {
209
+ const uniqueIds = Array.from(new Set(ids.map((id) => id.trim()).filter(Boolean)));
210
+ if (uniqueIds.length === 0) return true;
211
+ try {
212
+ let loadedAny = false;
213
+ for (let i = 0; i < uniqueIds.length; i += 200) {
214
+ const chunk = uniqueIds.slice(i, i + 200);
215
+ const page = await client$1.getMessagesPage(threadId.value, {
216
+ ids: chunk,
217
+ depth,
218
+ includeSilent,
219
+ includeWorkblocks: options2.includeWorkblocks
220
+ });
221
+ if (page.messages.length > 0) {
222
+ messages.value = mergeMessages(page.messages, messages.value);
223
+ loadedAny = true;
224
+ }
225
+ }
226
+ return loadedAny;
227
+ } catch (err) {
228
+ error.value = err instanceof Error ? err : new Error(String(err));
229
+ return false;
230
+ }
231
+ }
120
232
  async function loadFiles() {
121
233
  try {
122
234
  const fileList = await client$1.listFiles(threadId.value);
@@ -228,7 +340,7 @@ function useThreadSetup(threadIdInput, options = {}) {
228
340
  connectionManager.connect();
229
341
  }
230
342
  async function sendMessage(payload) {
231
- const optimisticId = `optimistic-${crypto.randomUUID()}`;
343
+ const optimisticId = `optimistic-${createClientId()}`;
232
344
  const optimisticAttachments = attachments.value.map((a) => ({
233
345
  id: a.id,
234
346
  type: "file",
@@ -342,7 +454,7 @@ function useThreadSetup(threadIdInput, options = {}) {
342
454
  const newAttachments = filesToAdd.map((file) => {
343
455
  const isImage = file.type.startsWith("image/");
344
456
  return {
345
- id: crypto.randomUUID(),
457
+ id: createClientId(),
346
458
  file,
347
459
  name: file.name,
348
460
  mimeType: file.type,
@@ -390,6 +502,9 @@ function useThreadSetup(threadIdInput, options = {}) {
390
502
  if (newThreadId !== oldThreadId) {
391
503
  disconnect();
392
504
  messages.value = [];
505
+ paginatedMessagesLoaded.value = 0;
506
+ hasMoreMessages.value = false;
507
+ isLoadingOlderMessages.value = false;
393
508
  error.value = null;
394
509
  pendingFiles.value = [];
395
510
  serverFiles.value = [];
@@ -422,6 +537,10 @@ function useThreadSetup(threadIdInput, options = {}) {
422
537
  threadId,
423
538
  options: resolvedOptions,
424
539
  messages,
540
+ hasMoreMessages,
541
+ isLoadingOlderMessages,
542
+ loadOlderMessages,
543
+ loadMessagesByIds,
425
544
  workblocks,
426
545
  subagentBlocks,
427
546
  groupedMessages,
package/dist/index.d.cts CHANGED
@@ -47,6 +47,16 @@ interface ThreadContext {
47
47
  options: ThreadProviderOptions;
48
48
  /** Current messages in the thread */
49
49
  messages: Ref<_standardagents_client.Message[]>;
50
+ /** Whether older messages are available */
51
+ hasMoreMessages: Ref<boolean>;
52
+ /** Whether older messages are currently loading */
53
+ isLoadingOlderMessages: Ref<boolean>;
54
+ /** Load the next older message page */
55
+ loadOlderMessages: () => Promise<boolean>;
56
+ /** Load specific messages, optionally expanded to complete workblocks */
57
+ loadMessagesByIds: (ids: string[], options?: {
58
+ includeWorkblocks?: boolean;
59
+ }) => Promise<boolean>;
50
60
  /** Messages transformed to workblocks (if useWorkblocks is true) */
51
61
  workblocks: ComputedRef<_standardagents_client.ThreadMessage[]>;
52
62
  /** Messages transformed to subagent blocks (if useSubagentBlocks is true) */
package/dist/index.d.ts CHANGED
@@ -47,6 +47,16 @@ interface ThreadContext {
47
47
  options: ThreadProviderOptions;
48
48
  /** Current messages in the thread */
49
49
  messages: Ref<_standardagents_client.Message[]>;
50
+ /** Whether older messages are available */
51
+ hasMoreMessages: Ref<boolean>;
52
+ /** Whether older messages are currently loading */
53
+ isLoadingOlderMessages: Ref<boolean>;
54
+ /** Load the next older message page */
55
+ loadOlderMessages: () => Promise<boolean>;
56
+ /** Load specific messages, optionally expanded to complete workblocks */
57
+ loadMessagesByIds: (ids: string[], options?: {
58
+ includeWorkblocks?: boolean;
59
+ }) => Promise<boolean>;
50
60
  /** Messages transformed to workblocks (if useWorkblocks is true) */
51
61
  workblocks: ComputedRef<_standardagents_client.ThreadMessage[]>;
52
62
  /** Messages transformed to subagent blocks (if useSubagentBlocks is true) */
package/dist/index.js CHANGED
@@ -32,6 +32,29 @@ function useStandardAgents() {
32
32
  return context;
33
33
  }
34
34
 
35
+ // src/utils/id.ts
36
+ function createClientId() {
37
+ const cryptoRef = globalThis.crypto;
38
+ if (typeof cryptoRef?.randomUUID === "function") {
39
+ return cryptoRef.randomUUID();
40
+ }
41
+ if (typeof cryptoRef?.getRandomValues === "function") {
42
+ const bytes = new Uint8Array(16);
43
+ cryptoRef.getRandomValues(bytes);
44
+ bytes[6] = bytes[6] & 15 | 64;
45
+ bytes[8] = bytes[8] & 63 | 128;
46
+ const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
47
+ return [
48
+ hex.slice(0, 4).join(""),
49
+ hex.slice(4, 6).join(""),
50
+ hex.slice(6, 8).join(""),
51
+ hex.slice(8, 10).join(""),
52
+ hex.slice(10, 16).join("")
53
+ ].join("-");
54
+ }
55
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
56
+ }
57
+
35
58
  // src/composables/useThreadSetup.ts
36
59
  var uploadManager = new FileUploadManager();
37
60
  function fileToBase64(file) {
@@ -68,6 +91,9 @@ function useThreadSetup(threadIdInput, options = {}) {
68
91
  includeSilent
69
92
  };
70
93
  const messages = ref([]);
94
+ const paginatedMessagesLoaded = ref(0);
95
+ const hasMoreMessages = ref(false);
96
+ const isLoadingOlderMessages = ref(false);
71
97
  const status = ref("disconnected");
72
98
  const isLoading = ref(preload);
73
99
  const error = ref(null);
@@ -104,18 +130,104 @@ function useThreadSetup(threadIdInput, options = {}) {
104
130
  }
105
131
  return messages.value;
106
132
  });
133
+ const MESSAGE_PAGE_SIZE = 100;
134
+ const mergeMessages = (olderMessages, newerMessages) => {
135
+ const messageMap = /* @__PURE__ */ new Map();
136
+ for (const message of olderMessages) {
137
+ messageMap.set(message.id, message);
138
+ }
139
+ for (const message of newerMessages) {
140
+ messageMap.set(message.id, message);
141
+ }
142
+ return Array.from(messageMap.values()).sort((a, b) => {
143
+ if (a.created_at !== b.created_at) return a.created_at - b.created_at;
144
+ return a.id.localeCompare(b.id);
145
+ });
146
+ };
147
+ const hasCompleteOldestWorkblockBoundary = () => {
148
+ const firstMessage = messages.value[0];
149
+ if (!firstMessage) return true;
150
+ if (firstMessage.role === "tool") return false;
151
+ if (firstMessage.role === "assistant" && firstMessage.tool_calls) return false;
152
+ return true;
153
+ };
107
154
  async function loadMessages() {
108
155
  isLoading.value = true;
109
156
  error.value = null;
110
157
  try {
111
- const loadedMessages = await client.getMessages(threadId.value, { depth, includeSilent });
112
- messages.value = loadedMessages;
158
+ const page = await client.getMessagesPage(threadId.value, {
159
+ limit: MESSAGE_PAGE_SIZE,
160
+ offset: 0,
161
+ depth,
162
+ includeSilent
163
+ });
164
+ messages.value = page.messages;
165
+ paginatedMessagesLoaded.value = page.messages.length;
166
+ hasMoreMessages.value = page.hasMore;
113
167
  } catch (err) {
114
168
  error.value = err instanceof Error ? err : new Error(String(err));
115
169
  } finally {
116
170
  isLoading.value = false;
117
171
  }
118
172
  }
173
+ async function loadOlderMessages() {
174
+ if (isLoadingOlderMessages.value || isLoading.value || !hasMoreMessages.value) {
175
+ return false;
176
+ }
177
+ isLoadingOlderMessages.value = true;
178
+ error.value = null;
179
+ try {
180
+ let loadedAny = false;
181
+ let keepLoading = true;
182
+ while (keepLoading && hasMoreMessages.value) {
183
+ const page = await client.getMessagesPage(threadId.value, {
184
+ limit: MESSAGE_PAGE_SIZE,
185
+ offset: paginatedMessagesLoaded.value,
186
+ depth,
187
+ includeSilent
188
+ });
189
+ if (page.messages.length === 0) {
190
+ hasMoreMessages.value = false;
191
+ break;
192
+ }
193
+ messages.value = mergeMessages(page.messages, messages.value);
194
+ paginatedMessagesLoaded.value += page.messages.length;
195
+ hasMoreMessages.value = page.hasMore;
196
+ loadedAny = true;
197
+ keepLoading = !hasCompleteOldestWorkblockBoundary();
198
+ }
199
+ return loadedAny;
200
+ } catch (err) {
201
+ error.value = err instanceof Error ? err : new Error(String(err));
202
+ return false;
203
+ } finally {
204
+ isLoadingOlderMessages.value = false;
205
+ }
206
+ }
207
+ async function loadMessagesByIds(ids, options2 = {}) {
208
+ const uniqueIds = Array.from(new Set(ids.map((id) => id.trim()).filter(Boolean)));
209
+ if (uniqueIds.length === 0) return true;
210
+ try {
211
+ let loadedAny = false;
212
+ for (let i = 0; i < uniqueIds.length; i += 200) {
213
+ const chunk = uniqueIds.slice(i, i + 200);
214
+ const page = await client.getMessagesPage(threadId.value, {
215
+ ids: chunk,
216
+ depth,
217
+ includeSilent,
218
+ includeWorkblocks: options2.includeWorkblocks
219
+ });
220
+ if (page.messages.length > 0) {
221
+ messages.value = mergeMessages(page.messages, messages.value);
222
+ loadedAny = true;
223
+ }
224
+ }
225
+ return loadedAny;
226
+ } catch (err) {
227
+ error.value = err instanceof Error ? err : new Error(String(err));
228
+ return false;
229
+ }
230
+ }
119
231
  async function loadFiles() {
120
232
  try {
121
233
  const fileList = await client.listFiles(threadId.value);
@@ -227,7 +339,7 @@ function useThreadSetup(threadIdInput, options = {}) {
227
339
  connectionManager.connect();
228
340
  }
229
341
  async function sendMessage(payload) {
230
- const optimisticId = `optimistic-${crypto.randomUUID()}`;
342
+ const optimisticId = `optimistic-${createClientId()}`;
231
343
  const optimisticAttachments = attachments.value.map((a) => ({
232
344
  id: a.id,
233
345
  type: "file",
@@ -341,7 +453,7 @@ function useThreadSetup(threadIdInput, options = {}) {
341
453
  const newAttachments = filesToAdd.map((file) => {
342
454
  const isImage = file.type.startsWith("image/");
343
455
  return {
344
- id: crypto.randomUUID(),
456
+ id: createClientId(),
345
457
  file,
346
458
  name: file.name,
347
459
  mimeType: file.type,
@@ -389,6 +501,9 @@ function useThreadSetup(threadIdInput, options = {}) {
389
501
  if (newThreadId !== oldThreadId) {
390
502
  disconnect();
391
503
  messages.value = [];
504
+ paginatedMessagesLoaded.value = 0;
505
+ hasMoreMessages.value = false;
506
+ isLoadingOlderMessages.value = false;
392
507
  error.value = null;
393
508
  pendingFiles.value = [];
394
509
  serverFiles.value = [];
@@ -421,6 +536,10 @@ function useThreadSetup(threadIdInput, options = {}) {
421
536
  threadId,
422
537
  options: resolvedOptions,
423
538
  messages,
539
+ hasMoreMessages,
540
+ isLoadingOlderMessages,
541
+ loadOlderMessages,
542
+ loadMessagesByIds,
424
543
  workblocks,
425
544
  subagentBlocks,
426
545
  groupedMessages,
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@standardagents/vue",
3
- "version": "0.14.1",
3
+ "version": "0.15.1",
4
+ "private": false,
4
5
  "description": "Vue SDK for Standard Agents",
5
6
  "type": "module",
6
7
  "main": "./dist/index.cjs",
@@ -22,7 +23,7 @@
22
23
  "dist"
23
24
  ],
24
25
  "dependencies": {
25
- "@standardagents/client": "0.14.1"
26
+ "@standardagents/client": "0.15.1"
26
27
  },
27
28
  "peerDependencies": {
28
29
  "vue": "^3.3.0"
@@ -39,7 +40,7 @@
39
40
  "vue": "^3.5.13"
40
41
  },
41
42
  "publishConfig": {
42
- "access": "restricted",
43
+ "access": "public",
43
44
  "registry": "https://registry.npmjs.org/"
44
45
  },
45
46
  "keywords": [