@a-t-h-i/bot-lobby 0.6.45 → 0.6.47
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/THIRD_PARTY_NOTICES.md +10 -0
- package/package.json +7 -1
- package/prompts/qa.md +12 -4
- package/prompts/reviewer.md +7 -1
- package/src/execution/task-cancellation.ts +27 -0
- package/src/lobby/host.ts +4 -0
- package/src/lobby/prompts.ts +1 -2
- package/src/lobby/service.ts +77 -1
- package/src/master/master.ts +3 -3
- package/src/roles/reviewer.ts +91 -13
- package/src/schemas/findings.ts +2 -0
- package/src/state/persistence.ts +26 -1
- package/src/webui/api/index.ts +13 -6
- package/src/webui/api/tasks.ts +39 -2
- package/src/webui/palette-core.ts +233 -2
- package/src/webui/protocol.ts +6 -74
- package/src/workflow/workflow.ts +18 -4
- package/webui/dist/assets/index-CkQ5Eduy.js +110 -0
- package/webui/dist/assets/index-Dl4yHBRY.css +2 -0
- package/webui/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/webui/dist/build.json +57 -69
- package/webui/dist/index.html +2 -2
- package/src/lobby/models/metrics.ts +0 -14
- package/src/webui/api/metrics.ts +0 -96
- package/webui/dist/assets/index-ClwTDiyo.css +0 -2
- package/webui/dist/assets/index-Ct47Kp7Q.js +0 -110
package/webui/dist/build.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"hash": "
|
|
3
|
-
"builtAt": "2026-10-
|
|
2
|
+
"hash": "56dcd349378fe3008e95b540d11d84045f859e52c86a04678883ffe79b22b4d2",
|
|
3
|
+
"builtAt": "2026-10-14T05:49:26.037Z",
|
|
4
4
|
"files": [
|
|
5
5
|
{
|
|
6
6
|
"path": "src/lobby/prompts.ts",
|
|
7
|
-
"sha256": "
|
|
7
|
+
"sha256": "4a705f59f54682a71b9ffa53570a3d9be1fe139f5da8372b0598c8707d63aee7"
|
|
8
8
|
},
|
|
9
9
|
{
|
|
10
10
|
"path": "src/webui/protocol.ts",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "d5a2b938c1ff5cb4f50c13268bb437766f65c202bd7607b9fbfb7a058e4e36d4"
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"path": "webui/components.json",
|
|
@@ -24,15 +24,15 @@
|
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"path": "webui/src/app/AltH.tsx",
|
|
27
|
-
"sha256": "
|
|
27
|
+
"sha256": "a760972ea3deaaa3fefcbc4352d63c010b09fb1ea7d3aa29b7eb67c2a6420f4d"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"path": "webui/src/app/AppTools.tsx",
|
|
31
|
-
"sha256": "
|
|
31
|
+
"sha256": "2a8e7fe846bb8d1262df80a577fcc5136a02d9be4cbd321eb4220918a46a3786"
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"path": "webui/src/app/Composer.tsx",
|
|
35
|
-
"sha256": "
|
|
35
|
+
"sha256": "bc1857ac4cbea8d7ad71587372ed8a687e68f98e4779acea9c525222963cc12a"
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
38
|
"path": "webui/src/app/Header.tsx",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"path": "webui/src/app/PhoneTabs.tsx",
|
|
51
|
-
"sha256": "
|
|
51
|
+
"sha256": "eab9d2bdd15a702b529fbf292d9335a2a7243ae10a2148e450e0fdbb918fcf84"
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
"path": "webui/src/app/ProjectFolderDialog.tsx",
|
|
55
|
-
"sha256": "
|
|
55
|
+
"sha256": "a2bd027322c72a947c4c85ee583f3b401c9415a46a55a38fc93efc2de7030b34"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
"path": "webui/src/app/ProjectSwitcher.tsx",
|
|
@@ -60,11 +60,11 @@
|
|
|
60
60
|
},
|
|
61
61
|
{
|
|
62
62
|
"path": "webui/src/app/Shell.tsx",
|
|
63
|
-
"sha256": "
|
|
63
|
+
"sha256": "fe5739ce1f56b2002274ed948f85cd99a0f33c097a82ae62ab31baf5f9e75fa7"
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
"path": "webui/src/app/Sidebar.tsx",
|
|
67
|
-
"sha256": "
|
|
67
|
+
"sha256": "1a134fcd71f4fd960fc072e876d15dbd2c5daef58b2db42b5a127f521d1a0244"
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
"path": "webui/src/app/SignIn.tsx",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
78
|
"path": "webui/src/app/TabIcons.tsx",
|
|
79
|
-
"sha256": "
|
|
79
|
+
"sha256": "6205394cd77f672efe6affc9dc4f765c7b0b28b69ee1c87393028a7234672ec8"
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
"path": "webui/src/app/TabStrip.tsx",
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
},
|
|
121
121
|
{
|
|
122
122
|
"path": "webui/src/app/phoneCarousel.ts",
|
|
123
|
-
"sha256": "
|
|
123
|
+
"sha256": "e3031ac90e2062b27d7d7e8958eaa29721bea25e2097749771fe35d5be81f1b2"
|
|
124
124
|
},
|
|
125
125
|
{
|
|
126
126
|
"path": "webui/src/app/readTopic.ts",
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
},
|
|
133
133
|
{
|
|
134
134
|
"path": "webui/src/app/router.ts",
|
|
135
|
-
"sha256": "
|
|
135
|
+
"sha256": "c205e52d7591e67bdcc4bb47e83f890deda169abcc7d3710526e860246b0650a"
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
138
|
"path": "webui/src/app/sound.ts",
|
|
@@ -140,7 +140,11 @@
|
|
|
140
140
|
},
|
|
141
141
|
{
|
|
142
142
|
"path": "webui/src/app/taskRoute.ts",
|
|
143
|
-
"sha256": "
|
|
143
|
+
"sha256": "0d683f985c5f3787bef4a481dbefea30b93c960523879313c25cea01ec1208cd"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
"path": "webui/src/app/typeface.ts",
|
|
147
|
+
"sha256": "fc8614da8f6835951da10a3fe59db2bd62626073fc454ce940d5db61226b358d"
|
|
144
148
|
},
|
|
145
149
|
{
|
|
146
150
|
"path": "webui/src/app/useApiRead.ts",
|
|
@@ -196,7 +200,7 @@
|
|
|
196
200
|
},
|
|
197
201
|
{
|
|
198
202
|
"path": "webui/src/components/ui/alert-dialog.tsx",
|
|
199
|
-
"sha256": "
|
|
203
|
+
"sha256": "119fded71513a3b1ea22f1a9e833c36fa63e74405ae7a83e74cb9faa04f086b5"
|
|
200
204
|
},
|
|
201
205
|
{
|
|
202
206
|
"path": "webui/src/components/ui/badge.tsx",
|
|
@@ -252,15 +256,19 @@
|
|
|
252
256
|
},
|
|
253
257
|
{
|
|
254
258
|
"path": "webui/src/components/ui/toaster.tsx",
|
|
255
|
-
"sha256": "
|
|
259
|
+
"sha256": "6b77318cdbb2e03883bab82709fd5fe856edd6c3ebeb0d3e29f8900aad342e04"
|
|
256
260
|
},
|
|
257
261
|
{
|
|
258
262
|
"path": "webui/src/components/ui/tooltip.tsx",
|
|
259
263
|
"sha256": "a19c3e22e5221eebbd49a59be5978b0bde59dc04b8c18386bbb0f3e1e19f99a8"
|
|
260
264
|
},
|
|
265
|
+
{
|
|
266
|
+
"path": "webui/src/fonts.css",
|
|
267
|
+
"sha256": "c0e7110979aa9122ca443c0a3d06b4314633d5d81e0c54422d45b8e117ebf353"
|
|
268
|
+
},
|
|
261
269
|
{
|
|
262
270
|
"path": "webui/src/index.css",
|
|
263
|
-
"sha256": "
|
|
271
|
+
"sha256": "a8e09f9247c1665e0957fc3bcf96e6f90befe84d9714c7bd2a3795a56bd64655"
|
|
264
272
|
},
|
|
265
273
|
{
|
|
266
274
|
"path": "webui/src/lib/act.ts",
|
|
@@ -356,7 +364,7 @@
|
|
|
356
364
|
},
|
|
357
365
|
{
|
|
358
366
|
"path": "webui/src/main.tsx",
|
|
359
|
-
"sha256": "
|
|
367
|
+
"sha256": "e7d640fbfe8d008f5cfb6b6c0e6c51dc091526624e8902525994d1b2936def5d"
|
|
360
368
|
},
|
|
361
369
|
{
|
|
362
370
|
"path": "webui/src/nonce.ts",
|
|
@@ -364,15 +372,15 @@
|
|
|
364
372
|
},
|
|
365
373
|
{
|
|
366
374
|
"path": "webui/src/prompts/MockupViewer.tsx",
|
|
367
|
-
"sha256": "
|
|
375
|
+
"sha256": "bcf076888a230e89f9d4dbac2b544f5ff9852ad0b29a839abcd71357b649cf12"
|
|
368
376
|
},
|
|
369
377
|
{
|
|
370
378
|
"path": "webui/src/prompts/QuestionCard.tsx",
|
|
371
|
-
"sha256": "
|
|
379
|
+
"sha256": "71a2cd5175918b5f393d81d34445b5810c136519700f5d0c245e9fedfa16550c"
|
|
372
380
|
},
|
|
373
381
|
{
|
|
374
382
|
"path": "webui/src/prompts/QuestionPopup.tsx",
|
|
375
|
-
"sha256": "
|
|
383
|
+
"sha256": "1db09e21bc793672b68f3bdd099de50fe5a2069362ef0ca9f22bb58be4fa793d"
|
|
376
384
|
},
|
|
377
385
|
{
|
|
378
386
|
"path": "webui/src/prompts/StaticPreview.tsx",
|
|
@@ -388,7 +396,7 @@
|
|
|
388
396
|
},
|
|
389
397
|
{
|
|
390
398
|
"path": "webui/src/tabs/git/GitTab.tsx",
|
|
391
|
-
"sha256": "
|
|
399
|
+
"sha256": "386d7cfcb679d9fb3007aa2152d8eb36b45d487dc3deec67b07d499cdd84227d"
|
|
392
400
|
},
|
|
393
401
|
{
|
|
394
402
|
"path": "webui/src/tabs/git/PullDetail.tsx",
|
|
@@ -420,7 +428,7 @@
|
|
|
420
428
|
},
|
|
421
429
|
{
|
|
422
430
|
"path": "webui/src/tabs/knowledge/Editors.tsx",
|
|
423
|
-
"sha256": "
|
|
431
|
+
"sha256": "ba8f8670ffde33cf4cc3d671a76b6f41b0e09ada927338a0dbc8927279d62c4e"
|
|
424
432
|
},
|
|
425
433
|
{
|
|
426
434
|
"path": "webui/src/tabs/knowledge/FileDetail.tsx",
|
|
@@ -460,7 +468,7 @@
|
|
|
460
468
|
},
|
|
461
469
|
{
|
|
462
470
|
"path": "webui/src/tabs/lobby/Thoughts.tsx",
|
|
463
|
-
"sha256": "
|
|
471
|
+
"sha256": "1ecf5f407247a2206d4999fe06672c91a6144388ca96bc62f3d8a64d8aa26562"
|
|
464
472
|
},
|
|
465
473
|
{
|
|
466
474
|
"path": "webui/src/tabs/lobby/busy.ts",
|
|
@@ -482,34 +490,6 @@
|
|
|
482
490
|
"path": "webui/src/tabs/lobby/weave.ts",
|
|
483
491
|
"sha256": "c22b23e409642a05d6b50dcb90f606f4635b8ebf6b7c56f443ec7d9c810d6b5a"
|
|
484
492
|
},
|
|
485
|
-
{
|
|
486
|
-
"path": "webui/src/tabs/metrics/Charts.tsx",
|
|
487
|
-
"sha256": "e0f6294f2f0f31b79fca4d291524c0dc46e229a44de602595f2d89c7826d041f"
|
|
488
|
-
},
|
|
489
|
-
{
|
|
490
|
-
"path": "webui/src/tabs/metrics/Classifier.tsx",
|
|
491
|
-
"sha256": "08624cdf2e74b01e1ec3640b5145ee21e995d19db971fea6628c17ce80991671"
|
|
492
|
-
},
|
|
493
|
-
{
|
|
494
|
-
"path": "webui/src/tabs/metrics/DateFilter.tsx",
|
|
495
|
-
"sha256": "49b9955a9a314ce2aed14811b405a1b6c81af4eff69e887c2a72a16d772a7163"
|
|
496
|
-
},
|
|
497
|
-
{
|
|
498
|
-
"path": "webui/src/tabs/metrics/MetricsTab.tsx",
|
|
499
|
-
"sha256": "06f8ba70e205c134548c5602da03974d199a63bb1eae41a5d340a8d29d823cf9"
|
|
500
|
-
},
|
|
501
|
-
{
|
|
502
|
-
"path": "webui/src/tabs/metrics/MetricsTable.tsx",
|
|
503
|
-
"sha256": "dde7487a676dc7514b1124b91fbd1c930c6d184afc1ce9d4aeefff6a30373a45"
|
|
504
|
-
},
|
|
505
|
-
{
|
|
506
|
-
"path": "webui/src/tabs/metrics/Tiles.tsx",
|
|
507
|
-
"sha256": "ed968d73751ebb511516e8c9b3e89b01cb470124c27effb935dc305797409288"
|
|
508
|
-
},
|
|
509
|
-
{
|
|
510
|
-
"path": "webui/src/tabs/metrics/words.ts",
|
|
511
|
-
"sha256": "684c84d1ec9e782140d7d4796529f00fcbf1d0a36f9f4e50c081f19c3df61e73"
|
|
512
|
-
},
|
|
513
493
|
{
|
|
514
494
|
"path": "webui/src/tabs/plan/Conversation.tsx",
|
|
515
495
|
"sha256": "8fe5db3fdf973afda7fd0bfedca5ad0cb4b0ff3db275ecdb412df14d2bd1fee8"
|
|
@@ -564,11 +544,11 @@
|
|
|
564
544
|
},
|
|
565
545
|
{
|
|
566
546
|
"path": "webui/src/tabs/registry.tsx",
|
|
567
|
-
"sha256": "
|
|
547
|
+
"sha256": "6205bec77f47a8a83dee0ee88a3644a05f8c25ab62c2065bf47da3fe8d374749"
|
|
568
548
|
},
|
|
569
549
|
{
|
|
570
550
|
"path": "webui/src/tabs/settings/SettingsForm.tsx",
|
|
571
|
-
"sha256": "
|
|
551
|
+
"sha256": "5dad4d3081ad579d714aae0872f39596f823c08db7c9192d732f5d5084028b0c"
|
|
572
552
|
},
|
|
573
553
|
{
|
|
574
554
|
"path": "webui/src/tabs/settings/SettingsTab.tsx",
|
|
@@ -576,11 +556,11 @@
|
|
|
576
556
|
},
|
|
577
557
|
{
|
|
578
558
|
"path": "webui/src/tabs/settings/ThemeGroup.tsx",
|
|
579
|
-
"sha256": "
|
|
559
|
+
"sha256": "161c3ad0b92573daecff14c900a2c2d4fc54f14c96d294f46c5ff0f923c14f20"
|
|
580
560
|
},
|
|
581
561
|
{
|
|
582
562
|
"path": "webui/src/tabs/settings/parts.tsx",
|
|
583
|
-
"sha256": "
|
|
563
|
+
"sha256": "29ad5b69cc1b67caa8b304ed5942d19197b9c5670583dbec1e46337768822e76"
|
|
584
564
|
},
|
|
585
565
|
{
|
|
586
566
|
"path": "webui/src/tabs/settings/words.ts",
|
|
@@ -592,11 +572,11 @@
|
|
|
592
572
|
},
|
|
593
573
|
{
|
|
594
574
|
"path": "webui/src/tabs/tasks/DeliveryReview.tsx",
|
|
595
|
-
"sha256": "
|
|
575
|
+
"sha256": "72d76d6e6736f5e6d56534696d98c51e1ede44024dc3f31e0adb09c9ff0b3f7d"
|
|
596
576
|
},
|
|
597
577
|
{
|
|
598
578
|
"path": "webui/src/tabs/tasks/DetailSections.tsx",
|
|
599
|
-
"sha256": "
|
|
579
|
+
"sha256": "2abf152f2a36e60a35fa31465a1b18380a2a912e8125ada54e0bb9947b6685a7"
|
|
600
580
|
},
|
|
601
581
|
{
|
|
602
582
|
"path": "webui/src/tabs/tasks/OpenInSession.tsx",
|
|
@@ -615,20 +595,20 @@
|
|
|
615
595
|
"sha256": "3bbaa2342151be92262f350a7aee0c832a3609a02e1737c356070a17fad67837"
|
|
616
596
|
},
|
|
617
597
|
{
|
|
618
|
-
"path": "webui/src/tabs/tasks/
|
|
619
|
-
"sha256": "
|
|
598
|
+
"path": "webui/src/tabs/tasks/TaskDetail.tsx",
|
|
599
|
+
"sha256": "45459fa495940ec37f44a5e54be228a7c1b368bfefcd00052ba27df41c0193d6"
|
|
620
600
|
},
|
|
621
601
|
{
|
|
622
|
-
"path": "webui/src/tabs/tasks/
|
|
623
|
-
"sha256": "
|
|
602
|
+
"path": "webui/src/tabs/tasks/TaskInterventions.tsx",
|
|
603
|
+
"sha256": "6e7d22e9c41052c3fdc624e24026012b0258a0e93f93683c50328c34bc5a82dc"
|
|
624
604
|
},
|
|
625
605
|
{
|
|
626
606
|
"path": "webui/src/tabs/tasks/TaskList.tsx",
|
|
627
|
-
"sha256": "
|
|
607
|
+
"sha256": "1005f150fe3b91331c66c0e10e89526ef8a80ae6ecbfdf02d64de04fd1b65b64"
|
|
628
608
|
},
|
|
629
609
|
{
|
|
630
610
|
"path": "webui/src/tabs/tasks/TasksTab.tsx",
|
|
631
|
-
"sha256": "
|
|
611
|
+
"sha256": "9923567df7cb9a52f8a1e2f84567eab5d7fdc26107ff248302019bb81e498491"
|
|
632
612
|
},
|
|
633
613
|
{
|
|
634
614
|
"path": "webui/src/tabs/tasks/words.ts",
|
|
@@ -636,7 +616,7 @@
|
|
|
636
616
|
},
|
|
637
617
|
{
|
|
638
618
|
"path": "webui/src/ui/Actions.tsx",
|
|
639
|
-
"sha256": "
|
|
619
|
+
"sha256": "13e1abf67a0f0bc4e5eceaf480f6dc60cc534200af5aa88521d6c1cb6f89106d"
|
|
640
620
|
},
|
|
641
621
|
{
|
|
642
622
|
"path": "webui/src/ui/AgentIcon.tsx",
|
|
@@ -652,7 +632,7 @@
|
|
|
652
632
|
},
|
|
653
633
|
{
|
|
654
634
|
"path": "webui/src/ui/EffortSlider.tsx",
|
|
655
|
-
"sha256": "
|
|
635
|
+
"sha256": "faf1ed2ca0b34e68f41cc705be6e5e5cc10f9282e1a51bd617bf80e4336e78d7"
|
|
656
636
|
},
|
|
657
637
|
{
|
|
658
638
|
"path": "webui/src/ui/Frame.tsx",
|
|
@@ -678,9 +658,17 @@
|
|
|
678
658
|
"path": "webui/src/ui/Section.tsx",
|
|
679
659
|
"sha256": "7fe2b657e62e7da1eab8568efaaae72c9b952eb62a0da6491d69601a1af91900"
|
|
680
660
|
},
|
|
661
|
+
{
|
|
662
|
+
"path": "webui/src/ui/Segmented.tsx",
|
|
663
|
+
"sha256": "75379724dc93d3a3016af77e7d9de166e8b9f72e7187c3a1d7d712d65569d48f"
|
|
664
|
+
},
|
|
681
665
|
{
|
|
682
666
|
"path": "webui/src/ui/SplitPane.tsx",
|
|
683
|
-
"sha256": "
|
|
667
|
+
"sha256": "ce830d22df75821a073944d764b3e7daef3096fc541399f5f1433d67428053d3"
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
"path": "webui/src/ui/TypefacePicker.tsx",
|
|
671
|
+
"sha256": "e25079a764b41726935c5dc1bc5b61892137cf83150b20f97aae9efa16b789aa"
|
|
684
672
|
},
|
|
685
673
|
{
|
|
686
674
|
"path": "webui/src/ui/WorkingMark.tsx",
|
|
@@ -692,7 +680,7 @@
|
|
|
692
680
|
},
|
|
693
681
|
{
|
|
694
682
|
"path": "webui/src/ui/rows.ts",
|
|
695
|
-
"sha256": "
|
|
683
|
+
"sha256": "41c1e5f9f0c3b8abc0006209bb76dff6e45366740be1c7aa623c348c9253685f"
|
|
696
684
|
},
|
|
697
685
|
{
|
|
698
686
|
"path": "webui/src/ui/task-facts.tsx",
|
package/webui/dist/index.html
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
14
14
|
<title>bot-lobby</title>
|
|
15
15
|
<meta property="csp-nonce" nonce="__CSP_NONCE__">
|
|
16
|
-
<script type="module" crossorigin src="/assets/index-
|
|
17
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-CkQ5Eduy.js" nonce="__CSP_NONCE__"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Dl4yHBRY.css" nonce="__CSP_NONCE__">
|
|
18
18
|
</head>
|
|
19
19
|
<body>
|
|
20
20
|
<div id="root"></div>
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure metrics data helpers shared by the terminal tab and the web API.
|
|
3
|
-
* This module touches neither the terminal nor pi-tui (unlike
|
|
4
|
-
* `../tabs/metrics.ts`, which draws through `layout.ts`), so the loopback
|
|
5
|
-
* server can import it freely.
|
|
6
|
-
*/
|
|
7
|
-
import type { MetricRecord } from "../../state/metrics.ts";
|
|
8
|
-
|
|
9
|
-
/** Runs whose agent, model, thinking level, kind, status or task mention `query`. */
|
|
10
|
-
export function filterRecords(records: readonly MetricRecord[], query: string | undefined): MetricRecord[] {
|
|
11
|
-
const needle = query?.trim().toLowerCase();
|
|
12
|
-
if (!needle) return [...records];
|
|
13
|
-
return records.filter((record) => [record.agent, record.model ?? "", record.thinking ?? "", record.kind, record.status, record.taskId ?? ""].join(" ").toLowerCase().includes(needle));
|
|
14
|
-
}
|
package/src/webui/api/metrics.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The Metrics tab over HTTP: the KPI tiles, the per-model groups, where the
|
|
3
|
-
* time goes, and what the classifier did — the same figures the terminal
|
|
4
|
-
* tab draws, as data. Search narrows runs exactly like the tab's `/`.
|
|
5
|
-
*/
|
|
6
|
-
import { aggregateMetrics, collectMetrics, sortGroups, summarizeClassifier, taskStats, taskTimesByModel, type MetricRecord } from "../../state/metrics.ts";
|
|
7
|
-
import { filterRecords } from "../../lobby/models/metrics.ts";
|
|
8
|
-
import type { Api, MetricsData } from "../protocol.ts";
|
|
9
|
-
import { fail, type ApiContext } from "./index.ts";
|
|
10
|
-
|
|
11
|
-
function timed(records: readonly MetricRecord[]): MetricRecord[] {
|
|
12
|
-
return records.filter((record) => record.status !== "cancelled" && record.durationMs > 0);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** The KPI row as data: runs, success, average run, cost, tasks. */
|
|
16
|
-
function tilesOf(records: readonly MetricRecord[], stats: ReturnType<typeof taskStats>): MetricsData["tiles"] {
|
|
17
|
-
const done = timed(records);
|
|
18
|
-
const ok = records.filter((record) => record.status === "success").length;
|
|
19
|
-
const cost = records.reduce((sum, record) => sum + (record.cost ?? 0), 0);
|
|
20
|
-
const avg = done.length > 0 ? done.reduce((sum, record) => sum + record.durationMs, 0) / done.length : 0;
|
|
21
|
-
const sorted = done.map((record) => record.durationMs).sort((a, b) => a - b);
|
|
22
|
-
const p90 = sorted.length > 0 ? sorted[Math.min(sorted.length - 1, Math.ceil(0.9 * sorted.length) - 1)]! : 0;
|
|
23
|
-
return {
|
|
24
|
-
runs: records.length,
|
|
25
|
-
successes: ok,
|
|
26
|
-
stalls: records.filter((record) => record.stalled || record.status === "timeout").length,
|
|
27
|
-
avgMs: avg,
|
|
28
|
-
p90Ms: p90,
|
|
29
|
-
cost,
|
|
30
|
-
completed: stats.completed,
|
|
31
|
-
active: stats.active,
|
|
32
|
-
avgCompleteMs: stats.avgCompleteMs,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Each agent's share of all run time, longest first. */
|
|
37
|
-
function shareOf(records: readonly MetricRecord[]): MetricsData["timeShare"]["byAgent"] {
|
|
38
|
-
const byAgent = new Map<string, { runs: number; ms: number }>();
|
|
39
|
-
for (const record of timed(records)) {
|
|
40
|
-
const entry = byAgent.get(record.agent) ?? { runs: 0, ms: 0 };
|
|
41
|
-
entry.runs += 1;
|
|
42
|
-
entry.ms += record.durationMs;
|
|
43
|
-
byAgent.set(record.agent, entry);
|
|
44
|
-
}
|
|
45
|
-
const total = [...byAgent.values()].reduce((sum, entry) => sum + entry.ms, 0);
|
|
46
|
-
return [...byAgent.entries()]
|
|
47
|
-
.sort((a, b) => b[1].ms - a[1].ms)
|
|
48
|
-
.map(([agent, entry]) => ({ agent, runs: entry.runs, ms: entry.ms, share: total > 0 ? entry.ms / total : 0 }));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** The dashboard figures for one grouping and search. */
|
|
52
|
-
export function metricsGet(body: Api["metrics.get"]["request"], ctx: ApiContext): MetricsData {
|
|
53
|
-
const { from, to } = body;
|
|
54
|
-
const validDate = (value: string) => /^\d{4}-\d{2}-\d{2}$/.test(value) && Number.isFinite(Date.parse(value)) && new Date(value).toISOString().slice(0, 10) === value;
|
|
55
|
-
if ((from === undefined) !== (to === undefined) || (from !== undefined && (!validDate(from) || !validDate(to!) || from > to!))) {
|
|
56
|
-
fail(400, "bad_request", "Choose a valid start and end date, with the start on or before the end.");
|
|
57
|
-
}
|
|
58
|
-
let formatter: Intl.DateTimeFormat;
|
|
59
|
-
try {
|
|
60
|
-
formatter = new Intl.DateTimeFormat("en", { timeZone: body.timeZone ?? "UTC", year: "numeric", month: "2-digit", day: "2-digit" });
|
|
61
|
-
} catch {
|
|
62
|
-
fail(400, "bad_request", "Choose a valid time zone.");
|
|
63
|
-
}
|
|
64
|
-
const dayOf = (timestamp: string) => {
|
|
65
|
-
const date = new Date(timestamp);
|
|
66
|
-
if (!Number.isFinite(date.getTime())) return "";
|
|
67
|
-
const parts = formatter.formatToParts(date);
|
|
68
|
-
return ["year", "month", "day"].map((part) => parts.find((item) => item.type === part)!.value).join("-");
|
|
69
|
-
};
|
|
70
|
-
const inRange = (timestamp: string) => !from || (dayOf(timestamp) >= from && dayOf(timestamp) <= to!);
|
|
71
|
-
const allTasks = ctx.service.tasks();
|
|
72
|
-
const tasks = allTasks.filter((task) => inRange(task.state === "completed" ? task.updatedAt : task.createdAt));
|
|
73
|
-
const allRecords = filterRecords(collectMetrics(ctx.service.metrics(), allTasks), body.query);
|
|
74
|
-
const records = allRecords.filter((record) => inRange(record.startedAt));
|
|
75
|
-
const stats = taskStats(tasks);
|
|
76
|
-
const classifier = summarizeClassifier((ctx.service.classifierMetrics?.() ?? []).filter((record) => inRange(record.startedAt)), records);
|
|
77
|
-
const daily = new Map<string, MetricsData["daily"][number]>();
|
|
78
|
-
for (const record of records) {
|
|
79
|
-
const date = dayOf(record.startedAt);
|
|
80
|
-
if (!date) continue;
|
|
81
|
-
const entry = daily.get(date) ?? { date, runs: 0, successes: 0, cost: 0 };
|
|
82
|
-
entry.runs += 1;
|
|
83
|
-
entry.successes += Number(record.status === "success");
|
|
84
|
-
entry.cost += record.cost ?? 0;
|
|
85
|
-
daily.set(date, entry);
|
|
86
|
-
}
|
|
87
|
-
// Include range edges without allocating an entry for every empty day.
|
|
88
|
-
for (const date of [from, to]) if (date && !daily.has(date)) daily.set(date, { date, runs: 0, successes: 0, cost: 0 });
|
|
89
|
-
return {
|
|
90
|
-
tiles: tilesOf(records, stats),
|
|
91
|
-
daily: [...daily.values()].sort((a, b) => a.date.localeCompare(b.date)),
|
|
92
|
-
groups: sortGroups(aggregateMetrics(records, body.groupBy), "runs"),
|
|
93
|
-
timeShare: { byAgent: shareOf(records), taskTimes: taskTimesByModel(tasks, allRecords) },
|
|
94
|
-
...(classifier ? { classifier } : {}),
|
|
95
|
-
};
|
|
96
|
-
}
|