@agentdeck/bridge 1.1.0 → 1.2.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/README.md +14 -6
- package/assets/fonts/NOTICE-PocketSansWorld.md +10 -0
- package/assets/fonts/OFL-PocketSansWorld.txt +93 -0
- package/assets/fonts/PocketSansWorld_12.cpfont +0 -0
- package/assets/fonts/pocket-sans-world.manifest.json +49 -0
- package/assets/learning/LICENSE-CC-BY-SA-4.0.txt +10 -0
- package/assets/learning/NOTICE.md +33 -0
- package/assets/learning/jp-n3-ko.manifest.json +27 -0
- package/assets/learning/jp-n3-ko.pdl +0 -0
- package/dist/agent-cli-diagnostics.d.ts +20 -0
- package/dist/agent-cli-diagnostics.d.ts.map +1 -0
- package/dist/agent-cli-diagnostics.js +100 -0
- package/dist/agent-cli-diagnostics.js.map +1 -0
- package/dist/apme/classifier.d.ts.map +1 -1
- package/dist/apme/classifier.js +18 -10
- package/dist/apme/classifier.js.map +1 -1
- package/dist/apme/claude-transcript-reader.d.ts +36 -0
- package/dist/apme/claude-transcript-reader.d.ts.map +1 -1
- package/dist/apme/claude-transcript-reader.js +78 -2
- package/dist/apme/claude-transcript-reader.js.map +1 -1
- package/dist/apme/collector.d.ts +126 -3
- package/dist/apme/collector.d.ts.map +1 -1
- package/dist/apme/collector.js +450 -41
- package/dist/apme/collector.js.map +1 -1
- package/dist/apme/dashboard-html.d.ts.map +1 -1
- package/dist/apme/dashboard-html.js +278 -36
- package/dist/apme/dashboard-html.js.map +1 -1
- package/dist/apme/graph.d.ts +1 -1
- package/dist/apme/graph.d.ts.map +1 -1
- package/dist/apme/graph.js +51 -1
- package/dist/apme/graph.js.map +1 -1
- package/dist/apme/http.d.ts.map +1 -1
- package/dist/apme/http.js +37 -5
- package/dist/apme/http.js.map +1 -1
- package/dist/apme/index.d.ts +4 -0
- package/dist/apme/index.d.ts.map +1 -1
- package/dist/apme/index.js +19 -3
- package/dist/apme/index.js.map +1 -1
- package/dist/apme/runner.d.ts +90 -0
- package/dist/apme/runner.d.ts.map +1 -1
- package/dist/apme/runner.js +524 -48
- package/dist/apme/runner.js.map +1 -1
- package/dist/apme/sample-to-timeline.d.ts.map +1 -1
- package/dist/apme/sample-to-timeline.js +5 -0
- package/dist/apme/sample-to-timeline.js.map +1 -1
- package/dist/apme/settings.d.ts +8 -0
- package/dist/apme/settings.d.ts.map +1 -1
- package/dist/apme/settings.js +4 -0
- package/dist/apme/settings.js.map +1 -1
- package/dist/apme/store.d.ts +118 -9
- package/dist/apme/store.d.ts.map +1 -1
- package/dist/apme/store.js +342 -44
- package/dist/apme/store.js.map +1 -1
- package/dist/apme/task-gradeability.d.ts +82 -0
- package/dist/apme/task-gradeability.d.ts.map +1 -0
- package/dist/apme/task-gradeability.js +126 -0
- package/dist/apme/task-gradeability.js.map +1 -0
- package/dist/awaiting-overlay.d.ts +13 -26
- package/dist/awaiting-overlay.d.ts.map +1 -1
- package/dist/awaiting-overlay.js +7 -40
- package/dist/awaiting-overlay.js.map +1 -1
- package/dist/bridge-core.d.ts +15 -0
- package/dist/bridge-core.d.ts.map +1 -1
- package/dist/bridge-core.js +30 -4
- package/dist/bridge-core.js.map +1 -1
- package/dist/claude-permission-rules.d.ts +20 -32
- package/dist/claude-permission-rules.d.ts.map +1 -1
- package/dist/claude-permission-rules.js +19 -102
- package/dist/claude-permission-rules.js.map +1 -1
- package/dist/claude-usage-recovery.d.ts +54 -0
- package/dist/claude-usage-recovery.d.ts.map +1 -0
- package/dist/claude-usage-recovery.js +200 -0
- package/dist/claude-usage-recovery.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +81 -14
- package/dist/cli.js.map +1 -1
- package/dist/codex-rate-limits-live.d.ts +180 -10
- package/dist/codex-rate-limits-live.d.ts.map +1 -1
- package/dist/codex-rate-limits-live.js +475 -22
- package/dist/codex-rate-limits-live.js.map +1 -1
- package/dist/codex-rollout-response.d.ts +43 -0
- package/dist/codex-rollout-response.d.ts.map +1 -1
- package/dist/codex-rollout-response.js +67 -0
- package/dist/codex-rollout-response.js.map +1 -1
- package/dist/coordination-evidence.d.ts +150 -0
- package/dist/coordination-evidence.d.ts.map +1 -0
- package/dist/coordination-evidence.js +455 -0
- package/dist/coordination-evidence.js.map +1 -0
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +592 -35
- package/dist/daemon-server.js.map +1 -1
- package/dist/daemon-ws-client.d.ts +1 -0
- package/dist/daemon-ws-client.d.ts.map +1 -1
- package/dist/daemon-ws-client.js +25 -16
- package/dist/daemon-ws-client.js.map +1 -1
- package/dist/daemon.js +1 -1
- package/dist/deferred-reply-read.d.ts +24 -0
- package/dist/deferred-reply-read.d.ts.map +1 -0
- package/dist/deferred-reply-read.js +42 -0
- package/dist/deferred-reply-read.js.map +1 -0
- package/dist/esp32-serial.d.ts +15 -0
- package/dist/esp32-serial.d.ts.map +1 -1
- package/dist/esp32-serial.js +61 -2
- package/dist/esp32-serial.js.map +1 -1
- package/dist/font-pack.d.ts +15 -0
- package/dist/font-pack.d.ts.map +1 -0
- package/dist/font-pack.js +75 -0
- package/dist/font-pack.js.map +1 -0
- package/dist/glance-frame.d.ts.map +1 -1
- package/dist/glance-frame.js +2 -0
- package/dist/glance-frame.js.map +1 -1
- package/dist/hook-codex-sessions.d.ts +9 -0
- package/dist/hook-codex-sessions.d.ts.map +1 -1
- package/dist/hook-codex-sessions.js +35 -2
- package/dist/hook-codex-sessions.js.map +1 -1
- package/dist/hook-opencode-sessions.d.ts +62 -0
- package/dist/hook-opencode-sessions.d.ts.map +1 -0
- package/dist/hook-opencode-sessions.js +180 -0
- package/dist/hook-opencode-sessions.js.map +1 -0
- package/dist/hook-response-source.d.ts +40 -0
- package/dist/hook-response-source.d.ts.map +1 -0
- package/dist/hook-response-source.js +31 -0
- package/dist/hook-response-source.js.map +1 -0
- package/dist/http-auth-gate.d.ts.map +1 -1
- package/dist/http-auth-gate.js +9 -1
- package/dist/http-auth-gate.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/learning-pack.d.ts +24 -0
- package/dist/learning-pack.d.ts.map +1 -0
- package/dist/learning-pack.js +125 -0
- package/dist/learning-pack.js.map +1 -0
- package/dist/mdns.js +1 -1
- package/dist/mdns.js.map +1 -1
- package/dist/native-dependency-diagnostics.d.ts +29 -0
- package/dist/native-dependency-diagnostics.d.ts.map +1 -0
- package/dist/native-dependency-diagnostics.js +95 -0
- package/dist/native-dependency-diagnostics.js.map +1 -0
- package/dist/observed-steering.d.ts +4 -4
- package/dist/observed-steering.d.ts.map +1 -1
- package/dist/observed-steering.js +28 -32
- package/dist/observed-steering.js.map +1 -1
- package/dist/openclaw-gateway-stability.d.ts +94 -0
- package/dist/openclaw-gateway-stability.d.ts.map +1 -0
- package/dist/openclaw-gateway-stability.js +176 -0
- package/dist/openclaw-gateway-stability.js.map +1 -0
- package/dist/pairing-knocks.d.ts +80 -0
- package/dist/pairing-knocks.d.ts.map +1 -0
- package/dist/pairing-knocks.js +312 -0
- package/dist/pairing-knocks.js.map +1 -0
- package/dist/passive-observer.d.ts +5 -0
- package/dist/passive-observer.d.ts.map +1 -1
- package/dist/passive-observer.js +6 -0
- package/dist/passive-observer.js.map +1 -1
- package/dist/pixoo/micro-glyphs.d.ts +4 -0
- package/dist/pixoo/micro-glyphs.d.ts.map +1 -1
- package/dist/pixoo/micro-glyphs.js +29 -0
- package/dist/pixoo/micro-glyphs.js.map +1 -1
- package/dist/pixoo/pixoo-font.d.ts.map +1 -1
- package/dist/pixoo/pixoo-font.js +3 -1
- package/dist/pixoo/pixoo-font.js.map +1 -1
- package/dist/pixoo/pixoo-renderer.d.ts +1 -1
- package/dist/pixoo/pixoo-renderer.d.ts.map +1 -1
- package/dist/pixoo/pixoo-renderer.js +17 -2
- package/dist/pixoo/pixoo-renderer.js.map +1 -1
- package/dist/pty-manager.d.ts +9 -0
- package/dist/pty-manager.d.ts.map +1 -1
- package/dist/pty-manager.js +63 -4
- package/dist/pty-manager.js.map +1 -1
- package/dist/relayed-usage.d.ts +30 -0
- package/dist/relayed-usage.d.ts.map +1 -1
- package/dist/relayed-usage.js +25 -2
- package/dist/relayed-usage.js.map +1 -1
- package/dist/review-runner.js +1 -1
- package/dist/subagent-timeline.d.ts +27 -0
- package/dist/subagent-timeline.d.ts.map +1 -1
- package/dist/subagent-timeline.js +52 -5
- package/dist/subagent-timeline.js.map +1 -1
- package/dist/surface-protocol.d.ts.map +1 -1
- package/dist/surface-protocol.js +2 -0
- package/dist/surface-protocol.js.map +1 -1
- package/dist/tui/dashboard.d.ts.map +1 -1
- package/dist/tui/dashboard.js +8 -1
- package/dist/tui/dashboard.js.map +1 -1
- package/dist/usage-api.d.ts +3 -0
- package/dist/usage-api.d.ts.map +1 -1
- package/dist/usage-api.js +101 -36
- package/dist/usage-api.js.map +1 -1
- package/dist/usage-event.d.ts.map +1 -1
- package/dist/usage-event.js +2 -1
- package/dist/usage-event.js.map +1 -1
- package/dist/ws-server.d.ts +18 -0
- package/dist/ws-server.d.ts.map +1 -1
- package/dist/ws-server.js +40 -2
- package/dist/ws-server.js.map +1 -1
- package/package.json +6 -5
- package/src/timebox/sync_ble.py +35 -16
package/dist/apme/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/apme/store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,eAAe,EACf,aAAa,EACb,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,eAAe,EACf,mBAAmB,EACpB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EACV,kBAAkB,EAClB,sBAAsB,EACtB,aAAa,EAEb,eAAe,EAChB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/apme/store.ts"],"names":[],"mappings":"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"}
|
package/dist/apme/store.js
CHANGED
|
@@ -15,6 +15,7 @@ import { debug } from '../logger.js';
|
|
|
15
15
|
// workspace symlinks, regardless of the process CWD (vitest runs from the
|
|
16
16
|
// repo root, where the symlink doesn't exist).
|
|
17
17
|
const require = createRequire(import.meta.url);
|
|
18
|
+
import { TASK_ATTENTION_WINDOW_MS, TASK_ATTENTION_RED_SCORE } from '@agentdeck/shared';
|
|
18
19
|
// ─── Schema ────────────────────────────────────────────────────────────────────
|
|
19
20
|
const SCORECARD_DDL = `
|
|
20
21
|
-- Pre-aggregate metrics at the level they actually describe. New rows prefer
|
|
@@ -313,6 +314,7 @@ CREATE TABLE IF NOT EXISTS vibe_feedback (
|
|
|
313
314
|
CREATE INDEX IF NOT EXISTS idx_runs_model ON runs(model_id);
|
|
314
315
|
CREATE INDEX IF NOT EXISTS idx_runs_agent ON runs(agent_type);
|
|
315
316
|
CREATE INDEX IF NOT EXISTS idx_runs_started ON runs(started_at);
|
|
317
|
+
CREATE INDEX IF NOT EXISTS idx_runs_session ON runs(session_id);
|
|
316
318
|
CREATE INDEX IF NOT EXISTS idx_evals_run ON evals(run_id);
|
|
317
319
|
CREATE INDEX IF NOT EXISTS idx_steps_run ON steps(run_id);
|
|
318
320
|
|
|
@@ -530,6 +532,81 @@ Examples of well-calibrated overall scores:
|
|
|
530
532
|
notes: 'task-unit rollup (TodoWrite all-completed / /clear / session_end)',
|
|
531
533
|
},
|
|
532
534
|
};
|
|
535
|
+
/** The latest overall judge score for a task, else its composite. Inlined into
|
|
536
|
+
* several `TASK_VIEW_SQL` buckets so "judged" means one thing everywhere. */
|
|
537
|
+
const TASK_SCORE_SQL = `COALESCE((SELECT e.score FROM evals e WHERE e.task_id = t.id AND e.metric = 'overall'
|
|
538
|
+
ORDER BY e.created_at DESC LIMIT 1), t.composite_score)`;
|
|
539
|
+
/** The recency window and red-score band live in shared/src/eval-schema.ts
|
|
540
|
+
* (TASK_ATTENTION_WINDOW_MS / TASK_ATTENTION_RED_SCORE): both daemons build
|
|
541
|
+
* the same attention SQL, so the numbers are cross-daemon contracts, not
|
|
542
|
+
* store-local tuning knobs. Re-exported for existing importers. */
|
|
543
|
+
export { TASK_ATTENTION_WINDOW_MS } from '@agentdeck/shared';
|
|
544
|
+
/** The attention bucket, anchored at a caller-supplied cutoff (epoch ms) so
|
|
545
|
+
* the filter, the row flag and the badge are computed against the SAME
|
|
546
|
+
* instant within one request. Needs eyes = recent AND (reaper-closed, a
|
|
547
|
+
* closed task with an unarchived reply the judge can only partly see, or a
|
|
548
|
+
* judged score below the dashboard's red band). `cutoffMs` is always a
|
|
549
|
+
* number we computed — never user input — so inlining it is safe. */
|
|
550
|
+
function taskAttentionSql(cutoffMs) {
|
|
551
|
+
// IFNULL is load-bearing: a NULL score makes `score < 0.4` NULL, NULL OR
|
|
552
|
+
// false is NULL, and SQLite sorts NULL LAST under DESC — so without it,
|
|
553
|
+
// recent unjudged rows sank BELOW week-old rows (which get a determinate 0
|
|
554
|
+
// from the cutoff test) on the attention-first ordering.
|
|
555
|
+
return `IFNULL((t.started_at >= ${Math.floor(cutoffMs)}
|
|
556
|
+
AND (t.boundary_signal = 'orphaned'
|
|
557
|
+
OR (t.ended_at IS NOT NULL AND EXISTS (
|
|
558
|
+
SELECT 1 FROM turns tu WHERE tu.task_id = t.id AND tu.response IS NULL))
|
|
559
|
+
OR ${TASK_SCORE_SQL} < ${TASK_ATTENTION_RED_SCORE})), 0)`;
|
|
560
|
+
}
|
|
561
|
+
/** The NARROWING filters `listTaskPage` and `taskViewCounts` share — one
|
|
562
|
+
* builder so a filtered board's badges and its rows read the same WHERE. */
|
|
563
|
+
function buildTaskFilterWhere(opts) {
|
|
564
|
+
const where = [];
|
|
565
|
+
const args = [];
|
|
566
|
+
// `_empty` runs are bookkeeping shells, never work the user did.
|
|
567
|
+
where.push("COALESCE(r.task_category, '') != '_empty'");
|
|
568
|
+
if (opts.agentType) {
|
|
569
|
+
where.push('r.agent_type = ?');
|
|
570
|
+
args.push(opts.agentType);
|
|
571
|
+
}
|
|
572
|
+
if (opts.sessionId) {
|
|
573
|
+
where.push('r.session_id = ?');
|
|
574
|
+
args.push(opts.sessionId);
|
|
575
|
+
}
|
|
576
|
+
if (opts.projectName) {
|
|
577
|
+
where.push('r.project_name = ?');
|
|
578
|
+
args.push(opts.projectName);
|
|
579
|
+
}
|
|
580
|
+
if (opts.category) {
|
|
581
|
+
where.push('COALESCE(t.task_category, r.task_category) = ?');
|
|
582
|
+
args.push(opts.category);
|
|
583
|
+
}
|
|
584
|
+
if (opts.outcome) {
|
|
585
|
+
where.push('t.outcome = ?');
|
|
586
|
+
args.push(opts.outcome);
|
|
587
|
+
}
|
|
588
|
+
if (opts.q) {
|
|
589
|
+
where.push('(t.summary LIKE ? OR r.task_prompt LIKE ?)');
|
|
590
|
+
const like = `%${opts.q}%`;
|
|
591
|
+
args.push(like, like);
|
|
592
|
+
}
|
|
593
|
+
return { where, args };
|
|
594
|
+
}
|
|
595
|
+
/** ONE SQL definition per Work-board lifecycle bucket — the filter, the row's
|
|
596
|
+
* `attention` flag and the tab badges all read these same expressions, so a
|
|
597
|
+
* badge count can never disagree with the rows its tab lists.
|
|
598
|
+
*
|
|
599
|
+
* attention — see `taskAttentionSql` (recency-windowed, hence a function).
|
|
600
|
+
* inprogress — still accumulating turns.
|
|
601
|
+
* judged — carries an overall judge score or a composite.
|
|
602
|
+
* reported — closed but never scored (no judge configured / skipped).
|
|
603
|
+
* orphaned — reaper-closed; the un-windowed ledger of segmentation debt. */
|
|
604
|
+
const TASK_VIEW_SQL = {
|
|
605
|
+
inprogress: 't.ended_at IS NULL',
|
|
606
|
+
judged: `${TASK_SCORE_SQL} IS NOT NULL`,
|
|
607
|
+
reported: `(t.ended_at IS NOT NULL AND ${TASK_SCORE_SQL} IS NULL)`,
|
|
608
|
+
orphaned: `t.boundary_signal = 'orphaned'`,
|
|
609
|
+
};
|
|
533
610
|
export class ApmeStore {
|
|
534
611
|
db = null;
|
|
535
612
|
enabled = false;
|
|
@@ -554,7 +631,8 @@ export class ApmeStore {
|
|
|
554
631
|
Ctor = require('better-sqlite3');
|
|
555
632
|
}
|
|
556
633
|
catch (err) {
|
|
557
|
-
this.lastInitError =
|
|
634
|
+
this.lastInitError =
|
|
635
|
+
`better-sqlite3 native binding unavailable (${String(err).slice(0, 200)})`;
|
|
558
636
|
debug('APME', this.lastInitError);
|
|
559
637
|
return false;
|
|
560
638
|
}
|
|
@@ -929,6 +1007,17 @@ export class ApmeStore {
|
|
|
929
1007
|
vals.push(id);
|
|
930
1008
|
this.db.prepare(`UPDATE turns SET ${sets.join(', ')} WHERE id = ?`).run(...vals);
|
|
931
1009
|
}
|
|
1010
|
+
/** The newest closed turn of any run that `sessionId` ever owned, provided
|
|
1011
|
+
* it closed at or after `endedSinceMs`. The collector's fallback for a
|
|
1012
|
+
* reply that arrives after the run's in-memory edges are gone. */
|
|
1013
|
+
latestClosedTurnIdForSession(sessionId, endedSinceMs) {
|
|
1014
|
+
if (!this.db)
|
|
1015
|
+
return null;
|
|
1016
|
+
const row = this.db.prepare(`SELECT t.id AS id FROM turns t JOIN runs r ON r.id = t.run_id
|
|
1017
|
+
WHERE r.session_id = ? AND t.ended_at IS NOT NULL AND t.ended_at >= ?
|
|
1018
|
+
ORDER BY t.ended_at DESC LIMIT 1`).get(sessionId, endedSinceMs);
|
|
1019
|
+
return row?.id ?? null;
|
|
1020
|
+
}
|
|
932
1021
|
getTurn(id) {
|
|
933
1022
|
if (!this.db)
|
|
934
1023
|
return null;
|
|
@@ -974,7 +1063,8 @@ export class ApmeStore {
|
|
|
974
1063
|
SUM(t.end_source = 'interrupted') AS interrupted,
|
|
975
1064
|
SUM(t.end_source = 'aborted') AS aborted,
|
|
976
1065
|
SUM(t.end_source = 'superseded') AS superseded,
|
|
977
|
-
SUM(t.end_source IN ('session_end','
|
|
1066
|
+
SUM(t.end_source IN ('session_end','clear')) AS sessionEnd,
|
|
1067
|
+
SUM(t.end_source = 'run_close') AS runClose,
|
|
978
1068
|
SUM(t.ended_at IS NULL) AS open,
|
|
979
1069
|
SUM(t.ended_at IS NOT NULL AND t.end_source IS NULL) AS preInstrument
|
|
980
1070
|
FROM turns t JOIN runs r ON r.id = t.run_id
|
|
@@ -991,6 +1081,7 @@ export class ApmeStore {
|
|
|
991
1081
|
aborted: Number(r.aborted ?? 0),
|
|
992
1082
|
superseded: Number(r.superseded ?? 0),
|
|
993
1083
|
sessionEnd: Number(r.sessionEnd ?? 0),
|
|
1084
|
+
runClose: Number(r.runClose ?? 0),
|
|
994
1085
|
open: Number(r.open ?? 0),
|
|
995
1086
|
preInstrument: Number(r.preInstrument ?? 0),
|
|
996
1087
|
}));
|
|
@@ -1081,36 +1172,18 @@ export class ApmeStore {
|
|
|
1081
1172
|
return { total: 0, tasks: [] };
|
|
1082
1173
|
const limit = Math.min(Math.max(opts.limit ?? 50, 1), 500);
|
|
1083
1174
|
const offset = Math.max(opts.offset ?? 0, 0);
|
|
1084
|
-
const where =
|
|
1085
|
-
const
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
if (opts.agentType) {
|
|
1089
|
-
where.push('r.agent_type = ?');
|
|
1090
|
-
args.push(opts.agentType);
|
|
1091
|
-
}
|
|
1092
|
-
if (opts.projectName) {
|
|
1093
|
-
where.push('r.project_name = ?');
|
|
1094
|
-
args.push(opts.projectName);
|
|
1095
|
-
}
|
|
1096
|
-
if (opts.category) {
|
|
1097
|
-
where.push('COALESCE(t.task_category, r.task_category) = ?');
|
|
1098
|
-
args.push(opts.category);
|
|
1099
|
-
}
|
|
1100
|
-
if (opts.outcome) {
|
|
1101
|
-
where.push('t.outcome = ?');
|
|
1102
|
-
args.push(opts.outcome);
|
|
1103
|
-
}
|
|
1175
|
+
const { where, args } = buildTaskFilterWhere(opts);
|
|
1176
|
+
const attentionSql = taskAttentionSql(Date.now() - TASK_ATTENTION_WINDOW_MS);
|
|
1177
|
+
if (opts.view)
|
|
1178
|
+
where.push(opts.view === 'attention' ? attentionSql : TASK_VIEW_SQL[opts.view]);
|
|
1104
1179
|
if (opts.state === 'closed')
|
|
1105
1180
|
where.push('t.ended_at IS NOT NULL');
|
|
1106
1181
|
if (opts.state === 'open')
|
|
1107
1182
|
where.push('t.ended_at IS NULL');
|
|
1108
|
-
if (opts.q) {
|
|
1109
|
-
where.push('(t.summary LIKE ? OR r.task_prompt LIKE ?)');
|
|
1110
|
-
const like = `%${opts.q}%`;
|
|
1111
|
-
args.push(like, like);
|
|
1112
|
-
}
|
|
1113
1183
|
const whereSql = `WHERE ${where.join(' AND ')}`;
|
|
1184
|
+
const orderSql = opts.order === 'attention'
|
|
1185
|
+
? 'ORDER BY attention DESC, t.started_at DESC'
|
|
1186
|
+
: 'ORDER BY t.started_at DESC';
|
|
1114
1187
|
const total = this.db.prepare(`SELECT COUNT(*) AS n FROM tasks t JOIN runs r ON r.id = t.run_id ${whereSql}`).get(...args).n;
|
|
1115
1188
|
const rows = this.db.prepare(`SELECT t.*,
|
|
1116
1189
|
r.session_id, r.agent_type, r.model_id AS run_model_id, r.project_name,
|
|
@@ -1119,15 +1192,78 @@ export class ApmeStore {
|
|
|
1119
1192
|
(SELECT COUNT(*) FROM turns tu WHERE tu.task_id = t.id AND tu.response IS NOT NULL) AS answered_turns,
|
|
1120
1193
|
(SELECT COUNT(*) FROM sample_events se WHERE se.task_id = t.id) AS event_count,
|
|
1121
1194
|
(SELECT COUNT(*) FROM sample_events se WHERE se.task_id = t.id AND se.kind = 'tool') AS tool_count,
|
|
1195
|
+
(SELECT COALESCE(SUM(COALESCE(tu.files_modified, 0) + COALESCE(tu.files_created, 0)), 0)
|
|
1196
|
+
FROM turns tu WHERE tu.task_id = t.id) AS files_touched,
|
|
1122
1197
|
(SELECT tu.prompt FROM turns tu WHERE tu.task_id = t.id ORDER BY tu.turn_index ASC LIMIT 1) AS first_prompt,
|
|
1123
1198
|
(SELECT e.score FROM evals e WHERE e.task_id = t.id AND e.metric = 'overall' ORDER BY e.created_at DESC LIMIT 1) AS overall_score,
|
|
1124
|
-
(SELECT COUNT(*) FROM evals e WHERE e.task_id = t.id) AS eval_count
|
|
1199
|
+
(SELECT COUNT(*) FROM evals e WHERE e.task_id = t.id) AS eval_count,
|
|
1200
|
+
(${attentionSql}) AS attention
|
|
1125
1201
|
FROM tasks t JOIN runs r ON r.id = t.run_id
|
|
1126
1202
|
${whereSql}
|
|
1127
|
-
|
|
1203
|
+
${orderSql}
|
|
1128
1204
|
LIMIT ? OFFSET ?`).all(...args, limit, offset);
|
|
1129
1205
|
return { total, tasks: rows.map(rowToTaskListRow) };
|
|
1130
1206
|
}
|
|
1207
|
+
/** 10 s TTL cache for `taskViewCounts`, keyed by the filter tuple. The Work
|
|
1208
|
+
* board polls every 15 s and refetches on every interaction; the badges
|
|
1209
|
+
* are a full-table aggregate with correlated eval subqueries, so paying it
|
|
1210
|
+
* at most once per TTL bounds the cost of leaving the dashboard open. */
|
|
1211
|
+
viewCountsCache = new Map();
|
|
1212
|
+
/** Per-lifecycle-bucket totals for the Work board's tab badges. Takes the
|
|
1213
|
+
* same NARROWING filters as `listTaskPage` (agent/project/category/
|
|
1214
|
+
* outcome/q) so a filtered board's badges count what its tabs would list.
|
|
1215
|
+
* Buckets and filters read the same SQL definitions; the TTL means a badge
|
|
1216
|
+
* may lag its rows by up to 10 s after a task moves buckets — a bounded
|
|
1217
|
+
* staleness, not a different definition. */
|
|
1218
|
+
taskViewCounts(filters = {}) {
|
|
1219
|
+
const empty = { all: 0, attention: 0, inprogress: 0, judged: 0, reported: 0, orphaned: 0 };
|
|
1220
|
+
if (!this.db)
|
|
1221
|
+
return { ...empty };
|
|
1222
|
+
const key = JSON.stringify([filters.agentType, filters.sessionId, filters.projectName, filters.category, filters.outcome, filters.q]);
|
|
1223
|
+
const cached = this.viewCountsCache.get(key);
|
|
1224
|
+
if (cached && Date.now() - cached.at < 10_000)
|
|
1225
|
+
return cached.value;
|
|
1226
|
+
const attentionSql = taskAttentionSql(Date.now() - TASK_ATTENTION_WINDOW_MS);
|
|
1227
|
+
const { where, args } = buildTaskFilterWhere(filters);
|
|
1228
|
+
const row = this.db.prepare(`SELECT COUNT(*) AS all_n,
|
|
1229
|
+
SUM(CASE WHEN ${attentionSql} THEN 1 ELSE 0 END) AS attention_n,
|
|
1230
|
+
SUM(CASE WHEN ${TASK_VIEW_SQL.inprogress} THEN 1 ELSE 0 END) AS inprogress_n,
|
|
1231
|
+
SUM(CASE WHEN ${TASK_VIEW_SQL.judged} THEN 1 ELSE 0 END) AS judged_n,
|
|
1232
|
+
SUM(CASE WHEN ${TASK_VIEW_SQL.reported} THEN 1 ELSE 0 END) AS reported_n,
|
|
1233
|
+
SUM(CASE WHEN ${TASK_VIEW_SQL.orphaned} THEN 1 ELSE 0 END) AS orphaned_n
|
|
1234
|
+
FROM tasks t JOIN runs r ON r.id = t.run_id
|
|
1235
|
+
WHERE ${where.join(' AND ')}`).get(...args);
|
|
1236
|
+
const value = {
|
|
1237
|
+
all: row.all_n ?? 0,
|
|
1238
|
+
attention: row.attention_n ?? 0,
|
|
1239
|
+
inprogress: row.inprogress_n ?? 0,
|
|
1240
|
+
judged: row.judged_n ?? 0,
|
|
1241
|
+
reported: row.reported_n ?? 0,
|
|
1242
|
+
orphaned: row.orphaned_n ?? 0,
|
|
1243
|
+
};
|
|
1244
|
+
if (this.viewCountsCache.size > 20)
|
|
1245
|
+
this.viewCountsCache.clear();
|
|
1246
|
+
this.viewCountsCache.set(key, { at: Date.now(), value });
|
|
1247
|
+
return value;
|
|
1248
|
+
}
|
|
1249
|
+
/** Per-tool call counts for a page of tasks, in one grouped query. Feeds the
|
|
1250
|
+
* shared `foldActionCounts` projection — the store returns raw counts, the
|
|
1251
|
+
* HTTP layer folds. */
|
|
1252
|
+
toolCountsForTasks(taskIds) {
|
|
1253
|
+
const out = new Map();
|
|
1254
|
+
if (!this.db || taskIds.length === 0)
|
|
1255
|
+
return out;
|
|
1256
|
+
const placeholders = taskIds.map(() => '?').join(',');
|
|
1257
|
+
const rows = this.db.prepare(`SELECT task_id, tool_name, COUNT(*) AS n FROM sample_events
|
|
1258
|
+
WHERE kind = 'tool' AND tool_name IS NOT NULL AND task_id IN (${placeholders})
|
|
1259
|
+
GROUP BY task_id, tool_name`).all(...taskIds);
|
|
1260
|
+
for (const r of rows) {
|
|
1261
|
+
const list = out.get(r.task_id) ?? [];
|
|
1262
|
+
list.push({ name: r.tool_name, count: r.n });
|
|
1263
|
+
out.set(r.task_id, list);
|
|
1264
|
+
}
|
|
1265
|
+
return out;
|
|
1266
|
+
}
|
|
1131
1267
|
/** Distinct values behind the task list's filters, so the UI offers what the
|
|
1132
1268
|
* data actually contains rather than a hardcoded menu. */
|
|
1133
1269
|
taskFacets() {
|
|
@@ -1147,15 +1283,24 @@ export class ApmeStore {
|
|
|
1147
1283
|
return [];
|
|
1148
1284
|
return this.db.prepare('SELECT * FROM turns WHERE task_id = ? ORDER BY turn_index ASC').all(taskId);
|
|
1149
1285
|
}
|
|
1150
|
-
/** Ended tasks (boundary hit) that haven't been judged yet —
|
|
1151
|
-
|
|
1286
|
+
/** Ended tasks (boundary hit) that haven't been judged yet — the judge
|
|
1287
|
+
* backlog. The daemon's eval tick drains this a few per sweep; before it
|
|
1288
|
+
* did (2026-09-03) nothing called it, so a task whose one judge call was
|
|
1289
|
+
* lost — daemon restarted mid-eval, judge offline, backend probe not yet
|
|
1290
|
+
* ready — stayed unjudged for good: 1,060 closed tasks sat in `reported`.
|
|
1291
|
+
* `sinceMs` bounds how far back the drain reaches. */
|
|
1292
|
+
listTasksNeedingSummary(limit = 20, sinceMs = 0) {
|
|
1152
1293
|
if (!this.db)
|
|
1153
1294
|
return [];
|
|
1154
1295
|
const rows = this.db.prepare(`SELECT t.id, t.run_id, t.task_category FROM tasks t
|
|
1155
1296
|
WHERE t.ended_at IS NOT NULL
|
|
1297
|
+
AND t.ended_at >= ?
|
|
1156
1298
|
AND t.summary IS NULL
|
|
1299
|
+
-- A task the judge already declined (task-gradeability.ts) is not a
|
|
1300
|
+
-- backlog; re-offering it every sweep re-declines it forever.
|
|
1301
|
+
AND (t.notes_json IS NULL OR t.notes_json NOT LIKE '%"notGradeable"%')
|
|
1157
1302
|
ORDER BY t.ended_at DESC
|
|
1158
|
-
LIMIT ?`).all(limit);
|
|
1303
|
+
LIMIT ?`).all(sinceMs, limit);
|
|
1159
1304
|
return rows.map((r) => ({ id: r.id, runId: r.run_id, taskCategory: r.task_category }));
|
|
1160
1305
|
}
|
|
1161
1306
|
insertEvalForTask(row) {
|
|
@@ -1363,27 +1508,51 @@ export class ApmeStore {
|
|
|
1363
1508
|
LIMIT ?`).all(cutoff, cutoff, limit);
|
|
1364
1509
|
return rows.map((r) => ({ id: r.id, projectPath: r.project_path, lastActivity: r.last_activity }));
|
|
1365
1510
|
}
|
|
1366
|
-
/** Finalize an abandoned run: close its dangling turns, close its
|
|
1367
|
-
*
|
|
1368
|
-
*
|
|
1369
|
-
*
|
|
1511
|
+
/** Finalize an abandoned run: close its dangling turns, close its open
|
|
1512
|
+
* tasks, then close the run itself — all stamped at `endedAt` (the run's
|
|
1513
|
+
* last activity), not `now`, so a run abandoned last night doesn't report a
|
|
1514
|
+
* 12-hour turn.
|
|
1515
|
+
*
|
|
1516
|
+
* The task's boundary says what the reaper actually found, not merely that
|
|
1517
|
+
* it was the reaper who found it. A task whose every turn had closed is a
|
|
1518
|
+
* task that went quiet after a clean finish — the definition of the
|
|
1519
|
+
* `idle_gap` boundary (`AGENT_IDLE_GAP_MS`), reached late because the
|
|
1520
|
+
* in-memory timer that would have fired did not survive the process. Only a
|
|
1521
|
+
* task still holding an OPEN turn is `orphaned`: the work was cut off
|
|
1522
|
+
* mid-turn with nothing left to tell how it ended. Stamping both
|
|
1523
|
+
* `orphaned` put 79% of a week's tasks in the "reaper" chip and hid that
|
|
1524
|
+
* the segmentation itself had been right. Tasks are classified BEFORE the
|
|
1525
|
+
* dangling turns are closed, since closing them is what would erase the
|
|
1526
|
+
* distinction.
|
|
1370
1527
|
*
|
|
1371
1528
|
* Tasks are backfilled with their real first/last turn index when the
|
|
1372
1529
|
* in-memory close never ran, since the task rollup reads those columns.
|
|
1373
|
-
* Returns the closed
|
|
1374
|
-
* the whole point of closing them. */
|
|
1530
|
+
* Returns the closed tasks — with the boundary each was given — so the
|
|
1531
|
+
* caller can enqueue task-level evals, the whole point of closing them. */
|
|
1375
1532
|
reapAbandonedRun(runId, endedAt) {
|
|
1376
1533
|
if (!this.db)
|
|
1377
1534
|
return [];
|
|
1378
1535
|
const bounds = this.db.prepare('SELECT MIN(turn_index) AS lo, MAX(turn_index) AS hi FROM turns WHERE run_id = ?').get(runId);
|
|
1379
|
-
const tasks = this.db.prepare(
|
|
1536
|
+
const tasks = this.db.prepare(`SELECT k.id, k.task_category,
|
|
1537
|
+
EXISTS (SELECT 1 FROM turns t WHERE t.task_id = k.id AND t.ended_at IS NULL) AS has_open_turn
|
|
1538
|
+
FROM tasks k WHERE k.run_id = ? AND k.ended_at IS NULL`).all(runId);
|
|
1380
1539
|
const tx = this.db.transaction(() => {
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1540
|
+
// Tasks first: the open-turn test below is destroyed by the turn UPDATE.
|
|
1541
|
+
this.db.prepare(`UPDATE tasks SET ended_at = ?,
|
|
1542
|
+
boundary_signal = CASE
|
|
1543
|
+
WHEN EXISTS (SELECT 1 FROM turns t WHERE t.task_id = tasks.id AND t.ended_at IS NULL)
|
|
1544
|
+
THEN 'orphaned' ELSE 'idle_gap' END,
|
|
1384
1545
|
first_turn_index = COALESCE(first_turn_index, ?),
|
|
1385
|
-
last_turn_index = COALESCE(last_turn_index, ?)
|
|
1546
|
+
last_turn_index = COALESCE(last_turn_index, ?),
|
|
1547
|
+
-- The in-memory close resolves a category at close time; a reaped
|
|
1548
|
+
-- task never had one, and the judge then fell back to the generic
|
|
1549
|
+
-- rubric (66 of 135 uncategorised tasks in a week sat on runs
|
|
1550
|
+
-- already classified 'ops'). Inherit the run's.
|
|
1551
|
+
task_category = COALESCE(task_category,
|
|
1552
|
+
(SELECT r.task_category FROM runs r WHERE r.id = tasks.run_id AND r.task_category <> 'unknown'))
|
|
1386
1553
|
WHERE run_id = ? AND ended_at IS NULL`).run(endedAt, bounds?.lo ?? null, bounds?.hi ?? null, runId);
|
|
1554
|
+
this.db.prepare(`UPDATE turns SET ended_at = ?, end_source = 'run_close'
|
|
1555
|
+
WHERE run_id = ? AND ended_at IS NULL`).run(endedAt, runId);
|
|
1387
1556
|
this.db.prepare('UPDATE runs SET ended_at = ? WHERE id = ? AND ended_at IS NULL').run(endedAt, runId);
|
|
1388
1557
|
});
|
|
1389
1558
|
try {
|
|
@@ -1393,7 +1562,109 @@ export class ApmeStore {
|
|
|
1393
1562
|
debug('APME', `reapAbandonedRun ${runId.slice(0, 8)} failed: ${String(err)}`);
|
|
1394
1563
|
return [];
|
|
1395
1564
|
}
|
|
1396
|
-
return tasks.map((t) => ({
|
|
1565
|
+
return tasks.map((t) => ({
|
|
1566
|
+
id: t.id,
|
|
1567
|
+
category: t.task_category ?? this.getTask(t.id)?.taskCategory ?? null,
|
|
1568
|
+
boundarySignal: t.has_open_turn ? 'orphaned' : 'idle_gap',
|
|
1569
|
+
}));
|
|
1570
|
+
}
|
|
1571
|
+
/** Closed tasks that carry a verdict, newest first — the candidates for
|
|
1572
|
+
* `retractTaskVerdict` when what they were scored on turns out not to
|
|
1573
|
+
* have been the agent's work. `sinceMs` bounds the sweep. */
|
|
1574
|
+
listJudgedTasks(sinceMs, limit = 2000) {
|
|
1575
|
+
if (!this.db)
|
|
1576
|
+
return [];
|
|
1577
|
+
return this.db.prepare(`SELECT id FROM tasks
|
|
1578
|
+
WHERE ended_at IS NOT NULL AND ended_at >= ?
|
|
1579
|
+
AND (composite_score IS NOT NULL OR summary IS NOT NULL)
|
|
1580
|
+
AND (notes_json IS NULL OR notes_json NOT LIKE '%"notGradeable"%')
|
|
1581
|
+
ORDER BY ended_at DESC LIMIT ?`).all(sinceMs, limit);
|
|
1582
|
+
}
|
|
1583
|
+
/** Closed tasks the judge declined (`notGradeable` stamped), newest first. */
|
|
1584
|
+
listDeclinedTasks(sinceMs, limit = 2000) {
|
|
1585
|
+
if (!this.db)
|
|
1586
|
+
return [];
|
|
1587
|
+
return this.db.prepare(`SELECT id FROM tasks
|
|
1588
|
+
WHERE ended_at IS NOT NULL AND ended_at >= ?
|
|
1589
|
+
AND notes_json LIKE '%"notGradeable"%'
|
|
1590
|
+
ORDER BY ended_at DESC LIMIT ?`).all(sinceMs, limit);
|
|
1591
|
+
}
|
|
1592
|
+
/** Clear a declined task's stamp so the backlog drain offers it again. */
|
|
1593
|
+
readmitTask(taskId) {
|
|
1594
|
+
if (!this.db)
|
|
1595
|
+
return;
|
|
1596
|
+
this.db.prepare(`UPDATE tasks SET notes_json = NULL WHERE id = ? AND notes_json LIKE '%"notGradeable"%'`).run(taskId);
|
|
1597
|
+
}
|
|
1598
|
+
/** Withdraw a task's verdict: its judge and scorer rows are deleted and the
|
|
1599
|
+
* summary / score / outcome cleared, and the row is stamped with why it
|
|
1600
|
+
* cannot be graded. A verdict reached against silence — or against a
|
|
1601
|
+
* usage-limit notice standing in for the reply — is not a measurement of
|
|
1602
|
+
* the agent, and leaving it in place keeps it ranking real work on the
|
|
1603
|
+
* scorecard and floating to the top of the attention sort. A manually set
|
|
1604
|
+
* outcome (`agentdeck task cancel`) is the user's statement and is kept. */
|
|
1605
|
+
retractTaskVerdict(taskId, reason) {
|
|
1606
|
+
if (!this.db)
|
|
1607
|
+
return;
|
|
1608
|
+
const tx = this.db.transaction(() => {
|
|
1609
|
+
this.db.prepare(`DELETE FROM evals WHERE task_id = ? AND layer IN ('task_judge', 'trajectory')`).run(taskId);
|
|
1610
|
+
this.db.prepare(`UPDATE tasks SET summary = NULL, composite_score = NULL,
|
|
1611
|
+
outcome = CASE WHEN outcome = 'abandoned' THEN outcome ELSE NULL END,
|
|
1612
|
+
notes_json = ?
|
|
1613
|
+
WHERE id = ?`).run(JSON.stringify({ notGradeable: reason, retractedAt: Date.now() }), taskId);
|
|
1614
|
+
});
|
|
1615
|
+
tx();
|
|
1616
|
+
}
|
|
1617
|
+
/** One-time, idempotent re-stamp of tasks the OLD reaper closed as
|
|
1618
|
+
* `orphaned` although every one of their turns had closed normally —
|
|
1619
|
+
* the `idle_gap` boundary reached late, which is what the reaper now
|
|
1620
|
+
* writes. Only rows with EVIDENCE move: every turn carries a known
|
|
1621
|
+
* `end_source`, none is `run_close` (the old reaper's mark on a turn it
|
|
1622
|
+
* cut open) and none is still open. Rows from before `end_source`
|
|
1623
|
+
* existed are left as they are — their closing signal is unknown, and a
|
|
1624
|
+
* guess would corrupt the chip that exists to show how much to trust the
|
|
1625
|
+
* segmentation. Measured 2026-09-03: 165 of 1,026 orphaned tasks qualify,
|
|
1626
|
+
* 861 predate the column. Returns the number of rows changed. */
|
|
1627
|
+
reclassifyReapedTasks() {
|
|
1628
|
+
if (!this.db)
|
|
1629
|
+
return 0;
|
|
1630
|
+
try {
|
|
1631
|
+
const info = this.db.prepare(`UPDATE tasks SET boundary_signal = 'idle_gap'
|
|
1632
|
+
WHERE boundary_signal = 'orphaned'
|
|
1633
|
+
AND ended_at IS NOT NULL
|
|
1634
|
+
AND EXISTS (SELECT 1 FROM turns u WHERE u.task_id = tasks.id)
|
|
1635
|
+
AND NOT EXISTS (SELECT 1 FROM turns u WHERE u.task_id = tasks.id
|
|
1636
|
+
AND (u.ended_at IS NULL OR u.end_source IS NULL OR u.end_source = 'run_close'))`).run();
|
|
1637
|
+
return Number(info.changes ?? 0);
|
|
1638
|
+
}
|
|
1639
|
+
catch (err) {
|
|
1640
|
+
debug('APME', `reclassifyReapedTasks failed: ${String(err)}`);
|
|
1641
|
+
return 0;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
/** Runs still open in the store, oldest first — what a freshly started
|
|
1645
|
+
* daemon must re-adopt before it handles a single hook. Only the run's
|
|
1646
|
+
* identity comes from here; the collector reads the turns and tasks back
|
|
1647
|
+
* through the existing per-run helpers. */
|
|
1648
|
+
listOpenRuns(limit = 500) {
|
|
1649
|
+
if (!this.db)
|
|
1650
|
+
return [];
|
|
1651
|
+
const rows = this.db.prepare('SELECT * FROM runs WHERE ended_at IS NULL ORDER BY started_at ASC LIMIT ?').all(limit);
|
|
1652
|
+
return rows.map(rowToRun);
|
|
1653
|
+
}
|
|
1654
|
+
/** Tool-call counters for one turn, recovered from the trajectory it wrote.
|
|
1655
|
+
* The collector keeps these in memory and flushes them only when the turn
|
|
1656
|
+
* closes, so a turn open across a restart would otherwise close with
|
|
1657
|
+
* `tool_calls = 0` whatever it did — every reaped codex turn in the measured
|
|
1658
|
+
* week read exactly that. `Edit`/`Write` are the two names the live counter
|
|
1659
|
+
* singles out (`filesModified` / `filesCreated`). */
|
|
1660
|
+
countToolEventsForTurn(taskId, turnIndex) {
|
|
1661
|
+
if (!this.db)
|
|
1662
|
+
return { toolCalls: 0, filesModified: 0, filesCreated: 0 };
|
|
1663
|
+
const row = this.db.prepare(`SELECT COUNT(*) AS n,
|
|
1664
|
+
COALESCE(SUM(tool_name = 'Edit'), 0) AS edits,
|
|
1665
|
+
COALESCE(SUM(tool_name = 'Write'), 0) AS writes
|
|
1666
|
+
FROM sample_events WHERE task_id = ? AND turn_index = ? AND kind = 'tool'`).get(taskId, turnIndex);
|
|
1667
|
+
return { toolCalls: Number(row?.n ?? 0), filesModified: Number(row?.edits ?? 0), filesCreated: Number(row?.writes ?? 0) };
|
|
1397
1668
|
}
|
|
1398
1669
|
/** Orphaned runs: started long ago, never closed, no turns.
|
|
1399
1670
|
* Typically from session bridges that crashed without cleanup. */
|
|
@@ -1668,12 +1939,17 @@ function rowToTaskListRow(r) {
|
|
|
1668
1939
|
projectPath: r.project_path ?? null,
|
|
1669
1940
|
parentRunId: r.parent_run_id ?? null,
|
|
1670
1941
|
firstPrompt: r.first_prompt ?? r.run_prompt ?? null,
|
|
1942
|
+
// The task's OWN first turn prompt, with NO run-prompt fallback: title
|
|
1943
|
+
// derivation must never name task 2+ of a split run after task 0's intent.
|
|
1944
|
+
ownFirstPrompt: r.first_prompt ?? null,
|
|
1671
1945
|
turnCount: r.turn_count ?? 0,
|
|
1672
1946
|
answeredTurns: r.answered_turns ?? 0,
|
|
1673
1947
|
eventCount: r.event_count ?? 0,
|
|
1674
1948
|
toolCount: r.tool_count ?? 0,
|
|
1949
|
+
filesTouched: r.files_touched ?? 0,
|
|
1675
1950
|
evalCount: r.eval_count ?? 0,
|
|
1676
1951
|
overallScore: r.overall_score ?? r.composite_score ?? null,
|
|
1952
|
+
attention: r.attention === 1,
|
|
1677
1953
|
};
|
|
1678
1954
|
}
|
|
1679
1955
|
function rowToSampleEvent(r) {
|
|
@@ -1718,10 +1994,32 @@ function sampleEventRowToTrajectory(r) {
|
|
|
1718
1994
|
return { ...base, kind: 'model', model: r.model ?? 'unknown', inputTokens: r.inputTokens ?? 0, outputTokens: r.outputTokens ?? 0, costUsd: r.costUsd ?? 0, latencyMs: r.latencyMs ?? 0 };
|
|
1719
1995
|
case 'tool':
|
|
1720
1996
|
return { ...base, kind: 'tool', name: r.toolName ?? 'tool', input: p.input, output: p.output, error: r.toolError ?? null, status: r.toolStatus ?? undefined };
|
|
1997
|
+
case 'subagent':
|
|
1998
|
+
return {
|
|
1999
|
+
...base,
|
|
2000
|
+
kind: 'subagent',
|
|
2001
|
+
id: p.id ?? 'unknown',
|
|
2002
|
+
name: p.name ?? 'Subagent',
|
|
2003
|
+
phase: p.phase === 'completed' ? 'completed' : 'started',
|
|
2004
|
+
summary: p.summary ?? null,
|
|
2005
|
+
durationMs: typeof p.durationMs === 'number' ? p.durationMs : null,
|
|
2006
|
+
};
|
|
1721
2007
|
case 'state':
|
|
1722
2008
|
return { ...base, kind: 'state', from: p.from ?? null, to: p.to ?? 'unknown' };
|
|
1723
2009
|
case 'info':
|
|
1724
2010
|
return { ...base, kind: 'info', label: p.label ?? 'info', detail: p.detail ?? null };
|
|
2011
|
+
case 'relation':
|
|
2012
|
+
return {
|
|
2013
|
+
...base,
|
|
2014
|
+
kind: 'relation',
|
|
2015
|
+
relation: p.relation === 'spawned' || p.relation === 'messaged' ? p.relation : 'waiting_on',
|
|
2016
|
+
direction: p.direction === 'in' ? 'in' : 'out',
|
|
2017
|
+
phase: p.phase === 'closed' ? 'closed' : 'open',
|
|
2018
|
+
peerSessionId: p.peerSessionId ?? null,
|
|
2019
|
+
peerName: p.peerName ?? null,
|
|
2020
|
+
evidence: p.evidence ?? 'unknown',
|
|
2021
|
+
detail: p.detail ?? null,
|
|
2022
|
+
};
|
|
1725
2023
|
default:
|
|
1726
2024
|
return null;
|
|
1727
2025
|
}
|