@pasko70/pibo 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -6
- package/dist/agent-runtime/context-build.js +26 -2
- package/dist/agent-runtime/routed-session.js +108 -9
- package/dist/agent-runtimes/codex-native/adapter.js +12 -0
- package/dist/agent-runtimes/codex-native/resource-delivery.js +35 -7
- package/dist/agent-runtimes/omp/adapter.js +3 -7
- package/dist/agent-runtimes/pi/adapter.js +5 -3
- package/dist/agent-runtimes/pi/routed-session.js +49 -8
- package/dist/agent-runtimes/pi/runtime.js +6 -0
- package/dist/apps/chat/agent-profiles.js +31 -2
- package/dist/apps/chat/agent-store.js +43 -3
- package/dist/apps/chat/chat-request-normalizers.js +31 -0
- package/dist/apps/chat/data/chat-data-mappers.js +61 -11
- package/dist/apps/chat/data/session-query-service.js +33 -10
- package/dist/apps/chat/data/timeline-query-service.js +60 -35
- package/dist/apps/chat/output-compactor.js +144 -21
- package/dist/apps/chat/output-event-policy.js +179 -2
- package/dist/apps/chat/stream.js +16 -7
- package/dist/apps/chat/trace-v2.js +1 -0
- package/dist/apps/chat/web-app.js +236 -64
- package/dist/apps/chat-ui/assets/{dist-BBDMeU5-.js → dist-B6GZgWSj.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-mqCviI-c.js → dist-BPotHecb.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-JnW4v8UE.js → dist-BzqQKeVO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BDIATCQt.js → dist-CvaPTBTN.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-lRiLP9rr.js → dist-paagejNj.js} +1 -1
- package/dist/apps/chat-ui/assets/index-6JJV-eic.js +228 -0
- package/dist/apps/chat-ui/assets/index-CeL9JPP5.css +1 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/{index-Dtw2Z7jz.js → index-U-MSErGa.js} +4 -4
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/cli-ui/cliSessionsCommand.js +34 -8
- package/dist/cli-session/localSessionSource.js +153 -161
- package/dist/cli.js +7 -11
- package/dist/core/context-build.js +7 -16
- package/dist/core/output-persistence-retry.js +484 -0
- package/dist/core/output-render-sequence.js +331 -0
- package/dist/core/profiles.js +24 -0
- package/dist/core/provider-recovery.js +7 -1
- package/dist/core/session-model.js +37 -1
- package/dist/core/session-router.js +67 -20
- package/dist/data/ingest-service.js +91 -9
- package/dist/data/navigation-store.js +5 -5
- package/dist/data/schema.js +122 -2
- package/dist/data/session-store.js +3 -3
- package/dist/debug/index.js +44 -2
- package/dist/gateway/web.js +8 -8
- package/dist/local/client.js +3 -2
- package/dist/plugins/context-files-store.js +30 -0
- package/dist/plugins/context-files.js +52 -1
- package/dist/plugins/registry.js +2 -0
- package/dist/plugins/user-profile-resources.js +22 -0
- package/dist/reliability/store.js +246 -37
- package/dist/session-ui/terminalRows.js +6 -3
- package/dist/sessions/pibo-data-store.js +145 -0
- package/dist/sessions/store.js +42 -0
- package/dist/setup/cli.js +422 -6
- package/dist/setup/installation-profiles.js +464 -0
- package/dist/shared/deterministic-digest.js +94 -0
- package/dist/shared/trace-engine.js +54 -0
- package/dist/shared/trace-event-projection.js +124 -67
- package/dist/shared/trace-history.js +47 -12
- package/dist/shared/trace-live-reducer.js +23 -4
- package/dist/shared/trace-nodes.js +17 -28
- package/dist/shared/trace-order.js +41 -5
- package/dist/shared/trace-page-merge.js +44 -14
- package/dist/shared/trace-patch-nodes.js +2 -0
- package/dist/shared/trace-subagent-links.js +4 -1
- package/dist/shared/trace-tool-identity.js +15 -8
- package/dist/signals/projector.js +28 -6
- package/dist/subagents/tool.js +7 -3
- package/docs/ops/vscode-extension-release.md +9 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -1
- package/dist/apps/chat-ui/assets/index-0XOOVxLP.js +0 -228
- package/dist/apps/chat-ui/assets/index-DV7_CgsC.css +0 -1
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-3.0.0.vsix +0 -0
|
@@ -36,6 +36,11 @@ function ensurePiboRunColumn(db, name, definition) {
|
|
|
36
36
|
if (!columns.has(name))
|
|
37
37
|
db.exec(`ALTER TABLE pibo_runs ADD COLUMN ${name} ${definition}`);
|
|
38
38
|
}
|
|
39
|
+
function ensurePiboJobColumn(db, name, definition) {
|
|
40
|
+
const columns = sqliteTableColumns(db, "pibo_jobs");
|
|
41
|
+
if (!columns.has(name))
|
|
42
|
+
db.exec(`ALTER TABLE pibo_jobs ADD COLUMN ${name} ${definition}`);
|
|
43
|
+
}
|
|
39
44
|
export class PiboReliabilityStore {
|
|
40
45
|
db;
|
|
41
46
|
appendEventStatement;
|
|
@@ -74,6 +79,13 @@ export class PiboReliabilityStore {
|
|
|
74
79
|
CREATE INDEX IF NOT EXISTS idx_pibo_event_stream_topic_stream
|
|
75
80
|
ON pibo_event_stream(topic, stream_id);
|
|
76
81
|
|
|
82
|
+
CREATE TABLE IF NOT EXISTS pibo_delivery_receipts (
|
|
83
|
+
delivery_id TEXT NOT NULL,
|
|
84
|
+
projection TEXT NOT NULL,
|
|
85
|
+
delivered_at TEXT NOT NULL,
|
|
86
|
+
PRIMARY KEY(delivery_id, projection)
|
|
87
|
+
);
|
|
88
|
+
|
|
77
89
|
CREATE TABLE IF NOT EXISTS pibo_event_consumers (
|
|
78
90
|
consumer TEXT NOT NULL,
|
|
79
91
|
topic TEXT NOT NULL,
|
|
@@ -91,6 +103,7 @@ export class PiboReliabilityStore {
|
|
|
91
103
|
priority INTEGER NOT NULL DEFAULT 0,
|
|
92
104
|
worker_id TEXT,
|
|
93
105
|
claim_expires_at TEXT,
|
|
106
|
+
claim_token INTEGER NOT NULL DEFAULT 0,
|
|
94
107
|
attempts INTEGER NOT NULL DEFAULT 0,
|
|
95
108
|
max_attempts INTEGER NOT NULL DEFAULT 1,
|
|
96
109
|
idempotency_key TEXT,
|
|
@@ -157,6 +170,7 @@ export class PiboReliabilityStore {
|
|
|
157
170
|
CREATE INDEX IF NOT EXISTS idx_pibo_runs_status
|
|
158
171
|
ON pibo_runs(status);
|
|
159
172
|
`);
|
|
173
|
+
ensurePiboJobColumn(this.db, "claim_token", "INTEGER NOT NULL DEFAULT 0");
|
|
160
174
|
ensurePiboRunColumn(this.db, "timeout_ms", "INTEGER");
|
|
161
175
|
ensurePiboRunColumn(this.db, "timeout_at", "TEXT");
|
|
162
176
|
ensurePiboRunColumn(this.db, "timeout_phase", "TEXT");
|
|
@@ -189,6 +203,21 @@ export class PiboReliabilityStore {
|
|
|
189
203
|
throw error;
|
|
190
204
|
}
|
|
191
205
|
}
|
|
206
|
+
hasDeliveryReceipt(deliveryId, projection) {
|
|
207
|
+
return this.db
|
|
208
|
+
.prepare("SELECT 1 AS found FROM pibo_delivery_receipts WHERE delivery_id = ? AND projection = ?")
|
|
209
|
+
.get(deliveryId, projection) !== undefined;
|
|
210
|
+
}
|
|
211
|
+
recordDeliveryReceipt(deliveryId, projection, deliveredAt = now()) {
|
|
212
|
+
this.db.prepare(`
|
|
213
|
+
INSERT OR IGNORE INTO pibo_delivery_receipts (delivery_id, projection, delivered_at)
|
|
214
|
+
VALUES (?, ?, ?)
|
|
215
|
+
`).run(deliveryId, projection, deliveredAt);
|
|
216
|
+
const row = this.db
|
|
217
|
+
.prepare("SELECT delivery_id, projection, delivered_at FROM pibo_delivery_receipts WHERE delivery_id = ? AND projection = ?")
|
|
218
|
+
.get(deliveryId, projection);
|
|
219
|
+
return { deliveryId: row.delivery_id, projection: row.projection, deliveredAt: row.delivered_at };
|
|
220
|
+
}
|
|
192
221
|
list(input = {}) {
|
|
193
222
|
const clauses = [];
|
|
194
223
|
const values = [];
|
|
@@ -339,6 +368,7 @@ export class PiboReliabilityStore {
|
|
|
339
368
|
SET state = 'running',
|
|
340
369
|
worker_id = ?,
|
|
341
370
|
claim_expires_at = ?,
|
|
371
|
+
claim_token = claim_token + 1,
|
|
342
372
|
attempts = attempts + 1,
|
|
343
373
|
updated_at = ?
|
|
344
374
|
WHERE job_id IN (
|
|
@@ -361,6 +391,7 @@ export class PiboReliabilityStore {
|
|
|
361
391
|
SET state = 'running',
|
|
362
392
|
worker_id = ?,
|
|
363
393
|
claim_expires_at = ?,
|
|
394
|
+
claim_token = claim_token + 1,
|
|
364
395
|
attempts = attempts + 1,
|
|
365
396
|
updated_at = ?
|
|
366
397
|
WHERE job_id = ?
|
|
@@ -372,7 +403,50 @@ export class PiboReliabilityStore {
|
|
|
372
403
|
.get(workerId, claimExpiresAt, timestamp, jobId, timestamp, timestamp);
|
|
373
404
|
return row ? jobFromRow(row) : undefined;
|
|
374
405
|
}
|
|
375
|
-
|
|
406
|
+
claimRecoverableJob(jobId, workerId, visibilityTimeoutMs = 30000, forcePending = false) {
|
|
407
|
+
const timestamp = now();
|
|
408
|
+
const claimExpiresAt = new Date(Date.now() + visibilityTimeoutMs).toISOString();
|
|
409
|
+
const row = this.db.prepare(`
|
|
410
|
+
UPDATE pibo_jobs
|
|
411
|
+
SET state = 'running',
|
|
412
|
+
worker_id = ?,
|
|
413
|
+
claim_expires_at = ?,
|
|
414
|
+
claim_token = claim_token + 1,
|
|
415
|
+
attempts = attempts + 1,
|
|
416
|
+
updated_at = ?
|
|
417
|
+
WHERE job_id = ?
|
|
418
|
+
AND (
|
|
419
|
+
(state = 'pending' AND (? = 1 OR run_at <= ?))
|
|
420
|
+
OR (state = 'running' AND claim_expires_at IS NOT NULL AND claim_expires_at <= ?)
|
|
421
|
+
)
|
|
422
|
+
AND (expires_at IS NULL OR expires_at > ?)
|
|
423
|
+
RETURNING *
|
|
424
|
+
`).get(workerId, claimExpiresAt, timestamp, jobId, forcePending ? 1 : 0, timestamp, timestamp, timestamp);
|
|
425
|
+
return row ? jobFromRow(row) : undefined;
|
|
426
|
+
}
|
|
427
|
+
updateJobPayload(jobId, workerId, payload, claimToken) {
|
|
428
|
+
const result = this.db.prepare(`
|
|
429
|
+
UPDATE pibo_jobs
|
|
430
|
+
SET payload_json = ?, updated_at = ?
|
|
431
|
+
WHERE job_id = ? AND state = 'running' AND worker_id = ?
|
|
432
|
+
AND (? IS NULL OR claim_token = ?)
|
|
433
|
+
AND claim_expires_at IS NOT NULL AND claim_expires_at > ?
|
|
434
|
+
`).run(json(payload), now(), jobId, workerId, claimToken ?? null, claimToken ?? null, now());
|
|
435
|
+
return Number(result.changes ?? 0) > 0;
|
|
436
|
+
}
|
|
437
|
+
releaseJob(jobId, workerId, delayMs = 0, claimToken) {
|
|
438
|
+
const timestamp = now();
|
|
439
|
+
const runAt = new Date(Date.parse(timestamp) + Math.max(0, delayMs)).toISOString();
|
|
440
|
+
const result = this.db.prepare(`
|
|
441
|
+
UPDATE pibo_jobs
|
|
442
|
+
SET state = 'pending', worker_id = NULL, claim_expires_at = NULL, run_at = ?, updated_at = ?
|
|
443
|
+
WHERE job_id = ? AND state = 'running' AND worker_id = ?
|
|
444
|
+
AND (? IS NULL OR claim_token = ?)
|
|
445
|
+
AND claim_expires_at IS NOT NULL AND claim_expires_at > ?
|
|
446
|
+
`).run(runAt, timestamp, jobId, workerId, claimToken ?? null, claimToken ?? null, timestamp);
|
|
447
|
+
return Number(result.changes ?? 0) > 0;
|
|
448
|
+
}
|
|
449
|
+
ack(jobId, workerId, claimToken) {
|
|
376
450
|
const timestamp = now();
|
|
377
451
|
const result = this.db
|
|
378
452
|
.prepare(`
|
|
@@ -380,47 +454,53 @@ export class PiboReliabilityStore {
|
|
|
380
454
|
WHERE job_id = ?
|
|
381
455
|
AND state = 'running'
|
|
382
456
|
AND worker_id = ?
|
|
457
|
+
AND (? IS NULL OR claim_token = ?)
|
|
383
458
|
AND claim_expires_at IS NOT NULL
|
|
384
459
|
AND claim_expires_at > ?
|
|
385
460
|
`)
|
|
386
|
-
.run(jobId, workerId, timestamp);
|
|
461
|
+
.run(jobId, workerId, claimToken ?? null, claimToken ?? null, timestamp);
|
|
387
462
|
return Number(result.changes ?? 0) > 0;
|
|
388
463
|
}
|
|
389
464
|
retry(jobId, workerId, input = {}) {
|
|
390
465
|
const timestamp = now();
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
.
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
466
|
+
return this.inImmediateTransaction(() => {
|
|
467
|
+
const row = this.getLiveWorkerJob(jobId, workerId, timestamp, input.claimToken);
|
|
468
|
+
if (!row)
|
|
469
|
+
return false;
|
|
470
|
+
const job = jobFromRow(row);
|
|
471
|
+
if (job.attempts >= job.maxAttempts) {
|
|
472
|
+
this.moveJobToDead(row, input.error ?? "Job exhausted retry attempts.", "max_attempts", timestamp);
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
const delayMs = input.delayMs ?? retryDelayMs(job.attempts, input);
|
|
476
|
+
const runAt = new Date(asDate(input.now).getTime() + delayMs).toISOString();
|
|
477
|
+
const result = this.db
|
|
478
|
+
.prepare(`
|
|
479
|
+
UPDATE pibo_jobs
|
|
480
|
+
SET state = 'pending',
|
|
481
|
+
worker_id = NULL,
|
|
482
|
+
claim_expires_at = NULL,
|
|
483
|
+
run_at = ?,
|
|
484
|
+
updated_at = ?,
|
|
485
|
+
last_error = ?
|
|
486
|
+
WHERE job_id = ? AND state = 'running' AND worker_id = ?
|
|
487
|
+
AND (? IS NULL OR claim_token = ?)
|
|
488
|
+
`)
|
|
489
|
+
.run(runAt, timestamp, input.error ?? null, jobId, workerId, input.claimToken ?? null, input.claimToken ?? null);
|
|
490
|
+
return Number(result.changes ?? 0) > 0;
|
|
491
|
+
});
|
|
414
492
|
}
|
|
415
|
-
fail(jobId, workerId, error) {
|
|
493
|
+
fail(jobId, workerId, error, claimToken) {
|
|
416
494
|
const timestamp = now();
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
495
|
+
return this.inImmediateTransaction(() => {
|
|
496
|
+
const row = this.getLiveWorkerJob(jobId, workerId, timestamp, claimToken);
|
|
497
|
+
if (!row)
|
|
498
|
+
return false;
|
|
499
|
+
this.moveJobToDead(row, error, "failed", timestamp);
|
|
500
|
+
return true;
|
|
501
|
+
});
|
|
422
502
|
}
|
|
423
|
-
heartbeat(jobId, workerId, extendMs) {
|
|
503
|
+
heartbeat(jobId, workerId, extendMs, claimToken) {
|
|
424
504
|
const timestamp = now();
|
|
425
505
|
const claimExpiresAt = new Date(Date.now() + Math.max(1, extendMs)).toISOString();
|
|
426
506
|
const result = this.db
|
|
@@ -430,10 +510,11 @@ export class PiboReliabilityStore {
|
|
|
430
510
|
WHERE job_id = ?
|
|
431
511
|
AND state = 'running'
|
|
432
512
|
AND worker_id = ?
|
|
513
|
+
AND (? IS NULL OR claim_token = ?)
|
|
433
514
|
AND claim_expires_at IS NOT NULL
|
|
434
515
|
AND claim_expires_at > ?
|
|
435
516
|
`)
|
|
436
|
-
.run(claimExpiresAt, timestamp, jobId, workerId, timestamp);
|
|
517
|
+
.run(claimExpiresAt, timestamp, jobId, workerId, claimToken ?? null, claimToken ?? null, timestamp);
|
|
437
518
|
return Number(result.changes ?? 0) > 0;
|
|
438
519
|
}
|
|
439
520
|
listJobs(input = {}) {
|
|
@@ -447,11 +528,56 @@ export class PiboReliabilityStore {
|
|
|
447
528
|
clauses.push("state = ?");
|
|
448
529
|
values.push(input.state);
|
|
449
530
|
}
|
|
531
|
+
if (input.excludeJobIds?.length) {
|
|
532
|
+
clauses.push(`job_id NOT IN (${input.excludeJobIds.map(() => "?").join(", ")})`);
|
|
533
|
+
values.push(...input.excludeJobIds);
|
|
534
|
+
}
|
|
450
535
|
const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
451
536
|
const rows = this.db
|
|
452
537
|
.prepare(`SELECT * FROM pibo_jobs ${where} ORDER BY priority DESC, run_at ASC, created_at ASC LIMIT ?`)
|
|
453
538
|
.all(...values, clampLimit(input.limit, 100));
|
|
454
|
-
|
|
539
|
+
const jobs = [];
|
|
540
|
+
for (const row of rows) {
|
|
541
|
+
try {
|
|
542
|
+
jobs.push(jobFromRow(row));
|
|
543
|
+
}
|
|
544
|
+
catch {
|
|
545
|
+
this.quarantineJobRow(row, "payload_malformed");
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return jobs;
|
|
549
|
+
}
|
|
550
|
+
listRecoverableJobs(input = {}) {
|
|
551
|
+
const timestamp = now();
|
|
552
|
+
const clauses = [
|
|
553
|
+
"((state = 'pending' AND (? = 1 OR run_at <= ?)) OR (state = 'running' AND claim_expires_at IS NOT NULL AND claim_expires_at <= ?))",
|
|
554
|
+
"(expires_at IS NULL OR expires_at > ?)",
|
|
555
|
+
];
|
|
556
|
+
const values = [input.includeDeferredPending ? 1 : 0, timestamp, timestamp, timestamp];
|
|
557
|
+
if (input.queue) {
|
|
558
|
+
clauses.push("queue = ?");
|
|
559
|
+
values.push(input.queue);
|
|
560
|
+
}
|
|
561
|
+
if (input.excludeJobIds?.length) {
|
|
562
|
+
clauses.push(`job_id NOT IN (${input.excludeJobIds.map(() => "?").join(", ")})`);
|
|
563
|
+
values.push(...input.excludeJobIds);
|
|
564
|
+
}
|
|
565
|
+
const rows = this.db.prepare(`
|
|
566
|
+
SELECT * FROM pibo_jobs
|
|
567
|
+
WHERE ${clauses.join(" AND ")}
|
|
568
|
+
ORDER BY priority DESC, run_at ASC, created_at ASC
|
|
569
|
+
LIMIT ?
|
|
570
|
+
`).all(...values, clampLimit(input.limit, 100));
|
|
571
|
+
const jobs = [];
|
|
572
|
+
for (const row of rows) {
|
|
573
|
+
try {
|
|
574
|
+
jobs.push(jobFromRow(row));
|
|
575
|
+
}
|
|
576
|
+
catch {
|
|
577
|
+
this.quarantineJobRow(row, "payload_malformed");
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
return jobs;
|
|
455
581
|
}
|
|
456
582
|
listDead(input = {}) {
|
|
457
583
|
const clauses = [];
|
|
@@ -466,6 +592,46 @@ export class PiboReliabilityStore {
|
|
|
466
592
|
.all(...values, clampLimit(input.limit, 100));
|
|
467
593
|
return rows.map(deadJobFromRow);
|
|
468
594
|
}
|
|
595
|
+
hasLiveJob(jobId) {
|
|
596
|
+
return this.db.prepare("SELECT 1 AS found FROM pibo_jobs WHERE job_id = ?").get(jobId) !== undefined;
|
|
597
|
+
}
|
|
598
|
+
hasJobs(queue) {
|
|
599
|
+
return queue
|
|
600
|
+
? this.db.prepare("SELECT 1 AS found FROM pibo_jobs WHERE queue = ? LIMIT 1").get(queue) !== undefined
|
|
601
|
+
: this.db.prepare("SELECT 1 AS found FROM pibo_jobs LIMIT 1").get() !== undefined;
|
|
602
|
+
}
|
|
603
|
+
hasRecoverableJobs(queue, includeDeferredPending = false) {
|
|
604
|
+
const timestamp = now();
|
|
605
|
+
return this.db.prepare(`
|
|
606
|
+
SELECT 1 AS found FROM pibo_jobs
|
|
607
|
+
WHERE queue = ?
|
|
608
|
+
AND (
|
|
609
|
+
(state = 'pending' AND (? = 1 OR run_at <= ?))
|
|
610
|
+
OR (state = 'running' AND claim_expires_at IS NOT NULL AND claim_expires_at <= ?)
|
|
611
|
+
)
|
|
612
|
+
AND (expires_at IS NULL OR expires_at > ?)
|
|
613
|
+
LIMIT 1
|
|
614
|
+
`).get(queue, includeDeferredPending ? 1 : 0, timestamp, timestamp, timestamp) !== undefined;
|
|
615
|
+
}
|
|
616
|
+
quarantineJob(jobId, reason, correlation = {}) {
|
|
617
|
+
const row = this.db.prepare("SELECT * FROM pibo_jobs WHERE job_id = ?").get(jobId);
|
|
618
|
+
if (!row)
|
|
619
|
+
return false;
|
|
620
|
+
this.quarantineJobRow(row, reason, correlation);
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
623
|
+
deadLetter(input) {
|
|
624
|
+
const timestamp = now();
|
|
625
|
+
const jobId = input.jobId ?? `job_${randomUUID()}`;
|
|
626
|
+
this.db.prepare(`
|
|
627
|
+
INSERT OR REPLACE INTO pibo_dead_jobs (
|
|
628
|
+
job_id, queue, payload_json, attempts, max_attempts, idempotency_key, created_at,
|
|
629
|
+
updated_at, expires_at, last_error, dead_at, dead_reason
|
|
630
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?)
|
|
631
|
+
`).run(jobId, input.queue, json(input.payload ?? null), Math.max(0, input.attempts ?? 0), Math.max(1, input.maxAttempts ?? 1), input.idempotencyKey ?? null, timestamp, timestamp, input.error ?? input.reason, timestamp, input.reason);
|
|
632
|
+
const row = this.db.prepare("SELECT * FROM pibo_dead_jobs WHERE job_id = ?").get(jobId);
|
|
633
|
+
return deadJobFromRow(row);
|
|
634
|
+
}
|
|
469
635
|
requeueDead(jobId, input = {}) {
|
|
470
636
|
const dead = this.db.prepare("SELECT * FROM pibo_dead_jobs WHERE job_id = ?").get(jobId);
|
|
471
637
|
if (!dead)
|
|
@@ -659,17 +825,18 @@ export class PiboReliabilityStore {
|
|
|
659
825
|
.get(queue, idempotencyKey);
|
|
660
826
|
return row ? jobFromRow(row) : undefined;
|
|
661
827
|
}
|
|
662
|
-
getLiveWorkerJob(jobId, workerId, timestamp) {
|
|
828
|
+
getLiveWorkerJob(jobId, workerId, timestamp, claimToken) {
|
|
663
829
|
return this.db
|
|
664
830
|
.prepare(`
|
|
665
831
|
SELECT * FROM pibo_jobs
|
|
666
832
|
WHERE job_id = ?
|
|
667
833
|
AND state = 'running'
|
|
668
834
|
AND worker_id = ?
|
|
835
|
+
AND (? IS NULL OR claim_token = ?)
|
|
669
836
|
AND claim_expires_at IS NOT NULL
|
|
670
837
|
AND claim_expires_at > ?
|
|
671
838
|
`)
|
|
672
|
-
.get(jobId, workerId, timestamp);
|
|
839
|
+
.get(jobId, workerId, claimToken ?? null, claimToken ?? null, timestamp);
|
|
673
840
|
}
|
|
674
841
|
moveExpiredJobs(timestamp) {
|
|
675
842
|
const expired = this.db.prepare("SELECT * FROM pibo_jobs WHERE expires_at IS NOT NULL AND expires_at <= ?").all(timestamp);
|
|
@@ -718,6 +885,39 @@ export class PiboReliabilityStore {
|
|
|
718
885
|
.run(row.job_id, row.queue, row.payload_json, row.attempts, row.max_attempts, row.idempotency_key, row.created_at, timestamp, row.expires_at, error, timestamp, reason);
|
|
719
886
|
this.db.prepare("DELETE FROM pibo_jobs WHERE job_id = ?").run(row.job_id);
|
|
720
887
|
}
|
|
888
|
+
quarantineJobRow(row, reason, correlation = {}) {
|
|
889
|
+
this.inImmediateTransaction(() => {
|
|
890
|
+
const current = this.db.prepare("SELECT * FROM pibo_jobs WHERE job_id = ?").get(row.job_id);
|
|
891
|
+
if (!current)
|
|
892
|
+
return;
|
|
893
|
+
const payload = {
|
|
894
|
+
version: 1,
|
|
895
|
+
key: correlation.key ?? current.job_id,
|
|
896
|
+
...(correlation.piboSessionId ? { piboSessionId: correlation.piboSessionId } : {}),
|
|
897
|
+
...(correlation.eventId ? { eventId: correlation.eventId } : {}),
|
|
898
|
+
state: { phase: "quarantined", reasonCode: reason },
|
|
899
|
+
};
|
|
900
|
+
const sanitized = {
|
|
901
|
+
...current,
|
|
902
|
+
payload_json: json(payload),
|
|
903
|
+
idempotency_key: correlation.key ?? null,
|
|
904
|
+
last_error: reason,
|
|
905
|
+
};
|
|
906
|
+
this.moveJobToDead(sanitized, reason, reason, now());
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
inImmediateTransaction(operation) {
|
|
910
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
911
|
+
try {
|
|
912
|
+
const result = operation();
|
|
913
|
+
this.db.exec("COMMIT");
|
|
914
|
+
return result;
|
|
915
|
+
}
|
|
916
|
+
catch (error) {
|
|
917
|
+
this.db.exec("ROLLBACK");
|
|
918
|
+
throw error;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
721
921
|
requireRun(runId) {
|
|
722
922
|
const run = this.getRun(runId);
|
|
723
923
|
if (!run)
|
|
@@ -750,6 +950,7 @@ function jobFromRow(row) {
|
|
|
750
950
|
priority: row.priority,
|
|
751
951
|
workerId: row.worker_id ?? undefined,
|
|
752
952
|
claimExpiresAt: row.claim_expires_at ?? undefined,
|
|
953
|
+
claimToken: row.claim_token,
|
|
753
954
|
attempts: row.attempts,
|
|
754
955
|
maxAttempts: row.max_attempts,
|
|
755
956
|
idempotencyKey: row.idempotency_key ?? undefined,
|
|
@@ -763,7 +964,7 @@ function deadJobFromRow(row) {
|
|
|
763
964
|
return {
|
|
764
965
|
jobId: row.job_id,
|
|
765
966
|
queue: row.queue,
|
|
766
|
-
payload:
|
|
967
|
+
payload: safeDeadPayload(row.payload_json, row.dead_reason, row.job_id),
|
|
767
968
|
attempts: row.attempts,
|
|
768
969
|
maxAttempts: row.max_attempts,
|
|
769
970
|
idempotencyKey: row.idempotency_key ?? undefined,
|
|
@@ -775,6 +976,14 @@ function deadJobFromRow(row) {
|
|
|
775
976
|
deadReason: row.dead_reason,
|
|
776
977
|
};
|
|
777
978
|
}
|
|
979
|
+
function safeDeadPayload(value, reason, jobId) {
|
|
980
|
+
try {
|
|
981
|
+
return parseJson(value);
|
|
982
|
+
}
|
|
983
|
+
catch {
|
|
984
|
+
return { version: 1, key: jobId, state: { phase: "quarantined", reasonCode: reason } };
|
|
985
|
+
}
|
|
986
|
+
}
|
|
778
987
|
function runFromRow(row) {
|
|
779
988
|
const output = {
|
|
780
989
|
runId: row.run_id,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { compareTraceNodes } from "../shared/trace-nodes.js";
|
|
2
|
+
import { parseTraceToolNodeIdentity } from "../shared/trace-tool-identity.js";
|
|
2
3
|
import { terminalTextValue } from "./terminalValue.js";
|
|
3
4
|
export const MAX_COMPACT_TERMINAL_IMAGE_PREVIEWS = 20;
|
|
4
5
|
export const COMPACT_TERMINAL_OUTPUT_PREVIEW_LINES = 5;
|
|
@@ -168,9 +169,11 @@ function createRowCandidate(node, turnId) {
|
|
|
168
169
|
}
|
|
169
170
|
export function compactTerminalRowIdentity(node) {
|
|
170
171
|
if (node.type === "tool.call" || node.type === "tool.result" || node.type === "agent.delegation") {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
if (node.toolCallId) {
|
|
173
|
+
return parseTraceToolNodeIdentity(node.id)?.qualifier
|
|
174
|
+
? `terminal:${node.id}`
|
|
175
|
+
: `terminal:tool:${node.toolCallId}`;
|
|
176
|
+
}
|
|
174
177
|
if (node.type === "agent.delegation" && node.linkedPiboSessionId) {
|
|
175
178
|
return `terminal:delegation:${node.linkedPiboSessionId}`;
|
|
176
179
|
}
|
|
@@ -100,6 +100,151 @@ export class PiboDataSessionStore {
|
|
|
100
100
|
`).run(updated.piSessionId || null, rootSessionId(updated), updated.parentId ?? null, updated.originId ?? null, updated.profile, updated.activeModel ? JSON.stringify(updated.activeModel) : null, updated.workspace ?? null, updated.title ?? "Untitled Session", JSON.stringify(updated.metadata ?? {}), updated.updatedAt, updated.updatedAt, id);
|
|
101
101
|
return this.get(id);
|
|
102
102
|
}
|
|
103
|
+
claimOutputRenderSequence(piboSessionId, minimum) {
|
|
104
|
+
return this.dataStore.transaction(() => {
|
|
105
|
+
const session = this.db.prepare("SELECT 1 AS present FROM sessions WHERE id = ? AND deleted_at IS NULL").get(piboSessionId);
|
|
106
|
+
if (!session)
|
|
107
|
+
return minimum;
|
|
108
|
+
const row = this.db.prepare("SELECT high_water FROM session_output_render_high_water WHERE pibo_session_id = ?").get(piboSessionId);
|
|
109
|
+
const current = Math.max(row?.high_water ?? 0, this.durableOutputRenderSequenceHighWater(piboSessionId));
|
|
110
|
+
const next = Math.max(minimum, current + 1);
|
|
111
|
+
this.db.prepare(`
|
|
112
|
+
INSERT INTO session_output_render_high_water (pibo_session_id, high_water, updated_at)
|
|
113
|
+
VALUES (?, ?, ?)
|
|
114
|
+
ON CONFLICT(pibo_session_id) DO UPDATE SET
|
|
115
|
+
high_water = MAX(session_output_render_high_water.high_water, excluded.high_water),
|
|
116
|
+
updated_at = CASE
|
|
117
|
+
WHEN excluded.high_water > session_output_render_high_water.high_water THEN excluded.updated_at
|
|
118
|
+
ELSE session_output_render_high_water.updated_at
|
|
119
|
+
END
|
|
120
|
+
`).run(piboSessionId, next, new Date().toISOString());
|
|
121
|
+
return next;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
durableOutputRenderSequenceHighWater(piboSessionId) {
|
|
125
|
+
const row = this.db.prepare(`
|
|
126
|
+
SELECT MAX(MAX(
|
|
127
|
+
COALESCE(CAST(json_extract(attributes_json, '$.renderSequence') AS INTEGER), 0),
|
|
128
|
+
COALESCE(session_sequence, 0)
|
|
129
|
+
)) AS high_water
|
|
130
|
+
FROM event_log
|
|
131
|
+
WHERE session_id = ?
|
|
132
|
+
`).get(piboSessionId);
|
|
133
|
+
const value = row?.high_water;
|
|
134
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : 0;
|
|
135
|
+
}
|
|
136
|
+
observeOutputRenderSequence(piboSessionId, sequence) {
|
|
137
|
+
this.dataStore.transaction(() => {
|
|
138
|
+
this.db.prepare(`
|
|
139
|
+
INSERT INTO session_output_render_high_water (pibo_session_id, high_water, updated_at)
|
|
140
|
+
SELECT id, ?, ? FROM sessions WHERE id = ? AND deleted_at IS NULL
|
|
141
|
+
ON CONFLICT(pibo_session_id) DO UPDATE SET
|
|
142
|
+
high_water = MAX(session_output_render_high_water.high_water, excluded.high_water),
|
|
143
|
+
updated_at = CASE
|
|
144
|
+
WHEN excluded.high_water > session_output_render_high_water.high_water THEN excluded.updated_at
|
|
145
|
+
ELSE session_output_render_high_water.updated_at
|
|
146
|
+
END
|
|
147
|
+
`).run(sequence, new Date().toISOString(), piboSessionId);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
claimOutputToolInvocationOrdinal(piboSessionId, eventId, toolCallId) {
|
|
151
|
+
return this.dataStore.transaction(() => {
|
|
152
|
+
const durable = this.db.prepare(`
|
|
153
|
+
SELECT MAX(COALESCE(CAST(json_extract(attributes_json, '$.toolInvocationOrdinal') AS INTEGER), 0)) AS maximum
|
|
154
|
+
FROM event_log
|
|
155
|
+
WHERE session_id = ? AND event_id = ? AND tool_call_id = ?
|
|
156
|
+
`).get(piboSessionId, eventId, toolCallId);
|
|
157
|
+
const minimumNextOrdinal = typeof durable.maximum === "number" && Number.isSafeInteger(durable.maximum)
|
|
158
|
+
? durable.maximum + 1
|
|
159
|
+
: 0;
|
|
160
|
+
const row = this.db.prepare(`
|
|
161
|
+
INSERT INTO session_tool_invocation_counters (
|
|
162
|
+
pibo_session_id, event_id, tool_call_id, next_ordinal, updated_at
|
|
163
|
+
) VALUES (?, ?, ?, ? + 1, ?)
|
|
164
|
+
ON CONFLICT(pibo_session_id, event_id, tool_call_id) DO UPDATE SET
|
|
165
|
+
next_ordinal = MAX(session_tool_invocation_counters.next_ordinal, ? ) + 1,
|
|
166
|
+
updated_at = excluded.updated_at
|
|
167
|
+
RETURNING next_ordinal - 1 AS ordinal
|
|
168
|
+
`).get(piboSessionId, eventId, toolCallId, minimumNextOrdinal, new Date().toISOString(), minimumNextOrdinal);
|
|
169
|
+
return row.ordinal;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
observeOutputToolInvocationOrdinal(piboSessionId, eventId, toolCallId, ordinal) {
|
|
173
|
+
this.dataStore.transaction(() => {
|
|
174
|
+
this.db.prepare(`
|
|
175
|
+
INSERT INTO session_tool_invocation_counters (
|
|
176
|
+
pibo_session_id, event_id, tool_call_id, next_ordinal, updated_at
|
|
177
|
+
) VALUES (?, ?, ?, ?, ?)
|
|
178
|
+
ON CONFLICT(pibo_session_id, event_id, tool_call_id) DO UPDATE SET
|
|
179
|
+
next_ordinal = MAX(session_tool_invocation_counters.next_ordinal, excluded.next_ordinal),
|
|
180
|
+
updated_at = CASE
|
|
181
|
+
WHEN excluded.next_ordinal > session_tool_invocation_counters.next_ordinal THEN excluded.updated_at
|
|
182
|
+
ELSE session_tool_invocation_counters.updated_at
|
|
183
|
+
END
|
|
184
|
+
`).run(piboSessionId, eventId, toolCallId, ordinal + 1, new Date().toISOString());
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
claimOrAttachOutputToolInvocation(input) {
|
|
188
|
+
return this.dataStore.transaction(() => {
|
|
189
|
+
const rows = this.db.prepare(`
|
|
190
|
+
SELECT invocation_ordinal, call_fingerprint, status, seen_call
|
|
191
|
+
FROM session_tool_invocations
|
|
192
|
+
WHERE pibo_session_id = ? AND event_id = ? AND tool_call_id = ?
|
|
193
|
+
ORDER BY invocation_ordinal DESC
|
|
194
|
+
`).all(input.piboSessionId, input.eventId, input.toolCallId);
|
|
195
|
+
const latestOpen = rows.find((row) => row.status === "open");
|
|
196
|
+
let ordinal;
|
|
197
|
+
if (input.eventType === "tool_call"
|
|
198
|
+
&& latestOpen
|
|
199
|
+
&& (latestOpen.seen_call === 0 || latestOpen.call_fingerprint === input.callFingerprint)) {
|
|
200
|
+
ordinal = latestOpen.invocation_ordinal;
|
|
201
|
+
}
|
|
202
|
+
else if (input.eventType !== "tool_call" && latestOpen) {
|
|
203
|
+
ordinal = latestOpen.invocation_ordinal;
|
|
204
|
+
}
|
|
205
|
+
else if (input.eventType !== "tool_call" && rows[0]) {
|
|
206
|
+
// A lifecycle replay after completion belongs to the last proven
|
|
207
|
+
// invocation. Only a new tool_call may cross a closed boundary.
|
|
208
|
+
ordinal = rows[0].invocation_ordinal;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
ordinal = this.claimOutputToolInvocationOrdinal(input.piboSessionId, input.eventId, input.toolCallId);
|
|
212
|
+
}
|
|
213
|
+
this.persistToolInvocationTransition(input, ordinal);
|
|
214
|
+
return ordinal;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
observeOutputToolInvocation(input) {
|
|
218
|
+
this.dataStore.transaction(() => {
|
|
219
|
+
this.observeOutputToolInvocationOrdinal(input.piboSessionId, input.eventId, input.toolCallId, input.ordinal);
|
|
220
|
+
this.persistToolInvocationTransition(input, input.ordinal);
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
persistToolInvocationTransition(input, ordinal) {
|
|
224
|
+
const timestamp = new Date().toISOString();
|
|
225
|
+
const seenCall = input.eventType === "tool_call" ? 1 : 0;
|
|
226
|
+
const seenStarted = input.eventType === "tool_execution_started" ? 1 : 0;
|
|
227
|
+
const seenUpdated = input.eventType === "tool_execution_updated" ? 1 : 0;
|
|
228
|
+
const seenFinished = input.eventType === "tool_execution_finished" ? 1 : 0;
|
|
229
|
+
this.db.prepare(`
|
|
230
|
+
INSERT INTO session_tool_invocations (
|
|
231
|
+
pibo_session_id, event_id, tool_call_id, invocation_ordinal,
|
|
232
|
+
call_fingerprint, status, seen_call, seen_started, seen_updated, seen_finished,
|
|
233
|
+
created_at, updated_at
|
|
234
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
235
|
+
ON CONFLICT(pibo_session_id, event_id, tool_call_id, invocation_ordinal) DO UPDATE SET
|
|
236
|
+
call_fingerprint = COALESCE(session_tool_invocations.call_fingerprint, excluded.call_fingerprint),
|
|
237
|
+
status = CASE
|
|
238
|
+
WHEN session_tool_invocations.status = 'closed' OR excluded.status = 'closed' THEN 'closed'
|
|
239
|
+
ELSE 'open'
|
|
240
|
+
END,
|
|
241
|
+
seen_call = MAX(session_tool_invocations.seen_call, excluded.seen_call),
|
|
242
|
+
seen_started = MAX(session_tool_invocations.seen_started, excluded.seen_started),
|
|
243
|
+
seen_updated = MAX(session_tool_invocations.seen_updated, excluded.seen_updated),
|
|
244
|
+
seen_finished = MAX(session_tool_invocations.seen_finished, excluded.seen_finished),
|
|
245
|
+
updated_at = excluded.updated_at
|
|
246
|
+
`).run(input.piboSessionId, input.eventId, input.toolCallId, ordinal, input.callFingerprint ?? null, seenFinished ? "closed" : "open", seenCall, seenStarted, seenUpdated, seenFinished, timestamp, timestamp);
|
|
247
|
+
}
|
|
103
248
|
delete(id) {
|
|
104
249
|
const result = this.db.prepare("DELETE FROM sessions WHERE id = ?").run(id);
|
|
105
250
|
return Number(result.changes ?? 0) > 0;
|
package/dist/sessions/store.js
CHANGED
|
@@ -48,6 +48,8 @@ export class InMemoryPiboSessionStore {
|
|
|
48
48
|
byId = new Map();
|
|
49
49
|
byPiSessionId = new Map();
|
|
50
50
|
byNativeSession = new Map();
|
|
51
|
+
outputRenderHighWater = new Map();
|
|
52
|
+
outputToolInvocationNextOrdinal = new Map();
|
|
51
53
|
get(id) {
|
|
52
54
|
return this.byId.get(id);
|
|
53
55
|
}
|
|
@@ -101,6 +103,33 @@ export class InMemoryPiboSessionStore {
|
|
|
101
103
|
this.set(updated, existing.piSessionId, existing.runtimeBinding);
|
|
102
104
|
return updated;
|
|
103
105
|
}
|
|
106
|
+
claimOutputRenderSequence(piboSessionId, minimum) {
|
|
107
|
+
const session = this.byId.get(piboSessionId);
|
|
108
|
+
if (!session)
|
|
109
|
+
return minimum;
|
|
110
|
+
const current = Math.max(this.outputRenderHighWater.get(piboSessionId) ?? 0, outputRenderSequenceHighWater(session.metadata));
|
|
111
|
+
const next = Math.max(minimum, current + 1);
|
|
112
|
+
this.outputRenderHighWater.set(piboSessionId, next);
|
|
113
|
+
return next;
|
|
114
|
+
}
|
|
115
|
+
observeOutputRenderSequence(piboSessionId, sequence) {
|
|
116
|
+
const session = this.byId.get(piboSessionId);
|
|
117
|
+
if (!session)
|
|
118
|
+
return;
|
|
119
|
+
const current = Math.max(this.outputRenderHighWater.get(piboSessionId) ?? 0, outputRenderSequenceHighWater(session.metadata));
|
|
120
|
+
if (sequence > current)
|
|
121
|
+
this.outputRenderHighWater.set(piboSessionId, sequence);
|
|
122
|
+
}
|
|
123
|
+
claimOutputToolInvocationOrdinal(piboSessionId, eventId, toolCallId) {
|
|
124
|
+
const key = outputToolInvocationCounterKey(piboSessionId, eventId, toolCallId);
|
|
125
|
+
const ordinal = this.outputToolInvocationNextOrdinal.get(key) ?? 0;
|
|
126
|
+
this.outputToolInvocationNextOrdinal.set(key, ordinal + 1);
|
|
127
|
+
return ordinal;
|
|
128
|
+
}
|
|
129
|
+
observeOutputToolInvocationOrdinal(piboSessionId, eventId, toolCallId, ordinal) {
|
|
130
|
+
const key = outputToolInvocationCounterKey(piboSessionId, eventId, toolCallId);
|
|
131
|
+
this.outputToolInvocationNextOrdinal.set(key, Math.max(this.outputToolInvocationNextOrdinal.get(key) ?? 0, ordinal + 1));
|
|
132
|
+
}
|
|
104
133
|
getRuntimeBinding(id) {
|
|
105
134
|
const session = this.byId.get(id);
|
|
106
135
|
if (!session)
|
|
@@ -133,6 +162,12 @@ export class InMemoryPiboSessionStore {
|
|
|
133
162
|
const nativeKey = runtimeBindingNativeKey(existing.runtimeBinding);
|
|
134
163
|
if (nativeKey)
|
|
135
164
|
this.byNativeSession.delete(nativeKey);
|
|
165
|
+
this.outputRenderHighWater.delete(id);
|
|
166
|
+
const counterPrefix = `${JSON.stringify([id]).slice(0, -1)},`;
|
|
167
|
+
for (const key of this.outputToolInvocationNextOrdinal.keys()) {
|
|
168
|
+
if (key.startsWith(counterPrefix))
|
|
169
|
+
this.outputToolInvocationNextOrdinal.delete(key);
|
|
170
|
+
}
|
|
136
171
|
return true;
|
|
137
172
|
}
|
|
138
173
|
find(input) {
|
|
@@ -165,6 +200,13 @@ export class InMemoryPiboSessionStore {
|
|
|
165
200
|
return sessions.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
166
201
|
}
|
|
167
202
|
}
|
|
203
|
+
function outputRenderSequenceHighWater(metadata) {
|
|
204
|
+
const value = metadata?.outputRenderSequenceHighWater;
|
|
205
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : 0;
|
|
206
|
+
}
|
|
207
|
+
function outputToolInvocationCounterKey(piboSessionId, eventId, toolCallId) {
|
|
208
|
+
return JSON.stringify([piboSessionId, eventId, toolCallId]);
|
|
209
|
+
}
|
|
168
210
|
export function matchesFindInput(session, input) {
|
|
169
211
|
if (input.ids && !input.ids.includes(session.id))
|
|
170
212
|
return false;
|