@langchain/langgraph-api 0.0.59 → 0.0.61
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/CHANGELOG.md +16 -0
- package/dist/api/assistants.mjs +16 -11
- package/dist/api/meta.mjs +24 -17
- package/dist/api/runs.mjs +19 -19
- package/dist/api/store.mjs +1 -1
- package/dist/api/threads.mjs +19 -14
- package/dist/auth/custom.d.mts +1 -4
- package/dist/auth/custom.mjs +1 -34
- package/dist/auth/index.d.mts +3 -0
- package/dist/auth/index.mjs +33 -0
- package/dist/experimental/embed.d.mts +1 -1
- package/dist/graph/api.d.mts +1 -0
- package/dist/graph/api.mjs +2 -0
- package/dist/graph/load.d.mts +3 -1
- package/dist/graph/load.mjs +9 -5
- package/dist/http/middleware.mjs +14 -10
- package/dist/loopback.d.mts +2 -1
- package/dist/queue.d.mts +2 -1
- package/dist/queue.mjs +10 -11
- package/dist/schemas.d.mts +141 -118
- package/dist/schemas.mjs +25 -0
- package/dist/server.d.mts +16 -13
- package/dist/server.mjs +27 -8
- package/dist/state.d.mts +1 -1
- package/dist/storage/context.d.mts +3 -0
- package/dist/storage/context.mjs +11 -0
- package/dist/storage/ops.d.mts +62 -202
- package/dist/storage/ops.mjs +187 -94
- package/dist/storage/types.d.mts +288 -0
- package/dist/storage/types.mjs +1 -0
- package/dist/stream.d.mts +1 -1
- package/dist/stream.mjs +12 -0
- package/dist/utils/runnableConfig.d.mts +1 -1
- package/dist/webhook.d.mts +1 -1
- package/package.json +16 -4
package/dist/storage/ops.mjs
CHANGED
|
@@ -1,20 +1,40 @@
|
|
|
1
1
|
import { HTTPException } from "hono/http-exception";
|
|
2
2
|
import { v4 as uuid4, v5 as uuid5 } from "uuid";
|
|
3
|
-
import { handleAuthEvent, isAuthMatching } from "../auth/
|
|
3
|
+
import { handleAuthEvent, isAuthMatching } from "../auth/index.mjs";
|
|
4
4
|
import { getLangGraphCommand } from "../command.mjs";
|
|
5
5
|
import { getGraph, NAMESPACE_GRAPH } from "../graph/load.mjs";
|
|
6
6
|
import { logger } from "../logging.mjs";
|
|
7
7
|
import { serializeError } from "../utils/serde.mjs";
|
|
8
8
|
import { checkpointer } from "./checkpoint.mjs";
|
|
9
|
-
import { FileSystemPersistence } from "./persist.mjs";
|
|
10
9
|
import { store } from "./store.mjs";
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
export class FileSystemOps {
|
|
11
|
+
conn;
|
|
12
|
+
assistants;
|
|
13
|
+
runs;
|
|
14
|
+
threads;
|
|
15
|
+
constructor(conn) {
|
|
16
|
+
this.conn = conn;
|
|
17
|
+
this.assistants = new FileSystemAssistants(this.conn);
|
|
18
|
+
this.runs = new FileSystemRuns(this.conn);
|
|
19
|
+
this.threads = new FileSystemThreads(this.conn);
|
|
20
|
+
}
|
|
21
|
+
truncate(flags) {
|
|
22
|
+
return this.conn.with((STORE) => {
|
|
23
|
+
if (flags.runs)
|
|
24
|
+
STORE.runs = {};
|
|
25
|
+
if (flags.threads)
|
|
26
|
+
STORE.threads = {};
|
|
27
|
+
if (flags.assistants) {
|
|
28
|
+
STORE.assistants = Object.fromEntries(Object.entries(STORE.assistants).filter(([key, assistant]) => assistant.metadata?.created_by === "system" &&
|
|
29
|
+
uuid5(assistant.graph_id, NAMESPACE_GRAPH) === key));
|
|
30
|
+
}
|
|
31
|
+
if (flags.checkpointer)
|
|
32
|
+
checkpointer.clear();
|
|
33
|
+
if (flags.store)
|
|
34
|
+
store.clear();
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
18
38
|
class TimeoutError extends Error {
|
|
19
39
|
}
|
|
20
40
|
class AbortError extends Error {
|
|
@@ -113,22 +133,6 @@ class StreamManagerImpl {
|
|
|
113
133
|
}
|
|
114
134
|
}
|
|
115
135
|
export const StreamManager = new StreamManagerImpl();
|
|
116
|
-
export const truncate = (flags) => {
|
|
117
|
-
return conn.with((STORE) => {
|
|
118
|
-
if (flags.runs)
|
|
119
|
-
STORE.runs = {};
|
|
120
|
-
if (flags.threads)
|
|
121
|
-
STORE.threads = {};
|
|
122
|
-
if (flags.assistants) {
|
|
123
|
-
STORE.assistants = Object.fromEntries(Object.entries(STORE.assistants).filter(([key, assistant]) => assistant.metadata?.created_by === "system" &&
|
|
124
|
-
uuid5(assistant.graph_id, NAMESPACE_GRAPH) === key));
|
|
125
|
-
}
|
|
126
|
-
if (flags.checkpointer)
|
|
127
|
-
checkpointer.clear();
|
|
128
|
-
if (flags.store)
|
|
129
|
-
store.clear();
|
|
130
|
-
});
|
|
131
|
-
};
|
|
132
136
|
const isObject = (value) => {
|
|
133
137
|
return typeof value === "object" && value !== null;
|
|
134
138
|
};
|
|
@@ -148,15 +152,19 @@ const isJsonbContained = (superset, subset) => {
|
|
|
148
152
|
}
|
|
149
153
|
return true;
|
|
150
154
|
};
|
|
151
|
-
export class
|
|
152
|
-
|
|
155
|
+
export class FileSystemAssistants {
|
|
156
|
+
conn;
|
|
157
|
+
constructor(conn) {
|
|
158
|
+
this.conn = conn;
|
|
159
|
+
}
|
|
160
|
+
async *search(options, auth) {
|
|
153
161
|
const [filters] = await handleAuthEvent(auth, "assistants:search", {
|
|
154
162
|
graph_id: options.graph_id,
|
|
155
163
|
metadata: options.metadata,
|
|
156
164
|
limit: options.limit,
|
|
157
165
|
offset: options.offset,
|
|
158
166
|
});
|
|
159
|
-
yield* conn.withGenerator(async function* (STORE) {
|
|
167
|
+
yield* this.conn.withGenerator(async function* (STORE) {
|
|
160
168
|
let filtered = Object.values(STORE.assistants)
|
|
161
169
|
.filter((assistant) => {
|
|
162
170
|
if (options.graph_id != null &&
|
|
@@ -190,11 +198,11 @@ export class Assistants {
|
|
|
190
198
|
}
|
|
191
199
|
});
|
|
192
200
|
}
|
|
193
|
-
|
|
201
|
+
async get(assistant_id, auth) {
|
|
194
202
|
const [filters] = await handleAuthEvent(auth, "assistants:read", {
|
|
195
203
|
assistant_id,
|
|
196
204
|
});
|
|
197
|
-
return conn.with((STORE) => {
|
|
205
|
+
return this.conn.with((STORE) => {
|
|
198
206
|
const result = STORE.assistants[assistant_id];
|
|
199
207
|
if (result == null)
|
|
200
208
|
throw new HTTPException(404, { message: "Assistant not found" });
|
|
@@ -204,7 +212,7 @@ export class Assistants {
|
|
|
204
212
|
return { ...result, name: result.name ?? result.graph_id };
|
|
205
213
|
});
|
|
206
214
|
}
|
|
207
|
-
|
|
215
|
+
async put(assistant_id, options, auth) {
|
|
208
216
|
const [filters, mutable] = await handleAuthEvent(auth, "assistants:create", {
|
|
209
217
|
assistant_id,
|
|
210
218
|
config: options.config,
|
|
@@ -214,7 +222,7 @@ export class Assistants {
|
|
|
214
222
|
if_exists: options.if_exists,
|
|
215
223
|
name: options.name,
|
|
216
224
|
});
|
|
217
|
-
return conn.with((STORE) => {
|
|
225
|
+
return this.conn.with((STORE) => {
|
|
218
226
|
if (STORE.assistants[assistant_id] != null) {
|
|
219
227
|
const existingAssistant = STORE.assistants[assistant_id];
|
|
220
228
|
if (!isAuthMatching(existingAssistant?.metadata, filters)) {
|
|
@@ -250,7 +258,7 @@ export class Assistants {
|
|
|
250
258
|
return STORE.assistants[assistant_id];
|
|
251
259
|
});
|
|
252
260
|
}
|
|
253
|
-
|
|
261
|
+
async patch(assistantId, options, auth) {
|
|
254
262
|
const [filters, mutable] = await handleAuthEvent(auth, "assistants:update", {
|
|
255
263
|
assistant_id: assistantId,
|
|
256
264
|
graph_id: options?.graph_id,
|
|
@@ -258,7 +266,7 @@ export class Assistants {
|
|
|
258
266
|
metadata: options?.metadata,
|
|
259
267
|
name: options?.name,
|
|
260
268
|
});
|
|
261
|
-
return conn.with((STORE) => {
|
|
269
|
+
return this.conn.with((STORE) => {
|
|
262
270
|
const assistant = STORE.assistants[assistantId];
|
|
263
271
|
if (!assistant) {
|
|
264
272
|
throw new HTTPException(404, { message: "Assistant not found" });
|
|
@@ -307,11 +315,11 @@ export class Assistants {
|
|
|
307
315
|
return assistant;
|
|
308
316
|
});
|
|
309
317
|
}
|
|
310
|
-
|
|
318
|
+
async delete(assistant_id, auth) {
|
|
311
319
|
const [filters] = await handleAuthEvent(auth, "assistants:delete", {
|
|
312
320
|
assistant_id,
|
|
313
321
|
});
|
|
314
|
-
return conn.with((STORE) => {
|
|
322
|
+
return this.conn.with((STORE) => {
|
|
315
323
|
const assistant = STORE.assistants[assistant_id];
|
|
316
324
|
if (!assistant) {
|
|
317
325
|
throw new HTTPException(404, { message: "Assistant not found" });
|
|
@@ -330,12 +338,12 @@ export class Assistants {
|
|
|
330
338
|
return [assistant.assistant_id];
|
|
331
339
|
});
|
|
332
340
|
}
|
|
333
|
-
|
|
341
|
+
async setLatest(assistant_id, version, auth) {
|
|
334
342
|
const [filters] = await handleAuthEvent(auth, "assistants:update", {
|
|
335
343
|
assistant_id,
|
|
336
344
|
version,
|
|
337
345
|
});
|
|
338
|
-
return conn.with((STORE) => {
|
|
346
|
+
return this.conn.with((STORE) => {
|
|
339
347
|
const assistant = STORE.assistants[assistant_id];
|
|
340
348
|
if (!assistant) {
|
|
341
349
|
throw new HTTPException(404, { message: "Assistant not found" });
|
|
@@ -360,11 +368,11 @@ export class Assistants {
|
|
|
360
368
|
return STORE.assistants[assistant_id];
|
|
361
369
|
});
|
|
362
370
|
}
|
|
363
|
-
|
|
371
|
+
async getVersions(assistant_id, options, auth) {
|
|
364
372
|
const [filters] = await handleAuthEvent(auth, "assistants:read", {
|
|
365
373
|
assistant_id,
|
|
366
374
|
});
|
|
367
|
-
return conn.with((STORE) => {
|
|
375
|
+
return this.conn.with((STORE) => {
|
|
368
376
|
const versions = STORE.assistant_versions
|
|
369
377
|
.filter((version) => {
|
|
370
378
|
if (version["assistant_id"] !== assistant_id)
|
|
@@ -382,9 +390,39 @@ export class Assistants {
|
|
|
382
390
|
return versions.slice(options.offset, options.offset + options.limit);
|
|
383
391
|
});
|
|
384
392
|
}
|
|
393
|
+
async count(options, auth) {
|
|
394
|
+
const [filters] = await handleAuthEvent(auth, "assistants:search", {
|
|
395
|
+
graph_id: options.graph_id,
|
|
396
|
+
metadata: options.metadata,
|
|
397
|
+
limit: 0,
|
|
398
|
+
offset: 0,
|
|
399
|
+
});
|
|
400
|
+
return this.conn.with((STORE) => {
|
|
401
|
+
return Object.values(STORE.assistants).filter((assistant) => {
|
|
402
|
+
if (options.graph_id != null &&
|
|
403
|
+
assistant["graph_id"] !== options.graph_id) {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
if (options.metadata != null &&
|
|
407
|
+
!isJsonbContained(assistant["metadata"], options.metadata)) {
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
if (!isAuthMatching(assistant["metadata"], filters)) {
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
return true;
|
|
414
|
+
}).length;
|
|
415
|
+
});
|
|
416
|
+
}
|
|
385
417
|
}
|
|
386
|
-
export class
|
|
387
|
-
|
|
418
|
+
export class FileSystemThreads {
|
|
419
|
+
conn;
|
|
420
|
+
state;
|
|
421
|
+
constructor(conn) {
|
|
422
|
+
this.conn = conn;
|
|
423
|
+
this.state = new FileSystemThreads.State(conn, this);
|
|
424
|
+
}
|
|
425
|
+
async *search(options, auth) {
|
|
388
426
|
const [filters] = await handleAuthEvent(auth, "threads:search", {
|
|
389
427
|
metadata: options.metadata,
|
|
390
428
|
status: options.status,
|
|
@@ -392,7 +430,7 @@ export class Threads {
|
|
|
392
430
|
limit: options.limit,
|
|
393
431
|
offset: options.offset,
|
|
394
432
|
});
|
|
395
|
-
yield* conn.withGenerator(async function* (STORE) {
|
|
433
|
+
yield* this.conn.withGenerator(async function* (STORE) {
|
|
396
434
|
const filtered = Object.values(STORE.threads)
|
|
397
435
|
.filter((thread) => {
|
|
398
436
|
if (options.metadata != null &&
|
|
@@ -433,11 +471,11 @@ export class Threads {
|
|
|
433
471
|
});
|
|
434
472
|
}
|
|
435
473
|
// TODO: make this accept `undefined`
|
|
436
|
-
|
|
474
|
+
async get(thread_id, auth) {
|
|
437
475
|
const [filters] = await handleAuthEvent(auth, "threads:read", {
|
|
438
476
|
thread_id,
|
|
439
477
|
});
|
|
440
|
-
return conn.with((STORE) => {
|
|
478
|
+
return this.conn.with((STORE) => {
|
|
441
479
|
const result = STORE.threads[thread_id];
|
|
442
480
|
if (result == null) {
|
|
443
481
|
throw new HTTPException(404, {
|
|
@@ -452,13 +490,13 @@ export class Threads {
|
|
|
452
490
|
return result;
|
|
453
491
|
});
|
|
454
492
|
}
|
|
455
|
-
|
|
493
|
+
async put(thread_id, options, auth) {
|
|
456
494
|
const [filters, mutable] = await handleAuthEvent(auth, "threads:create", {
|
|
457
495
|
thread_id,
|
|
458
496
|
metadata: options.metadata,
|
|
459
497
|
if_exists: options.if_exists,
|
|
460
498
|
});
|
|
461
|
-
return conn.with((STORE) => {
|
|
499
|
+
return this.conn.with((STORE) => {
|
|
462
500
|
const now = new Date();
|
|
463
501
|
if (STORE.threads[thread_id] != null) {
|
|
464
502
|
const existingThread = STORE.threads[thread_id];
|
|
@@ -482,12 +520,12 @@ export class Threads {
|
|
|
482
520
|
return STORE.threads[thread_id];
|
|
483
521
|
});
|
|
484
522
|
}
|
|
485
|
-
|
|
523
|
+
async patch(threadId, options, auth) {
|
|
486
524
|
const [filters, mutable] = await handleAuthEvent(auth, "threads:update", {
|
|
487
525
|
thread_id: threadId,
|
|
488
526
|
metadata: options.metadata,
|
|
489
527
|
});
|
|
490
|
-
return conn.with((STORE) => {
|
|
528
|
+
return this.conn.with((STORE) => {
|
|
491
529
|
const thread = STORE.threads[threadId];
|
|
492
530
|
if (!thread) {
|
|
493
531
|
throw new HTTPException(404, { message: "Thread not found" });
|
|
@@ -507,8 +545,8 @@ export class Threads {
|
|
|
507
545
|
return thread;
|
|
508
546
|
});
|
|
509
547
|
}
|
|
510
|
-
|
|
511
|
-
return conn.with((STORE) => {
|
|
548
|
+
async setStatus(threadId, options) {
|
|
549
|
+
return this.conn.with((STORE) => {
|
|
512
550
|
const thread = STORE.threads[threadId];
|
|
513
551
|
if (!thread)
|
|
514
552
|
throw new HTTPException(404, { message: "Thread not found" });
|
|
@@ -542,11 +580,11 @@ export class Threads {
|
|
|
542
580
|
: undefined;
|
|
543
581
|
});
|
|
544
582
|
}
|
|
545
|
-
|
|
583
|
+
async delete(thread_id, auth) {
|
|
546
584
|
const [filters] = await handleAuthEvent(auth, "threads:delete", {
|
|
547
585
|
thread_id,
|
|
548
586
|
});
|
|
549
|
-
return conn.with((STORE) => {
|
|
587
|
+
return this.conn.with((STORE) => {
|
|
550
588
|
const thread = STORE.threads[thread_id];
|
|
551
589
|
if (!thread) {
|
|
552
590
|
throw new HTTPException(404, {
|
|
@@ -568,11 +606,11 @@ export class Threads {
|
|
|
568
606
|
return [thread.thread_id];
|
|
569
607
|
});
|
|
570
608
|
}
|
|
571
|
-
|
|
609
|
+
async copy(thread_id, auth) {
|
|
572
610
|
const [filters] = await handleAuthEvent(auth, "threads:read", {
|
|
573
611
|
thread_id,
|
|
574
612
|
});
|
|
575
|
-
return conn.with((STORE) => {
|
|
613
|
+
return this.conn.with((STORE) => {
|
|
576
614
|
const thread = STORE.threads[thread_id];
|
|
577
615
|
if (!thread)
|
|
578
616
|
throw new HTTPException(409, { message: "Thread not found" });
|
|
@@ -593,11 +631,48 @@ export class Threads {
|
|
|
593
631
|
return STORE.threads[newThreadId];
|
|
594
632
|
});
|
|
595
633
|
}
|
|
634
|
+
async count(options, auth) {
|
|
635
|
+
const [filters] = await handleAuthEvent(auth, "threads:search", {
|
|
636
|
+
metadata: options.metadata,
|
|
637
|
+
values: options.values,
|
|
638
|
+
status: options.status,
|
|
639
|
+
limit: 0,
|
|
640
|
+
offset: 0,
|
|
641
|
+
});
|
|
642
|
+
return this.conn.with((STORE) => {
|
|
643
|
+
return Object.values(STORE.threads).filter((thread) => {
|
|
644
|
+
if (options.metadata != null &&
|
|
645
|
+
!isJsonbContained(thread["metadata"], options.metadata)) {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
648
|
+
if (options.values != null &&
|
|
649
|
+
typeof thread["values"] !== "undefined" &&
|
|
650
|
+
!isJsonbContained(thread["values"], options.values)) {
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
if (options.status != null && thread["status"] !== options.status) {
|
|
654
|
+
return false;
|
|
655
|
+
}
|
|
656
|
+
if (!isAuthMatching(thread["metadata"], filters)) {
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
return true;
|
|
660
|
+
}).length;
|
|
661
|
+
});
|
|
662
|
+
}
|
|
596
663
|
static State = class {
|
|
597
|
-
|
|
664
|
+
conn;
|
|
665
|
+
threads;
|
|
666
|
+
constructor(conn, threads) {
|
|
667
|
+
this.conn = conn;
|
|
668
|
+
this.threads = threads;
|
|
669
|
+
}
|
|
670
|
+
async get(config, options, auth) {
|
|
598
671
|
const subgraphs = options.subgraphs ?? false;
|
|
599
672
|
const threadId = config.configurable?.thread_id;
|
|
600
|
-
const thread = threadId
|
|
673
|
+
const thread = threadId
|
|
674
|
+
? await this.threads.get(threadId, auth)
|
|
675
|
+
: undefined;
|
|
601
676
|
const metadata = thread?.metadata ?? {};
|
|
602
677
|
const graphId = metadata?.graph_id;
|
|
603
678
|
if (!thread || graphId == null) {
|
|
@@ -623,12 +698,14 @@ export class Threads {
|
|
|
623
698
|
}
|
|
624
699
|
return result;
|
|
625
700
|
}
|
|
626
|
-
|
|
701
|
+
async post(config, values, asNode, auth) {
|
|
627
702
|
const threadId = config.configurable?.thread_id;
|
|
628
703
|
const [filters] = await handleAuthEvent(auth, "threads:update", {
|
|
629
704
|
thread_id: threadId,
|
|
630
705
|
});
|
|
631
|
-
const thread = threadId
|
|
706
|
+
const thread = threadId
|
|
707
|
+
? await this.threads.get(threadId, auth)
|
|
708
|
+
: undefined;
|
|
632
709
|
if (!thread)
|
|
633
710
|
throw new HTTPException(404, {
|
|
634
711
|
message: `Thread ${threadId} not found`,
|
|
@@ -637,7 +714,7 @@ export class Threads {
|
|
|
637
714
|
throw new HTTPException(403);
|
|
638
715
|
}
|
|
639
716
|
// do a check if there are no pending runs
|
|
640
|
-
await conn.with(async (STORE) => {
|
|
717
|
+
await this.conn.with(async (STORE) => {
|
|
641
718
|
if (Object.values(STORE.runs).some((run) => run.thread_id === threadId &&
|
|
642
719
|
(run.status === "pending" || run.status === "running"))) {
|
|
643
720
|
throw new HTTPException(409, { message: "Thread is busy" });
|
|
@@ -659,9 +736,9 @@ export class Threads {
|
|
|
659
736
|
updateConfig.configurable ??= {};
|
|
660
737
|
updateConfig.configurable.checkpoint_ns ??= "";
|
|
661
738
|
const nextConfig = await graph.updateState(updateConfig, values, asNode);
|
|
662
|
-
const state = await
|
|
739
|
+
const state = await this.get(config, { subgraphs: false }, auth);
|
|
663
740
|
// update thread values
|
|
664
|
-
await conn.with(async (STORE) => {
|
|
741
|
+
await this.conn.with(async (STORE) => {
|
|
665
742
|
for (const thread of Object.values(STORE.threads)) {
|
|
666
743
|
if (thread.thread_id === threadId) {
|
|
667
744
|
thread.values = state.values;
|
|
@@ -671,14 +748,14 @@ export class Threads {
|
|
|
671
748
|
});
|
|
672
749
|
return { checkpoint: nextConfig.configurable };
|
|
673
750
|
}
|
|
674
|
-
|
|
751
|
+
async bulk(config, supersteps, auth) {
|
|
675
752
|
const threadId = config.configurable?.thread_id;
|
|
676
753
|
if (!threadId)
|
|
677
754
|
return [];
|
|
678
755
|
const [filters] = await handleAuthEvent(auth, "threads:update", {
|
|
679
756
|
thread_id: threadId,
|
|
680
757
|
});
|
|
681
|
-
const thread = await
|
|
758
|
+
const thread = await this.threads.get(threadId, auth);
|
|
682
759
|
if (!isAuthMatching(thread["metadata"], filters)) {
|
|
683
760
|
throw new HTTPException(403);
|
|
684
761
|
}
|
|
@@ -703,9 +780,9 @@ export class Threads {
|
|
|
703
780
|
asNode: j.as_node,
|
|
704
781
|
})),
|
|
705
782
|
})));
|
|
706
|
-
const state = await
|
|
783
|
+
const state = await this.get(config, { subgraphs: false }, auth);
|
|
707
784
|
// update thread values
|
|
708
|
-
await conn.with(async (STORE) => {
|
|
785
|
+
await this.conn.with(async (STORE) => {
|
|
709
786
|
for (const thread of Object.values(STORE.threads)) {
|
|
710
787
|
if (thread.thread_id === threadId) {
|
|
711
788
|
thread.values = state.values;
|
|
@@ -715,14 +792,14 @@ export class Threads {
|
|
|
715
792
|
});
|
|
716
793
|
return { checkpoint: nextConfig.configurable };
|
|
717
794
|
}
|
|
718
|
-
|
|
795
|
+
async list(config, options, auth) {
|
|
719
796
|
const threadId = config.configurable?.thread_id;
|
|
720
797
|
if (!threadId)
|
|
721
798
|
return [];
|
|
722
799
|
const [filters] = await handleAuthEvent(auth, "threads:read", {
|
|
723
800
|
thread_id: threadId,
|
|
724
801
|
});
|
|
725
|
-
const thread = await
|
|
802
|
+
const thread = await this.threads.get(threadId, auth);
|
|
726
803
|
if (!isAuthMatching(thread["metadata"], filters))
|
|
727
804
|
return [];
|
|
728
805
|
const graphId = thread.metadata?.graph_id;
|
|
@@ -747,9 +824,17 @@ export class Threads {
|
|
|
747
824
|
}
|
|
748
825
|
};
|
|
749
826
|
}
|
|
750
|
-
export class
|
|
751
|
-
|
|
752
|
-
|
|
827
|
+
export class FileSystemRuns {
|
|
828
|
+
conn;
|
|
829
|
+
threads;
|
|
830
|
+
stream;
|
|
831
|
+
constructor(conn) {
|
|
832
|
+
this.conn = conn;
|
|
833
|
+
this.threads = new FileSystemThreads(conn);
|
|
834
|
+
this.stream = new FileSystemRuns.Stream(conn, this);
|
|
835
|
+
}
|
|
836
|
+
async *next() {
|
|
837
|
+
yield* this.conn.withGenerator(async function* (STORE, options) {
|
|
753
838
|
const now = new Date();
|
|
754
839
|
const pendingRunIds = Object.values(STORE.runs)
|
|
755
840
|
.filter((run) => run.status === "pending" && run.created_at < now)
|
|
@@ -790,8 +875,8 @@ export class Runs {
|
|
|
790
875
|
}
|
|
791
876
|
});
|
|
792
877
|
}
|
|
793
|
-
|
|
794
|
-
return conn.with(async (STORE) => {
|
|
878
|
+
async put(runId, assistantId, kwargs, options, auth) {
|
|
879
|
+
return this.conn.with(async (STORE) => {
|
|
795
880
|
const assistant = STORE.assistants[assistantId];
|
|
796
881
|
if (!assistant) {
|
|
797
882
|
throw new HTTPException(404, {
|
|
@@ -897,11 +982,11 @@ export class Runs {
|
|
|
897
982
|
return [newRun, ...inflightRuns];
|
|
898
983
|
});
|
|
899
984
|
}
|
|
900
|
-
|
|
985
|
+
async get(runId, thread_id, auth) {
|
|
901
986
|
const [filters] = await handleAuthEvent(auth, "threads:read", {
|
|
902
987
|
thread_id,
|
|
903
988
|
});
|
|
904
|
-
return conn.with(async (STORE) => {
|
|
989
|
+
return this.conn.with(async (STORE) => {
|
|
905
990
|
const run = STORE.runs[runId];
|
|
906
991
|
if (!run ||
|
|
907
992
|
run.run_id !== runId ||
|
|
@@ -915,12 +1000,12 @@ export class Runs {
|
|
|
915
1000
|
return run;
|
|
916
1001
|
});
|
|
917
1002
|
}
|
|
918
|
-
|
|
1003
|
+
async delete(run_id, thread_id, auth) {
|
|
919
1004
|
const [filters] = await handleAuthEvent(auth, "threads:delete", {
|
|
920
1005
|
run_id,
|
|
921
1006
|
thread_id,
|
|
922
1007
|
});
|
|
923
|
-
return conn.with(async (STORE) => {
|
|
1008
|
+
return this.conn.with(async (STORE) => {
|
|
924
1009
|
const run = STORE.runs[run_id];
|
|
925
1010
|
if (!run || (thread_id != null && run.thread_id !== thread_id))
|
|
926
1011
|
throw new HTTPException(404, { message: "Run not found" });
|
|
@@ -936,8 +1021,8 @@ export class Runs {
|
|
|
936
1021
|
return run.run_id;
|
|
937
1022
|
});
|
|
938
1023
|
}
|
|
939
|
-
|
|
940
|
-
const runStream =
|
|
1024
|
+
async wait(runId, threadId, auth) {
|
|
1025
|
+
const runStream = this.stream.join(runId, threadId, { ignore404: threadId == null, lastEventId: undefined }, auth);
|
|
941
1026
|
const lastChunk = new Promise(async (resolve, reject) => {
|
|
942
1027
|
try {
|
|
943
1028
|
let lastChunk = null;
|
|
@@ -957,17 +1042,17 @@ export class Runs {
|
|
|
957
1042
|
});
|
|
958
1043
|
return lastChunk;
|
|
959
1044
|
}
|
|
960
|
-
|
|
1045
|
+
async join(runId, threadId, auth) {
|
|
961
1046
|
// check if thread exists
|
|
962
|
-
await
|
|
963
|
-
const lastChunk = await
|
|
1047
|
+
await this.threads.get(threadId, auth);
|
|
1048
|
+
const lastChunk = await this.wait(runId, threadId, auth);
|
|
964
1049
|
if (lastChunk != null)
|
|
965
1050
|
return lastChunk;
|
|
966
|
-
const thread = await
|
|
1051
|
+
const thread = await this.threads.get(threadId, auth);
|
|
967
1052
|
return thread.values ?? null;
|
|
968
1053
|
}
|
|
969
|
-
|
|
970
|
-
return conn.with(async (STORE) => {
|
|
1054
|
+
async cancel(threadId, runIds, options, auth) {
|
|
1055
|
+
return this.conn.with(async (STORE) => {
|
|
971
1056
|
const action = options.action ?? "interrupt";
|
|
972
1057
|
const promises = [];
|
|
973
1058
|
const [filters] = await handleAuthEvent(auth, "threads:update", {
|
|
@@ -1004,7 +1089,7 @@ export class Runs {
|
|
|
1004
1089
|
run_id: runId,
|
|
1005
1090
|
thread_id: threadId,
|
|
1006
1091
|
});
|
|
1007
|
-
promises.push(
|
|
1092
|
+
promises.push(this.delete(runId, threadId, auth));
|
|
1008
1093
|
}
|
|
1009
1094
|
}
|
|
1010
1095
|
else {
|
|
@@ -1027,13 +1112,13 @@ export class Runs {
|
|
|
1027
1112
|
}
|
|
1028
1113
|
});
|
|
1029
1114
|
}
|
|
1030
|
-
|
|
1115
|
+
async search(threadId, options, auth) {
|
|
1031
1116
|
const [filters] = await handleAuthEvent(auth, "threads:search", {
|
|
1032
1117
|
thread_id: threadId,
|
|
1033
1118
|
metadata: options.metadata,
|
|
1034
1119
|
status: options.status,
|
|
1035
1120
|
});
|
|
1036
|
-
return conn.with(async (STORE) => {
|
|
1121
|
+
return this.conn.with(async (STORE) => {
|
|
1037
1122
|
const runs = Object.values(STORE.runs).filter((run) => {
|
|
1038
1123
|
if (run.thread_id !== threadId)
|
|
1039
1124
|
return false;
|
|
@@ -1052,8 +1137,8 @@ export class Runs {
|
|
|
1052
1137
|
return runs.slice(options?.offset ?? 0, options?.limit ?? 10);
|
|
1053
1138
|
});
|
|
1054
1139
|
}
|
|
1055
|
-
|
|
1056
|
-
return conn.with(async (STORE) => {
|
|
1140
|
+
async setStatus(runId, status) {
|
|
1141
|
+
return this.conn.with(async (STORE) => {
|
|
1057
1142
|
const run = STORE.runs[runId];
|
|
1058
1143
|
if (!run)
|
|
1059
1144
|
throw new Error(`Run ${runId} not found`);
|
|
@@ -1062,7 +1147,15 @@ export class Runs {
|
|
|
1062
1147
|
});
|
|
1063
1148
|
}
|
|
1064
1149
|
static Stream = class {
|
|
1065
|
-
|
|
1150
|
+
conn;
|
|
1151
|
+
runs;
|
|
1152
|
+
constructor(conn, runs) {
|
|
1153
|
+
this.conn = conn;
|
|
1154
|
+
this.runs = runs;
|
|
1155
|
+
}
|
|
1156
|
+
async *join(runId, threadId, options, auth) {
|
|
1157
|
+
const conn = this.conn;
|
|
1158
|
+
const runs = this.runs;
|
|
1066
1159
|
yield* conn.withGenerator(async function* (STORE) {
|
|
1067
1160
|
// TODO: what if we're joining an already completed run? Should we check before?
|
|
1068
1161
|
const signal = options?.cancelOnDisconnect;
|
|
@@ -1105,7 +1198,7 @@ export class Runs {
|
|
|
1105
1198
|
catch (error) {
|
|
1106
1199
|
if (error instanceof AbortError)
|
|
1107
1200
|
break;
|
|
1108
|
-
const run = await
|
|
1201
|
+
const run = await runs.get(runId, threadId, auth);
|
|
1109
1202
|
if (run == null) {
|
|
1110
1203
|
if (!options?.ignore404)
|
|
1111
1204
|
yield { event: "error", data: "Run not found" };
|
|
@@ -1117,11 +1210,11 @@ export class Runs {
|
|
|
1117
1210
|
}
|
|
1118
1211
|
}
|
|
1119
1212
|
if (signal?.aborted && threadId != null) {
|
|
1120
|
-
await
|
|
1213
|
+
await runs.cancel(threadId, [runId], { action: "interrupt" }, auth);
|
|
1121
1214
|
}
|
|
1122
1215
|
});
|
|
1123
1216
|
}
|
|
1124
|
-
|
|
1217
|
+
async publish(payload) {
|
|
1125
1218
|
const queue = StreamManager.getQueue(payload.runId, {
|
|
1126
1219
|
ifNotFound: "create",
|
|
1127
1220
|
resumable: payload.resumable,
|