@openviking/openclaw-plugin 2026.5.26 → 2026.6.17-dev.1
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/INSTALL-AGENT.md +355 -355
- package/INSTALL-ZH.md +405 -345
- package/INSTALL.md +366 -362
- package/README.md +364 -338
- package/adapters/http-transport.ts +3 -0
- package/adapters/resource-packager.ts +141 -0
- package/auto-recall.ts +518 -257
- package/client.ts +963 -939
- package/commands/setup.ts +1169 -1002
- package/config/feature-gates.json +10 -0
- package/config.ts +819 -476
- package/context-engine.ts +408 -1737
- package/dist/adapters/http-transport.js +1 -0
- package/dist/adapters/resource-packager.js +114 -0
- package/dist/auto-recall.js +228 -32
- package/dist/client.js +125 -161
- package/dist/commands/setup.js +170 -32
- package/dist/config.js +285 -64
- package/dist/context-engine.js +64 -1179
- package/dist/index.js +209 -1470
- package/dist/memory-ranking.js +35 -12
- package/dist/plugin/command-registration.js +5 -0
- package/dist/plugin/openviking-archive-tools.js +210 -0
- package/dist/plugin/openviking-bypass-runtime.js +8 -0
- package/dist/plugin/openviking-client-runtime.js +28 -0
- package/dist/plugin/openviking-command-args.js +146 -0
- package/dist/plugin/openviking-command-definitions.js +206 -0
- package/dist/plugin/openviking-context-engine-ref.js +11 -0
- package/dist/plugin/openviking-context-engine-registration.js +23 -0
- package/dist/plugin/openviking-feature-gates.js +250 -0
- package/dist/plugin/openviking-import-runtime.js +50 -0
- package/dist/plugin/openviking-import-tools.js +86 -0
- package/dist/plugin/openviking-lifecycle-hooks.js +33 -0
- package/dist/plugin/openviking-memory-recall-tools.js +233 -0
- package/dist/plugin/openviking-memory-tools.js +199 -0
- package/dist/plugin/openviking-query-config-command.js +203 -0
- package/dist/plugin/openviking-query-runtime.js +367 -0
- package/dist/plugin/openviking-query-tools.js +91 -0
- package/dist/plugin/openviking-recall-trace-runtime.js +387 -0
- package/dist/plugin/openviking-recall-trace-tools.js +38 -0
- package/dist/plugin/openviking-runtime-state.js +26 -0
- package/dist/plugin/openviking-runtime-utils.js +62 -0
- package/dist/plugin/openviking-services.js +20 -0
- package/dist/plugin/openviking-session-routing-runtime.js +61 -0
- package/dist/plugin/openviking-tool-result-tools.js +268 -0
- package/dist/plugin/recall-trace-routes.js +77 -0
- package/dist/plugin/tool-registration.js +23 -0
- package/dist/process-manager.js +5 -17
- package/dist/query-config.js +336 -0
- package/dist/recall-trace.js +309 -0
- package/dist/registries/recall-resource-types.js +58 -0
- package/dist/routing/identity-routing.js +152 -0
- package/dist/routing/memory-uri.js +7 -0
- package/dist/services/context-lifecycle-service.js +847 -0
- package/dist/services/context-message-adapter.js +340 -0
- package/dist/session-transcript-repair.js +0 -1
- package/dist/text-utils.js +14 -31
- package/dist/token-estimator.js +51 -0
- package/index.ts +408 -1985
- package/install-manifest.json +57 -47
- package/memory-ranking.ts +303 -267
- package/openclaw.plugin.json +497 -335
- package/package.json +86 -76
- package/plugin/command-registration.ts +34 -0
- package/plugin/openviking-archive-tools.ts +301 -0
- package/plugin/openviking-bypass-runtime.ts +26 -0
- package/plugin/openviking-client-runtime.ts +74 -0
- package/plugin/openviking-command-args.ts +187 -0
- package/plugin/openviking-command-definitions.ts +294 -0
- package/plugin/openviking-context-engine-ref.ts +16 -0
- package/plugin/openviking-context-engine-registration.ts +97 -0
- package/plugin/openviking-feature-gates.ts +335 -0
- package/plugin/openviking-import-runtime.ts +105 -0
- package/plugin/openviking-import-tools.ts +133 -0
- package/plugin/openviking-lifecycle-hooks.ts +65 -0
- package/plugin/openviking-memory-recall-tools.ts +368 -0
- package/plugin/openviking-memory-tools.ts +299 -0
- package/plugin/openviking-query-config-command.ts +230 -0
- package/plugin/openviking-query-formatters.ts +108 -0
- package/plugin/openviking-query-runtime.ts +476 -0
- package/plugin/openviking-query-tools.ts +161 -0
- package/plugin/openviking-recall-trace-runtime.ts +482 -0
- package/plugin/openviking-recall-trace-tools.ts +99 -0
- package/plugin/openviking-runtime-state.ts +52 -0
- package/plugin/openviking-runtime-utils.ts +67 -0
- package/plugin/openviking-services.ts +49 -0
- package/plugin/openviking-session-routing-runtime.ts +105 -0
- package/plugin/openviking-tool-result-tools.ts +397 -0
- package/plugin/recall-trace-routes.ts +133 -0
- package/plugin/tool-registration.ts +51 -0
- package/process-manager.ts +41 -45
- package/query-config.ts +400 -0
- package/recall-trace.ts +442 -0
- package/registries/openviking-tools.ts +84 -0
- package/registries/recall-resource-types.ts +74 -0
- package/routing/identity-routing.ts +210 -0
- package/routing/memory-uri.ts +8 -0
- package/runtime-utils.ts +5 -5
- package/services/context-lifecycle-service.ts +1209 -0
- package/services/context-message-adapter.ts +375 -0
- package/services/setup/config-writer.ts +125 -0
- package/services/setup/exit-utils.ts +5 -0
- package/services/setup/package-metadata.ts +56 -0
- package/services/setup/probe-service.ts +143 -0
- package/services/setup/setup-flow.ts +306 -0
- package/services/setup/version-compatibility.ts +41 -0
- package/session-transcript-repair.ts +528 -530
- package/skills/install-openviking-memory/SKILL.md +752 -665
- package/skills/openviking-context-database/SKILL.md +286 -0
- package/text-utils.ts +488 -507
- package/token-estimator.ts +65 -0
- package/tool-call-id.ts +331 -331
package/client.ts
CHANGED
|
@@ -1,939 +1,963 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { once } from "node:events";
|
|
3
|
-
import { createWriteStream } from "node:fs";
|
|
4
|
-
import { mkdtemp, readdir, readFile, rm, stat } from "node:fs/promises";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
6
|
-
import { basename, dirname, join, relative } from "node:path";
|
|
7
|
-
|
|
8
|
-
import { Zip, ZipDeflate } from "fflate";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
const
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
if (
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
return
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
}
|
|
510
|
-
return this.request<
|
|
511
|
-
`/api/v1/
|
|
512
|
-
{},
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
if (options?.
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
const
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
);
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
/**
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
);
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
async
|
|
898
|
-
sessionId: string,
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
return this.request(
|
|
916
|
-
|
|
917
|
-
{
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
}
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { once } from "node:events";
|
|
3
|
+
import { createWriteStream } from "node:fs";
|
|
4
|
+
import { mkdtemp, readdir, readFile, rm, stat } from "node:fs/promises";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { basename, dirname, join, relative } from "node:path";
|
|
7
|
+
|
|
8
|
+
import { Zip, ZipDeflate } from "fflate";
|
|
9
|
+
|
|
10
|
+
import { defaultHttpTransport, type HttpTransport } from "./adapters/http-transport.js";
|
|
11
|
+
import {
|
|
12
|
+
defaultResourcePackager,
|
|
13
|
+
type ResourcePackager,
|
|
14
|
+
} from "./adapters/resource-packager.js";
|
|
15
|
+
|
|
16
|
+
export type FindResultItem = {
|
|
17
|
+
uri: string;
|
|
18
|
+
level?: number;
|
|
19
|
+
abstract?: string;
|
|
20
|
+
overview?: string;
|
|
21
|
+
category?: string;
|
|
22
|
+
score?: number;
|
|
23
|
+
match_reason?: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type FindResult = {
|
|
27
|
+
memories?: FindResultItem[];
|
|
28
|
+
resources?: FindResultItem[];
|
|
29
|
+
skills?: FindResultItem[];
|
|
30
|
+
total?: number;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type FsListEntry = string | Record<string, unknown>;
|
|
34
|
+
|
|
35
|
+
export type FsListResult = FsListEntry[];
|
|
36
|
+
|
|
37
|
+
export type CaptureMode = "semantic" | "keyword";
|
|
38
|
+
function userSessionUri(sessionId: string): string {
|
|
39
|
+
return `viking://user/sessions/${encodeURIComponent(sessionId)}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type OpenVikingClientOptions = {
|
|
43
|
+
transport?: HttpTransport;
|
|
44
|
+
resourcePackager?: ResourcePackager;
|
|
45
|
+
now?: () => number;
|
|
46
|
+
sleep?: (ms: number) => Promise<void>;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type CommitSessionResult = {
|
|
50
|
+
session_id: string;
|
|
51
|
+
/** "accepted" (async), "completed", "failed", or "timeout" (wait mode). */
|
|
52
|
+
status: string;
|
|
53
|
+
task_id?: string;
|
|
54
|
+
archive_uri?: string;
|
|
55
|
+
archived?: boolean;
|
|
56
|
+
/** Present when wait=true and extraction completed. Keyed by category. */
|
|
57
|
+
memories_extracted?: Record<string, number>;
|
|
58
|
+
error?: string;
|
|
59
|
+
trace_id?: string;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type OVMemoryPolicySwitch = {
|
|
63
|
+
enabled?: boolean;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type OVMemoryPolicy = {
|
|
67
|
+
self?: OVMemoryPolicySwitch;
|
|
68
|
+
peer?: OVMemoryPolicySwitch;
|
|
69
|
+
memory_types?: string[];
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type TaskResult = {
|
|
73
|
+
task_id: string;
|
|
74
|
+
task_type: string;
|
|
75
|
+
status: string;
|
|
76
|
+
created_at: number;
|
|
77
|
+
updated_at: number;
|
|
78
|
+
resource_id?: string;
|
|
79
|
+
result?: Record<string, unknown>;
|
|
80
|
+
error?: string;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type OVMessagePart = {
|
|
84
|
+
type: string;
|
|
85
|
+
text?: string;
|
|
86
|
+
uri?: string;
|
|
87
|
+
abstract?: string;
|
|
88
|
+
context_type?: string;
|
|
89
|
+
tool_id?: string;
|
|
90
|
+
tool_name?: string;
|
|
91
|
+
tool_input?: unknown;
|
|
92
|
+
tool_output?: string;
|
|
93
|
+
tool_status?: string;
|
|
94
|
+
skill_uri?: string;
|
|
95
|
+
duration_ms?: number;
|
|
96
|
+
prompt_tokens?: number;
|
|
97
|
+
completion_tokens?: number;
|
|
98
|
+
tool_output_ref?: string;
|
|
99
|
+
tool_output_truncated?: boolean;
|
|
100
|
+
tool_output_original_chars?: number;
|
|
101
|
+
tool_output_preview_chars?: number;
|
|
102
|
+
tool_output_sha256?: string;
|
|
103
|
+
tool_output_storage_uri?: string;
|
|
104
|
+
tool_output_mime_type?: string;
|
|
105
|
+
tool_output_source_ref?: string;
|
|
106
|
+
tool_output_source_offset?: number;
|
|
107
|
+
tool_output_source_limit?: number;
|
|
108
|
+
tool_output_externalization_error?: string;
|
|
109
|
+
tool_output_group_id?: string;
|
|
110
|
+
tool_output_externalized_reason?: string;
|
|
111
|
+
tool_output_group_original_chars?: number;
|
|
112
|
+
tool_output_group_budget_chars?: number;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export type OVMessage = {
|
|
116
|
+
id: string;
|
|
117
|
+
role: string;
|
|
118
|
+
parts: OVMessagePart[];
|
|
119
|
+
created_at: string;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export type PreArchiveAbstract = {
|
|
123
|
+
archive_id: string;
|
|
124
|
+
abstract: string;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export type SessionContextResult = {
|
|
128
|
+
latest_archive_overview: string;
|
|
129
|
+
pre_archive_abstracts: PreArchiveAbstract[];
|
|
130
|
+
messages: OVMessage[];
|
|
131
|
+
estimatedTokens: number;
|
|
132
|
+
stats: {
|
|
133
|
+
totalArchives: number;
|
|
134
|
+
includedArchives: number;
|
|
135
|
+
droppedArchives: number;
|
|
136
|
+
failedArchives: number;
|
|
137
|
+
activeTokens: number;
|
|
138
|
+
archiveTokens: number;
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export type ToolResultReadResult = {
|
|
143
|
+
tool_result_id: string;
|
|
144
|
+
content: string;
|
|
145
|
+
offset: number;
|
|
146
|
+
limit: number;
|
|
147
|
+
offset_unit: "unicode_code_point";
|
|
148
|
+
total_chars: number;
|
|
149
|
+
has_more: boolean;
|
|
150
|
+
metadata?: Record<string, unknown>;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export type ToolResultSearchResult = {
|
|
154
|
+
tool_result_id: string;
|
|
155
|
+
matches: Array<{
|
|
156
|
+
offset: number;
|
|
157
|
+
offset_unit: "unicode_code_point";
|
|
158
|
+
snippet: string;
|
|
159
|
+
}>;
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export type ToolResultListResult = {
|
|
163
|
+
tool_results: Array<Record<string, unknown>>;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export type SessionArchiveResult = {
|
|
167
|
+
archive_id: string;
|
|
168
|
+
abstract: string;
|
|
169
|
+
overview: string;
|
|
170
|
+
messages: OVMessage[];
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export type AddResourceInput = {
|
|
174
|
+
pathOrUrl: string;
|
|
175
|
+
to?: string;
|
|
176
|
+
parent?: string;
|
|
177
|
+
reason?: string;
|
|
178
|
+
instruction?: string;
|
|
179
|
+
wait?: boolean;
|
|
180
|
+
timeout?: number;
|
|
181
|
+
strict?: boolean;
|
|
182
|
+
ignoreDirs?: string;
|
|
183
|
+
include?: string;
|
|
184
|
+
exclude?: string;
|
|
185
|
+
preserveStructure?: boolean;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export type AddResourceResult = {
|
|
189
|
+
status?: string;
|
|
190
|
+
root_uri?: string;
|
|
191
|
+
temp_uri?: string;
|
|
192
|
+
source_path?: string;
|
|
193
|
+
warnings?: string[];
|
|
194
|
+
errors?: string[];
|
|
195
|
+
queue_status?: unknown;
|
|
196
|
+
meta?: unknown;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export type AddSkillInput = {
|
|
200
|
+
path?: string;
|
|
201
|
+
data?: unknown;
|
|
202
|
+
wait?: boolean;
|
|
203
|
+
timeout?: number;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
export type AddSkillResult = {
|
|
207
|
+
status?: string;
|
|
208
|
+
uri?: string;
|
|
209
|
+
name?: string;
|
|
210
|
+
auxiliary_files?: number;
|
|
211
|
+
queue_status?: unknown;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const DEFAULT_WAIT_REQUEST_TIMEOUT_MS = 120_000;
|
|
215
|
+
export const DEFAULT_PHASE2_POLL_TIMEOUT_MS = 300_000;
|
|
216
|
+
const WAIT_REQUEST_TIMEOUT_BUFFER_MS = 5_000;
|
|
217
|
+
|
|
218
|
+
function sleep(ms: number): Promise<void> {
|
|
219
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const MEMORY_URI_PATTERNS = [
|
|
223
|
+
/^viking:\/\/user\/(?:[^/]+\/)?memories(?:\/|$)/,
|
|
224
|
+
];
|
|
225
|
+
const REMOTE_RESOURCE_PREFIXES = ["http://", "https://", "git@", "ssh://", "git://"];
|
|
226
|
+
|
|
227
|
+
export function isMemoryUri(uri: string): boolean {
|
|
228
|
+
return MEMORY_URI_PATTERNS.some((pattern) => pattern.test(uri));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function isRemoteResourceSource(source: string): boolean {
|
|
232
|
+
return REMOTE_RESOURCE_PREFIXES.some((prefix) => source.startsWith(prefix));
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function toBlobPart(value: Buffer): ArrayBuffer {
|
|
236
|
+
return value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength) as ArrayBuffer;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function resolveWaitRequestTimeoutMs(defaultTimeoutMs: number, waitTimeoutSeconds?: number): number {
|
|
240
|
+
const requestedMs =
|
|
241
|
+
typeof waitTimeoutSeconds === "number" && Number.isFinite(waitTimeoutSeconds) && waitTimeoutSeconds > 0
|
|
242
|
+
? Math.ceil(waitTimeoutSeconds * 1000) + WAIT_REQUEST_TIMEOUT_BUFFER_MS
|
|
243
|
+
: DEFAULT_WAIT_REQUEST_TIMEOUT_MS;
|
|
244
|
+
return Math.max(defaultTimeoutMs, requestedMs);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async function cleanupUploadTempPath(path?: string): Promise<void> {
|
|
248
|
+
if (!path) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
await rm(path, { force: true }).catch(() => undefined);
|
|
252
|
+
await rm(dirname(path), { recursive: true, force: true }).catch(() => undefined);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export class OpenVikingClient {
|
|
256
|
+
private readonly transport: HttpTransport;
|
|
257
|
+
private readonly now: () => number;
|
|
258
|
+
private readonly sleep: (ms: number) => Promise<void>;
|
|
259
|
+
private readonly resourcePackager: ResourcePackager;
|
|
260
|
+
|
|
261
|
+
constructor(
|
|
262
|
+
private readonly baseUrl: string,
|
|
263
|
+
private readonly apiKey: string,
|
|
264
|
+
private readonly defaultAgentId: string,
|
|
265
|
+
private readonly timeoutMs: number,
|
|
266
|
+
/** When set, sent so ROOT keys or trusted deployments can select tenant identity. */
|
|
267
|
+
private readonly accountId: string = "",
|
|
268
|
+
private readonly userId: string = "",
|
|
269
|
+
/** When set, logs routing for find + session writes (tenant headers + paths; never apiKey). */
|
|
270
|
+
private readonly routingDebugLog?: (message: string) => void,
|
|
271
|
+
optionsOrLegacyUserScope: OpenVikingClientOptions | boolean = {},
|
|
272
|
+
_legacyAgentScope?: boolean,
|
|
273
|
+
legacyOptions?: OpenVikingClientOptions,
|
|
274
|
+
) {
|
|
275
|
+
const options =
|
|
276
|
+
typeof optionsOrLegacyUserScope === "object" && optionsOrLegacyUserScope !== null
|
|
277
|
+
? optionsOrLegacyUserScope
|
|
278
|
+
: (legacyOptions ?? {});
|
|
279
|
+
this.transport = options.transport ?? defaultHttpTransport;
|
|
280
|
+
this.now = options.now ?? Date.now;
|
|
281
|
+
this.sleep = options.sleep ?? sleep;
|
|
282
|
+
this.resourcePackager = options.resourcePackager ?? defaultResourcePackager;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
getDefaultAgentId(): string {
|
|
286
|
+
return this.defaultAgentId;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
private resolveTenantHeaders():
|
|
290
|
+
| { apiKey?: string; accountId?: string; userId?: string }
|
|
291
|
+
{
|
|
292
|
+
const apiKey = this.apiKey.trim();
|
|
293
|
+
const accountId = this.accountId.trim();
|
|
294
|
+
const userId = this.userId.trim();
|
|
295
|
+
return {
|
|
296
|
+
...(apiKey ? { apiKey } : {}),
|
|
297
|
+
...(accountId ? { accountId } : {}),
|
|
298
|
+
...(userId ? { userId } : {}),
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private resolveActorPeerHeader(actorPeerId?: string): string | undefined {
|
|
303
|
+
const value = actorPeerId?.trim();
|
|
304
|
+
return value || undefined;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private resolveDefaultActorPeerHeader(): string {
|
|
308
|
+
const peerPrefix = this.defaultAgentId.trim();
|
|
309
|
+
return peerPrefix ? `${peerPrefix}_main` : "main";
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
private async emitRoutingDebug(
|
|
313
|
+
label: string,
|
|
314
|
+
detail: Record<string, unknown>,
|
|
315
|
+
actorPeerId?: string,
|
|
316
|
+
): Promise<void> {
|
|
317
|
+
if (!this.routingDebugLog) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const tenantHeaders = this.resolveTenantHeaders();
|
|
321
|
+
const actorPeerHeader = this.resolveActorPeerHeader(actorPeerId);
|
|
322
|
+
this.routingDebugLog(
|
|
323
|
+
`openviking: ${label} ` +
|
|
324
|
+
JSON.stringify({
|
|
325
|
+
...detail,
|
|
326
|
+
X_OpenViking_Account: tenantHeaders.accountId ?? null,
|
|
327
|
+
X_OpenViking_User: tenantHeaders.userId ?? null,
|
|
328
|
+
X_OpenViking_Actor_Peer: actorPeerHeader ?? null,
|
|
329
|
+
session_vfs_hint: detail.sessionId
|
|
330
|
+
? userSessionUri(String(detail.sessionId))
|
|
331
|
+
: undefined,
|
|
332
|
+
}),
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
private async request<T>(
|
|
337
|
+
path: string,
|
|
338
|
+
init: RequestInit = {},
|
|
339
|
+
requestTimeoutMs?: number,
|
|
340
|
+
actorPeerId?: string,
|
|
341
|
+
): Promise<T> {
|
|
342
|
+
const controller = new AbortController();
|
|
343
|
+
const timer = setTimeout(() => controller.abort(), requestTimeoutMs ?? this.timeoutMs);
|
|
344
|
+
try {
|
|
345
|
+
const headers = new Headers(init.headers ?? {});
|
|
346
|
+
const tenantHeaders = this.resolveTenantHeaders();
|
|
347
|
+
if (tenantHeaders.apiKey) {
|
|
348
|
+
headers.set("X-API-Key", tenantHeaders.apiKey);
|
|
349
|
+
}
|
|
350
|
+
if (tenantHeaders.accountId) {
|
|
351
|
+
headers.set("X-OpenViking-Account", tenantHeaders.accountId);
|
|
352
|
+
}
|
|
353
|
+
if (tenantHeaders.userId) {
|
|
354
|
+
headers.set("X-OpenViking-User", tenantHeaders.userId);
|
|
355
|
+
}
|
|
356
|
+
const actorPeerHeader = this.resolveActorPeerHeader(actorPeerId);
|
|
357
|
+
if (actorPeerHeader) {
|
|
358
|
+
headers.set("X-OpenViking-Actor-Peer", actorPeerHeader);
|
|
359
|
+
}
|
|
360
|
+
if (init.body && !(init.body instanceof FormData) && !headers.has("Content-Type")) {
|
|
361
|
+
headers.set("Content-Type", "application/json");
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const response = await this.transport(`${this.baseUrl}${path}`, {
|
|
365
|
+
...init,
|
|
366
|
+
headers,
|
|
367
|
+
signal: controller.signal,
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
const payload = (await response.json().catch(() => ({}))) as {
|
|
371
|
+
status?: string;
|
|
372
|
+
result?: T;
|
|
373
|
+
error?: { code?: string; message?: string };
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
if (!response.ok || payload.status === "error") {
|
|
377
|
+
const code = payload.error?.code ? ` [${payload.error.code}]` : "";
|
|
378
|
+
const message = payload.error?.message ?? `HTTP ${response.status}`;
|
|
379
|
+
throw new Error(`OpenViking request failed${code}: ${message}`);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return (payload.result ?? payload) as T;
|
|
383
|
+
} finally {
|
|
384
|
+
clearTimeout(timer);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
async healthCheck(requestTimeoutMs?: number, actorPeerId?: string): Promise<void> {
|
|
389
|
+
await this.request<{ status: string }>(
|
|
390
|
+
"/health",
|
|
391
|
+
{},
|
|
392
|
+
requestTimeoutMs,
|
|
393
|
+
actorPeerId ?? this.resolveDefaultActorPeerHeader(),
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
async createSession(
|
|
398
|
+
sessionId: string,
|
|
399
|
+
options?: { memoryPolicy?: OVMemoryPolicy },
|
|
400
|
+
): Promise<{ session_id: string; user?: unknown }> {
|
|
401
|
+
const body: Record<string, unknown> = { session_id: sessionId };
|
|
402
|
+
if (options?.memoryPolicy) {
|
|
403
|
+
body.memory_policy = options.memoryPolicy;
|
|
404
|
+
}
|
|
405
|
+
return this.request<{ session_id: string; user?: unknown }>(
|
|
406
|
+
"/api/v1/sessions",
|
|
407
|
+
{ method: "POST", body: JSON.stringify(body) },
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
async ensureSession(
|
|
412
|
+
sessionId: string,
|
|
413
|
+
options?: { memoryPolicy?: OVMemoryPolicy },
|
|
414
|
+
): Promise<boolean> {
|
|
415
|
+
try {
|
|
416
|
+
await this.createSession(sessionId, options);
|
|
417
|
+
return true;
|
|
418
|
+
} catch (err) {
|
|
419
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
420
|
+
if (message.includes("[ALREADY_EXISTS]")) {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
throw err;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
async find(
|
|
428
|
+
query: string,
|
|
429
|
+
options: {
|
|
430
|
+
targetUri?: string;
|
|
431
|
+
limit?: number;
|
|
432
|
+
scoreThreshold?: number;
|
|
433
|
+
contextType?: string | string[];
|
|
434
|
+
actorPeerId?: string;
|
|
435
|
+
},
|
|
436
|
+
legacyActorPeerId?: string,
|
|
437
|
+
): Promise<FindResult> {
|
|
438
|
+
const targetUri = options.targetUri?.trim().replace(/\/+$/, "") ?? "";
|
|
439
|
+
const body: {
|
|
440
|
+
query: string;
|
|
441
|
+
target_uri?: string;
|
|
442
|
+
limit?: number;
|
|
443
|
+
score_threshold?: number;
|
|
444
|
+
context_type?: string | string[];
|
|
445
|
+
} = {
|
|
446
|
+
query,
|
|
447
|
+
limit: options.limit,
|
|
448
|
+
score_threshold: options.scoreThreshold,
|
|
449
|
+
context_type: options.contextType,
|
|
450
|
+
};
|
|
451
|
+
if (targetUri) {
|
|
452
|
+
body.target_uri = targetUri;
|
|
453
|
+
}
|
|
454
|
+
const actorPeerId = this.resolveActorPeerHeader(options.actorPeerId ?? legacyActorPeerId);
|
|
455
|
+
const tenantHeaders = this.resolveTenantHeaders();
|
|
456
|
+
this.routingDebugLog?.(
|
|
457
|
+
`openviking: find POST ${this.baseUrl}/api/v1/search/find ` +
|
|
458
|
+
JSON.stringify({
|
|
459
|
+
X_OpenViking_Account: tenantHeaders.accountId ?? null,
|
|
460
|
+
X_OpenViking_User: tenantHeaders.userId ?? null,
|
|
461
|
+
X_OpenViking_Actor_Peer: actorPeerId ?? null,
|
|
462
|
+
target_uri: targetUri || null,
|
|
463
|
+
target_uri_input: options.targetUri,
|
|
464
|
+
query:
|
|
465
|
+
query.length > 4000
|
|
466
|
+
? `${query.slice(0, 4000)}…(+${query.length - 4000} more chars)`
|
|
467
|
+
: query,
|
|
468
|
+
limit: body.limit,
|
|
469
|
+
score_threshold: body.score_threshold ?? null,
|
|
470
|
+
context_type: body.context_type ?? null,
|
|
471
|
+
}),
|
|
472
|
+
);
|
|
473
|
+
return this.request<FindResult>("/api/v1/search/find", {
|
|
474
|
+
method: "POST",
|
|
475
|
+
body: JSON.stringify(body),
|
|
476
|
+
}, undefined, actorPeerId);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
async read(uri: string, actorPeerId?: string): Promise<string> {
|
|
480
|
+
return this.request<string>(
|
|
481
|
+
`/api/v1/content/read?uri=${encodeURIComponent(uri)}`,
|
|
482
|
+
{},
|
|
483
|
+
undefined,
|
|
484
|
+
actorPeerId,
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
async list(
|
|
489
|
+
uri: string,
|
|
490
|
+
options?: {
|
|
491
|
+
recursive?: boolean;
|
|
492
|
+
simple?: boolean;
|
|
493
|
+
output?: "agent" | "original";
|
|
494
|
+
absLimit?: number;
|
|
495
|
+
showAllHidden?: boolean;
|
|
496
|
+
nodeLimit?: number;
|
|
497
|
+
actorPeerId?: string;
|
|
498
|
+
},
|
|
499
|
+
): Promise<FsListResult> {
|
|
500
|
+
const normalizedUri = uri.trim().replace(/\/+$/, "");
|
|
501
|
+
const params = new URLSearchParams({
|
|
502
|
+
uri: normalizedUri,
|
|
503
|
+
recursive: String(options?.recursive ?? false),
|
|
504
|
+
simple: String(options?.simple ?? false),
|
|
505
|
+
output: options?.output ?? "agent",
|
|
506
|
+
abs_limit: String(options?.absLimit ?? 256),
|
|
507
|
+
show_all_hidden: String(options?.showAllHidden ?? false),
|
|
508
|
+
node_limit: String(options?.nodeLimit ?? 1000),
|
|
509
|
+
});
|
|
510
|
+
return this.request<FsListResult>(
|
|
511
|
+
`/api/v1/fs/ls?${params.toString()}`,
|
|
512
|
+
{},
|
|
513
|
+
undefined,
|
|
514
|
+
options?.actorPeerId,
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
async readToolResult(
|
|
519
|
+
sessionId: string,
|
|
520
|
+
toolResultId: string,
|
|
521
|
+
options?: { offset?: number; limit?: number; includeMetadata?: boolean },
|
|
522
|
+
): Promise<ToolResultReadResult> {
|
|
523
|
+
const params = new URLSearchParams();
|
|
524
|
+
if (options?.offset !== undefined) params.set("offset", String(options.offset));
|
|
525
|
+
if (options?.limit !== undefined) params.set("limit", String(options.limit));
|
|
526
|
+
if (options?.includeMetadata !== undefined) {
|
|
527
|
+
params.set("include_metadata", String(options.includeMetadata));
|
|
528
|
+
}
|
|
529
|
+
const query = params.toString();
|
|
530
|
+
return this.request<ToolResultReadResult>(
|
|
531
|
+
`/api/v1/sessions/${encodeURIComponent(sessionId)}/tool-results/${encodeURIComponent(toolResultId)}${query ? `?${query}` : ""}`,
|
|
532
|
+
{},
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
async searchToolResult(
|
|
537
|
+
sessionId: string,
|
|
538
|
+
toolResultId: string,
|
|
539
|
+
queryText: string,
|
|
540
|
+
options?: { limit?: number; contextChars?: number },
|
|
541
|
+
): Promise<ToolResultSearchResult> {
|
|
542
|
+
const params = new URLSearchParams({ q: queryText });
|
|
543
|
+
if (options?.limit !== undefined) params.set("limit", String(options.limit));
|
|
544
|
+
if (options?.contextChars !== undefined) {
|
|
545
|
+
params.set("context_chars", String(options.contextChars));
|
|
546
|
+
}
|
|
547
|
+
return this.request<ToolResultSearchResult>(
|
|
548
|
+
`/api/v1/sessions/${encodeURIComponent(sessionId)}/tool-results/${encodeURIComponent(toolResultId)}/search?${params.toString()}`,
|
|
549
|
+
{},
|
|
550
|
+
);
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
async listToolResults(
|
|
554
|
+
sessionId: string,
|
|
555
|
+
options?: { toolName?: string; limit?: number },
|
|
556
|
+
): Promise<ToolResultListResult> {
|
|
557
|
+
const params = new URLSearchParams();
|
|
558
|
+
if (options?.toolName) params.set("tool_name", options.toolName);
|
|
559
|
+
if (options?.limit !== undefined) params.set("limit", String(options.limit));
|
|
560
|
+
const query = params.toString();
|
|
561
|
+
return this.request<ToolResultListResult>(
|
|
562
|
+
`/api/v1/sessions/${encodeURIComponent(sessionId)}/tool-results${query ? `?${query}` : ""}`,
|
|
563
|
+
{},
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
async uploadTempFile(filePath: string, actorPeerId?: string): Promise<string> {
|
|
568
|
+
const form = await this.resourcePackager.createTempUploadBody(filePath);
|
|
569
|
+
const result = await this.request<{ temp_file_id: string }>(
|
|
570
|
+
"/api/v1/resources/temp_upload",
|
|
571
|
+
{ method: "POST", body: form },
|
|
572
|
+
undefined,
|
|
573
|
+
actorPeerId,
|
|
574
|
+
);
|
|
575
|
+
if (!result.temp_file_id) {
|
|
576
|
+
throw new Error("OpenViking temp upload did not return temp_file_id");
|
|
577
|
+
}
|
|
578
|
+
return result.temp_file_id;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
async zipDirectoryForUpload(dirPath: string): Promise<string> {
|
|
582
|
+
const rootStats = await stat(dirPath);
|
|
583
|
+
if (!rootStats.isDirectory()) {
|
|
584
|
+
throw new Error(`Not a directory: ${dirPath}`);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const zipDir = await mkdtemp(join(tmpdir(), "openviking-openclaw-upload-"));
|
|
588
|
+
const zipPath = join(zipDir, `${basename(dirPath).replace(/[^a-zA-Z0-9._-]/g, "_")}-${randomUUID()}.zip`);
|
|
589
|
+
const output = createWriteStream(zipPath);
|
|
590
|
+
const outputClosed = once(output, "close");
|
|
591
|
+
const outputErrored = once(output, "error").then(([err]) => Promise.reject(err));
|
|
592
|
+
const zip = new Zip((err, chunk, final) => {
|
|
593
|
+
if (err) {
|
|
594
|
+
output.destroy(err);
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
if (chunk?.length) {
|
|
598
|
+
output.write(Buffer.from(chunk));
|
|
599
|
+
}
|
|
600
|
+
if (final) {
|
|
601
|
+
output.end();
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
const walk = async (currentDir: string) => {
|
|
606
|
+
const entries = await readdir(currentDir, { withFileTypes: true });
|
|
607
|
+
for (const entry of entries) {
|
|
608
|
+
const fullPath = join(currentDir, entry.name);
|
|
609
|
+
if (entry.isDirectory()) {
|
|
610
|
+
await walk(fullPath);
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
if (!entry.isFile()) {
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
const relPath = relative(dirPath, fullPath).replace(/\\/g, "/");
|
|
617
|
+
if (!relPath || relPath.startsWith("../") || relPath.includes("/../")) {
|
|
618
|
+
throw new Error(`Unsafe relative path while zipping: ${relPath}`);
|
|
619
|
+
}
|
|
620
|
+
const file = new ZipDeflate(relPath);
|
|
621
|
+
zip.add(file);
|
|
622
|
+
file.push(new Uint8Array(await readFile(fullPath)), true);
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
try {
|
|
626
|
+
await walk(dirPath);
|
|
627
|
+
zip.end();
|
|
628
|
+
await Promise.race([outputClosed, outputErrored]);
|
|
629
|
+
} catch (err) {
|
|
630
|
+
zip.terminate();
|
|
631
|
+
output.destroy(err as Error);
|
|
632
|
+
await cleanupUploadTempPath(zipPath);
|
|
633
|
+
throw err;
|
|
634
|
+
}
|
|
635
|
+
return zipPath;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
async addResource(input: AddResourceInput, actorPeerId?: string): Promise<AddResourceResult> {
|
|
639
|
+
const pathOrUrl = input.pathOrUrl.trim();
|
|
640
|
+
if (!pathOrUrl) {
|
|
641
|
+
throw new Error("pathOrUrl is required");
|
|
642
|
+
}
|
|
643
|
+
if (input.to && input.parent) {
|
|
644
|
+
throw new Error("Cannot specify both 'to' and 'parent'.");
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
const body: Record<string, unknown> = {
|
|
648
|
+
to: input.to,
|
|
649
|
+
parent: input.parent,
|
|
650
|
+
reason: input.reason ?? "",
|
|
651
|
+
instruction: input.instruction ?? "",
|
|
652
|
+
wait: input.wait ?? false,
|
|
653
|
+
timeout: input.timeout,
|
|
654
|
+
strict: input.strict ?? false,
|
|
655
|
+
ignore_dirs: input.ignoreDirs,
|
|
656
|
+
include: input.include,
|
|
657
|
+
exclude: input.exclude,
|
|
658
|
+
};
|
|
659
|
+
if (typeof input.preserveStructure === "boolean") {
|
|
660
|
+
body.preserve_structure = input.preserveStructure;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
let packagedSource: Awaited<ReturnType<ResourcePackager["prepareResourceSource"]>> | undefined;
|
|
664
|
+
const requestTimeoutMs =
|
|
665
|
+
input.wait ? resolveWaitRequestTimeoutMs(this.timeoutMs, input.timeout) : undefined;
|
|
666
|
+
try {
|
|
667
|
+
packagedSource = await this.resourcePackager.prepareResourceSource(pathOrUrl);
|
|
668
|
+
if (packagedSource.kind === "remote") {
|
|
669
|
+
body.path = packagedSource.path;
|
|
670
|
+
} else {
|
|
671
|
+
if (packagedSource.sourceName) {
|
|
672
|
+
body.source_name = packagedSource.sourceName;
|
|
673
|
+
}
|
|
674
|
+
body.temp_file_id = await this.uploadTempFile(packagedSource.uploadPath, actorPeerId);
|
|
675
|
+
}
|
|
676
|
+
return this.request<AddResourceResult>(
|
|
677
|
+
"/api/v1/resources",
|
|
678
|
+
{ method: "POST", body: JSON.stringify(body) },
|
|
679
|
+
requestTimeoutMs,
|
|
680
|
+
actorPeerId,
|
|
681
|
+
);
|
|
682
|
+
} finally {
|
|
683
|
+
await this.resourcePackager.cleanup(packagedSource);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
async addSkill(input: AddSkillInput, actorPeerId?: string): Promise<AddSkillResult> {
|
|
688
|
+
const hasPath = typeof input.path === "string" && input.path.trim().length > 0;
|
|
689
|
+
const hasData = input.data !== undefined && input.data !== null;
|
|
690
|
+
if (hasPath === hasData) {
|
|
691
|
+
throw new Error("Provide exactly one of 'path' or 'data' for skill import.");
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
const body: Record<string, unknown> = {
|
|
695
|
+
wait: input.wait ?? false,
|
|
696
|
+
timeout: input.timeout,
|
|
697
|
+
};
|
|
698
|
+
let packagedSource: Awaited<ReturnType<ResourcePackager["prepareLocalUploadSource"]>> | undefined;
|
|
699
|
+
const requestTimeoutMs =
|
|
700
|
+
input.wait ? resolveWaitRequestTimeoutMs(this.timeoutMs, input.timeout) : undefined;
|
|
701
|
+
try {
|
|
702
|
+
if (hasPath) {
|
|
703
|
+
const skillPath = input.path!.trim();
|
|
704
|
+
packagedSource = await this.resourcePackager.prepareLocalUploadSource(skillPath);
|
|
705
|
+
if (packagedSource.kind !== "upload") {
|
|
706
|
+
throw new Error(`Path is not a file or directory: ${skillPath}`);
|
|
707
|
+
}
|
|
708
|
+
body.temp_file_id = await this.uploadTempFile(packagedSource.uploadPath, actorPeerId);
|
|
709
|
+
} else {
|
|
710
|
+
body.data = input.data;
|
|
711
|
+
}
|
|
712
|
+
return this.request<AddSkillResult>(
|
|
713
|
+
"/api/v1/skills",
|
|
714
|
+
{ method: "POST", body: JSON.stringify(body) },
|
|
715
|
+
requestTimeoutMs,
|
|
716
|
+
actorPeerId,
|
|
717
|
+
);
|
|
718
|
+
} finally {
|
|
719
|
+
await this.resourcePackager.cleanup(packagedSource);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
async addSessionMessage(
|
|
724
|
+
sessionId: string,
|
|
725
|
+
role: string,
|
|
726
|
+
parts: Array<{
|
|
727
|
+
type: "text" | "tool" | "context";
|
|
728
|
+
text?: string;
|
|
729
|
+
tool_name?: string;
|
|
730
|
+
tool_output?: string;
|
|
731
|
+
tool_status?: string;
|
|
732
|
+
tool_input?: Record<string, unknown>;
|
|
733
|
+
tool_id?: string;
|
|
734
|
+
tool_output_ref?: string;
|
|
735
|
+
tool_output_truncated?: boolean;
|
|
736
|
+
tool_output_original_chars?: number;
|
|
737
|
+
tool_output_preview_chars?: number;
|
|
738
|
+
tool_output_sha256?: string;
|
|
739
|
+
tool_output_storage_uri?: string;
|
|
740
|
+
tool_output_mime_type?: string;
|
|
741
|
+
tool_output_source_ref?: string;
|
|
742
|
+
tool_output_source_offset?: number;
|
|
743
|
+
tool_output_source_limit?: number;
|
|
744
|
+
tool_output_group_id?: string;
|
|
745
|
+
tool_output_externalized_reason?: string;
|
|
746
|
+
tool_output_group_original_chars?: number;
|
|
747
|
+
tool_output_group_budget_chars?: number;
|
|
748
|
+
uri?: string;
|
|
749
|
+
abstract?: string;
|
|
750
|
+
context_type?: "memory" | "resource" | "skill";
|
|
751
|
+
}>,
|
|
752
|
+
actorPeerId?: string,
|
|
753
|
+
createdAt?: string,
|
|
754
|
+
roleId?: string,
|
|
755
|
+
): Promise<void> {
|
|
756
|
+
const body: {
|
|
757
|
+
role: string;
|
|
758
|
+
role_id?: string;
|
|
759
|
+
parts: typeof parts;
|
|
760
|
+
created_at?: string;
|
|
761
|
+
} = { role, parts };
|
|
762
|
+
if (createdAt) {
|
|
763
|
+
body.created_at = createdAt;
|
|
764
|
+
}
|
|
765
|
+
if (roleId) {
|
|
766
|
+
body.role_id = roleId;
|
|
767
|
+
}
|
|
768
|
+
await this.emitRoutingDebug(
|
|
769
|
+
"session message POST (with parts)",
|
|
770
|
+
{
|
|
771
|
+
path: `/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`,
|
|
772
|
+
sessionId,
|
|
773
|
+
role,
|
|
774
|
+
role_id: roleId ?? null,
|
|
775
|
+
partCount: parts.length,
|
|
776
|
+
created_at: createdAt ?? null,
|
|
777
|
+
},
|
|
778
|
+
actorPeerId,
|
|
779
|
+
);
|
|
780
|
+
await this.request<{ session_id: string }>(
|
|
781
|
+
`/api/v1/sessions/${encodeURIComponent(sessionId)}/messages`,
|
|
782
|
+
{
|
|
783
|
+
method: "POST",
|
|
784
|
+
body: JSON.stringify(body),
|
|
785
|
+
},
|
|
786
|
+
undefined,
|
|
787
|
+
actorPeerId,
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/** GET session — server auto-creates if absent; returns session meta including message stats and token usage. */
|
|
792
|
+
async getSession(sessionId: string, actorPeerId?: string): Promise<{
|
|
793
|
+
message_count?: number;
|
|
794
|
+
commit_count?: number;
|
|
795
|
+
last_commit_at?: string;
|
|
796
|
+
pending_tokens?: number;
|
|
797
|
+
llm_token_usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };
|
|
798
|
+
}> {
|
|
799
|
+
return this.request<{
|
|
800
|
+
message_count?: number;
|
|
801
|
+
commit_count?: number;
|
|
802
|
+
last_commit_at?: string;
|
|
803
|
+
pending_tokens?: number;
|
|
804
|
+
llm_token_usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number };
|
|
805
|
+
}>(
|
|
806
|
+
`/api/v1/sessions/${encodeURIComponent(sessionId)}`,
|
|
807
|
+
{ method: "GET" },
|
|
808
|
+
undefined,
|
|
809
|
+
actorPeerId,
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/**
|
|
814
|
+
* Commit a session: archive (Phase 1) and extract memories (Phase 2).
|
|
815
|
+
*
|
|
816
|
+
* wait=false (default): returns immediately after Phase 1 with task_id.
|
|
817
|
+
* wait=true: after Phase 1, polls GET /tasks/{task_id} until Phase 2
|
|
818
|
+
* completes (or times out), then returns the merged result.
|
|
819
|
+
*/
|
|
820
|
+
async commitSession(
|
|
821
|
+
sessionId: string,
|
|
822
|
+
options?: {
|
|
823
|
+
wait?: boolean;
|
|
824
|
+
timeoutMs?: number;
|
|
825
|
+
/**
|
|
826
|
+
* WM v2: number of most-recent messages to keep live after commit.
|
|
827
|
+
* Forwarded as `keep_recent_count` in the POST body. 0 (default)
|
|
828
|
+
* preserves the pre-v2 "archive everything" behavior.
|
|
829
|
+
*/
|
|
830
|
+
keepRecentCount?: number;
|
|
831
|
+
agentId?: string;
|
|
832
|
+
},
|
|
833
|
+
): Promise<CommitSessionResult> {
|
|
834
|
+
const keepRecentCount =
|
|
835
|
+
options?.keepRecentCount != null && Number.isFinite(options.keepRecentCount)
|
|
836
|
+
? Math.max(0, Math.floor(options.keepRecentCount))
|
|
837
|
+
: 0;
|
|
838
|
+
await this.emitRoutingDebug(
|
|
839
|
+
"session commit POST (archive + memory extraction)",
|
|
840
|
+
{
|
|
841
|
+
path: `/api/v1/sessions/${encodeURIComponent(sessionId)}/commit`,
|
|
842
|
+
sessionId,
|
|
843
|
+
wait: options?.wait ?? false,
|
|
844
|
+
keepRecentCount,
|
|
845
|
+
},
|
|
846
|
+
options?.agentId,
|
|
847
|
+
);
|
|
848
|
+
const body: Record<string, unknown> = {};
|
|
849
|
+
if (keepRecentCount > 0) {
|
|
850
|
+
body.keep_recent_count = keepRecentCount;
|
|
851
|
+
}
|
|
852
|
+
const result = await this.request<CommitSessionResult>(
|
|
853
|
+
`/api/v1/sessions/${encodeURIComponent(sessionId)}/commit`,
|
|
854
|
+
{ method: "POST", body: JSON.stringify(body) },
|
|
855
|
+
undefined,
|
|
856
|
+
options?.agentId,
|
|
857
|
+
);
|
|
858
|
+
|
|
859
|
+
if (!options?.wait || !result.task_id) {
|
|
860
|
+
return result;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// Client-side poll until Phase 2 finishes
|
|
864
|
+
const deadline = this.now() + (options.timeoutMs ?? DEFAULT_PHASE2_POLL_TIMEOUT_MS);
|
|
865
|
+
const pollInterval = 500;
|
|
866
|
+
while (this.now() < deadline) {
|
|
867
|
+
await this.sleep(pollInterval);
|
|
868
|
+
const task = await this.getTask(result.task_id, options.agentId).catch(() => null);
|
|
869
|
+
if (!task) break;
|
|
870
|
+
if (task.status === "completed") {
|
|
871
|
+
const taskResult = (task.result ?? {}) as Record<string, unknown>;
|
|
872
|
+
const memoriesExtracted = (taskResult.memories_extracted ?? {}) as Record<string, number>;
|
|
873
|
+
result.status = "completed";
|
|
874
|
+
result.memories_extracted = memoriesExtracted;
|
|
875
|
+
return result;
|
|
876
|
+
}
|
|
877
|
+
if (task.status === "failed") {
|
|
878
|
+
result.status = "failed";
|
|
879
|
+
result.error = task.error;
|
|
880
|
+
return result;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
result.status = "timeout";
|
|
884
|
+
return result;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/** Poll a background task by ID. */
|
|
888
|
+
async getTask(taskId: string, actorPeerId?: string): Promise<TaskResult> {
|
|
889
|
+
return this.request<TaskResult>(
|
|
890
|
+
`/api/v1/tasks/${encodeURIComponent(taskId)}`,
|
|
891
|
+
{ method: "GET" },
|
|
892
|
+
undefined,
|
|
893
|
+
actorPeerId,
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
async getSessionContext(
|
|
898
|
+
sessionId: string,
|
|
899
|
+
tokenBudget: number = 128_000,
|
|
900
|
+
actorPeerId?: string,
|
|
901
|
+
): Promise<SessionContextResult> {
|
|
902
|
+
return this.request(
|
|
903
|
+
`/api/v1/sessions/${encodeURIComponent(sessionId)}/context?token_budget=${tokenBudget}`,
|
|
904
|
+
{ method: "GET" },
|
|
905
|
+
undefined,
|
|
906
|
+
actorPeerId,
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
async getSessionArchive(
|
|
911
|
+
sessionId: string,
|
|
912
|
+
archiveId: string,
|
|
913
|
+
actorPeerId?: string,
|
|
914
|
+
): Promise<SessionArchiveResult> {
|
|
915
|
+
return this.request(
|
|
916
|
+
`/api/v1/sessions/${encodeURIComponent(sessionId)}/archives/${encodeURIComponent(archiveId)}`,
|
|
917
|
+
{ method: "GET" },
|
|
918
|
+
undefined,
|
|
919
|
+
actorPeerId,
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
async grepSessionArchives(
|
|
924
|
+
sessionId: string,
|
|
925
|
+
pattern: string,
|
|
926
|
+
options: {
|
|
927
|
+
archiveId?: string;
|
|
928
|
+
caseInsensitive?: boolean;
|
|
929
|
+
nodeLimit?: number;
|
|
930
|
+
levelLimit?: number;
|
|
931
|
+
} = {},
|
|
932
|
+
): Promise<{
|
|
933
|
+
matches: Array<{ line: number; uri: string; content: string }>;
|
|
934
|
+
count: number;
|
|
935
|
+
match_count?: number;
|
|
936
|
+
files_scanned?: number;
|
|
937
|
+
}> {
|
|
938
|
+
const baseUri = `${userSessionUri(sessionId)}/history`;
|
|
939
|
+
const uri = options.archiveId ? `${baseUri}/${options.archiveId}` : baseUri;
|
|
940
|
+
return this.request(
|
|
941
|
+
"/api/v1/search/grep",
|
|
942
|
+
{
|
|
943
|
+
method: "POST",
|
|
944
|
+
body: JSON.stringify({
|
|
945
|
+
uri,
|
|
946
|
+
pattern,
|
|
947
|
+
case_insensitive: options.caseInsensitive ?? true,
|
|
948
|
+
...(options.nodeLimit !== undefined ? { node_limit: options.nodeLimit } : {}),
|
|
949
|
+
...(options.levelLimit !== undefined ? { level_limit: options.levelLimit } : {}),
|
|
950
|
+
}),
|
|
951
|
+
},
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
async deleteSession(sessionId: string): Promise<void> {
|
|
956
|
+
await this.request(`/api/v1/sessions/${encodeURIComponent(sessionId)}`, { method: "DELETE" });
|
|
957
|
+
}
|
|
958
|
+
async deleteUri(uri: string, actorPeerId?: string): Promise<void> {
|
|
959
|
+
await this.request(`/api/v1/fs?uri=${encodeURIComponent(uri)}&recursive=false`, {
|
|
960
|
+
method: "DELETE",
|
|
961
|
+
}, undefined, actorPeerId);
|
|
962
|
+
}
|
|
963
|
+
}
|