@fencyai/js 0.1.191 → 0.1.193
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/AgentTaskEventData.d.ts +24 -0
- package/lib/AgentTaskEventData.d.ts.map +1 -1
- package/lib/api/createAgentTask.d.ts +2 -2
- package/lib/api/createAgentTask.d.ts.map +1 -1
- package/lib/api/createAgentTask.js +2 -1
- package/lib/api/createAgentTaskFileDownloadLink.d.ts +14 -0
- package/lib/api/createAgentTaskFileDownloadLink.d.ts.map +1 -0
- package/lib/api/createAgentTaskFileDownloadLink.js +36 -0
- package/lib/api/createStream.d.ts.map +1 -1
- package/lib/api/createStream.js +2 -1
- package/lib/api/extractApiErrorMessage.d.ts +2 -0
- package/lib/api/extractApiErrorMessage.d.ts.map +1 -0
- package/lib/api/extractApiErrorMessage.js +32 -0
- package/lib/constants/fencyFileLinkPrefix.d.ts +13 -0
- package/lib/constants/fencyFileLinkPrefix.d.ts.map +1 -0
- package/lib/constants/fencyFileLinkPrefix.js +12 -0
- package/lib/index.d.ts +17 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +15 -1
- package/lib/openapi/ct/index.d.ts +2 -0
- package/lib/openapi/ct/index.d.ts.map +1 -1
- package/lib/openapi/ct/models/PubCreateAgentTaskFileDownloadLinkRequest.d.ts +4 -0
- package/lib/openapi/ct/models/PubCreateAgentTaskFileDownloadLinkRequest.d.ts.map +1 -0
- package/lib/openapi/ct/models/PubCreateAgentTaskFileDownloadLinkRequest.js +1 -0
- package/lib/openapi/ct/models/PubCreateAgentTaskFileDownloadLinkResponse.d.ts +4 -0
- package/lib/openapi/ct/models/PubCreateAgentTaskFileDownloadLinkResponse.d.ts.map +1 -0
- package/lib/openapi/ct/models/PubCreateAgentTaskFileDownloadLinkResponse.js +1 -0
- package/lib/openapi/ct/services/PubService.d.ts +9 -0
- package/lib/openapi/ct/services/PubService.d.ts.map +1 -1
- package/lib/openapi/ct/services/PubService.js +14 -0
- package/lib/parsing/AgentTaskEventDataSchemas.d.ts +315 -0
- package/lib/parsing/AgentTaskEventDataSchemas.d.ts.map +1 -0
- package/lib/parsing/AgentTaskEventDataSchemas.js +415 -0
- package/lib/stream/StreamCacheManager.d.ts +41 -0
- package/lib/stream/StreamCacheManager.d.ts.map +1 -0
- package/lib/stream/StreamCacheManager.js +101 -0
- package/lib/stream/StreamEventManager.d.ts +52 -0
- package/lib/stream/StreamEventManager.d.ts.map +1 -0
- package/lib/stream/StreamEventManager.js +271 -0
- package/lib/stream/createStreamWorkerCode.d.ts +8 -0
- package/lib/stream/createStreamWorkerCode.d.ts.map +1 -0
- package/lib/stream/createStreamWorkerCode.js +152 -0
- package/lib/stream/toStreamData.d.ts +4 -0
- package/lib/stream/toStreamData.d.ts.map +1 -0
- package/lib/stream/toStreamData.js +61 -0
- package/lib/task/mapCreateAgentTaskParams.d.ts +18 -0
- package/lib/task/mapCreateAgentTaskParams.d.ts.map +1 -0
- package/lib/task/mapCreateAgentTaskParams.js +84 -0
- package/lib/task/progressItems.d.ts +5 -0
- package/lib/task/progressItems.d.ts.map +1 -0
- package/lib/task/progressItems.js +19 -0
- package/lib/task/taskReducer.d.ts +7 -0
- package/lib/task/taskReducer.d.ts.map +1 -0
- package/lib/task/taskReducer.js +89 -0
- package/lib/task/types.d.ts +40 -0
- package/lib/task/types.d.ts.map +1 -0
- package/lib/task/types.js +1 -0
- package/lib/types/AgentTask.d.ts +17 -7
- package/lib/types/AgentTask.d.ts.map +1 -1
- package/lib/types/AgentTask.js +1 -9
- package/lib/types/AgentTaskDto.d.ts +11 -0
- package/lib/types/AgentTaskDto.d.ts.map +1 -0
- package/lib/types/AgentTaskDto.js +11 -0
- package/lib/types/CreateAgentTaskApiResponse.d.ts +11 -0
- package/lib/types/CreateAgentTaskApiResponse.d.ts.map +1 -0
- package/lib/types/CreateAgentTaskApiResponse.js +1 -0
- package/lib/types/CreateAgentTaskFileDownloadLinkResult.d.ts +14 -0
- package/lib/types/CreateAgentTaskFileDownloadLinkResult.d.ts.map +1 -0
- package/lib/types/CreateAgentTaskFileDownloadLinkResult.js +1 -0
- package/lib/types/CreateAgentTaskParams.d.ts +47 -0
- package/lib/types/CreateAgentTaskParams.d.ts.map +1 -0
- package/lib/types/CreateAgentTaskParams.js +1 -0
- package/lib/types/CreateAgentTaskResponse.d.ts +17 -3
- package/lib/types/CreateAgentTaskResponse.d.ts.map +1 -1
- package/lib/types/StreamCache.d.ts +7 -0
- package/lib/types/StreamCache.d.ts.map +1 -0
- package/lib/types/StreamCache.js +1 -0
- package/lib/types/StreamData.d.ts +26 -0
- package/lib/types/StreamData.d.ts.map +1 -0
- package/lib/types/StreamData.js +1 -0
- package/lib/types/index.d.ts +6 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +6 -0
- package/lib/utils/base64Decode.d.ts +6 -0
- package/lib/utils/base64Decode.d.ts.map +1 -0
- package/lib/utils/base64Decode.js +12 -0
- package/lib/utils/parseAgentTaskFileIdFromFencyFileHref.d.ts +8 -0
- package/lib/utils/parseAgentTaskFileIdFromFencyFileHref.d.ts.map +1 -0
- package/lib/utils/parseAgentTaskFileIdFromFencyFileHref.js +43 -0
- package/lib/utils/version.js +1 -1
- package/package.json +15 -3
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { base64Decode } from '../utils/base64Decode';
|
|
2
|
+
import { EventStreamContentType, fetchEventSource, } from '@microsoft/fetch-event-source';
|
|
3
|
+
import { createStreamWorkerCode } from './createStreamWorkerCode';
|
|
4
|
+
function streamFailureMessage(error) {
|
|
5
|
+
if (error instanceof Error)
|
|
6
|
+
return error.message;
|
|
7
|
+
if (typeof error === 'string')
|
|
8
|
+
return error;
|
|
9
|
+
return 'Unknown stream error';
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Centralized manager for EventSource connections to streams.
|
|
13
|
+
* Ensures only one connection per stream regardless of how many hooks subscribe.
|
|
14
|
+
*
|
|
15
|
+
* When a Web Worker is available, the main thread performs fetch (correct CORS origin)
|
|
16
|
+
* and transfers the response body to the worker for parsing, so the read loop is not
|
|
17
|
+
* stalled by background tab throttling. Otherwise falls back to fetchEventSource on
|
|
18
|
+
* the main thread with openWhenHidden so the connection is not aborted on tab switch.
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export class StreamEventManager {
|
|
22
|
+
constructor(fency) {
|
|
23
|
+
this.activeConnections = new Map();
|
|
24
|
+
this.subscribers = new Map();
|
|
25
|
+
this.worker = null;
|
|
26
|
+
this.workerBlobUrl = null;
|
|
27
|
+
this.workerSupported = false;
|
|
28
|
+
this.fency = fency;
|
|
29
|
+
this.tryInitWorker();
|
|
30
|
+
}
|
|
31
|
+
tryInitWorker() {
|
|
32
|
+
try {
|
|
33
|
+
if (typeof Worker === 'undefined' ||
|
|
34
|
+
typeof Blob === 'undefined' ||
|
|
35
|
+
typeof URL === 'undefined' ||
|
|
36
|
+
typeof URL.createObjectURL !== 'function' ||
|
|
37
|
+
typeof ReadableStream === 'undefined') {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const code = createStreamWorkerCode();
|
|
41
|
+
const blob = new Blob([code], { type: 'application/javascript' });
|
|
42
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
43
|
+
const worker = new Worker(blobUrl);
|
|
44
|
+
worker.onmessage = (e) => {
|
|
45
|
+
this.handleWorkerMessage(e.data);
|
|
46
|
+
};
|
|
47
|
+
worker.onerror = (event) => {
|
|
48
|
+
console.error('Fency stream worker error:', event.message);
|
|
49
|
+
};
|
|
50
|
+
this.worker = worker;
|
|
51
|
+
this.workerBlobUrl = blobUrl;
|
|
52
|
+
this.workerSupported = true;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
this.workerSupported = false;
|
|
56
|
+
this.worker = null;
|
|
57
|
+
if (this.workerBlobUrl) {
|
|
58
|
+
URL.revokeObjectURL(this.workerBlobUrl);
|
|
59
|
+
this.workerBlobUrl = null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
handleWorkerMessage(data) {
|
|
64
|
+
if (!data || typeof data !== 'object')
|
|
65
|
+
return;
|
|
66
|
+
const msg = data;
|
|
67
|
+
switch (msg.type) {
|
|
68
|
+
case 'message':
|
|
69
|
+
if (msg.data && msg.streamId) {
|
|
70
|
+
const decodedData = base64Decode(msg.data);
|
|
71
|
+
this.broadcast(decodedData, msg.streamId);
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
case 'error':
|
|
75
|
+
if (msg.streamId) {
|
|
76
|
+
this.activeConnections.delete(msg.streamId);
|
|
77
|
+
this.broadcastError(msg.streamId, msg.error);
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
case 'open':
|
|
81
|
+
break;
|
|
82
|
+
default:
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Called by FencyProvider when activeStreams changes.
|
|
88
|
+
* Creates new connections and removes old ones.
|
|
89
|
+
*/
|
|
90
|
+
updateStreams(streams) {
|
|
91
|
+
streams.forEach((streamCache) => {
|
|
92
|
+
const streamId = streamCache.stream.id;
|
|
93
|
+
if (!this.activeConnections.has(streamId)) {
|
|
94
|
+
this.connectStream(streamCache);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
const activeStreamIds = new Set(streams.map((s) => s.stream.id));
|
|
98
|
+
this.activeConnections.forEach((connection, streamId) => {
|
|
99
|
+
if (!activeStreamIds.has(streamId)) {
|
|
100
|
+
connection.abort();
|
|
101
|
+
this.activeConnections.delete(streamId);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
connectStream(streamCache) {
|
|
106
|
+
if (this.workerSupported && this.worker) {
|
|
107
|
+
this.connectStreamInWorker(streamCache);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
this.connectStreamOnMainThread(streamCache);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
connectStreamInWorker(streamCache) {
|
|
114
|
+
const streamId = streamCache.stream.id;
|
|
115
|
+
const url = `${this.fency.baseUrl}/sse/streams/${streamId}`;
|
|
116
|
+
const fetchAbort = new AbortController();
|
|
117
|
+
const headers = {
|
|
118
|
+
accept: EventStreamContentType,
|
|
119
|
+
'X-Fency-Publishable-Key': this.fency.publishableKey,
|
|
120
|
+
'X-Fency-Stream-Token': streamCache.stream.token,
|
|
121
|
+
};
|
|
122
|
+
this.activeConnections.set(streamId, {
|
|
123
|
+
abort: () => {
|
|
124
|
+
fetchAbort.abort();
|
|
125
|
+
this.worker?.postMessage({ command: 'disconnect', streamId });
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
void this.startWorkerStream(streamId, url, headers, fetchAbort, streamCache);
|
|
129
|
+
}
|
|
130
|
+
async startWorkerStream(streamId, url, headers, fetchAbort, streamCache) {
|
|
131
|
+
const worker = this.worker;
|
|
132
|
+
if (!worker)
|
|
133
|
+
return;
|
|
134
|
+
const fail = (message) => {
|
|
135
|
+
if (fetchAbort.signal.aborted)
|
|
136
|
+
return;
|
|
137
|
+
this.activeConnections.delete(streamId);
|
|
138
|
+
this.broadcastError(streamId, message);
|
|
139
|
+
};
|
|
140
|
+
try {
|
|
141
|
+
const response = await fetch(url, {
|
|
142
|
+
method: 'GET',
|
|
143
|
+
headers,
|
|
144
|
+
signal: fetchAbort.signal,
|
|
145
|
+
});
|
|
146
|
+
if (!response.ok) {
|
|
147
|
+
if (response.status >= 400 &&
|
|
148
|
+
response.status < 500 &&
|
|
149
|
+
response.status !== 429) {
|
|
150
|
+
fail(`Client error ${response.status}`);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
fail(`HTTP ${response.status}`);
|
|
154
|
+
}
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const body = response.body;
|
|
158
|
+
if (!body) {
|
|
159
|
+
fail('No response body');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (!this.activeConnections.has(streamId)) {
|
|
163
|
+
await body.cancel().catch(() => {
|
|
164
|
+
// ignore
|
|
165
|
+
});
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
worker.postMessage({ command: 'start', streamId, readableStream: body }, [body]);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// ReadableStream transfer not supported (e.g. Safari).
|
|
173
|
+
// Disable worker for this session and fall back to main-thread SSE.
|
|
174
|
+
this.workerSupported = false;
|
|
175
|
+
body.cancel().catch(() => { });
|
|
176
|
+
this.activeConnections.delete(streamId);
|
|
177
|
+
this.connectStreamOnMainThread(streamCache);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
if (fetchAbort.signal.aborted)
|
|
182
|
+
return;
|
|
183
|
+
fail(streamFailureMessage(err));
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
connectStreamOnMainThread(streamCache) {
|
|
187
|
+
const streamId = streamCache.stream.id;
|
|
188
|
+
const abortController = new AbortController();
|
|
189
|
+
this.activeConnections.set(streamId, {
|
|
190
|
+
abort: () => abortController.abort(),
|
|
191
|
+
});
|
|
192
|
+
const url = `${this.fency.baseUrl}/sse/streams/${streamId}`;
|
|
193
|
+
const headers = {
|
|
194
|
+
'X-Fency-Publishable-Key': this.fency.publishableKey,
|
|
195
|
+
'X-Fency-Stream-Token': streamCache.stream.token,
|
|
196
|
+
};
|
|
197
|
+
fetchEventSource(url, {
|
|
198
|
+
headers,
|
|
199
|
+
signal: abortController.signal,
|
|
200
|
+
openWhenHidden: true,
|
|
201
|
+
onopen: async (response) => {
|
|
202
|
+
if (response.ok) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (response.status >= 400 &&
|
|
206
|
+
response.status < 500 &&
|
|
207
|
+
response.status !== 429) {
|
|
208
|
+
this.activeConnections.delete(streamId);
|
|
209
|
+
throw new Error(`Client error ${response.status}`);
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
onmessage: (message) => {
|
|
213
|
+
if (message.data) {
|
|
214
|
+
const decodedData = base64Decode(message.data);
|
|
215
|
+
this.broadcast(decodedData, streamId);
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
onerror: (error) => {
|
|
219
|
+
console.error('EventSource error for stream', streamId, ':', error);
|
|
220
|
+
this.activeConnections.delete(streamId);
|
|
221
|
+
this.broadcastError(streamId, streamFailureMessage(error));
|
|
222
|
+
throw error;
|
|
223
|
+
},
|
|
224
|
+
onclose() {
|
|
225
|
+
// Connection closed by server
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Subscribe to events from all active streams.
|
|
231
|
+
* Returns an unsubscribe function.
|
|
232
|
+
*/
|
|
233
|
+
subscribe(subscriberId, callbacks) {
|
|
234
|
+
this.subscribers.set(subscriberId, callbacks);
|
|
235
|
+
return () => {
|
|
236
|
+
this.subscribers.delete(subscriberId);
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
broadcast(data, streamId) {
|
|
240
|
+
this.subscribers.forEach((subscription) => {
|
|
241
|
+
subscription.onMessage(data, streamId);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
broadcastError(streamId, errorMessage) {
|
|
245
|
+
this.subscribers.forEach((subscription) => {
|
|
246
|
+
subscription.onError(streamId, errorMessage);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Cleanup all connections and subscriptions
|
|
251
|
+
*/
|
|
252
|
+
cleanup() {
|
|
253
|
+
this.activeConnections.forEach((connection) => connection.abort());
|
|
254
|
+
this.activeConnections.clear();
|
|
255
|
+
if (this.worker) {
|
|
256
|
+
try {
|
|
257
|
+
this.worker.postMessage({ command: 'cleanup' });
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// ignore
|
|
261
|
+
}
|
|
262
|
+
this.worker = null;
|
|
263
|
+
}
|
|
264
|
+
if (this.workerBlobUrl) {
|
|
265
|
+
URL.revokeObjectURL(this.workerBlobUrl);
|
|
266
|
+
this.workerBlobUrl = null;
|
|
267
|
+
}
|
|
268
|
+
this.workerSupported = false;
|
|
269
|
+
this.subscribers.clear();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the source code for the inline SSE stream Web Worker.
|
|
3
|
+
* Consumes a ReadableStream transferred from the main thread (same-origin fetch + CORS)
|
|
4
|
+
* so the read loop runs off the main thread and is not stalled by tab throttling.
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export declare function createStreamWorkerCode(): string;
|
|
8
|
+
//# sourceMappingURL=createStreamWorkerCode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createStreamWorkerCode.d.ts","sourceRoot":"","sources":["../../src/stream/createStreamWorkerCode.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAiJ/C"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the source code for the inline SSE stream Web Worker.
|
|
3
|
+
* Consumes a ReadableStream transferred from the main thread (same-origin fetch + CORS)
|
|
4
|
+
* so the read loop runs off the main thread and is not stalled by tab throttling.
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export function createStreamWorkerCode() {
|
|
8
|
+
return `
|
|
9
|
+
var connections = new Map();
|
|
10
|
+
|
|
11
|
+
function disconnectStream(streamId) {
|
|
12
|
+
var entry = connections.get(streamId);
|
|
13
|
+
if (entry) {
|
|
14
|
+
try {
|
|
15
|
+
entry.cancel();
|
|
16
|
+
} catch (e) {}
|
|
17
|
+
connections.delete(streamId);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function findEventBoundary(buf) {
|
|
22
|
+
var iCRLF = buf.indexOf("\\r\\n\\r\\n");
|
|
23
|
+
var iLF = buf.indexOf("\\n\\n");
|
|
24
|
+
if (iCRLF !== -1 && (iLF === -1 || iCRLF < iLF)) {
|
|
25
|
+
return { index: iCRLF, len: 4 };
|
|
26
|
+
}
|
|
27
|
+
if (iLF !== -1) {
|
|
28
|
+
return { index: iLF, len: 2 };
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function parseSseBuffer(buffer) {
|
|
34
|
+
var events = [];
|
|
35
|
+
var rest = buffer;
|
|
36
|
+
while (true) {
|
|
37
|
+
var boundary = findEventBoundary(rest);
|
|
38
|
+
if (!boundary) break;
|
|
39
|
+
var rawEvent = rest.slice(0, boundary.index);
|
|
40
|
+
rest = rest.slice(boundary.index + boundary.len);
|
|
41
|
+
if (!rawEvent.trim()) continue;
|
|
42
|
+
|
|
43
|
+
var eventType = "";
|
|
44
|
+
var eventId = "";
|
|
45
|
+
var dataLines = [];
|
|
46
|
+
var lines = rawEvent.split(/\\r\\n|\\r|\\n/);
|
|
47
|
+
for (var i = 0; i < lines.length; i++) {
|
|
48
|
+
var line = lines[i];
|
|
49
|
+
if (line.charAt(0) === ":") continue;
|
|
50
|
+
var colon = line.indexOf(":");
|
|
51
|
+
if (colon === -1) continue;
|
|
52
|
+
var field = line.slice(0, colon);
|
|
53
|
+
var value = line.slice(colon + 1);
|
|
54
|
+
if (value.charAt(0) === " ") value = value.slice(1);
|
|
55
|
+
if (field === "data") dataLines.push(value);
|
|
56
|
+
else if (field === "event") eventType = value;
|
|
57
|
+
else if (field === "id") eventId = value;
|
|
58
|
+
}
|
|
59
|
+
var data = dataLines.join("\\n");
|
|
60
|
+
if (data.length > 0) {
|
|
61
|
+
events.push({ data: data, event: eventType, id: eventId });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return { events: events, rest: rest };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function readStream(streamId, readableStream) {
|
|
68
|
+
disconnectStream(streamId);
|
|
69
|
+
if (!readableStream || typeof readableStream.getReader !== "function") {
|
|
70
|
+
self.postMessage({
|
|
71
|
+
type: "error",
|
|
72
|
+
streamId: streamId,
|
|
73
|
+
error: "No readable stream",
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
var reader = readableStream.getReader();
|
|
78
|
+
connections.set(streamId, {
|
|
79
|
+
cancel: function () {
|
|
80
|
+
reader.cancel().catch(function () {});
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
try {
|
|
84
|
+
var decoder = new TextDecoder();
|
|
85
|
+
var buf = "";
|
|
86
|
+
while (true) {
|
|
87
|
+
var readResult = await reader.read();
|
|
88
|
+
var done = readResult.done;
|
|
89
|
+
var value = readResult.value;
|
|
90
|
+
if (done) break;
|
|
91
|
+
buf += decoder.decode(value, { stream: true });
|
|
92
|
+
var parsed = parseSseBuffer(buf);
|
|
93
|
+
buf = parsed.rest;
|
|
94
|
+
for (var j = 0; j < parsed.events.length; j++) {
|
|
95
|
+
var ev = parsed.events[j];
|
|
96
|
+
self.postMessage({
|
|
97
|
+
type: "message",
|
|
98
|
+
streamId: streamId,
|
|
99
|
+
data: ev.data,
|
|
100
|
+
event: ev.event || undefined,
|
|
101
|
+
id: ev.id || undefined,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
buf += decoder.decode();
|
|
106
|
+
var finalParsed = parseSseBuffer(buf);
|
|
107
|
+
for (var k = 0; k < finalParsed.events.length; k++) {
|
|
108
|
+
var fev = finalParsed.events[k];
|
|
109
|
+
self.postMessage({
|
|
110
|
+
type: "message",
|
|
111
|
+
streamId: streamId,
|
|
112
|
+
data: fev.data,
|
|
113
|
+
event: fev.event || undefined,
|
|
114
|
+
id: fev.id || undefined,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
} catch (err) {
|
|
118
|
+
if (err && err.name === "AbortError") {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
var msg = err && err.message ? String(err.message) : String(err);
|
|
122
|
+
self.postMessage({ type: "error", streamId: streamId, error: msg });
|
|
123
|
+
} finally {
|
|
124
|
+
connections.delete(streamId);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
self.onmessage = function (e) {
|
|
129
|
+
var d = e.data;
|
|
130
|
+
if (!d || !d.command) return;
|
|
131
|
+
switch (d.command) {
|
|
132
|
+
case "start":
|
|
133
|
+
readStream(d.streamId, d.readableStream);
|
|
134
|
+
break;
|
|
135
|
+
case "disconnect":
|
|
136
|
+
disconnectStream(d.streamId);
|
|
137
|
+
break;
|
|
138
|
+
case "cleanup":
|
|
139
|
+
connections.forEach(function (entry) {
|
|
140
|
+
try {
|
|
141
|
+
entry.cancel();
|
|
142
|
+
} catch (e2) {}
|
|
143
|
+
});
|
|
144
|
+
connections.clear();
|
|
145
|
+
self.close();
|
|
146
|
+
break;
|
|
147
|
+
default:
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
`.trim();
|
|
152
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toStreamData.d.ts","sourceRoot":"","sources":["../../src/stream/toStreamData.ts"],"names":[],"mappings":"AAWA,OAAO,EAEH,UAAU,EAGb,MAAM,qBAAqB,CAAA;AAE5B,cAAc;AACd,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,UAAU,GAAG,IAQxD,CAAA"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { isAgentTaskProgressItemUpdatedEvent, isStreamNotFoundEvent, isStreamTimeoutEvent, } from '../utils/streamEventTypes';
|
|
2
|
+
import { parseAgentTaskEventData } from '../parsing/AgentTaskEventDataSchemas';
|
|
3
|
+
/** @public */
|
|
4
|
+
export const toStreamData = (data) => {
|
|
5
|
+
try {
|
|
6
|
+
const json = JSON.parse(data);
|
|
7
|
+
return toStreamDataRaw(json);
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
console.error('Error parsing message:', error);
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const toStreamDataRaw = (data) => {
|
|
15
|
+
if (isStreamTimeoutEvent(data)) {
|
|
16
|
+
return toStreamTimeout(data);
|
|
17
|
+
}
|
|
18
|
+
if (isStreamNotFoundEvent(data)) {
|
|
19
|
+
return toStreamNotFound(data);
|
|
20
|
+
}
|
|
21
|
+
if (isAgentTaskProgressItemUpdatedEvent(data)) {
|
|
22
|
+
return toAgentTaskProgressItemUpdated(data);
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
};
|
|
26
|
+
const toStreamTimeout = (data) => {
|
|
27
|
+
return {
|
|
28
|
+
type: 'STREAM_TIMEOUT',
|
|
29
|
+
streamId: data.streamId,
|
|
30
|
+
timestamp: data.timestamp,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
const toStreamNotFound = (data) => {
|
|
34
|
+
return {
|
|
35
|
+
type: 'STREAM_NOT_FOUND',
|
|
36
|
+
streamId: data.streamId,
|
|
37
|
+
timestamp: data.timestamp,
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
const toAgentTaskProgressItemUpdated = (data) => {
|
|
41
|
+
let raw;
|
|
42
|
+
try {
|
|
43
|
+
raw = JSON.parse(data.data);
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.warn('[fency] Invalid JSON in AGENT_TASK_PROGRESS_ITEM_UPDATED data payload:', error);
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const parsed = parseAgentTaskEventData(raw);
|
|
50
|
+
if (parsed === null)
|
|
51
|
+
return null;
|
|
52
|
+
return {
|
|
53
|
+
type: 'AGENT_TASK_PROGRESS_ITEM_UPDATED',
|
|
54
|
+
streamId: data.streamId,
|
|
55
|
+
agentTaskId: data.agentTaskId,
|
|
56
|
+
progressItemId: data.progressItemId,
|
|
57
|
+
timestamp: data.timestamp,
|
|
58
|
+
createdAt: data.createdAt,
|
|
59
|
+
data: parsed,
|
|
60
|
+
};
|
|
61
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AgentTaskEventData } from '../AgentTaskEventData';
|
|
2
|
+
import type { ApiError } from '../types/ApiError';
|
|
3
|
+
import type { CreateAgentTaskRequest } from '../types/CreateAgentTaskRequest';
|
|
4
|
+
import type { CreateAgentTaskParams } from '../types/CreateAgentTaskParams';
|
|
5
|
+
import type { CreateAgentTaskResponse } from '../types/CreateAgentTaskResponse';
|
|
6
|
+
/** @public */
|
|
7
|
+
export declare function mapCreateAgentTaskParams(params: CreateAgentTaskParams): CreateAgentTaskRequest;
|
|
8
|
+
/** @public */
|
|
9
|
+
export declare function isTerminalAgentTaskEventData(data: AgentTaskEventData): data is Extract<AgentTaskEventData, {
|
|
10
|
+
eventType: 'Completed' | 'Error';
|
|
11
|
+
}>;
|
|
12
|
+
/** @public */
|
|
13
|
+
export declare function shouldAppendCompletedToProgress(data: AgentTaskEventData): boolean;
|
|
14
|
+
/** @public */
|
|
15
|
+
export declare function agentTaskErrorFromEventData(data: AgentTaskEventData): ApiError | null;
|
|
16
|
+
/** @public */
|
|
17
|
+
export declare function getTerminalCreateAgentTaskResponse(streamId: string, agentTaskId: string, data: AgentTaskEventData): CreateAgentTaskResponse | null;
|
|
18
|
+
//# sourceMappingURL=mapCreateAgentTaskParams.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapCreateAgentTaskParams.d.ts","sourceRoot":"","sources":["../../src/task/mapCreateAgentTaskParams.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA;AAC7E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAA;AAC3E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAA;AAE/E,cAAc;AACd,wBAAgB,wBAAwB,CACpC,MAAM,EAAE,qBAAqB,GAC9B,sBAAsB,CAiDxB;AAED,cAAc;AACd,wBAAgB,4BAA4B,CACxC,IAAI,EAAE,kBAAkB,GACzB,IAAI,IAAI,OAAO,CAAC,kBAAkB,EAAE;IAAE,SAAS,EAAE,WAAW,GAAG,OAAO,CAAA;CAAE,CAAC,CAE3E;AAED,cAAc;AACd,wBAAgB,+BAA+B,CAC3C,IAAI,EAAE,kBAAkB,GACzB,OAAO,CAMT;AAED,cAAc;AACd,wBAAgB,2BAA2B,CACvC,IAAI,EAAE,kBAAkB,GACzB,QAAQ,GAAG,IAAI,CASjB;AAED,cAAc;AACd,wBAAgB,kCAAkC,CAC9C,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,kBAAkB,GACzB,uBAAuB,GAAG,IAAI,CAoBhC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/** @public */
|
|
2
|
+
export function mapCreateAgentTaskParams(params) {
|
|
3
|
+
return {
|
|
4
|
+
streamingChatCompletionTask: params.type === 'StreamingChatCompletion'
|
|
5
|
+
? {
|
|
6
|
+
messages: params.messages,
|
|
7
|
+
model: params.model,
|
|
8
|
+
...(params.temperature !== undefined
|
|
9
|
+
? { temperature: params.temperature }
|
|
10
|
+
: {}),
|
|
11
|
+
...(params.topP !== undefined ? { topP: params.topP } : {}),
|
|
12
|
+
}
|
|
13
|
+
: undefined,
|
|
14
|
+
structuredChatCompletionTask: params.type === 'StructuredChatCompletion'
|
|
15
|
+
? {
|
|
16
|
+
messages: params.messages,
|
|
17
|
+
jsonSchema: params.jsonSchema,
|
|
18
|
+
model: params.model,
|
|
19
|
+
...(params.temperature !== undefined
|
|
20
|
+
? { temperature: params.temperature }
|
|
21
|
+
: {}),
|
|
22
|
+
...(params.topP !== undefined ? { topP: params.topP } : {}),
|
|
23
|
+
}
|
|
24
|
+
: undefined,
|
|
25
|
+
memoryChatTask: params.type === 'MemoryChat'
|
|
26
|
+
? {
|
|
27
|
+
messages: params.messages,
|
|
28
|
+
model: params.model,
|
|
29
|
+
language: params.language ?? 'en',
|
|
30
|
+
chunkLimit: params.chunkLimit ?? 10,
|
|
31
|
+
memoryScanLimit: params.memoryScanLimit ?? 3,
|
|
32
|
+
}
|
|
33
|
+
: undefined,
|
|
34
|
+
memorySearchTask: params.type === 'MemorySearch'
|
|
35
|
+
? {
|
|
36
|
+
query: params.query,
|
|
37
|
+
model: params.model,
|
|
38
|
+
language: params.language ?? 'en',
|
|
39
|
+
chunkLimit: params.chunkLimit ?? 10,
|
|
40
|
+
contextExpansion: params.contextExpansion,
|
|
41
|
+
...(params.queryExpansion != null
|
|
42
|
+
? { queryExpansion: params.queryExpansion }
|
|
43
|
+
: {}),
|
|
44
|
+
}
|
|
45
|
+
: undefined,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** @public */
|
|
49
|
+
export function isTerminalAgentTaskEventData(data) {
|
|
50
|
+
return data.eventType === 'Completed' || data.eventType === 'Error';
|
|
51
|
+
}
|
|
52
|
+
/** @public */
|
|
53
|
+
export function shouldAppendCompletedToProgress(data) {
|
|
54
|
+
return ((data.taskType === 'MemorySearch' && data.eventType === 'Completed') ||
|
|
55
|
+
(data.taskType === 'StructuredChatCompletion' &&
|
|
56
|
+
data.eventType === 'Completed'));
|
|
57
|
+
}
|
|
58
|
+
/** @public */
|
|
59
|
+
export function agentTaskErrorFromEventData(data) {
|
|
60
|
+
if (data.eventType !== 'Error')
|
|
61
|
+
return null;
|
|
62
|
+
return {
|
|
63
|
+
code: 'AgentTaskError',
|
|
64
|
+
message: 'message' in data && typeof data.message === 'string'
|
|
65
|
+
? data.message
|
|
66
|
+
: 'Agent task failed',
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** @public */
|
|
70
|
+
export function getTerminalCreateAgentTaskResponse(streamId, agentTaskId, data) {
|
|
71
|
+
if (data.eventType === 'Error') {
|
|
72
|
+
const error = agentTaskErrorFromEventData(data);
|
|
73
|
+
return error ? { type: 'error', error } : null;
|
|
74
|
+
}
|
|
75
|
+
if (data.eventType === 'Completed') {
|
|
76
|
+
return {
|
|
77
|
+
type: 'success',
|
|
78
|
+
streamId,
|
|
79
|
+
agentTaskId,
|
|
80
|
+
response: data,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AgentTaskEventData } from '../AgentTaskEventData';
|
|
2
|
+
import type { AgentTaskProgressItemUpdated } from '../types/StreamData';
|
|
3
|
+
export declare function upsertProgressItem(progressItems: AgentTaskProgressItemUpdated[], item: AgentTaskProgressItemUpdated): AgentTaskProgressItemUpdated[];
|
|
4
|
+
export declare function createSyntheticCompletedProgressItem(agentTaskId: string, streamId: string, data: AgentTaskEventData): AgentTaskProgressItemUpdated;
|
|
5
|
+
//# sourceMappingURL=progressItems.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progressItems.d.ts","sourceRoot":"","sources":["../../src/task/progressItems.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC/D,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAA;AAEvE,wBAAgB,kBAAkB,CAC9B,aAAa,EAAE,4BAA4B,EAAE,EAC7C,IAAI,EAAE,4BAA4B,GACnC,4BAA4B,EAAE,CAUhC;AAED,wBAAgB,oCAAoC,CAChD,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,kBAAkB,GACzB,4BAA4B,CAW9B"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function upsertProgressItem(progressItems, item) {
|
|
2
|
+
const alreadyExists = progressItems.some((p) => p.progressItemId === item.progressItemId);
|
|
3
|
+
if (alreadyExists) {
|
|
4
|
+
return progressItems.map((p) => p.progressItemId === item.progressItemId ? item : p);
|
|
5
|
+
}
|
|
6
|
+
return [...progressItems, item];
|
|
7
|
+
}
|
|
8
|
+
export function createSyntheticCompletedProgressItem(agentTaskId, streamId, data) {
|
|
9
|
+
const timestamp = new Date().toISOString();
|
|
10
|
+
return {
|
|
11
|
+
type: 'AGENT_TASK_PROGRESS_ITEM_UPDATED',
|
|
12
|
+
streamId,
|
|
13
|
+
agentTaskId,
|
|
14
|
+
progressItemId: `completed-${agentTaskId}`,
|
|
15
|
+
timestamp,
|
|
16
|
+
createdAt: timestamp,
|
|
17
|
+
data,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TaskEvent, TaskStoreState } from './types';
|
|
2
|
+
/** @public */
|
|
3
|
+
export declare const initialTaskStoreState: TaskStoreState;
|
|
4
|
+
/** @public */
|
|
5
|
+
export declare function taskReducer(state: TaskStoreState, event: TaskEvent): TaskStoreState;
|
|
6
|
+
export { agentTaskErrorFromEventData, getTerminalCreateAgentTaskResponse, isTerminalAgentTaskEventData, mapCreateAgentTaskParams, shouldAppendCompletedToProgress, } from './mapCreateAgentTaskParams';
|
|
7
|
+
//# sourceMappingURL=taskReducer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"taskReducer.d.ts","sourceRoot":"","sources":["../../src/task/taskReducer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAOxD,cAAc;AACd,eAAO,MAAM,qBAAqB,EAAE,cAA8B,CAAA;AAElE,cAAc;AACd,wBAAgB,WAAW,CACvB,KAAK,EAAE,cAAc,EACrB,KAAK,EAAE,SAAS,GACjB,cAAc,CA+GhB;AAED,OAAO,EACH,2BAA2B,EAC3B,kCAAkC,EAClC,4BAA4B,EAC5B,wBAAwB,EACxB,+BAA+B,GAClC,MAAM,4BAA4B,CAAA"}
|