@neta-art/cohub 1.9.0 → 1.10.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/README.md +6 -105
- package/dist/chunks/environment.js +33 -0
- package/dist/chunks/http.d.ts +1615 -0
- package/dist/chunks/http.js +1919 -0
- package/dist/chunks/websocket.d.ts +266 -0
- package/dist/chunks/websocket.js +655 -0
- package/dist/http.d.ts +3 -32
- package/dist/http.js +2 -48
- package/dist/index.d.ts +35 -14
- package/dist/index.js +105 -8
- package/dist/websocket.d.ts +2 -141
- package/dist/websocket.js +2 -628
- package/package.json +7 -7
- package/dist/apis/channels.d.ts +0 -13
- package/dist/apis/channels.js +0 -24
- package/dist/apis/cron-jobs.d.ts +0 -18
- package/dist/apis/cron-jobs.js +0 -25
- package/dist/apis/explore.d.ts +0 -9
- package/dist/apis/explore.js +0 -9
- package/dist/apis/generations.d.ts +0 -7
- package/dist/apis/generations.js +0 -13
- package/dist/apis/invitations.d.ts +0 -20
- package/dist/apis/invitations.js +0 -36
- package/dist/apis/models.d.ts +0 -10
- package/dist/apis/models.js +0 -13
- package/dist/apis/prompts.d.ts +0 -9
- package/dist/apis/prompts.js +0 -16
- package/dist/apis/search.d.ts +0 -10
- package/dist/apis/search.js +0 -14
- package/dist/apis/session-access.d.ts +0 -13
- package/dist/apis/session-access.js +0 -19
- package/dist/apis/spaces.d.ts +0 -371
- package/dist/apis/spaces.js +0 -766
- package/dist/apis/tasks.d.ts +0 -13
- package/dist/apis/tasks.js +0 -18
- package/dist/apis/user.d.ts +0 -27
- package/dist/apis/user.js +0 -71
- package/dist/client.d.ts +0 -33
- package/dist/client.js +0 -103
- package/dist/environment.d.ts +0 -22
- package/dist/environment.js +0 -37
- package/dist/realtime.d.ts +0 -2
- package/dist/realtime.js +0 -8
- package/dist/session-generation-stream.d.ts +0 -114
- package/dist/session-generation-stream.js +0 -514
- package/dist/session-patch-reducer.d.ts +0 -61
- package/dist/session-patch-reducer.js +0 -432
- package/dist/transport.d.ts +0 -40
- package/dist/transport.js +0 -78
- package/dist/types.d.ts +0 -535
- package/dist/types.js +0 -1
|
@@ -0,0 +1,1919 @@
|
|
|
1
|
+
import { i as resolveApiBaseUrl } from "./environment.js";
|
|
2
|
+
//#region src/apis/channels.ts
|
|
3
|
+
var ChannelsApi = class {
|
|
4
|
+
transport;
|
|
5
|
+
constructor(transport) {
|
|
6
|
+
this.transport = transport;
|
|
7
|
+
}
|
|
8
|
+
list(customFetch) {
|
|
9
|
+
return this.transport.request("/api/channels", {
|
|
10
|
+
method: "GET",
|
|
11
|
+
fetch: customFetch
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
create(data) {
|
|
15
|
+
return this.transport.request("/api/channels", {
|
|
16
|
+
method: "POST",
|
|
17
|
+
headers: { "Content-Type": "application/json" },
|
|
18
|
+
body: JSON.stringify(data)
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
delete(id) {
|
|
22
|
+
return this.transport.request(`/api/channels/${id}`, { method: "DELETE" });
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/apis/cron-jobs.ts
|
|
27
|
+
var CronJobsApi = class {
|
|
28
|
+
transport;
|
|
29
|
+
constructor(transport) {
|
|
30
|
+
this.transport = transport;
|
|
31
|
+
}
|
|
32
|
+
list(spaceId) {
|
|
33
|
+
const query = spaceId ? `?spaceId=${encodeURIComponent(spaceId)}` : "";
|
|
34
|
+
return this.transport.request(`/api/cron-jobs${query}`);
|
|
35
|
+
}
|
|
36
|
+
delete(id) {
|
|
37
|
+
return this.transport.request(`/api/cron-jobs/${id}`, { method: "DELETE" });
|
|
38
|
+
}
|
|
39
|
+
toggle(id, enabled) {
|
|
40
|
+
return this.transport.request(`/api/cron-jobs/${id}`, {
|
|
41
|
+
method: "PATCH",
|
|
42
|
+
headers: { "Content-Type": "application/json" },
|
|
43
|
+
body: JSON.stringify({ enabled })
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
runs(cronJobId) {
|
|
47
|
+
return this.transport.request(`/api/cron-jobs/${cronJobId}/runs`);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
//#endregion
|
|
51
|
+
//#region src/apis/generations.ts
|
|
52
|
+
var GenerationsApi = class {
|
|
53
|
+
transport;
|
|
54
|
+
constructor(transport) {
|
|
55
|
+
this.transport = transport;
|
|
56
|
+
}
|
|
57
|
+
async create(request) {
|
|
58
|
+
return this.transport.request("/api/generations", {
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: { "Content-Type": "application/json" },
|
|
61
|
+
body: JSON.stringify(request)
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/apis/models.ts
|
|
67
|
+
const MULTIMODAL_MODEL_TYPE = "multimodal";
|
|
68
|
+
var ModelsApi = class {
|
|
69
|
+
transport;
|
|
70
|
+
constructor(transport) {
|
|
71
|
+
this.transport = transport;
|
|
72
|
+
}
|
|
73
|
+
async list() {
|
|
74
|
+
return this.transport.request("/api/models");
|
|
75
|
+
}
|
|
76
|
+
async listMultimodal() {
|
|
77
|
+
return this.transport.request(`/api/models?modelType=${MULTIMODAL_MODEL_TYPE}`);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/apis/prompts.ts
|
|
82
|
+
var PromptsApi = class {
|
|
83
|
+
transport;
|
|
84
|
+
constructor(transport) {
|
|
85
|
+
this.transport = transport;
|
|
86
|
+
}
|
|
87
|
+
async list(options, customFetch) {
|
|
88
|
+
const params = new URLSearchParams();
|
|
89
|
+
if (options?.spaceId) params.set("spaceId", options.spaceId);
|
|
90
|
+
const query = params.toString();
|
|
91
|
+
const path = query ? `/api/prompts?${query}` : "/api/prompts";
|
|
92
|
+
return this.transport.request(path, { fetch: customFetch });
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region src/apis/search.ts
|
|
97
|
+
var SearchApi = class {
|
|
98
|
+
transport;
|
|
99
|
+
constructor(transport) {
|
|
100
|
+
this.transport = transport;
|
|
101
|
+
}
|
|
102
|
+
query(input, customFetch) {
|
|
103
|
+
const params = new URLSearchParams({ q: input.q });
|
|
104
|
+
if (input.limit !== void 0) params.set("limit", String(input.limit));
|
|
105
|
+
for (const type of input.types ?? []) params.append("type", type);
|
|
106
|
+
if (input.spaceId) params.set("spaceId", input.spaceId);
|
|
107
|
+
return this.transport.request(`/api/search?${params.toString()}`, { fetch: customFetch });
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/apis/session-access.ts
|
|
112
|
+
var SessionAccessApi = class {
|
|
113
|
+
transport;
|
|
114
|
+
constructor(transport) {
|
|
115
|
+
this.transport = transport;
|
|
116
|
+
}
|
|
117
|
+
get(sessionId) {
|
|
118
|
+
return this.transport.request(`/api/sessions/${sessionId}/access`);
|
|
119
|
+
}
|
|
120
|
+
set(sessionId, body) {
|
|
121
|
+
return this.transport.request(`/api/sessions/${sessionId}/access`, {
|
|
122
|
+
method: "PATCH",
|
|
123
|
+
headers: { "Content-Type": "application/json" },
|
|
124
|
+
body: JSON.stringify(body)
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
remove(sessionId) {
|
|
128
|
+
return this.transport.request(`/api/sessions/${sessionId}/access`, { method: "DELETE" });
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/realtime.ts
|
|
133
|
+
function ensureRealtimeConnected(websocketClient) {
|
|
134
|
+
if (websocketClient.state === "open" || websocketClient.state === "connecting" || websocketClient.state === "reconnecting") return;
|
|
135
|
+
websocketClient.connect().catch((error) => {
|
|
136
|
+
console.error("[CohubClient] Failed to connect realtime websocket:", error);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region src/transport.ts
|
|
141
|
+
const responseBodyForError = async (response) => {
|
|
142
|
+
return (response.headers.get("content-type") ?? "").includes("application/json") ? await response.json().catch(() => null) : await response.text().catch(() => response.statusText);
|
|
143
|
+
};
|
|
144
|
+
const messageFromErrorBody = (body, fallback) => typeof body === "string" ? body : JSON.stringify(body ?? null) || fallback;
|
|
145
|
+
var HttpError = class extends Error {
|
|
146
|
+
status;
|
|
147
|
+
body;
|
|
148
|
+
constructor(message, status, body) {
|
|
149
|
+
super(message);
|
|
150
|
+
this.name = "HttpError";
|
|
151
|
+
this.status = status;
|
|
152
|
+
this.body = body;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
var HttpTransport = class {
|
|
156
|
+
baseUrl;
|
|
157
|
+
fetcher;
|
|
158
|
+
getAccessToken;
|
|
159
|
+
onUnauthorized;
|
|
160
|
+
constructor(options = {}) {
|
|
161
|
+
this.baseUrl = resolveApiBaseUrl(options);
|
|
162
|
+
this.fetcher = options.fetch ?? fetch;
|
|
163
|
+
this.getAccessToken = options.getAccessToken;
|
|
164
|
+
this.onUnauthorized = options.onUnauthorized;
|
|
165
|
+
}
|
|
166
|
+
async withAuthorization(init) {
|
|
167
|
+
const headers = new Headers(init?.headers);
|
|
168
|
+
const token = this.getAccessToken ? await this.getAccessToken() : null;
|
|
169
|
+
if (token) headers.set("Authorization", `Bearer ${token}`);
|
|
170
|
+
else headers.delete("Authorization");
|
|
171
|
+
return {
|
|
172
|
+
...init,
|
|
173
|
+
headers
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
async send(path, init) {
|
|
177
|
+
const response = await (init?.fetch ?? this.fetcher)(this.baseUrl ? `${this.baseUrl}${path}` : path, await this.withAuthorization(init));
|
|
178
|
+
if (response.status === 401) {
|
|
179
|
+
await this.onUnauthorized?.();
|
|
180
|
+
throw new HttpError("unauthorized", 401, null);
|
|
181
|
+
}
|
|
182
|
+
if (!response.ok) {
|
|
183
|
+
const body = await responseBodyForError(response);
|
|
184
|
+
throw new HttpError(messageFromErrorBody(body, response.statusText), response.status, body);
|
|
185
|
+
}
|
|
186
|
+
return response;
|
|
187
|
+
}
|
|
188
|
+
async request(path, init) {
|
|
189
|
+
const response = await this.send(path, init);
|
|
190
|
+
if (response.status === 204) return null;
|
|
191
|
+
return response.json();
|
|
192
|
+
}
|
|
193
|
+
async raw(path, init) {
|
|
194
|
+
const response = await this.send(path, init);
|
|
195
|
+
return {
|
|
196
|
+
response,
|
|
197
|
+
blob: () => response.blob(),
|
|
198
|
+
arrayBuffer: () => response.arrayBuffer(),
|
|
199
|
+
text: () => response.text(),
|
|
200
|
+
json: () => response.json()
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
async blob(path, init) {
|
|
204
|
+
return (await this.raw(path, init)).blob();
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/session-patch-reducer.ts
|
|
209
|
+
const blockSubPathPattern = /^\/message\/content\/blocks\/(\d+)\/(.+)$/;
|
|
210
|
+
const blockPathPattern = /^\/message\/content\/blocks\/(\d+)$/;
|
|
211
|
+
const blockMetaPathPattern = /^\/message\/content\/blocks\/(\d+)\/_meta$/;
|
|
212
|
+
const TERMINAL_PATCH_STATUSES = new Set([
|
|
213
|
+
"completed",
|
|
214
|
+
"failed",
|
|
215
|
+
"interrupted"
|
|
216
|
+
]);
|
|
217
|
+
const isTerminalPatchStatus = (status) => TERMINAL_PATCH_STATUSES.has(status);
|
|
218
|
+
const createIdleState = (input) => ({
|
|
219
|
+
spaceId: input.spaceId ?? null,
|
|
220
|
+
sessionId: input.sessionId,
|
|
221
|
+
status: "idle",
|
|
222
|
+
contentBlocks: [],
|
|
223
|
+
anchorUserMessageId: null,
|
|
224
|
+
patchSeq: 0,
|
|
225
|
+
turnId: null,
|
|
226
|
+
appendPath: null
|
|
227
|
+
});
|
|
228
|
+
function cloneBlock(block) {
|
|
229
|
+
return structuredClone(block);
|
|
230
|
+
}
|
|
231
|
+
function getStreamIndex$1(block) {
|
|
232
|
+
const value = block._meta?.streamIndex;
|
|
233
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
234
|
+
}
|
|
235
|
+
function blockIdentityCompatible(prev, next) {
|
|
236
|
+
if (prev.type !== next.type) return false;
|
|
237
|
+
if (prev.type === "tool_use" && next.type === "tool_use") return prev.id === next.id && prev.name === next.name;
|
|
238
|
+
if (prev.type === "tool_result" && next.type === "tool_result") return prev.tool_use_id === next.tool_use_id;
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
function findBlockByStreamIndex(blocks, streamIndex) {
|
|
242
|
+
return blocks.findIndex((block) => getStreamIndex$1(block) === streamIndex);
|
|
243
|
+
}
|
|
244
|
+
function findBlockForReplacement(blocks, streamIndex, nextBlock) {
|
|
245
|
+
const compatibleIndex = blocks.findIndex((block) => getStreamIndex$1(block) === streamIndex && blockIdentityCompatible(block, nextBlock));
|
|
246
|
+
if (compatibleIndex >= 0) return compatibleIndex;
|
|
247
|
+
const sameStreamIndex = blocks.findIndex((block) => getStreamIndex$1(block) === streamIndex);
|
|
248
|
+
if (sameStreamIndex >= 0 && nextBlock.type !== "tool_use" && nextBlock.type !== "tool_result") return sameStreamIndex;
|
|
249
|
+
return -1;
|
|
250
|
+
}
|
|
251
|
+
function sortBlocksByStreamIndex(blocks) {
|
|
252
|
+
return [...blocks].sort((a, b) => {
|
|
253
|
+
const aIndex = getStreamIndex$1(a);
|
|
254
|
+
const bIndex = getStreamIndex$1(b);
|
|
255
|
+
if (aIndex == null && bIndex == null) return 0;
|
|
256
|
+
if (aIndex == null) return 1;
|
|
257
|
+
if (bIndex == null) return -1;
|
|
258
|
+
return aIndex - bIndex;
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function isContentBlock(value) {
|
|
262
|
+
return Boolean(value && typeof value === "object" && "type" in value);
|
|
263
|
+
}
|
|
264
|
+
function isPlainObject(value) {
|
|
265
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
266
|
+
}
|
|
267
|
+
function decodePointerSegments(encoded) {
|
|
268
|
+
if (!encoded) return [];
|
|
269
|
+
return encoded.split("/").map((s) => s.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
270
|
+
}
|
|
271
|
+
function ensureTextLikeBlock(blocks, streamIndex, field) {
|
|
272
|
+
const existingIndex = findBlockByStreamIndex(blocks, streamIndex);
|
|
273
|
+
const existing = existingIndex >= 0 ? blocks[existingIndex] : void 0;
|
|
274
|
+
if (field === "text") {
|
|
275
|
+
if (existing?.type === "text") return existing;
|
|
276
|
+
const block = {
|
|
277
|
+
type: "text",
|
|
278
|
+
text: "",
|
|
279
|
+
_meta: { streamIndex }
|
|
280
|
+
};
|
|
281
|
+
blocks.push(block);
|
|
282
|
+
return block;
|
|
283
|
+
}
|
|
284
|
+
if (existing?.type === "thinking") return existing;
|
|
285
|
+
const block = {
|
|
286
|
+
type: "thinking",
|
|
287
|
+
thinking: "",
|
|
288
|
+
_meta: { streamIndex }
|
|
289
|
+
};
|
|
290
|
+
blocks.push(block);
|
|
291
|
+
return block;
|
|
292
|
+
}
|
|
293
|
+
function getOrCreateBlockForSubpath(blocks, streamIndex, firstSegment) {
|
|
294
|
+
const idx = findBlockByStreamIndex(blocks, streamIndex);
|
|
295
|
+
if (idx >= 0) return blocks[idx] ?? null;
|
|
296
|
+
if (firstSegment === "text") return ensureTextLikeBlock(blocks, streamIndex, "text");
|
|
297
|
+
if (firstSegment === "thinking") return ensureTextLikeBlock(blocks, streamIndex, "thinking");
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
function setDeepOnContentBlock(root, segments, value) {
|
|
301
|
+
if (segments.length === 0) return false;
|
|
302
|
+
let cur = root;
|
|
303
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
304
|
+
const k = segments[i];
|
|
305
|
+
if (k === void 0) return false;
|
|
306
|
+
if (!isPlainObject(cur)) return false;
|
|
307
|
+
const next = cur[k];
|
|
308
|
+
if (next === void 0) return false;
|
|
309
|
+
cur = next;
|
|
310
|
+
}
|
|
311
|
+
const last = segments[segments.length - 1];
|
|
312
|
+
if (last === void 0) return false;
|
|
313
|
+
if (!isPlainObject(cur)) return false;
|
|
314
|
+
const toAssign = value !== null && typeof value === "object" ? structuredClone(value) : value;
|
|
315
|
+
cur[last] = toAssign;
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
318
|
+
function appendDeepOnContentBlock(root, segments, suffix) {
|
|
319
|
+
if (segments.length === 0) return false;
|
|
320
|
+
let cur = root;
|
|
321
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
322
|
+
const k = segments[i];
|
|
323
|
+
if (k === void 0) return false;
|
|
324
|
+
if (!isPlainObject(cur)) return false;
|
|
325
|
+
const next = cur[k];
|
|
326
|
+
if (next === void 0) return false;
|
|
327
|
+
cur = next;
|
|
328
|
+
}
|
|
329
|
+
const last = segments[segments.length - 1];
|
|
330
|
+
if (last === void 0) return false;
|
|
331
|
+
if (!isPlainObject(cur)) return false;
|
|
332
|
+
const parent = cur;
|
|
333
|
+
const leaf = parent[last];
|
|
334
|
+
if (typeof leaf !== "string") return false;
|
|
335
|
+
parent[last] = leaf + suffix;
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
function resolveBlockForSubpath(blocks, streamIndex, firstSegment) {
|
|
339
|
+
const idx = findBlockByStreamIndex(blocks, streamIndex);
|
|
340
|
+
if (idx >= 0) return blocks[idx] ?? null;
|
|
341
|
+
return getOrCreateBlockForSubpath(blocks, streamIndex, firstSegment);
|
|
342
|
+
}
|
|
343
|
+
function applyReplaceAtBlockSubpath(blocks, streamIndex, encodedTail, value) {
|
|
344
|
+
const segs = decodePointerSegments(encodedTail);
|
|
345
|
+
if (segs.length === 0) return false;
|
|
346
|
+
const block = resolveBlockForSubpath(blocks, streamIndex, segs[0] ?? "");
|
|
347
|
+
if (!block) return false;
|
|
348
|
+
return setDeepOnContentBlock(block, segs, value);
|
|
349
|
+
}
|
|
350
|
+
function applyAppendAtBlockSubpath(blocks, streamIndex, encodedTail, suffix) {
|
|
351
|
+
if (typeof suffix !== "string") return false;
|
|
352
|
+
const segs = decodePointerSegments(encodedTail);
|
|
353
|
+
if (segs.length === 0) return false;
|
|
354
|
+
const block = resolveBlockForSubpath(blocks, streamIndex, segs[0] ?? "");
|
|
355
|
+
if (!block) return false;
|
|
356
|
+
return appendDeepOnContentBlock(block, segs, suffix);
|
|
357
|
+
}
|
|
358
|
+
function appendPatchStreamValue(blocks, path, value) {
|
|
359
|
+
const m = path.match(blockSubPathPattern);
|
|
360
|
+
if (!m) return false;
|
|
361
|
+
return applyAppendAtBlockSubpath(blocks, Number(m[1]), m[2] ?? "", value);
|
|
362
|
+
}
|
|
363
|
+
function applyPatchOpsToBlocks(current, ops, initialAppendPath) {
|
|
364
|
+
const next = current.map(cloneBlock);
|
|
365
|
+
let anchorUserMessageId;
|
|
366
|
+
let appendPath = initialAppendPath;
|
|
367
|
+
let failed = false;
|
|
368
|
+
for (const op of ops) {
|
|
369
|
+
if (!op.o && !op.p) {
|
|
370
|
+
if (!appendPath || !appendPatchStreamValue(next, appendPath, op.v)) {
|
|
371
|
+
failed = true;
|
|
372
|
+
break;
|
|
373
|
+
}
|
|
374
|
+
continue;
|
|
375
|
+
}
|
|
376
|
+
if (op.o === "merge" && op.p === "/message/metadata") {
|
|
377
|
+
const anchor = op.v.anchorUserMessageId;
|
|
378
|
+
if (typeof anchor === "string" && anchor.trim()) anchorUserMessageId = anchor;
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
if (op.o === "append") {
|
|
382
|
+
if (typeof op.p !== "string" || !appendPatchStreamValue(next, op.p, op.v)) {
|
|
383
|
+
failed = true;
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
appendPath = op.p;
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
if (op.o === "merge") {
|
|
390
|
+
const match = op.p.match(blockMetaPathPattern);
|
|
391
|
+
if (!match) continue;
|
|
392
|
+
const blockIndex = findBlockByStreamIndex(next, Number(match[1]));
|
|
393
|
+
const block = blockIndex >= 0 ? next[blockIndex] : void 0;
|
|
394
|
+
if (!block) continue;
|
|
395
|
+
block._meta = {
|
|
396
|
+
...block._meta ?? {},
|
|
397
|
+
...op.v
|
|
398
|
+
};
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
if (op.o === "replace") {
|
|
402
|
+
const sub = op.p.match(blockSubPathPattern);
|
|
403
|
+
if (sub?.[2] && typeof op.p === "string") {
|
|
404
|
+
const streamIndex = Number(sub[1]);
|
|
405
|
+
const encodedTail = sub[2];
|
|
406
|
+
if (applyReplaceAtBlockSubpath(next, streamIndex, encodedTail, op.v)) continue;
|
|
407
|
+
failed = true;
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (op.o === "replace" || op.o === "add") {
|
|
412
|
+
const match = op.p.match(blockPathPattern);
|
|
413
|
+
if (!match || !isContentBlock(op.v)) continue;
|
|
414
|
+
const streamIndex = Number(match[1]);
|
|
415
|
+
const block = cloneBlock(op.v);
|
|
416
|
+
block._meta = {
|
|
417
|
+
...block._meta ?? {},
|
|
418
|
+
streamIndex
|
|
419
|
+
};
|
|
420
|
+
const blockIndex = findBlockForReplacement(next, streamIndex, block);
|
|
421
|
+
if (blockIndex >= 0) next[blockIndex] = block;
|
|
422
|
+
else next.push(block);
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (op.o === "remove") {
|
|
426
|
+
const match = op.p.match(blockPathPattern);
|
|
427
|
+
if (!match) continue;
|
|
428
|
+
const blockIndex = findBlockByStreamIndex(next, Number(match[1]));
|
|
429
|
+
if (blockIndex >= 0) next.splice(blockIndex, 1);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return {
|
|
433
|
+
failed,
|
|
434
|
+
contentBlocks: sortBlocksByStreamIndex(next),
|
|
435
|
+
anchorUserMessageId,
|
|
436
|
+
appendPath
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
var SessionPatchReducer = class {
|
|
440
|
+
states = /* @__PURE__ */ new Map();
|
|
441
|
+
key(input) {
|
|
442
|
+
return `${input.spaceId ?? ""}:${input.sessionId}`;
|
|
443
|
+
}
|
|
444
|
+
get(input) {
|
|
445
|
+
const key = this.key(input);
|
|
446
|
+
return this.states.get(key) ?? createIdleState(input);
|
|
447
|
+
}
|
|
448
|
+
start(input) {
|
|
449
|
+
const state = {
|
|
450
|
+
...this.get(input),
|
|
451
|
+
status: "pending",
|
|
452
|
+
contentBlocks: [],
|
|
453
|
+
anchorUserMessageId: null,
|
|
454
|
+
patchSeq: 0,
|
|
455
|
+
turnId: input.turnId ?? null,
|
|
456
|
+
appendPath: null
|
|
457
|
+
};
|
|
458
|
+
this.states.set(this.key(input), state);
|
|
459
|
+
return state;
|
|
460
|
+
}
|
|
461
|
+
replaceTurnId(input) {
|
|
462
|
+
const state = {
|
|
463
|
+
...this.get(input),
|
|
464
|
+
turnId: input.nextTurnId
|
|
465
|
+
};
|
|
466
|
+
this.states.set(this.key(input), state);
|
|
467
|
+
return state;
|
|
468
|
+
}
|
|
469
|
+
complete(input) {
|
|
470
|
+
const current = this.get(input);
|
|
471
|
+
const state = {
|
|
472
|
+
...current,
|
|
473
|
+
turnId: input.turnId ?? current.turnId,
|
|
474
|
+
status: "completed",
|
|
475
|
+
contentBlocks: [],
|
|
476
|
+
anchorUserMessageId: null
|
|
477
|
+
};
|
|
478
|
+
this.states.set(this.key(input), state);
|
|
479
|
+
return state;
|
|
480
|
+
}
|
|
481
|
+
fail(input) {
|
|
482
|
+
const current = this.get(input);
|
|
483
|
+
const state = {
|
|
484
|
+
...current,
|
|
485
|
+
turnId: input.turnId ?? current.turnId,
|
|
486
|
+
status: "failed",
|
|
487
|
+
contentBlocks: [],
|
|
488
|
+
anchorUserMessageId: null
|
|
489
|
+
};
|
|
490
|
+
this.states.set(this.key(input), state);
|
|
491
|
+
return state;
|
|
492
|
+
}
|
|
493
|
+
interrupt(input) {
|
|
494
|
+
const current = this.get(input);
|
|
495
|
+
const state = {
|
|
496
|
+
...current,
|
|
497
|
+
turnId: input.turnId ?? current.turnId,
|
|
498
|
+
status: "interrupted",
|
|
499
|
+
contentBlocks: [],
|
|
500
|
+
anchorUserMessageId: null,
|
|
501
|
+
appendPath: null
|
|
502
|
+
};
|
|
503
|
+
this.states.set(this.key(input), state);
|
|
504
|
+
return state;
|
|
505
|
+
}
|
|
506
|
+
reset(input) {
|
|
507
|
+
this.states.delete(this.key(input));
|
|
508
|
+
}
|
|
509
|
+
applySnapshot(input) {
|
|
510
|
+
const current = this.get(input);
|
|
511
|
+
const inputTurnId = input.turnId ?? null;
|
|
512
|
+
const currentTurnId = current.turnId;
|
|
513
|
+
const isDifferentKnownTurn = Boolean(currentTurnId && inputTurnId && currentTurnId !== inputTurnId);
|
|
514
|
+
if (isTerminalPatchStatus(current.status) && Boolean(currentTurnId) && currentTurnId === inputTurnId || !isDifferentKnownTurn && input.seq < current.patchSeq) return {
|
|
515
|
+
applied: false,
|
|
516
|
+
reason: "duplicate",
|
|
517
|
+
state: current
|
|
518
|
+
};
|
|
519
|
+
const state = {
|
|
520
|
+
...current,
|
|
521
|
+
spaceId: input.spaceId ?? current.spaceId ?? null,
|
|
522
|
+
sessionId: input.sessionId,
|
|
523
|
+
status: "streaming",
|
|
524
|
+
contentBlocks: sortBlocksByStreamIndex(input.contentBlocks.map(cloneBlock)),
|
|
525
|
+
anchorUserMessageId: input.anchorUserMessageId ?? current.anchorUserMessageId ?? null,
|
|
526
|
+
patchSeq: input.seq,
|
|
527
|
+
turnId: inputTurnId ?? current.turnId ?? null,
|
|
528
|
+
appendPath: input.appendPath ?? null
|
|
529
|
+
};
|
|
530
|
+
this.states.set(this.key(input), state);
|
|
531
|
+
return {
|
|
532
|
+
applied: true,
|
|
533
|
+
state
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
resetAll() {
|
|
537
|
+
this.states.clear();
|
|
538
|
+
}
|
|
539
|
+
applyEvent(event) {
|
|
540
|
+
return this.applyPatch({
|
|
541
|
+
spaceId: event.spaceId,
|
|
542
|
+
sessionId: event.sessionId,
|
|
543
|
+
turnId: event.payload.turnId,
|
|
544
|
+
seq: event.payload.seq,
|
|
545
|
+
baseSeq: event.payload.baseSeq,
|
|
546
|
+
ops: event.payload.ops,
|
|
547
|
+
anchorUserMessageId: event.payload.anchorUserMessageId
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
applyPatch(input) {
|
|
551
|
+
const current = this.get(input);
|
|
552
|
+
const currentTurnId = current.turnId;
|
|
553
|
+
const inputTurnId = input.turnId ?? null;
|
|
554
|
+
const isDifferentKnownTurn = Boolean(currentTurnId && inputTurnId && currentTurnId !== inputTurnId);
|
|
555
|
+
const isFreshKnownTurn = isDifferentKnownTurn && input.baseSeq === 0;
|
|
556
|
+
const currentSeq = isFreshKnownTurn ? 0 : current.patchSeq;
|
|
557
|
+
const isSameTurnKeyframe = Boolean(currentTurnId && inputTurnId && currentTurnId === inputTurnId && input.baseSeq === 0 && input.seq >= currentSeq);
|
|
558
|
+
if (isTerminalPatchStatus(current.status) && Boolean(currentTurnId) && currentTurnId === inputTurnId) return {
|
|
559
|
+
applied: false,
|
|
560
|
+
reason: "duplicate",
|
|
561
|
+
state: current
|
|
562
|
+
};
|
|
563
|
+
if (isDifferentKnownTurn && !isFreshKnownTurn) return {
|
|
564
|
+
applied: false,
|
|
565
|
+
reason: "version_mismatch",
|
|
566
|
+
state: current
|
|
567
|
+
};
|
|
568
|
+
if (!isSameTurnKeyframe && input.seq <= currentSeq) return {
|
|
569
|
+
applied: false,
|
|
570
|
+
reason: "duplicate",
|
|
571
|
+
state: current
|
|
572
|
+
};
|
|
573
|
+
if (!isSameTurnKeyframe && input.baseSeq !== currentSeq) return {
|
|
574
|
+
applied: false,
|
|
575
|
+
reason: "version_mismatch",
|
|
576
|
+
state: current
|
|
577
|
+
};
|
|
578
|
+
const startingFresh = input.baseSeq === 0 || isFreshKnownTurn || isSameTurnKeyframe;
|
|
579
|
+
const patched = applyPatchOpsToBlocks(startingFresh ? [] : current.contentBlocks, input.ops, startingFresh ? null : current.appendPath);
|
|
580
|
+
if (patched.failed) return {
|
|
581
|
+
applied: false,
|
|
582
|
+
reason: "version_mismatch",
|
|
583
|
+
state: current
|
|
584
|
+
};
|
|
585
|
+
const next = {
|
|
586
|
+
...current,
|
|
587
|
+
spaceId: input.spaceId ?? current.spaceId ?? null,
|
|
588
|
+
sessionId: input.sessionId,
|
|
589
|
+
status: "streaming",
|
|
590
|
+
contentBlocks: patched.contentBlocks,
|
|
591
|
+
anchorUserMessageId: patched.anchorUserMessageId ?? input.anchorUserMessageId ?? current.anchorUserMessageId ?? null,
|
|
592
|
+
patchSeq: input.seq,
|
|
593
|
+
turnId: input.turnId ?? current.turnId ?? null,
|
|
594
|
+
appendPath: patched.appendPath
|
|
595
|
+
};
|
|
596
|
+
this.states.set(this.key(next), next);
|
|
597
|
+
return {
|
|
598
|
+
applied: true,
|
|
599
|
+
state: next
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
const createSessionPatchReducer = () => new SessionPatchReducer();
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region src/session-generation-stream.ts
|
|
606
|
+
const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
607
|
+
const isContentBlockArray = (value) => Array.isArray(value) && value.every((item) => isRecord(item) && typeof item.type === "string");
|
|
608
|
+
const stringField = (record, key) => {
|
|
609
|
+
const value = record[key];
|
|
610
|
+
return typeof value === "string" ? value : null;
|
|
611
|
+
};
|
|
612
|
+
const numberField = (record, key) => {
|
|
613
|
+
const value = record[key];
|
|
614
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
615
|
+
};
|
|
616
|
+
const getMessageKind = (message) => {
|
|
617
|
+
const kind = message.meta?.messageKind;
|
|
618
|
+
return typeof kind === "string" ? kind : null;
|
|
619
|
+
};
|
|
620
|
+
function parseAssistantMessageCommit(message) {
|
|
621
|
+
if (message.role !== "assistant") return {
|
|
622
|
+
kind: "ignored",
|
|
623
|
+
message,
|
|
624
|
+
isFinal: false
|
|
625
|
+
};
|
|
626
|
+
const kind = getMessageKind(message);
|
|
627
|
+
if (kind === "assistant_intermediate") return {
|
|
628
|
+
kind: "intermediate",
|
|
629
|
+
message,
|
|
630
|
+
isFinal: false
|
|
631
|
+
};
|
|
632
|
+
if (kind === "assistant_final") return {
|
|
633
|
+
kind: "final",
|
|
634
|
+
message,
|
|
635
|
+
isFinal: true
|
|
636
|
+
};
|
|
637
|
+
if (kind === "assistant_error") return {
|
|
638
|
+
kind: "error",
|
|
639
|
+
message,
|
|
640
|
+
isFinal: true
|
|
641
|
+
};
|
|
642
|
+
return {
|
|
643
|
+
kind: "ignored",
|
|
644
|
+
message,
|
|
645
|
+
isFinal: false
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
function cloneContentBlock(block) {
|
|
649
|
+
return structuredClone(block);
|
|
650
|
+
}
|
|
651
|
+
function getStreamIndex(block) {
|
|
652
|
+
const value = block._meta?.streamIndex;
|
|
653
|
+
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
654
|
+
}
|
|
655
|
+
function findMergeTargetIndex(result, block) {
|
|
656
|
+
const streamIndex = getStreamIndex(block);
|
|
657
|
+
if (streamIndex != null) return result.findIndex((existing) => existing.type === block.type && getStreamIndex(existing) === streamIndex);
|
|
658
|
+
if (block.type === "tool_use") return result.findIndex((existing) => existing.type === "tool_use" && existing.id === block.id);
|
|
659
|
+
if (block.type === "tool_result") return result.findIndex((existing) => existing.type === "tool_result" && existing.tool_use_id === block.tool_use_id);
|
|
660
|
+
return -1;
|
|
661
|
+
}
|
|
662
|
+
function mergeStreamingDeltaBlocks(existing, delta) {
|
|
663
|
+
if (delta.length === 0) return existing;
|
|
664
|
+
const result = existing.map(cloneContentBlock);
|
|
665
|
+
for (const block of delta) {
|
|
666
|
+
const targetIndex = findMergeTargetIndex(result, block);
|
|
667
|
+
if (targetIndex === -1) {
|
|
668
|
+
result.push(cloneContentBlock(block));
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
const target = result[targetIndex];
|
|
672
|
+
if (block.type === "text" && target?.type === "text") {
|
|
673
|
+
target.text += block.text;
|
|
674
|
+
continue;
|
|
675
|
+
}
|
|
676
|
+
if (block.type === "thinking" && target?.type === "thinking") {
|
|
677
|
+
target.thinking += block.thinking;
|
|
678
|
+
if (block.signature) target.signature = block.signature;
|
|
679
|
+
if (block._meta) target._meta = {
|
|
680
|
+
...target._meta ?? {},
|
|
681
|
+
...block._meta
|
|
682
|
+
};
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
result[targetIndex] = Object.assign(target ?? {}, cloneContentBlock(block));
|
|
686
|
+
}
|
|
687
|
+
return result;
|
|
688
|
+
}
|
|
689
|
+
function parseSnapshotMessage(value) {
|
|
690
|
+
if (!isRecord(value) || !isContentBlockArray(value.content)) return null;
|
|
691
|
+
return {
|
|
692
|
+
messageId: stringField(value, "messageId"),
|
|
693
|
+
messageOrdinal: numberField(value, "messageOrdinal"),
|
|
694
|
+
content: value.content,
|
|
695
|
+
...typeof value.id === "string" ? { id: value.id } : {},
|
|
696
|
+
...typeof value.sessionId === "string" ? { sessionId: value.sessionId } : {},
|
|
697
|
+
...value.role === "user" || value.role === "assistant" || value.role === "system" ? { role: value.role } : {},
|
|
698
|
+
...typeof value.text === "string" ? { text: value.text } : {},
|
|
699
|
+
...typeof value.provider === "string" ? { provider: value.provider } : {},
|
|
700
|
+
...typeof value.model === "string" ? { model: value.model } : {},
|
|
701
|
+
...typeof value.stopReason === "string" ? { stopReason: value.stopReason } : {},
|
|
702
|
+
...typeof value.errorMessage === "string" ? { errorMessage: value.errorMessage } : {},
|
|
703
|
+
...isRecord(value.usage) ? { usage: value.usage } : {},
|
|
704
|
+
...typeof value.toolCallsObjectKey === "string" ? { toolCallsObjectKey: value.toolCallsObjectKey } : {},
|
|
705
|
+
...isRecord(value.meta) ? { meta: value.meta } : {},
|
|
706
|
+
...typeof value.createdAt === "string" ? { createdAt: value.createdAt } : {}
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
function messageRecordToIntermediate(message) {
|
|
710
|
+
if (!isContentBlockArray(message.content) || message.content.length === 0) return null;
|
|
711
|
+
const meta = isRecord(message.meta) ? message.meta : {};
|
|
712
|
+
return {
|
|
713
|
+
id: message.id,
|
|
714
|
+
sessionId: message.sessionId,
|
|
715
|
+
role: message.role,
|
|
716
|
+
messageId: typeof meta.streamMessageId === "string" ? meta.streamMessageId : message.id ?? null,
|
|
717
|
+
messageOrdinal: typeof meta.messageOrdinal === "number" ? meta.messageOrdinal : null,
|
|
718
|
+
content: message.content,
|
|
719
|
+
text: message.text,
|
|
720
|
+
provider: message.provider,
|
|
721
|
+
model: message.model,
|
|
722
|
+
stopReason: message.stopReason,
|
|
723
|
+
errorMessage: message.errorMessage,
|
|
724
|
+
usage: message.usage,
|
|
725
|
+
meta: message.meta,
|
|
726
|
+
createdAt: message.createdAt
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
function resolveStreamMessageId(input) {
|
|
730
|
+
if (input.messageId?.trim()) return input.messageId.trim();
|
|
731
|
+
if (input.messageOrdinal == null) return null;
|
|
732
|
+
if (input.turnId?.trim()) return `turn:${input.turnId.trim()}:assistant:${input.messageOrdinal}`;
|
|
733
|
+
return `session:${input.sessionId}:assistant:${input.messageOrdinal}:${input.anchorUserMessageId ?? "unknown"}`;
|
|
734
|
+
}
|
|
735
|
+
function getTurnIdFromMessage(message) {
|
|
736
|
+
const turnId = message.meta?.turnId;
|
|
737
|
+
return typeof turnId === "string" ? turnId : null;
|
|
738
|
+
}
|
|
739
|
+
var SessionGenerationStreamClient = class SessionGenerationStreamClient {
|
|
740
|
+
websocketClient;
|
|
741
|
+
spaceId;
|
|
742
|
+
sessionId;
|
|
743
|
+
reducer = new SessionPatchReducer();
|
|
744
|
+
messageId = null;
|
|
745
|
+
messageOrdinal = null;
|
|
746
|
+
intermediateMessages = [];
|
|
747
|
+
progressState = null;
|
|
748
|
+
constructor(websocketClient, spaceId, sessionId) {
|
|
749
|
+
this.websocketClient = websocketClient;
|
|
750
|
+
this.spaceId = spaceId;
|
|
751
|
+
this.sessionId = sessionId;
|
|
752
|
+
}
|
|
753
|
+
subscribe(handlers) {
|
|
754
|
+
if (!this.websocketClient) throw new Error("realtime transport is not configured for this client");
|
|
755
|
+
ensureRealtimeConnected(this.websocketClient);
|
|
756
|
+
const stream = new SessionGenerationStreamClient(this.websocketClient, this.spaceId, this.sessionId);
|
|
757
|
+
const unsubscribe = this.websocketClient.on("event", (event) => {
|
|
758
|
+
if (event.spaceId !== this.spaceId || event.sessionId !== this.sessionId) return;
|
|
759
|
+
stream.handleEvent(event, handlers);
|
|
760
|
+
});
|
|
761
|
+
return () => unsubscribe();
|
|
762
|
+
}
|
|
763
|
+
emit(handlers, event) {
|
|
764
|
+
handlers.event?.(event);
|
|
765
|
+
if (event.type === "state") handlers.state?.(event);
|
|
766
|
+
if (event.type === "commit") handlers.commit?.(event);
|
|
767
|
+
if (event.type === "finalized") handlers.finalized?.(event);
|
|
768
|
+
if (event.type === "turn_updated") handlers.turnUpdated?.(event);
|
|
769
|
+
if (event.type === "error") handlers.error?.(event);
|
|
770
|
+
if (event.type === "out_of_sync") handlers.outOfSync?.(event);
|
|
771
|
+
}
|
|
772
|
+
resetCurrentMessage() {
|
|
773
|
+
this.messageId = null;
|
|
774
|
+
this.messageOrdinal = null;
|
|
775
|
+
this.progressState = null;
|
|
776
|
+
}
|
|
777
|
+
appendCurrentMessage(state) {
|
|
778
|
+
if (state.contentBlocks.length === 0) return;
|
|
779
|
+
this.addIntermediateMessage({
|
|
780
|
+
messageId: this.messageId,
|
|
781
|
+
messageOrdinal: this.messageOrdinal,
|
|
782
|
+
content: state.contentBlocks
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
addIntermediateMessage(message) {
|
|
786
|
+
const index = this.intermediateMessages.findIndex((existing) => {
|
|
787
|
+
if (message.messageId && existing.messageId) return existing.messageId === message.messageId;
|
|
788
|
+
return message.messageOrdinal !== null && existing.messageOrdinal === message.messageOrdinal;
|
|
789
|
+
});
|
|
790
|
+
if (index < 0) {
|
|
791
|
+
this.intermediateMessages = [...this.intermediateMessages, message];
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
this.intermediateMessages = this.intermediateMessages.map((existing, i) => i === index ? {
|
|
795
|
+
...existing,
|
|
796
|
+
...message
|
|
797
|
+
} : existing);
|
|
798
|
+
}
|
|
799
|
+
handleAppliedState(handlers, source, result, rawEvent, messageId, messageOrdinal) {
|
|
800
|
+
if (!result.applied) {
|
|
801
|
+
this.emit(handlers, {
|
|
802
|
+
type: "out_of_sync",
|
|
803
|
+
source: source === "progress" ? "patch" : source,
|
|
804
|
+
reason: result.reason,
|
|
805
|
+
state: result.state,
|
|
806
|
+
rawEvent
|
|
807
|
+
});
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
810
|
+
this.progressState = result.state;
|
|
811
|
+
this.messageId = messageId;
|
|
812
|
+
this.messageOrdinal = messageOrdinal;
|
|
813
|
+
this.emit(handlers, {
|
|
814
|
+
type: "state",
|
|
815
|
+
source,
|
|
816
|
+
state: result.state,
|
|
817
|
+
messageId,
|
|
818
|
+
messageOrdinal,
|
|
819
|
+
intermediateMessages: [...this.intermediateMessages],
|
|
820
|
+
rawEvent
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
prepareMessageBoundary(input) {
|
|
824
|
+
const current = this.progressState ?? this.reducer.get({
|
|
825
|
+
spaceId: this.spaceId,
|
|
826
|
+
sessionId: this.sessionId
|
|
827
|
+
});
|
|
828
|
+
const nextMessageId = resolveStreamMessageId({
|
|
829
|
+
sessionId: this.sessionId,
|
|
830
|
+
turnId: input.turnId,
|
|
831
|
+
anchorUserMessageId: input.anchorUserMessageId,
|
|
832
|
+
messageId: input.messageId,
|
|
833
|
+
messageOrdinal: input.messageOrdinal
|
|
834
|
+
});
|
|
835
|
+
const differentTurn = Boolean(current.turnId && input.turnId && current.turnId !== input.turnId);
|
|
836
|
+
const messageChanged = Boolean(nextMessageId && current.contentBlocks.length > 0 && this.messageId && nextMessageId !== this.messageId);
|
|
837
|
+
if (differentTurn) {
|
|
838
|
+
this.intermediateMessages = [];
|
|
839
|
+
this.resetCurrentMessage();
|
|
840
|
+
this.reducer.start({
|
|
841
|
+
spaceId: this.spaceId,
|
|
842
|
+
sessionId: this.sessionId,
|
|
843
|
+
turnId: input.turnId
|
|
844
|
+
});
|
|
845
|
+
} else if (messageChanged) {
|
|
846
|
+
this.appendCurrentMessage(current);
|
|
847
|
+
this.resetCurrentMessage();
|
|
848
|
+
this.reducer.start({
|
|
849
|
+
spaceId: this.spaceId,
|
|
850
|
+
sessionId: this.sessionId,
|
|
851
|
+
turnId: input.turnId ?? current.turnId
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
return nextMessageId;
|
|
855
|
+
}
|
|
856
|
+
handleSnapshot(event, handlers) {
|
|
857
|
+
const payload = event.payload;
|
|
858
|
+
const current = isRecord(payload.current) ? payload.current : null;
|
|
859
|
+
const content = current ? current.content : null;
|
|
860
|
+
const seq = typeof payload.seq === "number" ? payload.seq : null;
|
|
861
|
+
if (!current || !isContentBlockArray(content) || seq === null) {
|
|
862
|
+
this.emit(handlers, {
|
|
863
|
+
type: "out_of_sync",
|
|
864
|
+
source: "snapshot",
|
|
865
|
+
reason: "invalid",
|
|
866
|
+
state: this.reducer.get({
|
|
867
|
+
spaceId: this.spaceId,
|
|
868
|
+
sessionId: this.sessionId
|
|
869
|
+
}),
|
|
870
|
+
rawEvent: event
|
|
871
|
+
});
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
const turnId = typeof payload.turnId === "string" ? payload.turnId : null;
|
|
875
|
+
const anchorUserMessageId = typeof payload.anchorUserMessageId === "string" ? payload.anchorUserMessageId : null;
|
|
876
|
+
const messageOrdinal = numberField(current, "messageOrdinal");
|
|
877
|
+
const messageId = this.prepareMessageBoundary({
|
|
878
|
+
turnId,
|
|
879
|
+
messageId: stringField(current, "messageId"),
|
|
880
|
+
messageOrdinal,
|
|
881
|
+
anchorUserMessageId
|
|
882
|
+
});
|
|
883
|
+
this.intermediateMessages = Array.isArray(payload.intermediateMessages) ? payload.intermediateMessages.map(parseSnapshotMessage).filter((message) => message !== null) : [];
|
|
884
|
+
const result = this.reducer.applySnapshot({
|
|
885
|
+
spaceId: this.spaceId,
|
|
886
|
+
sessionId: this.sessionId,
|
|
887
|
+
turnId,
|
|
888
|
+
seq,
|
|
889
|
+
contentBlocks: content,
|
|
890
|
+
anchorUserMessageId,
|
|
891
|
+
appendPath: stringField(current, "appendPath")
|
|
892
|
+
});
|
|
893
|
+
this.handleAppliedState(handlers, "snapshot", result, event, messageId, messageOrdinal);
|
|
894
|
+
}
|
|
895
|
+
handlePatch(event, handlers) {
|
|
896
|
+
const payload = event.payload;
|
|
897
|
+
const seq = typeof payload.seq === "number" ? payload.seq : null;
|
|
898
|
+
const baseSeq = typeof payload.baseSeq === "number" ? payload.baseSeq : null;
|
|
899
|
+
if (seq === null || baseSeq === null || !Array.isArray(payload.ops)) {
|
|
900
|
+
this.emit(handlers, {
|
|
901
|
+
type: "out_of_sync",
|
|
902
|
+
source: "patch",
|
|
903
|
+
reason: "invalid",
|
|
904
|
+
state: this.reducer.get({
|
|
905
|
+
spaceId: this.spaceId,
|
|
906
|
+
sessionId: this.sessionId
|
|
907
|
+
}),
|
|
908
|
+
rawEvent: event
|
|
909
|
+
});
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
const turnId = typeof payload.turnId === "string" ? payload.turnId : null;
|
|
913
|
+
const anchorUserMessageId = typeof payload.anchorUserMessageId === "string" ? payload.anchorUserMessageId : null;
|
|
914
|
+
const messageOrdinal = typeof payload.messageOrdinal === "number" ? payload.messageOrdinal : null;
|
|
915
|
+
const messageId = this.prepareMessageBoundary({
|
|
916
|
+
turnId,
|
|
917
|
+
messageId: typeof payload.messageId === "string" ? payload.messageId : null,
|
|
918
|
+
messageOrdinal,
|
|
919
|
+
anchorUserMessageId
|
|
920
|
+
});
|
|
921
|
+
const input = {
|
|
922
|
+
spaceId: this.spaceId,
|
|
923
|
+
sessionId: this.sessionId,
|
|
924
|
+
turnId,
|
|
925
|
+
seq,
|
|
926
|
+
baseSeq,
|
|
927
|
+
ops: payload.ops,
|
|
928
|
+
anchorUserMessageId
|
|
929
|
+
};
|
|
930
|
+
const result = this.reducer.applyPatch(input);
|
|
931
|
+
this.handleAppliedState(handlers, "patch", result, event, messageId, messageOrdinal);
|
|
932
|
+
}
|
|
933
|
+
handleProgress(event, handlers) {
|
|
934
|
+
const payload = event.payload;
|
|
935
|
+
if (!isContentBlockArray(payload.content)) return;
|
|
936
|
+
const current = this.progressState ?? this.reducer.get({
|
|
937
|
+
spaceId: this.spaceId,
|
|
938
|
+
sessionId: this.sessionId
|
|
939
|
+
});
|
|
940
|
+
const turnId = typeof payload.turnId === "string" ? payload.turnId : current.turnId;
|
|
941
|
+
const anchorUserMessageId = typeof payload.anchorUserMessageId === "string" ? payload.anchorUserMessageId : current.anchorUserMessageId;
|
|
942
|
+
const messageOrdinal = typeof payload.messageOrdinal === "number" ? payload.messageOrdinal : this.messageOrdinal;
|
|
943
|
+
const messageId = this.prepareMessageBoundary({
|
|
944
|
+
turnId,
|
|
945
|
+
messageId: typeof payload.messageId === "string" ? payload.messageId : this.messageId,
|
|
946
|
+
messageOrdinal,
|
|
947
|
+
anchorUserMessageId
|
|
948
|
+
});
|
|
949
|
+
const base = this.progressState?.turnId === turnId ? this.progressState : current;
|
|
950
|
+
const state = {
|
|
951
|
+
...base,
|
|
952
|
+
spaceId: this.spaceId,
|
|
953
|
+
sessionId: this.sessionId,
|
|
954
|
+
status: "streaming",
|
|
955
|
+
contentBlocks: mergeStreamingDeltaBlocks(base.contentBlocks, payload.content),
|
|
956
|
+
anchorUserMessageId,
|
|
957
|
+
turnId
|
|
958
|
+
};
|
|
959
|
+
this.progressState = state;
|
|
960
|
+
this.messageId = messageId;
|
|
961
|
+
this.messageOrdinal = messageOrdinal;
|
|
962
|
+
this.emit(handlers, {
|
|
963
|
+
type: "state",
|
|
964
|
+
source: "progress",
|
|
965
|
+
state,
|
|
966
|
+
messageId,
|
|
967
|
+
messageOrdinal,
|
|
968
|
+
intermediateMessages: [...this.intermediateMessages],
|
|
969
|
+
rawEvent: event
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
handlePersisted(event, handlers) {
|
|
973
|
+
const message = event.payload.message;
|
|
974
|
+
if (!isRecord(message)) return;
|
|
975
|
+
const commit = parseAssistantMessageCommit(message);
|
|
976
|
+
if (commit.kind === "intermediate") {
|
|
977
|
+
const intermediate = messageRecordToIntermediate(commit.message);
|
|
978
|
+
if (intermediate) this.addIntermediateMessage(intermediate);
|
|
979
|
+
this.reducer.reset({
|
|
980
|
+
spaceId: this.spaceId,
|
|
981
|
+
sessionId: this.sessionId
|
|
982
|
+
});
|
|
983
|
+
this.resetCurrentMessage();
|
|
984
|
+
}
|
|
985
|
+
if (commit.kind === "final") {
|
|
986
|
+
this.reducer.complete({
|
|
987
|
+
spaceId: this.spaceId,
|
|
988
|
+
sessionId: this.sessionId,
|
|
989
|
+
turnId: getTurnIdFromMessage(commit.message)
|
|
990
|
+
});
|
|
991
|
+
this.resetCurrentMessage();
|
|
992
|
+
}
|
|
993
|
+
if (commit.kind === "error") {
|
|
994
|
+
this.reducer.fail({
|
|
995
|
+
spaceId: this.spaceId,
|
|
996
|
+
sessionId: this.sessionId,
|
|
997
|
+
turnId: getTurnIdFromMessage(commit.message)
|
|
998
|
+
});
|
|
999
|
+
this.resetCurrentMessage();
|
|
1000
|
+
}
|
|
1001
|
+
this.emit(handlers, {
|
|
1002
|
+
type: "commit",
|
|
1003
|
+
commit,
|
|
1004
|
+
rawEvent: event
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
handleFinalized(event, handlers) {
|
|
1008
|
+
const turn = event.payload.turn;
|
|
1009
|
+
if (!isRecord(turn)) return;
|
|
1010
|
+
const typedTurn = turn;
|
|
1011
|
+
if (typedTurn.status === "interrupted") this.reducer.interrupt({
|
|
1012
|
+
spaceId: this.spaceId,
|
|
1013
|
+
sessionId: this.sessionId,
|
|
1014
|
+
turnId: typedTurn.id
|
|
1015
|
+
});
|
|
1016
|
+
else this.reducer.complete({
|
|
1017
|
+
spaceId: this.spaceId,
|
|
1018
|
+
sessionId: this.sessionId,
|
|
1019
|
+
turnId: typedTurn.id
|
|
1020
|
+
});
|
|
1021
|
+
this.resetCurrentMessage();
|
|
1022
|
+
this.emit(handlers, {
|
|
1023
|
+
type: "finalized",
|
|
1024
|
+
turn: typedTurn,
|
|
1025
|
+
rawEvent: event
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
handleEvent(event, handlers) {
|
|
1029
|
+
switch (event.type) {
|
|
1030
|
+
case "session.turn.snapshot":
|
|
1031
|
+
this.handleSnapshot(event, handlers);
|
|
1032
|
+
return;
|
|
1033
|
+
case "session.turn.patch":
|
|
1034
|
+
this.handlePatch(event, handlers);
|
|
1035
|
+
return;
|
|
1036
|
+
case "session.turn.progress":
|
|
1037
|
+
this.handleProgress(event, handlers);
|
|
1038
|
+
return;
|
|
1039
|
+
case "session.message.persisted":
|
|
1040
|
+
this.handlePersisted(event, handlers);
|
|
1041
|
+
return;
|
|
1042
|
+
case "session.turn.finalized":
|
|
1043
|
+
this.handleFinalized(event, handlers);
|
|
1044
|
+
return;
|
|
1045
|
+
case "session.turn.updated": {
|
|
1046
|
+
const turn = event.payload.turn;
|
|
1047
|
+
if (!isRecord(turn)) return;
|
|
1048
|
+
this.emit(handlers, {
|
|
1049
|
+
type: "turn_updated",
|
|
1050
|
+
turn,
|
|
1051
|
+
rawEvent: event
|
|
1052
|
+
});
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
case "session.turn.error": {
|
|
1056
|
+
const message = typeof event.payload.error === "string" && event.payload.error.trim() ? event.payload.error.trim() : "Generation failed";
|
|
1057
|
+
this.reducer.fail({
|
|
1058
|
+
spaceId: this.spaceId,
|
|
1059
|
+
sessionId: this.sessionId
|
|
1060
|
+
});
|
|
1061
|
+
this.resetCurrentMessage();
|
|
1062
|
+
this.emit(handlers, {
|
|
1063
|
+
type: "error",
|
|
1064
|
+
message,
|
|
1065
|
+
rawEvent: event
|
|
1066
|
+
});
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
default: return;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
function createSessionGenerationStreamClient(input) {
|
|
1074
|
+
return new SessionGenerationStreamClient(input.websocketClient, input.spaceId, input.sessionId);
|
|
1075
|
+
}
|
|
1076
|
+
//#endregion
|
|
1077
|
+
//#region src/apis/invitations.ts
|
|
1078
|
+
var SpaceInvitationsApi = class {
|
|
1079
|
+
transport;
|
|
1080
|
+
spaceId;
|
|
1081
|
+
constructor(transport, spaceId) {
|
|
1082
|
+
this.transport = transport;
|
|
1083
|
+
this.spaceId = spaceId;
|
|
1084
|
+
}
|
|
1085
|
+
list() {
|
|
1086
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/invitations`);
|
|
1087
|
+
}
|
|
1088
|
+
create(input) {
|
|
1089
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/invitations`, {
|
|
1090
|
+
method: "POST",
|
|
1091
|
+
headers: { "Content-Type": "application/json" },
|
|
1092
|
+
body: JSON.stringify(input ?? {})
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1095
|
+
revoke(token) {
|
|
1096
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/invitations/${token}`, { method: "DELETE" });
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
var PublicInviteApi = class {
|
|
1100
|
+
transport;
|
|
1101
|
+
constructor(transport) {
|
|
1102
|
+
this.transport = transport;
|
|
1103
|
+
}
|
|
1104
|
+
get(token) {
|
|
1105
|
+
return this.transport.request(`/api/invite/${token}`);
|
|
1106
|
+
}
|
|
1107
|
+
accept(token) {
|
|
1108
|
+
return this.transport.request(`/api/invite/${token}/accept`, { method: "POST" });
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
//#endregion
|
|
1112
|
+
//#region src/apis/spaces.ts
|
|
1113
|
+
const DEFAULT_DEDUP_WINDOW_MS = 2e3;
|
|
1114
|
+
const getFilenameFromContentDisposition = (value) => {
|
|
1115
|
+
if (!value) return null;
|
|
1116
|
+
const encodedMatch = value.match(/filename\*=UTF-8''([^;]+)/i);
|
|
1117
|
+
if (encodedMatch?.[1]) try {
|
|
1118
|
+
return decodeURIComponent(encodedMatch[1]);
|
|
1119
|
+
} catch {
|
|
1120
|
+
return encodedMatch[1];
|
|
1121
|
+
}
|
|
1122
|
+
return value.match(/filename="?([^";]+)"?/i)?.[1] ?? null;
|
|
1123
|
+
};
|
|
1124
|
+
const toSessionEventName = (type) => {
|
|
1125
|
+
switch (type) {
|
|
1126
|
+
case "session.turn.patch": return "turn.patch";
|
|
1127
|
+
case "session.turn.snapshot": return "turn.snapshot";
|
|
1128
|
+
case "session.turn.progress": return "turn.progress";
|
|
1129
|
+
case "session.turn.error": return "turn.error";
|
|
1130
|
+
case "session.turn.updated": return "turn.updated";
|
|
1131
|
+
case "session.turn.finalized": return "turn.final";
|
|
1132
|
+
case "session.message.persisted": return "message.persisted";
|
|
1133
|
+
default: return null;
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1136
|
+
const isAssistantFinalPersistedEvent = (event) => {
|
|
1137
|
+
if (event.type !== "session.message.persisted") return false;
|
|
1138
|
+
const message = event.payload.message;
|
|
1139
|
+
if (!message || typeof message !== "object") return false;
|
|
1140
|
+
const record = message;
|
|
1141
|
+
return record.role === "assistant" && (record.meta?.messageKind === "assistant_final" || record.meta?.messageKind === "assistant_error");
|
|
1142
|
+
};
|
|
1143
|
+
const isAssistantIntermediatePersistedEvent = (event) => {
|
|
1144
|
+
if (event.type !== "session.message.persisted") return false;
|
|
1145
|
+
const message = event.payload.message;
|
|
1146
|
+
if (!message || typeof message !== "object") return false;
|
|
1147
|
+
const record = message;
|
|
1148
|
+
return record.role === "assistant" && record.meta?.messageKind === "assistant_intermediate";
|
|
1149
|
+
};
|
|
1150
|
+
const getPersistedMessageTurnId = (event) => {
|
|
1151
|
+
if (event.type !== "session.message.persisted") return null;
|
|
1152
|
+
const message = event.payload.message;
|
|
1153
|
+
if (!message || typeof message !== "object") return null;
|
|
1154
|
+
const meta = message.meta;
|
|
1155
|
+
return typeof meta?.turnId === "string" ? meta.turnId : null;
|
|
1156
|
+
};
|
|
1157
|
+
var SpacesApi = class {
|
|
1158
|
+
transport;
|
|
1159
|
+
constructor(transport) {
|
|
1160
|
+
this.transport = transport;
|
|
1161
|
+
}
|
|
1162
|
+
list(customFetch) {
|
|
1163
|
+
return this.transport.request("/api/spaces", {
|
|
1164
|
+
method: "GET",
|
|
1165
|
+
fetch: customFetch
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
get(spaceId, customFetch) {
|
|
1169
|
+
return this.transport.request(`/api/spaces/${spaceId}`, { fetch: customFetch });
|
|
1170
|
+
}
|
|
1171
|
+
create(input, headers) {
|
|
1172
|
+
return this.transport.request("/api/spaces", {
|
|
1173
|
+
method: "POST",
|
|
1174
|
+
headers: {
|
|
1175
|
+
...headers,
|
|
1176
|
+
"Content-Type": "application/json"
|
|
1177
|
+
},
|
|
1178
|
+
body: JSON.stringify(input ?? {})
|
|
1179
|
+
});
|
|
1180
|
+
}
|
|
1181
|
+
};
|
|
1182
|
+
var SpaceFilesApi = class {
|
|
1183
|
+
transport;
|
|
1184
|
+
spaceId;
|
|
1185
|
+
constructor(transport, spaceId) {
|
|
1186
|
+
this.transport = transport;
|
|
1187
|
+
this.spaceId = spaceId;
|
|
1188
|
+
}
|
|
1189
|
+
list(path = "", customFetch) {
|
|
1190
|
+
const params = new URLSearchParams();
|
|
1191
|
+
if (path) params.set("path", path);
|
|
1192
|
+
const query = params.toString();
|
|
1193
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/tree${query ? `?${query}` : ""}`, { fetch: customFetch });
|
|
1194
|
+
}
|
|
1195
|
+
read(path, customFetch) {
|
|
1196
|
+
const params = new URLSearchParams({ path });
|
|
1197
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/file?${params.toString()}`, { fetch: customFetch });
|
|
1198
|
+
}
|
|
1199
|
+
readMany(paths, customFetch) {
|
|
1200
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/files`, {
|
|
1201
|
+
method: "POST",
|
|
1202
|
+
headers: { "Content-Type": "application/json" },
|
|
1203
|
+
body: JSON.stringify({ paths }),
|
|
1204
|
+
fetch: customFetch
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
/**
|
|
1208
|
+
* Build a direct download URL. For private files, prefer `download()` so the
|
|
1209
|
+
* SDK can attach authorization headers.
|
|
1210
|
+
*/
|
|
1211
|
+
getDownloadUrl(path) {
|
|
1212
|
+
const params = new URLSearchParams({ path });
|
|
1213
|
+
return `/api/spaces/${this.spaceId}/fs/download?${params.toString()}`;
|
|
1214
|
+
}
|
|
1215
|
+
async download(path, customFetch) {
|
|
1216
|
+
const params = new URLSearchParams({ path });
|
|
1217
|
+
const raw = await this.transport.raw(`/api/spaces/${this.spaceId}/fs/download?${params.toString()}`, { fetch: customFetch });
|
|
1218
|
+
if (raw.response.status === 202) throw new HttpError("File is being prepared. Please retry shortly.", 202, await raw.json().catch(() => null));
|
|
1219
|
+
const blob = await raw.blob();
|
|
1220
|
+
return {
|
|
1221
|
+
blob,
|
|
1222
|
+
filename: getFilenameFromContentDisposition(raw.response.headers.get("content-disposition")) ?? path.split("/").pop() ?? "download",
|
|
1223
|
+
mimeType: raw.response.headers.get("content-type") ?? blob.type ?? "application/octet-stream"
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
write(input) {
|
|
1227
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/file`, {
|
|
1228
|
+
method: "PUT",
|
|
1229
|
+
headers: { "Content-Type": "application/json" },
|
|
1230
|
+
body: JSON.stringify(input)
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
createDir(path) {
|
|
1234
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/dir`, {
|
|
1235
|
+
method: "POST",
|
|
1236
|
+
headers: { "Content-Type": "application/json" },
|
|
1237
|
+
body: JSON.stringify({ path })
|
|
1238
|
+
});
|
|
1239
|
+
}
|
|
1240
|
+
delete(path, recursive = false) {
|
|
1241
|
+
const params = new URLSearchParams({ path });
|
|
1242
|
+
if (recursive) params.set("recursive", "true");
|
|
1243
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/node?${params.toString()}`, { method: "DELETE" });
|
|
1244
|
+
}
|
|
1245
|
+
move(input) {
|
|
1246
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/move`, {
|
|
1247
|
+
method: "POST",
|
|
1248
|
+
headers: { "Content-Type": "application/json" },
|
|
1249
|
+
body: JSON.stringify(input)
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
upload(files, dir = "") {
|
|
1253
|
+
const params = new URLSearchParams();
|
|
1254
|
+
if (dir) params.set("dir", dir);
|
|
1255
|
+
const query = params.toString();
|
|
1256
|
+
const formData = new FormData();
|
|
1257
|
+
for (const file of files) formData.append("files", file);
|
|
1258
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/upload${query ? `?${query}` : ""}`, {
|
|
1259
|
+
method: "POST",
|
|
1260
|
+
body: formData
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
createUpload(input) {
|
|
1264
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/uploads`, {
|
|
1265
|
+
method: "POST",
|
|
1266
|
+
headers: { "Content-Type": "application/json" },
|
|
1267
|
+
body: JSON.stringify(input)
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
completeUpload(uploadId, input) {
|
|
1271
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/uploads/${uploadId}/complete`, {
|
|
1272
|
+
method: "POST",
|
|
1273
|
+
headers: { "Content-Type": "application/json" },
|
|
1274
|
+
body: JSON.stringify(input)
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
};
|
|
1278
|
+
var SessionMessagesClient = class {
|
|
1279
|
+
transport;
|
|
1280
|
+
sessionId;
|
|
1281
|
+
lastSentSignature = "";
|
|
1282
|
+
lastSentSessionId = "";
|
|
1283
|
+
lastSentAt = 0;
|
|
1284
|
+
constructor(transport, sessionId) {
|
|
1285
|
+
this.transport = transport;
|
|
1286
|
+
this.sessionId = sessionId;
|
|
1287
|
+
}
|
|
1288
|
+
list(customFetch) {
|
|
1289
|
+
return this.transport.request(`/api/sessions/${this.sessionId}/messages`, { fetch: customFetch });
|
|
1290
|
+
}
|
|
1291
|
+
get(messageId, optionsOrFetch, customFetch) {
|
|
1292
|
+
const options = typeof optionsOrFetch === "function" ? void 0 : optionsOrFetch;
|
|
1293
|
+
const fetch = typeof optionsOrFetch === "function" ? optionsOrFetch : customFetch;
|
|
1294
|
+
const params = new URLSearchParams();
|
|
1295
|
+
if (options?.detail) params.set("detail", options.detail);
|
|
1296
|
+
const query = params.toString();
|
|
1297
|
+
return this.transport.request(`/api/sessions/${this.sessionId}/messages/${messageId}${query ? `?${query}` : ""}`, { fetch });
|
|
1298
|
+
}
|
|
1299
|
+
listPaginated(options, customFetch) {
|
|
1300
|
+
const params = new URLSearchParams();
|
|
1301
|
+
if (options?.cursor !== void 0) params.set("cursor", String(options.cursor));
|
|
1302
|
+
if (options?.limit !== void 0) params.set("limit", String(options.limit));
|
|
1303
|
+
if (options?.direction) params.set("direction", options.direction);
|
|
1304
|
+
const query = params.toString();
|
|
1305
|
+
return this.transport.request(`/api/sessions/${this.sessionId}/messages${query ? `?${query}` : ""}`, { fetch: customFetch });
|
|
1306
|
+
}
|
|
1307
|
+
async send(input) {
|
|
1308
|
+
const signature = JSON.stringify({
|
|
1309
|
+
sessionId: this.sessionId,
|
|
1310
|
+
input
|
|
1311
|
+
});
|
|
1312
|
+
const now = Date.now();
|
|
1313
|
+
if (this.sessionId === this.lastSentSessionId && signature === this.lastSentSignature && now - this.lastSentAt < DEFAULT_DEDUP_WINDOW_MS) throw new Error("Duplicate message ignored");
|
|
1314
|
+
this.lastSentSessionId = this.sessionId;
|
|
1315
|
+
this.lastSentSignature = signature;
|
|
1316
|
+
this.lastSentAt = now;
|
|
1317
|
+
return this.transport.request(`/api/sessions/${this.sessionId}/messages`, {
|
|
1318
|
+
method: "POST",
|
|
1319
|
+
headers: { "Content-Type": "application/json" },
|
|
1320
|
+
body: JSON.stringify({
|
|
1321
|
+
content: input.content,
|
|
1322
|
+
model: input.model,
|
|
1323
|
+
provider: input.provider,
|
|
1324
|
+
clientMessageId: input.clientMessageId
|
|
1325
|
+
})
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
var SessionTurnsClient = class {
|
|
1330
|
+
transport;
|
|
1331
|
+
sessionId;
|
|
1332
|
+
constructor(transport, sessionId) {
|
|
1333
|
+
this.transport = transport;
|
|
1334
|
+
this.sessionId = sessionId;
|
|
1335
|
+
}
|
|
1336
|
+
listPaginated(options, customFetch) {
|
|
1337
|
+
const params = new URLSearchParams();
|
|
1338
|
+
if (options?.cursor !== void 0) params.set("cursor", String(options.cursor));
|
|
1339
|
+
if (options?.limit !== void 0) params.set("limit", String(options.limit));
|
|
1340
|
+
if (options?.direction) params.set("direction", options.direction);
|
|
1341
|
+
const query = params.toString();
|
|
1342
|
+
return this.transport.request(`/api/sessions/${this.sessionId}/turns${query ? `?${query}` : ""}`, { fetch: customFetch });
|
|
1343
|
+
}
|
|
1344
|
+
index(options, customFetch) {
|
|
1345
|
+
const params = new URLSearchParams();
|
|
1346
|
+
if (options?.cursor !== void 0) params.set("cursor", String(options.cursor));
|
|
1347
|
+
if (options?.limit !== void 0) params.set("limit", String(options.limit));
|
|
1348
|
+
const query = params.toString();
|
|
1349
|
+
return this.transport.request(`/api/sessions/${this.sessionId}/turns/index${query ? `?${query}` : ""}`, { fetch: customFetch });
|
|
1350
|
+
}
|
|
1351
|
+
window(options, customFetch) {
|
|
1352
|
+
const params = new URLSearchParams();
|
|
1353
|
+
if (options.sequence !== void 0) params.set("sequence", String(options.sequence));
|
|
1354
|
+
if (options.turnId) params.set("turnId", options.turnId);
|
|
1355
|
+
if (options.before !== void 0) params.set("before", String(options.before));
|
|
1356
|
+
if (options.after !== void 0) params.set("after", String(options.after));
|
|
1357
|
+
const query = params.toString();
|
|
1358
|
+
return this.transport.request(`/api/sessions/${this.sessionId}/turns/window${query ? `?${query}` : ""}`, { fetch: customFetch });
|
|
1359
|
+
}
|
|
1360
|
+
streamSnapshot(customFetch) {
|
|
1361
|
+
return this.transport.request(`/api/sessions/${this.sessionId}/turns/stream-snapshot`, { fetch: customFetch });
|
|
1362
|
+
}
|
|
1363
|
+
get(turnId, customFetch) {
|
|
1364
|
+
return this.transport.request(`/api/sessions/${this.sessionId}/turns/${turnId}`, { fetch: customFetch });
|
|
1365
|
+
}
|
|
1366
|
+
signedUrls(turnId, objectKeys) {
|
|
1367
|
+
return this.transport.request(`/api/sessions/${this.sessionId}/turns/${turnId}/signed-urls`, {
|
|
1368
|
+
method: "POST",
|
|
1369
|
+
headers: { "Content-Type": "application/json" },
|
|
1370
|
+
body: JSON.stringify({ objectKeys })
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
var SessionRealtimeClient = class {
|
|
1375
|
+
websocketClient;
|
|
1376
|
+
spaceId;
|
|
1377
|
+
sessionId;
|
|
1378
|
+
patchReducer = new SessionPatchReducer();
|
|
1379
|
+
constructor(websocketClient, spaceId, sessionId) {
|
|
1380
|
+
this.websocketClient = websocketClient;
|
|
1381
|
+
this.spaceId = spaceId;
|
|
1382
|
+
this.sessionId = sessionId;
|
|
1383
|
+
}
|
|
1384
|
+
subscribe(handlers) {
|
|
1385
|
+
if (!this.websocketClient) throw new Error("realtime transport is not configured for this client");
|
|
1386
|
+
ensureRealtimeConnected(this.websocketClient);
|
|
1387
|
+
const unsubscribe = this.websocketClient.on("event", (event) => {
|
|
1388
|
+
if (event.spaceId !== this.spaceId || event.sessionId !== this.sessionId) return;
|
|
1389
|
+
handlers.event?.(event);
|
|
1390
|
+
const eventName = toSessionEventName(event.type);
|
|
1391
|
+
if (eventName === "turn.patch") {
|
|
1392
|
+
handlers.patch?.(event);
|
|
1393
|
+
if (event.type === "session.turn.patch") {
|
|
1394
|
+
const payload = event.payload;
|
|
1395
|
+
if (typeof payload.seq === "number" && typeof payload.baseSeq === "number" && Array.isArray(payload.ops)) handlers.patchState?.(this.patchReducer.applyPatch({
|
|
1396
|
+
spaceId: this.spaceId,
|
|
1397
|
+
sessionId: this.sessionId,
|
|
1398
|
+
turnId: typeof payload.turnId === "string" ? payload.turnId : null,
|
|
1399
|
+
seq: payload.seq,
|
|
1400
|
+
baseSeq: payload.baseSeq,
|
|
1401
|
+
ops: payload.ops,
|
|
1402
|
+
anchorUserMessageId: typeof payload.anchorUserMessageId === "string" ? payload.anchorUserMessageId : null
|
|
1403
|
+
}));
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
if (eventName === "turn.snapshot") handlers.snapshot?.(event);
|
|
1407
|
+
if (eventName === "turn.progress") handlers.progress?.(event);
|
|
1408
|
+
if (eventName === "turn.error") {
|
|
1409
|
+
this.patchReducer.fail({
|
|
1410
|
+
spaceId: this.spaceId,
|
|
1411
|
+
sessionId: this.sessionId
|
|
1412
|
+
});
|
|
1413
|
+
handlers.error?.(event);
|
|
1414
|
+
}
|
|
1415
|
+
if (eventName === "message.persisted") {
|
|
1416
|
+
handlers.persisted?.(event);
|
|
1417
|
+
if (isAssistantIntermediatePersistedEvent(event)) this.patchReducer.reset({
|
|
1418
|
+
spaceId: this.spaceId,
|
|
1419
|
+
sessionId: this.sessionId
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
if (eventName === "turn.updated") handlers.turnUpdated?.(event);
|
|
1423
|
+
if (eventName === "turn.final") {
|
|
1424
|
+
this.patchReducer.complete({
|
|
1425
|
+
spaceId: this.spaceId,
|
|
1426
|
+
sessionId: this.sessionId,
|
|
1427
|
+
turnId: typeof event.payload.turn === "object" && event.payload.turn && "id" in event.payload.turn ? String(event.payload.turn.id) : null
|
|
1428
|
+
});
|
|
1429
|
+
handlers.turnFinalized?.(event);
|
|
1430
|
+
handlers.final?.(event);
|
|
1431
|
+
}
|
|
1432
|
+
if (isAssistantFinalPersistedEvent(event)) {
|
|
1433
|
+
this.patchReducer.complete({
|
|
1434
|
+
spaceId: this.spaceId,
|
|
1435
|
+
sessionId: this.sessionId,
|
|
1436
|
+
turnId: getPersistedMessageTurnId(event)
|
|
1437
|
+
});
|
|
1438
|
+
handlers.final?.(event);
|
|
1439
|
+
}
|
|
1440
|
+
});
|
|
1441
|
+
return () => unsubscribe();
|
|
1442
|
+
}
|
|
1443
|
+
on(type, handler) {
|
|
1444
|
+
return this.subscribe({ event: (event) => {
|
|
1445
|
+
if (type === "turn.final" && isAssistantFinalPersistedEvent(event)) {
|
|
1446
|
+
handler(event);
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
if (toSessionEventName(event.type) === type) handler(event);
|
|
1450
|
+
} });
|
|
1451
|
+
}
|
|
1452
|
+
};
|
|
1453
|
+
var SessionClient = class {
|
|
1454
|
+
spaceId;
|
|
1455
|
+
id;
|
|
1456
|
+
transport;
|
|
1457
|
+
messages;
|
|
1458
|
+
turns;
|
|
1459
|
+
realtime;
|
|
1460
|
+
generation;
|
|
1461
|
+
constructor(spaceId, id, transport, websocketClient) {
|
|
1462
|
+
this.spaceId = spaceId;
|
|
1463
|
+
this.id = id;
|
|
1464
|
+
this.transport = transport;
|
|
1465
|
+
this.messages = new SessionMessagesClient(transport, id);
|
|
1466
|
+
this.turns = new SessionTurnsClient(transport, id);
|
|
1467
|
+
this.realtime = new SessionRealtimeClient(websocketClient, spaceId, id);
|
|
1468
|
+
this.generation = new SessionGenerationStreamClient(websocketClient, spaceId, id);
|
|
1469
|
+
}
|
|
1470
|
+
get(customFetch) {
|
|
1471
|
+
return this.transport.request(`/api/sessions/${this.id}`, { fetch: customFetch });
|
|
1472
|
+
}
|
|
1473
|
+
rename(title, customFetch) {
|
|
1474
|
+
return this.transport.request(`/api/sessions/${this.id}`, {
|
|
1475
|
+
method: "PATCH",
|
|
1476
|
+
body: JSON.stringify({ title }),
|
|
1477
|
+
fetch: customFetch
|
|
1478
|
+
});
|
|
1479
|
+
}
|
|
1480
|
+
abort(optionsOrFetch, customFetch) {
|
|
1481
|
+
const options = typeof optionsOrFetch === "function" ? void 0 : optionsOrFetch;
|
|
1482
|
+
const fetch = typeof optionsOrFetch === "function" ? optionsOrFetch : customFetch;
|
|
1483
|
+
return this.transport.request(`/api/sessions/${this.id}/abort`, {
|
|
1484
|
+
method: "POST",
|
|
1485
|
+
headers: { "Content-Type": "application/json" },
|
|
1486
|
+
body: JSON.stringify({ turnId: options?.turnId ?? null }),
|
|
1487
|
+
fetch
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
turn(turnId) {
|
|
1491
|
+
return { fork: (input = {}) => this.transport.request(`/api/sessions/${this.id}/turns/${turnId}/fork`, {
|
|
1492
|
+
method: "POST",
|
|
1493
|
+
headers: { "Content-Type": "application/json" },
|
|
1494
|
+
body: JSON.stringify(input)
|
|
1495
|
+
}) };
|
|
1496
|
+
}
|
|
1497
|
+
subscribe(handlers) {
|
|
1498
|
+
return this.realtime.subscribe(handlers);
|
|
1499
|
+
}
|
|
1500
|
+
subscribeGeneration(handlers) {
|
|
1501
|
+
return this.generation.subscribe(handlers);
|
|
1502
|
+
}
|
|
1503
|
+
on(type, handler) {
|
|
1504
|
+
return this.realtime.on(type, handler);
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
var SpaceSessionsApi = class {
|
|
1508
|
+
transport;
|
|
1509
|
+
spaceId;
|
|
1510
|
+
websocketClient;
|
|
1511
|
+
constructor(transport, spaceId, websocketClient) {
|
|
1512
|
+
this.transport = transport;
|
|
1513
|
+
this.spaceId = spaceId;
|
|
1514
|
+
this.websocketClient = websocketClient;
|
|
1515
|
+
}
|
|
1516
|
+
create(input) {
|
|
1517
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/sessions`, {
|
|
1518
|
+
method: "POST",
|
|
1519
|
+
headers: { "Content-Type": "application/json" },
|
|
1520
|
+
body: JSON.stringify(input ?? {})
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
list(optionsOrFetch, customFetch) {
|
|
1524
|
+
const options = typeof optionsOrFetch === "function" ? void 0 : optionsOrFetch;
|
|
1525
|
+
const fetch = typeof optionsOrFetch === "function" ? optionsOrFetch : customFetch;
|
|
1526
|
+
const params = new URLSearchParams();
|
|
1527
|
+
if (options?.limit !== void 0) params.set("limit", String(options.limit));
|
|
1528
|
+
if (options?.cursor) params.set("cursor", options.cursor);
|
|
1529
|
+
if (options?.includeForks) params.set("includeForks", "1");
|
|
1530
|
+
const query = params.toString();
|
|
1531
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/sessions${query ? `?${query}` : ""}`, { fetch });
|
|
1532
|
+
}
|
|
1533
|
+
byId(sessionId) {
|
|
1534
|
+
return new SessionClient(this.spaceId, sessionId, this.transport, this.websocketClient);
|
|
1535
|
+
}
|
|
1536
|
+
};
|
|
1537
|
+
var SpaceEventsApi = class {
|
|
1538
|
+
websocketClient;
|
|
1539
|
+
spaceId;
|
|
1540
|
+
constructor(websocketClient, spaceId) {
|
|
1541
|
+
this.websocketClient = websocketClient;
|
|
1542
|
+
this.spaceId = spaceId;
|
|
1543
|
+
}
|
|
1544
|
+
subscribe(handler) {
|
|
1545
|
+
if (!this.websocketClient) throw new Error("realtime transport is not configured for this client");
|
|
1546
|
+
ensureRealtimeConnected(this.websocketClient);
|
|
1547
|
+
return this.websocketClient.on("event", (event) => {
|
|
1548
|
+
if (event.spaceId !== this.spaceId) return;
|
|
1549
|
+
handler(event);
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
on(type, handler) {
|
|
1553
|
+
return this.subscribe((event) => {
|
|
1554
|
+
if (type === "event") {
|
|
1555
|
+
handler(event);
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
if (type === "ports.changed" && event.type === "space.ports.changed") {
|
|
1559
|
+
handler(event);
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
if (type === "turn.final" && isAssistantFinalPersistedEvent(event)) {
|
|
1563
|
+
handler(event);
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
if (toSessionEventName(event.type) === type) handler(event);
|
|
1567
|
+
});
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
var SpaceMembersApi = class {
|
|
1571
|
+
transport;
|
|
1572
|
+
spaceId;
|
|
1573
|
+
constructor(transport, spaceId) {
|
|
1574
|
+
this.transport = transport;
|
|
1575
|
+
this.spaceId = spaceId;
|
|
1576
|
+
}
|
|
1577
|
+
list() {
|
|
1578
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/members`);
|
|
1579
|
+
}
|
|
1580
|
+
update(userId, role) {
|
|
1581
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/members`, {
|
|
1582
|
+
method: "PUT",
|
|
1583
|
+
headers: { "Content-Type": "application/json" },
|
|
1584
|
+
body: JSON.stringify({
|
|
1585
|
+
userId,
|
|
1586
|
+
role
|
|
1587
|
+
})
|
|
1588
|
+
});
|
|
1589
|
+
}
|
|
1590
|
+
remove(userId) {
|
|
1591
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/members`, {
|
|
1592
|
+
method: "DELETE",
|
|
1593
|
+
headers: { "Content-Type": "application/json" },
|
|
1594
|
+
body: JSON.stringify({ userId })
|
|
1595
|
+
});
|
|
1596
|
+
}
|
|
1597
|
+
};
|
|
1598
|
+
var SpaceAccessApi = class {
|
|
1599
|
+
transport;
|
|
1600
|
+
spaceId;
|
|
1601
|
+
constructor(transport, spaceId) {
|
|
1602
|
+
this.transport = transport;
|
|
1603
|
+
this.spaceId = spaceId;
|
|
1604
|
+
}
|
|
1605
|
+
get() {
|
|
1606
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/access`);
|
|
1607
|
+
}
|
|
1608
|
+
set(body) {
|
|
1609
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/access`, {
|
|
1610
|
+
method: "PATCH",
|
|
1611
|
+
headers: { "Content-Type": "application/json" },
|
|
1612
|
+
body: JSON.stringify(body)
|
|
1613
|
+
});
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1616
|
+
var SpaceUsageApi = class {
|
|
1617
|
+
transport;
|
|
1618
|
+
spaceId;
|
|
1619
|
+
constructor(transport, spaceId) {
|
|
1620
|
+
this.transport = transport;
|
|
1621
|
+
this.spaceId = spaceId;
|
|
1622
|
+
}
|
|
1623
|
+
get(days = 30, customFetch) {
|
|
1624
|
+
const params = new URLSearchParams({ days: String(days) });
|
|
1625
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/usage?${params.toString()}`, { fetch: customFetch });
|
|
1626
|
+
}
|
|
1627
|
+
};
|
|
1628
|
+
var SpaceChannelsApi = class {
|
|
1629
|
+
transport;
|
|
1630
|
+
spaceId;
|
|
1631
|
+
constructor(transport, spaceId) {
|
|
1632
|
+
this.transport = transport;
|
|
1633
|
+
this.spaceId = spaceId;
|
|
1634
|
+
}
|
|
1635
|
+
list() {
|
|
1636
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/channels`);
|
|
1637
|
+
}
|
|
1638
|
+
bind(channelId, config) {
|
|
1639
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/channels/${channelId}`, {
|
|
1640
|
+
method: "POST",
|
|
1641
|
+
headers: { "Content-Type": "application/json" },
|
|
1642
|
+
body: JSON.stringify({ config: config ?? null })
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
unbind(channelId) {
|
|
1646
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/channels/${channelId}`, { method: "DELETE" });
|
|
1647
|
+
}
|
|
1648
|
+
};
|
|
1649
|
+
var SpaceEnvApi = class {
|
|
1650
|
+
transport;
|
|
1651
|
+
spaceId;
|
|
1652
|
+
constructor(transport, spaceId) {
|
|
1653
|
+
this.transport = transport;
|
|
1654
|
+
this.spaceId = spaceId;
|
|
1655
|
+
}
|
|
1656
|
+
list() {
|
|
1657
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/env`);
|
|
1658
|
+
}
|
|
1659
|
+
create(input) {
|
|
1660
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/env`, {
|
|
1661
|
+
method: "POST",
|
|
1662
|
+
headers: { "Content-Type": "application/json" },
|
|
1663
|
+
body: JSON.stringify(input)
|
|
1664
|
+
});
|
|
1665
|
+
}
|
|
1666
|
+
update(name, value) {
|
|
1667
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/env/${encodeURIComponent(name)}`, {
|
|
1668
|
+
method: "PUT",
|
|
1669
|
+
headers: { "Content-Type": "application/json" },
|
|
1670
|
+
body: JSON.stringify({ value })
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
remove(name) {
|
|
1674
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/env/${encodeURIComponent(name)}`, { method: "DELETE" });
|
|
1675
|
+
}
|
|
1676
|
+
};
|
|
1677
|
+
var SpaceSandboxApi = class {
|
|
1678
|
+
transport;
|
|
1679
|
+
spaceId;
|
|
1680
|
+
constructor(transport, spaceId) {
|
|
1681
|
+
this.transport = transport;
|
|
1682
|
+
this.spaceId = spaceId;
|
|
1683
|
+
}
|
|
1684
|
+
get() {
|
|
1685
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/sandbox`);
|
|
1686
|
+
}
|
|
1687
|
+
ports() {
|
|
1688
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/sandbox/ports`);
|
|
1689
|
+
}
|
|
1690
|
+
recreate() {
|
|
1691
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/sandbox/recreate`, { method: "POST" });
|
|
1692
|
+
}
|
|
1693
|
+
};
|
|
1694
|
+
var SpaceMarksApi = class {
|
|
1695
|
+
transport;
|
|
1696
|
+
spaceId;
|
|
1697
|
+
constructor(transport, spaceId) {
|
|
1698
|
+
this.transport = transport;
|
|
1699
|
+
this.spaceId = spaceId;
|
|
1700
|
+
}
|
|
1701
|
+
list(kind = "pin") {
|
|
1702
|
+
const params = new URLSearchParams({ kind });
|
|
1703
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/marks?${params.toString()}`);
|
|
1704
|
+
}
|
|
1705
|
+
create(input) {
|
|
1706
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/marks`, {
|
|
1707
|
+
method: "POST",
|
|
1708
|
+
headers: { "Content-Type": "application/json" },
|
|
1709
|
+
body: JSON.stringify({
|
|
1710
|
+
kind: "pin",
|
|
1711
|
+
...input
|
|
1712
|
+
})
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
delete(markId) {
|
|
1716
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/marks/${markId}`, { method: "DELETE" });
|
|
1717
|
+
}
|
|
1718
|
+
};
|
|
1719
|
+
var SpaceCheckpointsApi = class {
|
|
1720
|
+
transport;
|
|
1721
|
+
spaceId;
|
|
1722
|
+
constructor(transport, spaceId) {
|
|
1723
|
+
this.transport = transport;
|
|
1724
|
+
this.spaceId = spaceId;
|
|
1725
|
+
}
|
|
1726
|
+
create(description) {
|
|
1727
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/checkpoints`, {
|
|
1728
|
+
method: "POST",
|
|
1729
|
+
headers: { "Content-Type": "application/json" },
|
|
1730
|
+
body: JSON.stringify({ description: description ?? null })
|
|
1731
|
+
});
|
|
1732
|
+
}
|
|
1733
|
+
list() {
|
|
1734
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/checkpoints`);
|
|
1735
|
+
}
|
|
1736
|
+
get(checkpointId, customFetch) {
|
|
1737
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/checkpoints/${checkpointId}`, { fetch: customFetch });
|
|
1738
|
+
}
|
|
1739
|
+
};
|
|
1740
|
+
var SpaceClient = class {
|
|
1741
|
+
id;
|
|
1742
|
+
transport;
|
|
1743
|
+
websocketClient;
|
|
1744
|
+
files;
|
|
1745
|
+
sessions;
|
|
1746
|
+
members;
|
|
1747
|
+
access;
|
|
1748
|
+
checkpoints;
|
|
1749
|
+
usage;
|
|
1750
|
+
channels;
|
|
1751
|
+
env;
|
|
1752
|
+
sandbox;
|
|
1753
|
+
invitations;
|
|
1754
|
+
marks;
|
|
1755
|
+
constructor(id, transport, websocketClient) {
|
|
1756
|
+
this.id = id;
|
|
1757
|
+
this.transport = transport;
|
|
1758
|
+
this.websocketClient = websocketClient;
|
|
1759
|
+
this.files = new SpaceFilesApi(transport, id);
|
|
1760
|
+
this.sessions = new SpaceSessionsApi(transport, id, websocketClient);
|
|
1761
|
+
this.members = new SpaceMembersApi(transport, id);
|
|
1762
|
+
this.access = new SpaceAccessApi(transport, id);
|
|
1763
|
+
this.checkpoints = new SpaceCheckpointsApi(transport, id);
|
|
1764
|
+
this.usage = new SpaceUsageApi(transport, id);
|
|
1765
|
+
this.channels = new SpaceChannelsApi(transport, id);
|
|
1766
|
+
this.env = new SpaceEnvApi(transport, id);
|
|
1767
|
+
this.sandbox = new SpaceSandboxApi(transport, id);
|
|
1768
|
+
this.invitations = new SpaceInvitationsApi(transport, id);
|
|
1769
|
+
this.marks = new SpaceMarksApi(transport, id);
|
|
1770
|
+
}
|
|
1771
|
+
get(customFetch) {
|
|
1772
|
+
return this.transport.request(`/api/spaces/${this.id}`, { fetch: customFetch });
|
|
1773
|
+
}
|
|
1774
|
+
prompt(input) {
|
|
1775
|
+
return this.transport.request(`/api/spaces/${this.id}/prompt`, {
|
|
1776
|
+
method: "POST",
|
|
1777
|
+
headers: { "Content-Type": "application/json" },
|
|
1778
|
+
body: JSON.stringify(input)
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
1781
|
+
rename(name) {
|
|
1782
|
+
return this.transport.request(`/api/spaces/${this.id}`, {
|
|
1783
|
+
method: "PATCH",
|
|
1784
|
+
headers: { "Content-Type": "application/json" },
|
|
1785
|
+
body: JSON.stringify({ name })
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
profile(body) {
|
|
1789
|
+
return this.transport.request(`/api/spaces/${this.id}/profile`, {
|
|
1790
|
+
method: "PATCH",
|
|
1791
|
+
headers: { "Content-Type": "application/json" },
|
|
1792
|
+
body: JSON.stringify(body)
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
session(sessionId) {
|
|
1796
|
+
return new SessionClient(this.id, sessionId, this.transport, this.websocketClient);
|
|
1797
|
+
}
|
|
1798
|
+
subscribe(handler) {
|
|
1799
|
+
return new SpaceEventsApi(this.websocketClient, this.id).subscribe(handler);
|
|
1800
|
+
}
|
|
1801
|
+
on(type, handler) {
|
|
1802
|
+
return new SpaceEventsApi(this.websocketClient, this.id).on(type, handler);
|
|
1803
|
+
}
|
|
1804
|
+
};
|
|
1805
|
+
//#endregion
|
|
1806
|
+
//#region src/apis/tasks.ts
|
|
1807
|
+
var TasksApi = class {
|
|
1808
|
+
transport;
|
|
1809
|
+
constructor(transport) {
|
|
1810
|
+
this.transport = transport;
|
|
1811
|
+
}
|
|
1812
|
+
get(taskRunId) {
|
|
1813
|
+
return this.transport.request(`/api/tasks/${taskRunId}`);
|
|
1814
|
+
}
|
|
1815
|
+
list(filters) {
|
|
1816
|
+
const params = new URLSearchParams();
|
|
1817
|
+
if (filters?.cronJobId) params.set("cronJobId", filters.cronJobId);
|
|
1818
|
+
if (filters?.spaceId) params.set("spaceId", filters.spaceId);
|
|
1819
|
+
const query = params.toString();
|
|
1820
|
+
return this.transport.request(`/api/tasks${query ? `?${query}` : ""}`);
|
|
1821
|
+
}
|
|
1822
|
+
};
|
|
1823
|
+
//#endregion
|
|
1824
|
+
//#region src/apis/user.ts
|
|
1825
|
+
var UserApi = class {
|
|
1826
|
+
transport;
|
|
1827
|
+
transportBaseUrl;
|
|
1828
|
+
setStoredAuthToken;
|
|
1829
|
+
clearStoredAuthToken;
|
|
1830
|
+
constructor(transport, transportBaseUrl, setStoredAuthToken, clearStoredAuthToken) {
|
|
1831
|
+
this.transport = transport;
|
|
1832
|
+
this.transportBaseUrl = transportBaseUrl;
|
|
1833
|
+
this.setStoredAuthToken = setStoredAuthToken;
|
|
1834
|
+
this.clearStoredAuthToken = clearStoredAuthToken;
|
|
1835
|
+
}
|
|
1836
|
+
getMe(customFetch) {
|
|
1837
|
+
return this.transport.request("/api/me", { fetch: customFetch });
|
|
1838
|
+
}
|
|
1839
|
+
updateProfile(input) {
|
|
1840
|
+
return this.transport.request("/api/me/profile", {
|
|
1841
|
+
method: "PATCH",
|
|
1842
|
+
headers: { "Content-Type": "application/json" },
|
|
1843
|
+
body: JSON.stringify(input)
|
|
1844
|
+
});
|
|
1845
|
+
}
|
|
1846
|
+
getRules(customFetch) {
|
|
1847
|
+
return this.transport.request("/api/me/rules", {
|
|
1848
|
+
method: "GET",
|
|
1849
|
+
fetch: customFetch
|
|
1850
|
+
});
|
|
1851
|
+
}
|
|
1852
|
+
async setAuthToken(token) {
|
|
1853
|
+
const trimmedToken = token.trim();
|
|
1854
|
+
const response = await fetch(this.transportBaseUrl ? `${this.transportBaseUrl}/api/me` : "/api/me", { headers: { Authorization: `Bearer ${trimmedToken}` } });
|
|
1855
|
+
if (!response.ok) {
|
|
1856
|
+
const body = (response.headers.get("content-type") ?? "").includes("application/json") ? await response.json().catch(() => null) : await response.text().catch(() => response.statusText);
|
|
1857
|
+
throw new HttpError((typeof body === "string" ? body : JSON.stringify(body ?? null)) || response.statusText, response.status, body);
|
|
1858
|
+
}
|
|
1859
|
+
this.setStoredAuthToken?.(trimmedToken);
|
|
1860
|
+
return response.json();
|
|
1861
|
+
}
|
|
1862
|
+
async clearAuthToken() {
|
|
1863
|
+
this.clearStoredAuthToken?.();
|
|
1864
|
+
return null;
|
|
1865
|
+
}
|
|
1866
|
+
getSshKeys(customFetch) {
|
|
1867
|
+
return this.transport.request("/api/user/ssh-keys", {
|
|
1868
|
+
method: "GET",
|
|
1869
|
+
fetch: customFetch
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
createSshKey(data) {
|
|
1873
|
+
return this.transport.request("/api/user/ssh-keys", {
|
|
1874
|
+
method: "POST",
|
|
1875
|
+
headers: { "Content-Type": "application/json" },
|
|
1876
|
+
body: JSON.stringify(data)
|
|
1877
|
+
});
|
|
1878
|
+
}
|
|
1879
|
+
deleteSshKey(id) {
|
|
1880
|
+
return this.transport.request(`/api/user/ssh-keys/${id}`, { method: "DELETE" });
|
|
1881
|
+
}
|
|
1882
|
+
};
|
|
1883
|
+
//#endregion
|
|
1884
|
+
//#region src/http.ts
|
|
1885
|
+
var CohubHttpClient = class {
|
|
1886
|
+
spaces;
|
|
1887
|
+
channels;
|
|
1888
|
+
user;
|
|
1889
|
+
generations;
|
|
1890
|
+
models;
|
|
1891
|
+
prompts;
|
|
1892
|
+
sessionAccess;
|
|
1893
|
+
search;
|
|
1894
|
+
tasks;
|
|
1895
|
+
cronJobs;
|
|
1896
|
+
invite;
|
|
1897
|
+
transport;
|
|
1898
|
+
constructor(options = {}) {
|
|
1899
|
+
const apiBaseUrl = resolveApiBaseUrl(options);
|
|
1900
|
+
this.transport = new HttpTransport(options);
|
|
1901
|
+
this.spaces = new SpacesApi(this.transport);
|
|
1902
|
+
this.channels = new ChannelsApi(this.transport);
|
|
1903
|
+
this.user = new UserApi(this.transport, apiBaseUrl, options.setStoredAuthToken, options.clearStoredAuthToken);
|
|
1904
|
+
this.generations = new GenerationsApi(this.transport);
|
|
1905
|
+
this.models = new ModelsApi(this.transport);
|
|
1906
|
+
this.prompts = new PromptsApi(this.transport);
|
|
1907
|
+
this.sessionAccess = new SessionAccessApi(this.transport);
|
|
1908
|
+
this.search = new SearchApi(this.transport);
|
|
1909
|
+
this.tasks = new TasksApi(this.transport);
|
|
1910
|
+
this.cronJobs = new CronJobsApi(this.transport);
|
|
1911
|
+
this.invite = new PublicInviteApi(this.transport);
|
|
1912
|
+
}
|
|
1913
|
+
space(spaceId) {
|
|
1914
|
+
return new SpaceClient(spaceId, this.transport, null);
|
|
1915
|
+
}
|
|
1916
|
+
};
|
|
1917
|
+
const createHttpClient = (options) => new CohubHttpClient(options);
|
|
1918
|
+
//#endregion
|
|
1919
|
+
export { PromptsApi as _, SpaceClient as a, CronJobsApi as b, SessionGenerationStreamClient as c, SessionPatchReducer as d, createSessionPatchReducer as f, SearchApi as g, SessionAccessApi as h, TasksApi as i, createSessionGenerationStreamClient as l, HttpTransport as m, createHttpClient as n, SpacesApi as o, HttpError as p, UserApi as r, PublicInviteApi as s, CohubHttpClient as t, parseAssistantMessageCommit as u, ModelsApi as v, ChannelsApi as x, GenerationsApi as y };
|