@vertesia/client 0.56.0 → 0.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/store/FilesApi.js +29 -19
- package/lib/cjs/store/FilesApi.js.map +1 -1
- package/lib/cjs/store/ObjectsApi.js +22 -20
- package/lib/cjs/store/ObjectsApi.js.map +1 -1
- package/lib/cjs/store/WorkflowsApi.js +82 -16
- package/lib/cjs/store/WorkflowsApi.js.map +1 -1
- package/lib/esm/store/FilesApi.js +29 -19
- package/lib/esm/store/FilesApi.js.map +1 -1
- package/lib/esm/store/ObjectsApi.js +22 -20
- package/lib/esm/store/ObjectsApi.js.map +1 -1
- package/lib/esm/store/WorkflowsApi.js +82 -16
- package/lib/esm/store/WorkflowsApi.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types/AccountApi.d.ts +1 -0
- package/lib/types/AccountsApi.d.ts +1 -0
- package/lib/types/AnalyticsApi.d.ts +1 -0
- package/lib/types/ApiKeysApi.d.ts +1 -0
- package/lib/types/CommandsApi.d.ts +1 -0
- package/lib/types/EnvironmentsApi.d.ts +1 -0
- package/lib/types/IamApi.d.ts +1 -0
- package/lib/types/InteractionBase.d.ts +1 -0
- package/lib/types/InteractionsApi.d.ts +1 -0
- package/lib/types/PluginsApi.d.ts +1 -0
- package/lib/types/ProjectsApi.d.ts +1 -0
- package/lib/types/PromptsApi.d.ts +1 -0
- package/lib/types/RefsApi.d.ts +1 -0
- package/lib/types/RunsApi.d.ts +1 -0
- package/lib/types/StreamSource.d.ts +1 -0
- package/lib/types/TrainingApi.d.ts +1 -0
- package/lib/types/UsersApi.d.ts +1 -0
- package/lib/types/client.d.ts +1 -0
- package/lib/types/execute.d.ts +1 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/nodejs/NodeStreamSource.d.ts +1 -0
- package/lib/types/nodejs/index.d.ts +1 -0
- package/lib/types/store/AgentsApi.d.ts +1 -0
- package/lib/types/store/AnalyzeDocApi.d.ts +1 -0
- package/lib/types/store/CollectionsApi.d.ts +1 -0
- package/lib/types/store/CommandsApi.d.ts +1 -0
- package/lib/types/store/EmbeddingsApi.d.ts +1 -0
- package/lib/types/store/FilesApi.d.ts +2 -0
- package/lib/types/store/FilesApi.d.ts.map +1 -1
- package/lib/types/store/ObjectsApi.d.ts +2 -7
- package/lib/types/store/ObjectsApi.d.ts.map +1 -1
- package/lib/types/store/TypesApi.d.ts +1 -0
- package/lib/types/store/WorkflowsApi.d.ts +1 -0
- package/lib/types/store/WorkflowsApi.d.ts.map +1 -1
- package/lib/types/store/client.d.ts +1 -0
- package/lib/types/store/errors.d.ts +1 -0
- package/lib/types/store/index.d.ts +1 -0
- package/lib/vertesia-client.js +1 -1
- package/lib/vertesia-client.js.map +1 -1
- package/package.json +4 -4
- package/src/store/FilesApi.ts +83 -55
- package/src/store/ObjectsApi.ts +326 -313
- package/src/store/WorkflowsApi.ts +91 -17
|
@@ -73,14 +73,45 @@ export class WorkflowsApi extends ApiTopic {
|
|
|
73
73
|
|
|
74
74
|
async streamMessages(runId: string, onMessage?: (message: AgentMessage) => void, since?: number): Promise<void> {
|
|
75
75
|
return new Promise((resolve, reject) => {
|
|
76
|
-
|
|
76
|
+
let reconnectAttempts = 0;
|
|
77
|
+
let lastMessageTimestamp = since || 0;
|
|
78
|
+
let isClosed = false;
|
|
79
|
+
let currentSse: EventSource | null = null;
|
|
80
|
+
let interval: NodeJS.Timeout | null = null;
|
|
81
|
+
|
|
82
|
+
const maxReconnectAttempts = 10;
|
|
83
|
+
const baseDelay = 1000; // 1 second base delay
|
|
84
|
+
const maxDelay = 30000; // 30 seconds max delay
|
|
85
|
+
|
|
86
|
+
const calculateBackoffDelay = (attempts: number): number => {
|
|
87
|
+
const exponentialDelay = Math.min(baseDelay * Math.pow(2, attempts), maxDelay);
|
|
88
|
+
// Add jitter to prevent thundering herd
|
|
89
|
+
const jitter = Math.random() * 0.1 * exponentialDelay;
|
|
90
|
+
return exponentialDelay + jitter;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const cleanup = () => {
|
|
94
|
+
if (interval) {
|
|
95
|
+
clearInterval(interval);
|
|
96
|
+
interval = null;
|
|
97
|
+
}
|
|
98
|
+
if (currentSse) {
|
|
99
|
+
currentSse.close();
|
|
100
|
+
currentSse = null;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const setupStream = async (isReconnect: boolean = false) => {
|
|
105
|
+
if (isClosed) return;
|
|
106
|
+
|
|
77
107
|
try {
|
|
78
108
|
const EventSourceImpl = await EventSourceProvider();
|
|
79
109
|
const client = this.client as VertesiaClient;
|
|
80
110
|
const streamUrl = new URL(client.workflows.baseUrl + "/runs/" + runId + "/stream");
|
|
81
111
|
|
|
82
|
-
|
|
83
|
-
|
|
112
|
+
// Use the timestamp of the last received message for reconnection
|
|
113
|
+
if (lastMessageTimestamp > 0) {
|
|
114
|
+
streamUrl.searchParams.set("since", lastMessageTimestamp.toString());
|
|
84
115
|
}
|
|
85
116
|
|
|
86
117
|
const bearerToken = client._auth ? await client._auth() : undefined;
|
|
@@ -91,18 +122,25 @@ export class WorkflowsApi extends ApiTopic {
|
|
|
91
122
|
|
|
92
123
|
const token = bearerToken.split(" ")[1];
|
|
93
124
|
streamUrl.searchParams.set("access_token", token);
|
|
125
|
+
|
|
126
|
+
if (isReconnect) {
|
|
127
|
+
console.log(`Reconnecting to SSE stream for run ${runId} (attempt ${reconnectAttempts + 1}/${maxReconnectAttempts})`);
|
|
128
|
+
}
|
|
94
129
|
|
|
95
130
|
const sse = new EventSourceImpl(streamUrl.href);
|
|
96
|
-
|
|
131
|
+
currentSse = sse;
|
|
97
132
|
|
|
98
133
|
// Prevent Node from exiting prematurely
|
|
99
|
-
|
|
134
|
+
interval = setInterval(() => {}, 1000);
|
|
100
135
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
136
|
+
sse.onopen = () => {
|
|
137
|
+
if (isReconnect) {
|
|
138
|
+
console.log(`Successfully reconnected to SSE stream for run ${runId}`);
|
|
139
|
+
}
|
|
140
|
+
// Reset reconnect attempts on successful connection
|
|
141
|
+
reconnectAttempts = 0;
|
|
104
142
|
};
|
|
105
|
-
|
|
143
|
+
|
|
106
144
|
sse.onmessage = (ev: MessageEvent) => {
|
|
107
145
|
if (!ev.data || ev.data.startsWith(":")) {
|
|
108
146
|
console.log("Received comment or heartbeat; ignoring it.: ", ev.data);
|
|
@@ -111,6 +149,12 @@ export class WorkflowsApi extends ApiTopic {
|
|
|
111
149
|
|
|
112
150
|
try {
|
|
113
151
|
const message = JSON.parse(ev.data) as AgentMessage;
|
|
152
|
+
|
|
153
|
+
// Update last message timestamp for reconnection
|
|
154
|
+
if (message.timestamp) {
|
|
155
|
+
lastMessageTimestamp = Math.max(lastMessageTimestamp, message.timestamp);
|
|
156
|
+
}
|
|
157
|
+
|
|
114
158
|
if (onMessage) onMessage(message);
|
|
115
159
|
|
|
116
160
|
// Only close the stream when the main workstream completes
|
|
@@ -118,7 +162,6 @@ export class WorkflowsApi extends ApiTopic {
|
|
|
118
162
|
console.log("Closing stream due to COMPLETE message from main workstream");
|
|
119
163
|
if (!isClosed) {
|
|
120
164
|
isClosed = true;
|
|
121
|
-
sse.close();
|
|
122
165
|
cleanup();
|
|
123
166
|
resolve();
|
|
124
167
|
}
|
|
@@ -131,21 +174,52 @@ export class WorkflowsApi extends ApiTopic {
|
|
|
131
174
|
};
|
|
132
175
|
|
|
133
176
|
sse.onerror = (err: any) => {
|
|
134
|
-
if (
|
|
135
|
-
|
|
177
|
+
if (isClosed) return;
|
|
178
|
+
|
|
179
|
+
console.warn(`SSE stream error for run ${runId}:`, err);
|
|
180
|
+
cleanup();
|
|
181
|
+
|
|
182
|
+
// Check if we should attempt reconnection
|
|
183
|
+
if (reconnectAttempts < maxReconnectAttempts) {
|
|
184
|
+
const delay = calculateBackoffDelay(reconnectAttempts);
|
|
185
|
+
console.log(`Attempting to reconnect in ${delay}ms (attempt ${reconnectAttempts + 1}/${maxReconnectAttempts})`);
|
|
186
|
+
|
|
187
|
+
reconnectAttempts++;
|
|
188
|
+
setTimeout(() => {
|
|
189
|
+
if (!isClosed) {
|
|
190
|
+
setupStream(true);
|
|
191
|
+
}
|
|
192
|
+
}, delay);
|
|
193
|
+
} else {
|
|
194
|
+
console.error(`Failed to reconnect to SSE stream for run ${runId} after ${maxReconnectAttempts} attempts`);
|
|
136
195
|
isClosed = true;
|
|
137
|
-
|
|
138
|
-
cleanup();
|
|
139
|
-
reject(err);
|
|
196
|
+
reject(new Error(`SSE connection failed after ${maxReconnectAttempts} reconnection attempts`));
|
|
140
197
|
}
|
|
141
198
|
};
|
|
142
199
|
} catch (err) {
|
|
143
|
-
|
|
200
|
+
console.error("Error setting up SSE stream:", err);
|
|
201
|
+
if (reconnectAttempts < maxReconnectAttempts) {
|
|
202
|
+
const delay = calculateBackoffDelay(reconnectAttempts);
|
|
203
|
+
reconnectAttempts++;
|
|
204
|
+
setTimeout(() => {
|
|
205
|
+
if (!isClosed) {
|
|
206
|
+
setupStream(true);
|
|
207
|
+
}
|
|
208
|
+
}, delay);
|
|
209
|
+
} else {
|
|
210
|
+
reject(err);
|
|
211
|
+
}
|
|
144
212
|
}
|
|
145
213
|
};
|
|
146
214
|
|
|
147
215
|
// Start the async setup process
|
|
148
|
-
setupStream();
|
|
216
|
+
setupStream(false);
|
|
217
|
+
|
|
218
|
+
// Return cleanup function for external cancellation
|
|
219
|
+
return () => {
|
|
220
|
+
isClosed = true;
|
|
221
|
+
cleanup();
|
|
222
|
+
};
|
|
149
223
|
});
|
|
150
224
|
}
|
|
151
225
|
|