@neta-art/cohub 1.3.1 → 1.5.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/dist/apis/cron-jobs.d.ts +1 -2
- package/dist/apis/cron-jobs.js +0 -7
- package/dist/apis/spaces.d.ts +6 -1
- package/dist/apis/spaces.js +25 -0
- package/dist/apis/tasks.d.ts +2 -9
- package/dist/apis/tasks.js +0 -7
- package/dist/apis/user.d.ts +8 -2
- package/dist/apis/user.js +7 -0
- package/dist/session-patch-reducer.d.ts +8 -0
- package/dist/session-patch-reducer.js +133 -22
- package/dist/types.d.ts +124 -17
- package/dist/websocket.js +3 -8
- package/package.json +2 -2
package/dist/apis/cron-jobs.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type { HttpTransport } from "../transport.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { CronJobRecord, TaskRunRecord } from "../types.js";
|
|
3
3
|
export declare class CronJobsApi {
|
|
4
4
|
private readonly transport;
|
|
5
5
|
constructor(transport: HttpTransport);
|
|
6
6
|
list(spaceId?: string): Promise<{
|
|
7
7
|
jobs: CronJobRecord[];
|
|
8
8
|
}>;
|
|
9
|
-
create(data: CreateCronJobInput): Promise<CronJobRecord>;
|
|
10
9
|
delete(id: string): Promise<{
|
|
11
10
|
ok: true;
|
|
12
11
|
}>;
|
package/dist/apis/cron-jobs.js
CHANGED
|
@@ -7,13 +7,6 @@ export class CronJobsApi {
|
|
|
7
7
|
const query = spaceId ? `?spaceId=${encodeURIComponent(spaceId)}` : "";
|
|
8
8
|
return this.transport.request(`/api/cron-jobs${query}`);
|
|
9
9
|
}
|
|
10
|
-
create(data) {
|
|
11
|
-
return this.transport.request("/api/cron-jobs", {
|
|
12
|
-
method: "POST",
|
|
13
|
-
headers: { "Content-Type": "application/json" },
|
|
14
|
-
body: JSON.stringify(data),
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
10
|
delete(id) {
|
|
18
11
|
return this.transport.request(`/api/cron-jobs/${id}`, {
|
|
19
12
|
method: "DELETE",
|
package/dist/apis/spaces.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { SpacePublicEndpoints } from "@neta-art/cohub-protocol/ports";
|
|
|
2
2
|
import type { WebsocketClient, WebsocketEventPayload } from "../websocket.js";
|
|
3
3
|
import type { HttpTransport, Fetch } from "../transport.js";
|
|
4
4
|
import { type SessionPatchApplyResult } from "../session-patch-reducer.js";
|
|
5
|
-
import type { CheckpointRecord, ContentBlock, SessionMessageResponse, SessionMessagesPaginatedResponse, SessionMessagesResponse, SessionTurnResponse, SessionTurnIndexResponse, SessionTurnWindowResponse, SessionTurnsPaginatedResponse, SessionTurnSignedUrlsResponse, SessionRecord, SpaceAccessPolicy, SpaceBootstrapSource, SpaceChannelBindingInput, SpaceCheckpointDetailResponse, SpaceCreateResponse, SpaceEnvInput, SpaceFsFileResponse, SpaceFsMoveInput, SpaceFsTreeResponse, SpaceFsUploadResponse, SpaceUsageResponse, SpaceFsWriteFileInput, SpaceMarkKind, SpaceMarkListItem, SpaceMarkResourceType, SpaceMember, SpaceRecord, SpaceRole, SpaceSessionsResponse } from "../types.js";
|
|
5
|
+
import type { CheckpointRecord, ContentBlock, SessionMessageResponse, SessionMessagesPaginatedResponse, SessionMessagesResponse, SessionTurnResponse, SessionTurnStreamSnapshotResponse, SessionTurnIndexResponse, SessionTurnWindowResponse, SessionTurnsPaginatedResponse, SessionTurnSignedUrlsResponse, SessionRecord, SpaceAccessPolicy, SpaceBootstrapSource, SpaceChannelBindingInput, SpaceCheckpointDetailResponse, SpaceCreateResponse, CreateSpacePromptInput, CreateSpacePromptResponse, SpaceEnvInput, SpaceFsCompleteUploadInput, SpaceFsCompleteUploadResponse, SpaceFsCreateUploadInput, SpaceFsCreateUploadResponse, SpaceFsFileResponse, SpaceFsMoveInput, SpaceFsTreeResponse, SpaceFsUploadResponse, SpaceUsageResponse, SpaceFsWriteFileInput, SpaceMarkKind, SpaceMarkListItem, SpaceMarkResourceType, SpaceMember, SpaceRecord, SpaceRole, SpaceSessionsResponse } from "../types.js";
|
|
6
6
|
import { SpaceInvitationsApi } from "./invitations.js";
|
|
7
7
|
export type SessionSubscriptionHandlers = {
|
|
8
8
|
patch?: (event: WebsocketEventPayload) => void;
|
|
@@ -22,6 +22,7 @@ type SessionSendMessageInput = {
|
|
|
22
22
|
content: ContentBlock[];
|
|
23
23
|
model?: string;
|
|
24
24
|
provider?: string;
|
|
25
|
+
clientMessageId?: string;
|
|
25
26
|
};
|
|
26
27
|
export declare class SpacesApi {
|
|
27
28
|
private readonly transport;
|
|
@@ -75,6 +76,8 @@ export declare class SpaceFilesApi {
|
|
|
75
76
|
toPath: string;
|
|
76
77
|
}>;
|
|
77
78
|
upload(files: File[], dir?: string): Promise<SpaceFsUploadResponse>;
|
|
79
|
+
createUpload(input: SpaceFsCreateUploadInput): Promise<SpaceFsCreateUploadResponse>;
|
|
80
|
+
completeUpload(uploadId: string, input: SpaceFsCompleteUploadInput): Promise<SpaceFsCompleteUploadResponse>;
|
|
78
81
|
}
|
|
79
82
|
declare class SessionMessagesClient {
|
|
80
83
|
private readonly transport;
|
|
@@ -117,6 +120,7 @@ declare class SessionTurnsClient {
|
|
|
117
120
|
before?: number;
|
|
118
121
|
after?: number;
|
|
119
122
|
}, customFetch?: Fetch): Promise<SessionTurnWindowResponse>;
|
|
123
|
+
streamSnapshot(customFetch?: Fetch): Promise<SessionTurnStreamSnapshotResponse>;
|
|
120
124
|
get(turnId: string, customFetch?: Fetch): Promise<SessionTurnResponse>;
|
|
121
125
|
signedUrls(turnId: string, objectKeys: string[]): Promise<SessionTurnSignedUrlsResponse>;
|
|
122
126
|
}
|
|
@@ -327,6 +331,7 @@ export declare class SpaceClient {
|
|
|
327
331
|
readonly marks: SpaceMarksApi;
|
|
328
332
|
constructor(id: string, transport: HttpTransport, websocketClient: WebsocketClient | null);
|
|
329
333
|
get(customFetch?: Fetch): Promise<SpaceRecord>;
|
|
334
|
+
prompt(input: CreateSpacePromptInput): Promise<CreateSpacePromptResponse>;
|
|
330
335
|
rename(name: string): Promise<{
|
|
331
336
|
space: SpaceRecord;
|
|
332
337
|
}>;
|
package/dist/apis/spaces.js
CHANGED
|
@@ -169,6 +169,20 @@ export class SpaceFilesApi {
|
|
|
169
169
|
body: formData,
|
|
170
170
|
});
|
|
171
171
|
}
|
|
172
|
+
createUpload(input) {
|
|
173
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/uploads`, {
|
|
174
|
+
method: "POST",
|
|
175
|
+
headers: { "Content-Type": "application/json" },
|
|
176
|
+
body: JSON.stringify(input),
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
completeUpload(uploadId, input) {
|
|
180
|
+
return this.transport.request(`/api/spaces/${this.spaceId}/fs/uploads/${uploadId}/complete`, {
|
|
181
|
+
method: "POST",
|
|
182
|
+
headers: { "Content-Type": "application/json" },
|
|
183
|
+
body: JSON.stringify(input),
|
|
184
|
+
});
|
|
185
|
+
}
|
|
172
186
|
}
|
|
173
187
|
class SessionMessagesClient {
|
|
174
188
|
transport;
|
|
@@ -229,6 +243,7 @@ class SessionMessagesClient {
|
|
|
229
243
|
content: input.content,
|
|
230
244
|
model: input.model,
|
|
231
245
|
provider: input.provider,
|
|
246
|
+
clientMessageId: input.clientMessageId,
|
|
232
247
|
}),
|
|
233
248
|
});
|
|
234
249
|
}
|
|
@@ -273,6 +288,9 @@ class SessionTurnsClient {
|
|
|
273
288
|
const query = params.toString();
|
|
274
289
|
return this.transport.request(`/api/sessions/${this.sessionId}/turns/window${query ? `?${query}` : ""}`, { fetch: customFetch });
|
|
275
290
|
}
|
|
291
|
+
streamSnapshot(customFetch) {
|
|
292
|
+
return this.transport.request(`/api/sessions/${this.sessionId}/turns/stream-snapshot`, { fetch: customFetch });
|
|
293
|
+
}
|
|
276
294
|
get(turnId, customFetch) {
|
|
277
295
|
return this.transport.request(`/api/sessions/${this.sessionId}/turns/${turnId}`, { fetch: customFetch });
|
|
278
296
|
}
|
|
@@ -688,6 +706,13 @@ export class SpaceClient {
|
|
|
688
706
|
fetch: customFetch,
|
|
689
707
|
});
|
|
690
708
|
}
|
|
709
|
+
prompt(input) {
|
|
710
|
+
return this.transport.request(`/api/spaces/${this.id}/prompt`, {
|
|
711
|
+
method: "POST",
|
|
712
|
+
headers: { "Content-Type": "application/json" },
|
|
713
|
+
body: JSON.stringify(input),
|
|
714
|
+
});
|
|
715
|
+
}
|
|
691
716
|
rename(name) {
|
|
692
717
|
return this.transport.request(`/api/spaces/${this.id}`, {
|
|
693
718
|
method: "PATCH",
|
package/dist/apis/tasks.d.ts
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
import type { HttpTransport } from "../transport.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { TaskRunDetailResponse, TaskRunRecord } from "../types.js";
|
|
3
3
|
export declare class TasksApi {
|
|
4
4
|
private readonly transport;
|
|
5
5
|
constructor(transport: HttpTransport);
|
|
6
|
-
get(taskRunId: string): Promise<
|
|
7
|
-
run: TaskRunRecord;
|
|
8
|
-
}>;
|
|
6
|
+
get(taskRunId: string): Promise<TaskRunDetailResponse>;
|
|
9
7
|
list(filters?: {
|
|
10
8
|
cronJobId?: string;
|
|
11
9
|
spaceId?: string;
|
|
12
10
|
}): Promise<{
|
|
13
11
|
runs: TaskRunRecord[];
|
|
14
12
|
}>;
|
|
15
|
-
createScheduled(data: CreateScheduledTaskInput): Promise<{
|
|
16
|
-
ok: true;
|
|
17
|
-
taskRunId: string;
|
|
18
|
-
scheduledAt: string;
|
|
19
|
-
}>;
|
|
20
13
|
}
|
package/dist/apis/tasks.js
CHANGED
|
@@ -15,11 +15,4 @@ export class TasksApi {
|
|
|
15
15
|
const query = params.toString();
|
|
16
16
|
return this.transport.request(`/api/tasks${query ? `?${query}` : ""}`);
|
|
17
17
|
}
|
|
18
|
-
createScheduled(data) {
|
|
19
|
-
return this.transport.request("/api/tasks", {
|
|
20
|
-
method: "POST",
|
|
21
|
-
headers: { "Content-Type": "application/json" },
|
|
22
|
-
body: JSON.stringify(data),
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
18
|
}
|
package/dist/apis/user.d.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { type HttpTransport, type Fetch } from "../transport.js";
|
|
2
|
-
import type { UserRulesResponse, UserSshKey } from "../types.js";
|
|
2
|
+
import type { MeResponse, UserProfile, UserRulesResponse, UserSshKey } from "../types.js";
|
|
3
3
|
export declare class UserApi {
|
|
4
4
|
private readonly transport;
|
|
5
5
|
private readonly transportBaseUrl;
|
|
6
6
|
private readonly setStoredAuthToken?;
|
|
7
7
|
private readonly clearStoredAuthToken?;
|
|
8
8
|
constructor(transport: HttpTransport, transportBaseUrl: string, setStoredAuthToken?: ((token: string) => void) | undefined, clearStoredAuthToken?: (() => void) | undefined);
|
|
9
|
-
getMe(customFetch?: Fetch): Promise<
|
|
9
|
+
getMe(customFetch?: Fetch): Promise<MeResponse>;
|
|
10
|
+
updateProfile(input: {
|
|
11
|
+
displayName?: string;
|
|
12
|
+
avatarUrl?: string | null;
|
|
13
|
+
}): Promise<{
|
|
14
|
+
profile: UserProfile;
|
|
15
|
+
}>;
|
|
10
16
|
getRules(customFetch?: Fetch): Promise<UserRulesResponse>;
|
|
11
17
|
setAuthToken(token: string): Promise<any>;
|
|
12
18
|
clearAuthToken(): Promise<null>;
|
package/dist/apis/user.js
CHANGED
|
@@ -13,6 +13,13 @@ export class UserApi {
|
|
|
13
13
|
getMe(customFetch) {
|
|
14
14
|
return this.transport.request("/api/me", { fetch: customFetch });
|
|
15
15
|
}
|
|
16
|
+
updateProfile(input) {
|
|
17
|
+
return this.transport.request("/api/me/profile", {
|
|
18
|
+
method: "PATCH",
|
|
19
|
+
headers: { "Content-Type": "application/json" },
|
|
20
|
+
body: JSON.stringify(input),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
16
23
|
getRules(customFetch) {
|
|
17
24
|
return this.transport.request("/api/me/rules", {
|
|
18
25
|
method: "GET",
|
|
@@ -28,6 +28,13 @@ export type SessionPatchApplyResult = {
|
|
|
28
28
|
reason: "duplicate" | "version_mismatch" | "invalid";
|
|
29
29
|
state: SessionPatchState;
|
|
30
30
|
};
|
|
31
|
+
export type SessionPatchSnapshotInput = SessionPatchKeyInput & {
|
|
32
|
+
turnId?: string | null;
|
|
33
|
+
seq: number;
|
|
34
|
+
contentBlocks: ContentBlock[];
|
|
35
|
+
anchorUserMessageId?: string | null;
|
|
36
|
+
appendPath?: string | null;
|
|
37
|
+
};
|
|
31
38
|
type SessionPatchKeyInput = {
|
|
32
39
|
spaceId?: string | null;
|
|
33
40
|
sessionId: string;
|
|
@@ -44,6 +51,7 @@ export declare class SessionPatchReducer {
|
|
|
44
51
|
complete(input: SessionPatchKeyInput): SessionPatchState;
|
|
45
52
|
fail(input: SessionPatchKeyInput): SessionPatchState;
|
|
46
53
|
reset(input: SessionPatchKeyInput): void;
|
|
54
|
+
applySnapshot(input: SessionPatchSnapshotInput): SessionPatchApplyResult;
|
|
47
55
|
resetAll(): void;
|
|
48
56
|
applyEvent(event: SessionTurnPatchEvent): SessionPatchApplyResult;
|
|
49
57
|
applyPatch(input: SessionPatchApplyInput): SessionPatchApplyResult;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
const
|
|
1
|
+
const blockSubPathPattern = /^\/message\/content\/blocks\/(\d+)\/(.+)$/;
|
|
2
2
|
const blockPathPattern = /^\/message\/content\/blocks\/(\d+)$/;
|
|
3
3
|
const blockMetaPathPattern = /^\/message\/content\/blocks\/(\d+)\/_meta$/;
|
|
4
|
-
const blockSignaturePathPattern = /^\/message\/content\/blocks\/(\d+)\/signature$/;
|
|
5
4
|
const createIdleState = (input) => ({
|
|
6
5
|
spaceId: input.spaceId ?? null,
|
|
7
6
|
sessionId: input.sessionId,
|
|
@@ -38,6 +37,14 @@ function sortBlocksByStreamIndex(blocks) {
|
|
|
38
37
|
function isContentBlock(value) {
|
|
39
38
|
return Boolean(value && typeof value === "object" && "type" in value);
|
|
40
39
|
}
|
|
40
|
+
function isPlainObject(value) {
|
|
41
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
42
|
+
}
|
|
43
|
+
function decodePointerSegments(encoded) {
|
|
44
|
+
if (!encoded)
|
|
45
|
+
return [];
|
|
46
|
+
return encoded.split("/").map((s) => s.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
47
|
+
}
|
|
41
48
|
function ensureTextLikeBlock(blocks, streamIndex, field) {
|
|
42
49
|
const existingIndex = findBlockByStreamIndex(blocks, streamIndex);
|
|
43
50
|
const existing = existingIndex >= 0 ? blocks[existingIndex] : undefined;
|
|
@@ -62,21 +69,103 @@ function ensureTextLikeBlock(blocks, streamIndex, field) {
|
|
|
62
69
|
blocks.push(block);
|
|
63
70
|
return block;
|
|
64
71
|
}
|
|
65
|
-
function
|
|
66
|
-
const
|
|
67
|
-
if (
|
|
72
|
+
function getOrCreateBlockForSubpath(blocks, streamIndex, firstSegment) {
|
|
73
|
+
const idx = findBlockByStreamIndex(blocks, streamIndex);
|
|
74
|
+
if (idx >= 0)
|
|
75
|
+
return blocks[idx] ?? null;
|
|
76
|
+
if (firstSegment === "text") {
|
|
77
|
+
return ensureTextLikeBlock(blocks, streamIndex, "text");
|
|
78
|
+
}
|
|
79
|
+
if (firstSegment === "thinking") {
|
|
80
|
+
return ensureTextLikeBlock(blocks, streamIndex, "thinking");
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
function setDeepOnContentBlock(root, segments, value) {
|
|
85
|
+
if (segments.length === 0)
|
|
68
86
|
return false;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
let cur = root;
|
|
88
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
89
|
+
const k = segments[i];
|
|
90
|
+
if (k === undefined)
|
|
91
|
+
return false;
|
|
92
|
+
if (!isPlainObject(cur))
|
|
93
|
+
return false;
|
|
94
|
+
const next = cur[k];
|
|
95
|
+
if (next === undefined)
|
|
96
|
+
return false;
|
|
97
|
+
cur = next;
|
|
74
98
|
}
|
|
75
|
-
|
|
76
|
-
|
|
99
|
+
const last = segments[segments.length - 1];
|
|
100
|
+
if (last === undefined)
|
|
101
|
+
return false;
|
|
102
|
+
if (!isPlainObject(cur))
|
|
103
|
+
return false;
|
|
104
|
+
const toAssign = value !== null && typeof value === "object"
|
|
105
|
+
? structuredClone(value)
|
|
106
|
+
: value;
|
|
107
|
+
cur[last] = toAssign;
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
function appendDeepOnContentBlock(root, segments, suffix) {
|
|
111
|
+
if (segments.length === 0)
|
|
112
|
+
return false;
|
|
113
|
+
let cur = root;
|
|
114
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
115
|
+
const k = segments[i];
|
|
116
|
+
if (k === undefined)
|
|
117
|
+
return false;
|
|
118
|
+
if (!isPlainObject(cur))
|
|
119
|
+
return false;
|
|
120
|
+
const next = cur[k];
|
|
121
|
+
if (next === undefined)
|
|
122
|
+
return false;
|
|
123
|
+
cur = next;
|
|
77
124
|
}
|
|
125
|
+
const last = segments[segments.length - 1];
|
|
126
|
+
if (last === undefined)
|
|
127
|
+
return false;
|
|
128
|
+
if (!isPlainObject(cur))
|
|
129
|
+
return false;
|
|
130
|
+
const parent = cur;
|
|
131
|
+
const leaf = parent[last];
|
|
132
|
+
if (typeof leaf !== "string")
|
|
133
|
+
return false;
|
|
134
|
+
parent[last] = leaf + suffix;
|
|
78
135
|
return true;
|
|
79
136
|
}
|
|
137
|
+
function resolveBlockForSubpath(blocks, streamIndex, firstSegment) {
|
|
138
|
+
const idx = findBlockByStreamIndex(blocks, streamIndex);
|
|
139
|
+
if (idx >= 0)
|
|
140
|
+
return blocks[idx] ?? null;
|
|
141
|
+
return getOrCreateBlockForSubpath(blocks, streamIndex, firstSegment);
|
|
142
|
+
}
|
|
143
|
+
function applyReplaceAtBlockSubpath(blocks, streamIndex, encodedTail, value) {
|
|
144
|
+
const segs = decodePointerSegments(encodedTail);
|
|
145
|
+
if (segs.length === 0)
|
|
146
|
+
return false;
|
|
147
|
+
const block = resolveBlockForSubpath(blocks, streamIndex, segs[0] ?? "");
|
|
148
|
+
if (!block)
|
|
149
|
+
return false;
|
|
150
|
+
return setDeepOnContentBlock(block, segs, value);
|
|
151
|
+
}
|
|
152
|
+
function applyAppendAtBlockSubpath(blocks, streamIndex, encodedTail, suffix) {
|
|
153
|
+
if (typeof suffix !== "string")
|
|
154
|
+
return false;
|
|
155
|
+
const segs = decodePointerSegments(encodedTail);
|
|
156
|
+
if (segs.length === 0)
|
|
157
|
+
return false;
|
|
158
|
+
const block = resolveBlockForSubpath(blocks, streamIndex, segs[0] ?? "");
|
|
159
|
+
if (!block)
|
|
160
|
+
return false;
|
|
161
|
+
return appendDeepOnContentBlock(block, segs, suffix);
|
|
162
|
+
}
|
|
163
|
+
function appendPatchStreamValue(blocks, path, value) {
|
|
164
|
+
const m = path.match(blockSubPathPattern);
|
|
165
|
+
if (!m)
|
|
166
|
+
return false;
|
|
167
|
+
return applyAppendAtBlockSubpath(blocks, Number(m[1]), m[2] ?? "", value);
|
|
168
|
+
}
|
|
80
169
|
function applyPatchOpsToBlocks(current, ops, initialAppendPath) {
|
|
81
170
|
const next = current.map(cloneBlock);
|
|
82
171
|
let anchorUserMessageId;
|
|
@@ -84,7 +173,7 @@ function applyPatchOpsToBlocks(current, ops, initialAppendPath) {
|
|
|
84
173
|
let failed = false;
|
|
85
174
|
for (const op of ops) {
|
|
86
175
|
if (!op.o && !op.p) {
|
|
87
|
-
if (!appendPath || !
|
|
176
|
+
if (!appendPath || !appendPatchStreamValue(next, appendPath, op.v)) {
|
|
88
177
|
failed = true;
|
|
89
178
|
break;
|
|
90
179
|
}
|
|
@@ -98,7 +187,7 @@ function applyPatchOpsToBlocks(current, ops, initialAppendPath) {
|
|
|
98
187
|
continue;
|
|
99
188
|
}
|
|
100
189
|
if (op.o === "append") {
|
|
101
|
-
if (!
|
|
190
|
+
if (typeof op.p !== "string" || !appendPatchStreamValue(next, op.p, op.v)) {
|
|
102
191
|
failed = true;
|
|
103
192
|
break;
|
|
104
193
|
}
|
|
@@ -118,15 +207,15 @@ function applyPatchOpsToBlocks(current, ops, initialAppendPath) {
|
|
|
118
207
|
continue;
|
|
119
208
|
}
|
|
120
209
|
if (op.o === "replace") {
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
|
|
210
|
+
const sub = op.p.match(blockSubPathPattern);
|
|
211
|
+
if (sub?.[2] && typeof op.p === "string") {
|
|
212
|
+
const streamIndex = Number(sub[1]);
|
|
213
|
+
const encodedTail = sub[2];
|
|
214
|
+
if (applyReplaceAtBlockSubpath(next, streamIndex, encodedTail, op.v)) {
|
|
124
215
|
continue;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
block.signature = op.v;
|
|
129
|
-
continue;
|
|
216
|
+
}
|
|
217
|
+
failed = true;
|
|
218
|
+
break;
|
|
130
219
|
}
|
|
131
220
|
}
|
|
132
221
|
if (op.o === "replace" || op.o === "add") {
|
|
@@ -219,6 +308,28 @@ export class SessionPatchReducer {
|
|
|
219
308
|
reset(input) {
|
|
220
309
|
this.states.delete(this.key(input));
|
|
221
310
|
}
|
|
311
|
+
applySnapshot(input) {
|
|
312
|
+
const current = this.get(input);
|
|
313
|
+
const inputTurnId = input.turnId ?? null;
|
|
314
|
+
const currentTurnId = current.turnId;
|
|
315
|
+
const isDifferentKnownTurn = Boolean(currentTurnId && inputTurnId && currentTurnId !== inputTurnId);
|
|
316
|
+
if (!isDifferentKnownTurn && input.seq < current.patchSeq) {
|
|
317
|
+
return { applied: false, reason: "duplicate", state: current };
|
|
318
|
+
}
|
|
319
|
+
const state = {
|
|
320
|
+
...current,
|
|
321
|
+
spaceId: input.spaceId ?? current.spaceId ?? null,
|
|
322
|
+
sessionId: input.sessionId,
|
|
323
|
+
status: "streaming",
|
|
324
|
+
contentBlocks: sortBlocksByStreamIndex(input.contentBlocks.map(cloneBlock)),
|
|
325
|
+
anchorUserMessageId: input.anchorUserMessageId ?? current.anchorUserMessageId ?? null,
|
|
326
|
+
patchSeq: input.seq,
|
|
327
|
+
turnId: inputTurnId ?? current.turnId ?? null,
|
|
328
|
+
appendPath: input.appendPath ?? null,
|
|
329
|
+
};
|
|
330
|
+
this.states.set(this.key(input), state);
|
|
331
|
+
return { applied: true, state };
|
|
332
|
+
}
|
|
222
333
|
resetAll() {
|
|
223
334
|
this.states.clear();
|
|
224
335
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -6,6 +6,18 @@ export type { ChannelConfig, DiscordChannelConfig, } from "@neta-art/cohub-proto
|
|
|
6
6
|
export type ApiError = {
|
|
7
7
|
message: string;
|
|
8
8
|
};
|
|
9
|
+
export type UserProfile = {
|
|
10
|
+
userUuid: string;
|
|
11
|
+
logtoUserId?: string;
|
|
12
|
+
displayName: string;
|
|
13
|
+
avatarUrl: string | null;
|
|
14
|
+
syncedAt?: string;
|
|
15
|
+
};
|
|
16
|
+
export type MeResponse = {
|
|
17
|
+
uuid: string;
|
|
18
|
+
profile: UserProfile;
|
|
19
|
+
email: string | null;
|
|
20
|
+
};
|
|
9
21
|
export type UserRulesResponse = {
|
|
10
22
|
content: string;
|
|
11
23
|
updatedAt: string | null;
|
|
@@ -55,13 +67,55 @@ export type SpaceFsUploadEntry = {
|
|
|
55
67
|
};
|
|
56
68
|
export type SpaceFsUploadError = {
|
|
57
69
|
name: string;
|
|
58
|
-
code: "file_too_large" | "name_invalid" | "write_failed";
|
|
70
|
+
code: "file_too_large" | "name_invalid" | "path_invalid" | "write_failed" | "object_missing";
|
|
59
71
|
message: string;
|
|
60
72
|
};
|
|
61
73
|
export type SpaceFsUploadResponse = {
|
|
62
74
|
uploaded: SpaceFsUploadEntry[];
|
|
63
75
|
errors: SpaceFsUploadError[];
|
|
64
76
|
};
|
|
77
|
+
export type SpaceFsUploadPlanEntryInput = {
|
|
78
|
+
id: string;
|
|
79
|
+
name: string;
|
|
80
|
+
relativePath: string;
|
|
81
|
+
size: number;
|
|
82
|
+
mimeType?: string | null;
|
|
83
|
+
lastModified?: number;
|
|
84
|
+
};
|
|
85
|
+
export type SpaceFsCreateUploadInput = {
|
|
86
|
+
targetDir?: string;
|
|
87
|
+
entries: SpaceFsUploadPlanEntryInput[];
|
|
88
|
+
};
|
|
89
|
+
export type SpaceFsUploadPlanEntry = {
|
|
90
|
+
id: string;
|
|
91
|
+
objectKey: string;
|
|
92
|
+
uploadUrl: string;
|
|
93
|
+
headers?: Record<string, string>;
|
|
94
|
+
};
|
|
95
|
+
export type SpaceFsCreateUploadResponse = {
|
|
96
|
+
uploadId: string;
|
|
97
|
+
expiresAt: string;
|
|
98
|
+
entries: SpaceFsUploadPlanEntry[];
|
|
99
|
+
};
|
|
100
|
+
export type SpaceFsCompleteUploadInput = {
|
|
101
|
+
entries: Array<{
|
|
102
|
+
id: string;
|
|
103
|
+
etag?: string | null;
|
|
104
|
+
}>;
|
|
105
|
+
};
|
|
106
|
+
export type SpaceFsCompleteUploadResponse = {
|
|
107
|
+
ok: true;
|
|
108
|
+
taskRunId: string;
|
|
109
|
+
};
|
|
110
|
+
export type SpaceFsUploadProgress = {
|
|
111
|
+
phase: "queued" | "importing" | "done" | "failed";
|
|
112
|
+
totalFiles: number;
|
|
113
|
+
importedFiles: number;
|
|
114
|
+
totalBytes: number;
|
|
115
|
+
importedBytes: number;
|
|
116
|
+
currentPath?: string;
|
|
117
|
+
errors: SpaceFsUploadError[];
|
|
118
|
+
};
|
|
65
119
|
export type SessionBindingRecord = ProtocolSessionBindingRecord;
|
|
66
120
|
export type SessionRecord = ProtocolSessionRecord & {
|
|
67
121
|
bindings?: SessionBindingRecord[];
|
|
@@ -154,6 +208,28 @@ export type SessionTurnResponse = {
|
|
|
154
208
|
export type SessionTurnSignedUrlsResponse = {
|
|
155
209
|
urls: Record<string, string>;
|
|
156
210
|
};
|
|
211
|
+
export type SessionTurnStreamSnapshotResponse = {
|
|
212
|
+
snapshot: {
|
|
213
|
+
version: 2;
|
|
214
|
+
spaceId: string;
|
|
215
|
+
sessionId: string;
|
|
216
|
+
turnId: string | null;
|
|
217
|
+
anchorUserMessageId: string | null;
|
|
218
|
+
seq: number;
|
|
219
|
+
current: {
|
|
220
|
+
messageId: string | null;
|
|
221
|
+
messageOrdinal: number | null;
|
|
222
|
+
content: ContentBlock[];
|
|
223
|
+
appendPath: string | null;
|
|
224
|
+
};
|
|
225
|
+
intermediateMessages: Array<{
|
|
226
|
+
messageId: string | null;
|
|
227
|
+
messageOrdinal: number | null;
|
|
228
|
+
content: ContentBlock[];
|
|
229
|
+
}>;
|
|
230
|
+
updatedAt: number;
|
|
231
|
+
} | null;
|
|
232
|
+
};
|
|
157
233
|
export type ModelCatalogEntry = {
|
|
158
234
|
provider: string;
|
|
159
235
|
id: string;
|
|
@@ -205,9 +281,51 @@ export type UserSshKey = {
|
|
|
205
281
|
giteaKeyId: number;
|
|
206
282
|
createdAt: string;
|
|
207
283
|
};
|
|
284
|
+
export type CreateSpacePromptInput = {
|
|
285
|
+
sessionId?: string | null;
|
|
286
|
+
title?: string | null;
|
|
287
|
+
content: ContentBlock[];
|
|
288
|
+
model?: string | null;
|
|
289
|
+
provider?: string | null;
|
|
290
|
+
clientMessageId?: string | null;
|
|
291
|
+
schedule?: {
|
|
292
|
+
mode?: "immediate";
|
|
293
|
+
} | {
|
|
294
|
+
mode: "delay";
|
|
295
|
+
delayMs: number;
|
|
296
|
+
} | {
|
|
297
|
+
mode: "at";
|
|
298
|
+
sendAt: string;
|
|
299
|
+
} | {
|
|
300
|
+
mode: "repeat";
|
|
301
|
+
cronExpression: string;
|
|
302
|
+
timezone: string;
|
|
303
|
+
};
|
|
304
|
+
};
|
|
305
|
+
export type CreateSpacePromptResponse = {
|
|
306
|
+
ok: true;
|
|
307
|
+
mode: "immediate";
|
|
308
|
+
sessionId: string;
|
|
309
|
+
userMessageId: string;
|
|
310
|
+
turnId: string;
|
|
311
|
+
} | {
|
|
312
|
+
ok: true;
|
|
313
|
+
mode: "delay" | "at";
|
|
314
|
+
taskRunId: string;
|
|
315
|
+
scheduledAt: string;
|
|
316
|
+
sessionId: string | null;
|
|
317
|
+
} | {
|
|
318
|
+
ok: true;
|
|
319
|
+
mode: "repeat";
|
|
320
|
+
cronJobId: string;
|
|
321
|
+
nextRunAt: string;
|
|
322
|
+
timezone: string;
|
|
323
|
+
sessionId: string | null;
|
|
324
|
+
};
|
|
208
325
|
export type CronJobRecord = {
|
|
209
326
|
id: string;
|
|
210
327
|
userUuid: string;
|
|
328
|
+
userProfile?: UserProfile;
|
|
211
329
|
title: string;
|
|
212
330
|
taskType: string;
|
|
213
331
|
payload: Record<string, unknown>;
|
|
@@ -220,6 +338,10 @@ export type CronJobRecord = {
|
|
|
220
338
|
createdAt: string;
|
|
221
339
|
updatedAt: string;
|
|
222
340
|
};
|
|
341
|
+
export type TaskRunDetailResponse = {
|
|
342
|
+
run: TaskRunRecord;
|
|
343
|
+
progress: unknown;
|
|
344
|
+
};
|
|
223
345
|
export type TaskRunRecord = {
|
|
224
346
|
id: string;
|
|
225
347
|
jobId: string;
|
|
@@ -252,26 +374,11 @@ export type CheckpointRecord = {
|
|
|
252
374
|
export type SpaceCheckpointDetailResponse = {
|
|
253
375
|
checkpoint: CheckpointRecord;
|
|
254
376
|
};
|
|
255
|
-
export type CreateCronJobInput = {
|
|
256
|
-
title: string;
|
|
257
|
-
taskType: string;
|
|
258
|
-
payload: Record<string, unknown>;
|
|
259
|
-
cronExpression: string;
|
|
260
|
-
timezone?: string;
|
|
261
|
-
spaceId?: string;
|
|
262
|
-
sessionId?: string;
|
|
263
|
-
};
|
|
264
|
-
export type CreateScheduledTaskInput = {
|
|
265
|
-
taskType: string;
|
|
266
|
-
payload: Record<string, unknown>;
|
|
267
|
-
scheduleAt: string;
|
|
268
|
-
spaceId?: string;
|
|
269
|
-
sessionId?: string;
|
|
270
|
-
};
|
|
271
377
|
export type SpaceRole = "host" | "builder" | "guest";
|
|
272
378
|
export type SpaceMember = {
|
|
273
379
|
userId: string;
|
|
274
380
|
role: SpaceRole;
|
|
381
|
+
profile: UserProfile;
|
|
275
382
|
createdAt: string;
|
|
276
383
|
updatedAt: string;
|
|
277
384
|
};
|
package/dist/websocket.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { realtimeCompactFrameSchema, realtimeEnvelopeSchema, WS_COMPACT_STREAM_CAPABILITY, } from "@neta-art/cohub-protocol/realtime";
|
|
1
|
+
import { getSessionTurnPatchStreamKey, realtimeCompactFrameSchema, realtimeEnvelopeSchema, WS_COMPACT_STREAM_CAPABILITY, } from "@neta-art/cohub-protocol/realtime";
|
|
2
2
|
import { resolveWebsocketUrl } from "./environment.js";
|
|
3
3
|
const createEventMap = () => ({
|
|
4
4
|
connecting: new Set(),
|
|
@@ -446,13 +446,7 @@ export class WebsocketClient {
|
|
|
446
446
|
if (typeof realtimeMeta?.sid === "string" && realtimeMeta.sid.trim()) {
|
|
447
447
|
return realtimeMeta.sid;
|
|
448
448
|
}
|
|
449
|
-
|
|
450
|
-
return payload.turnId;
|
|
451
|
-
if (typeof payload.messageId === "string" && payload.messageId.trim())
|
|
452
|
-
return payload.messageId;
|
|
453
|
-
return typeof envelope.sessionId === "string" && envelope.sessionId.trim()
|
|
454
|
-
? envelope.sessionId
|
|
455
|
-
: null;
|
|
449
|
+
return getSessionTurnPatchStreamKey(payload, { includeSessionFallback: true });
|
|
456
450
|
}
|
|
457
451
|
handlePatchEnvelope(envelope) {
|
|
458
452
|
const payload = envelope.payload;
|
|
@@ -543,6 +537,7 @@ export class WebsocketClient {
|
|
|
543
537
|
turnId: context.turnId,
|
|
544
538
|
messageId: context.messageId,
|
|
545
539
|
messageOrdinal: context.messageOrdinal,
|
|
540
|
+
sourceMessageId: context.messageId,
|
|
546
541
|
anchorUserMessageId: context.anchorUserMessageId,
|
|
547
542
|
seq: frame.s,
|
|
548
543
|
baseSeq: frame.b,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neta-art/cohub",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Cohub SDK for spaces, sessions, checkpoints, and realtime agent collaboration.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"README.md"
|
|
45
45
|
],
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@neta-art/cohub-protocol": "1.
|
|
47
|
+
"@neta-art/cohub-protocol": "1.3.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"typescript": "^6.0.3"
|