opencastle 0.22.0 → 0.23.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/dist/cli/convoy/engine.d.ts +1 -0
- package/dist/cli/convoy/engine.d.ts.map +1 -1
- package/dist/cli/convoy/engine.js +1 -0
- package/dist/cli/convoy/engine.js.map +1 -1
- package/dist/cli/convoy/export.d.ts +1 -0
- package/dist/cli/convoy/export.d.ts.map +1 -1
- package/dist/cli/convoy/export.js +34 -0
- package/dist/cli/convoy/export.js.map +1 -1
- package/dist/cli/convoy/pipeline.d.ts +35 -0
- package/dist/cli/convoy/pipeline.d.ts.map +1 -0
- package/dist/cli/convoy/pipeline.js +353 -0
- package/dist/cli/convoy/pipeline.js.map +1 -0
- package/dist/cli/convoy/pipeline.test.d.ts +2 -0
- package/dist/cli/convoy/pipeline.test.d.ts.map +1 -0
- package/dist/cli/convoy/pipeline.test.js +778 -0
- package/dist/cli/convoy/pipeline.test.js.map +1 -0
- package/dist/cli/convoy/store.d.ts +14 -2
- package/dist/cli/convoy/store.d.ts.map +1 -1
- package/dist/cli/convoy/store.js +84 -5
- package/dist/cli/convoy/store.js.map +1 -1
- package/dist/cli/convoy/store.test.js +216 -7
- package/dist/cli/convoy/store.test.js.map +1 -1
- package/dist/cli/convoy/types.d.ts +15 -0
- package/dist/cli/convoy/types.d.ts.map +1 -1
- package/dist/cli/dashboard.d.ts.map +1 -1
- package/dist/cli/dashboard.js +1 -0
- package/dist/cli/dashboard.js.map +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +8 -1
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/run/schema.d.ts +5 -1
- package/dist/cli/run/schema.d.ts.map +1 -1
- package/dist/cli/run/schema.js +41 -8
- package/dist/cli/run/schema.js.map +1 -1
- package/dist/cli/run/schema.test.js +194 -5
- package/dist/cli/run/schema.test.js.map +1 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +143 -3
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/types.d.ts +3 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cli/convoy/engine.ts +2 -0
- package/src/cli/convoy/export.ts +41 -0
- package/src/cli/convoy/pipeline.test.ts +939 -0
- package/src/cli/convoy/pipeline.ts +430 -0
- package/src/cli/convoy/store.test.ts +239 -7
- package/src/cli/convoy/store.ts +110 -7
- package/src/cli/convoy/types.ts +17 -0
- package/src/cli/dashboard.ts +1 -0
- package/src/cli/init.ts +9 -1
- package/src/cli/run/schema.test.ts +244 -5
- package/src/cli/run/schema.ts +49 -8
- package/src/cli/run.ts +142 -3
- package/src/cli/types.ts +3 -1
- package/src/dashboard/dist/_astro/{index.DyyaCW8L.css → index.Cq68OHaZ.css} +1 -1
- package/src/dashboard/dist/index.html +214 -2
- package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
- package/src/dashboard/src/pages/index.astro +230 -1
- package/src/dashboard/src/styles/dashboard.css +116 -0
- package/src/orchestrator/customizations/KNOWN-ISSUES.md +1 -1
- package/src/orchestrator/skills/decomposition/SKILL.md +1 -0
- package/src/orchestrator/skills/orchestration-protocols/SKILL.md +32 -1
|
@@ -27,8 +27,9 @@ const base = import.meta.env.BASE_URL;
|
|
|
27
27
|
<nav class="dash-sidebar" id="dash-sidebar">
|
|
28
28
|
<ul class="dash-sidebar__list">
|
|
29
29
|
<li><a class="dash-sidebar__link" href="#convoy-section" data-section="convoy-section">Convoy</a></li>
|
|
30
|
+
<li><a class="dash-sidebar__link" href="#convoy-pipeline-section" data-section="convoy-pipeline-section">Convoy Chain</a></li>
|
|
30
31
|
<li><a class="dash-sidebar__link dash-sidebar__link--active" href="#kpi-row" data-section="kpi-row">Overview</a></li>
|
|
31
|
-
<li><a class="dash-sidebar__link" href="#pipeline-section" data-section="pipeline-section">
|
|
32
|
+
<li><a class="dash-sidebar__link" href="#pipeline-section" data-section="pipeline-section">Task Flow</a></li>
|
|
32
33
|
<li><a class="dash-sidebar__link" href="#agent-section" data-section="agent-section">Agents</a></li>
|
|
33
34
|
<li><a class="dash-sidebar__link" href="#tier-section" data-section="tier-section">Tiers</a></li>
|
|
34
35
|
<li><a class="dash-sidebar__link" href="#delegation-section" data-section="delegation-section">Delegations</a></li>
|
|
@@ -73,6 +74,12 @@ const base = import.meta.env.BASE_URL;
|
|
|
73
74
|
<option value="">All convoys</option>
|
|
74
75
|
</select>
|
|
75
76
|
</div>
|
|
77
|
+
<div class="filter-group">
|
|
78
|
+
<label class="filter-label" for="filter-pipeline">Pipeline</label>
|
|
79
|
+
<select class="filter-select" id="filter-pipeline">
|
|
80
|
+
<option value="">All</option>
|
|
81
|
+
</select>
|
|
82
|
+
</div>
|
|
76
83
|
<button class="dash-btn dash-btn--ghost filter-reset" id="filter-reset" type="button">Reset</button>
|
|
77
84
|
</div>
|
|
78
85
|
|
|
@@ -86,6 +93,16 @@ const base = import.meta.env.BASE_URL;
|
|
|
86
93
|
</div>
|
|
87
94
|
</section>
|
|
88
95
|
|
|
96
|
+
<!-- Convoy Pipeline (Chaining) Section -->
|
|
97
|
+
<section class="chart-card" id="convoy-pipeline-section" data-nav-section style="display:none">
|
|
98
|
+
<div class="chart-card__header">
|
|
99
|
+
<h2 class="chart-card__title">Convoy Pipeline</h2>
|
|
100
|
+
<p class="chart-card__desc" id="convoy-pipeline-desc">Pipeline convoy chain progress</p>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="chart-card__body" id="convoy-pipeline-body">
|
|
103
|
+
</div>
|
|
104
|
+
</section>
|
|
105
|
+
|
|
89
106
|
<!-- KPI Row -->
|
|
90
107
|
<section class="kpi-row" id="kpi-row" data-nav-section>
|
|
91
108
|
<div class="kpi-card" id="kpi-sessions">
|
|
@@ -1178,6 +1195,7 @@ const base = import.meta.env.BASE_URL;
|
|
|
1178
1195
|
let rawPanels = [];
|
|
1179
1196
|
let rawReviews = [];
|
|
1180
1197
|
let rawConvoys = [];
|
|
1198
|
+
let rawPipelines = [];
|
|
1181
1199
|
|
|
1182
1200
|
function applyFilters() {
|
|
1183
1201
|
const dateFrom = document.getElementById('filter-date-from').value;
|
|
@@ -1185,6 +1203,7 @@ const base = import.meta.env.BASE_URL;
|
|
|
1185
1203
|
const agentFilter = document.getElementById('filter-agent').value;
|
|
1186
1204
|
const outcomeFilter = document.getElementById('filter-outcome').value;
|
|
1187
1205
|
const convoyFilter = document.getElementById('filter-convoy').value;
|
|
1206
|
+
const pipelineFilter = document.getElementById('filter-pipeline')?.value || '';
|
|
1188
1207
|
|
|
1189
1208
|
function matchDate(ts) {
|
|
1190
1209
|
const date = ts.slice(0, 10);
|
|
@@ -1214,6 +1233,18 @@ const base = import.meta.env.BASE_URL;
|
|
|
1214
1233
|
return true;
|
|
1215
1234
|
});
|
|
1216
1235
|
|
|
1236
|
+
// Pipeline filter: restrict events to convoy_ids within the selected pipeline
|
|
1237
|
+
if (pipelineFilter) {
|
|
1238
|
+
const activePipeline = rawPipelines.find((p) => p.id === pipelineFilter);
|
|
1239
|
+
const pipelineConvoyIds = new Set((activePipeline && activePipeline.convoy_ids) || []);
|
|
1240
|
+
if (pipelineConvoyIds.size > 0) {
|
|
1241
|
+
sessions = sessions.filter((s) => !s.convoy_id || pipelineConvoyIds.has(s.convoy_id));
|
|
1242
|
+
delegations = delegations.filter((d) => !d.convoy_id || pipelineConvoyIds.has(d.convoy_id));
|
|
1243
|
+
panels = panels.filter((p2) => !p2.convoy_id || pipelineConvoyIds.has(p2.convoy_id));
|
|
1244
|
+
reviews = reviews.filter((r) => !r.convoy_id || pipelineConvoyIds.has(r.convoy_id));
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1217
1248
|
if (convoyFilter) {
|
|
1218
1249
|
sessions = sessions.filter((s) => s.convoy_id === convoyFilter);
|
|
1219
1250
|
delegations = delegations.filter((d) => d.convoy_id === convoyFilter);
|
|
@@ -1230,6 +1261,17 @@ const base = import.meta.env.BASE_URL;
|
|
|
1230
1261
|
}
|
|
1231
1262
|
}
|
|
1232
1263
|
|
|
1264
|
+
// Show/hide convoy pipeline section based on pipeline filter
|
|
1265
|
+
const pipelineSectionEl = document.getElementById('convoy-pipeline-section');
|
|
1266
|
+
if (pipelineSectionEl) {
|
|
1267
|
+
if (pipelineFilter) {
|
|
1268
|
+
const activePipeline = rawPipelines.find((p) => p.id === pipelineFilter);
|
|
1269
|
+
renderConvoyPipeline(activePipeline, rawConvoys);
|
|
1270
|
+
} else {
|
|
1271
|
+
pipelineSectionEl.style.display = 'none';
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1233
1275
|
renderAll(sessions, delegations, panels, reviews);
|
|
1234
1276
|
}
|
|
1235
1277
|
|
|
@@ -1416,9 +1458,186 @@ const base = import.meta.env.BASE_URL;
|
|
|
1416
1458
|
bodyEl.innerHTML = html;
|
|
1417
1459
|
}
|
|
1418
1460
|
|
|
1461
|
+
// ── Pipeline Filter Population ───────────────────────────
|
|
1462
|
+
|
|
1463
|
+
function populatePipelineFilter(pipelines) {
|
|
1464
|
+
const select = document.getElementById('filter-pipeline');
|
|
1465
|
+
if (!select) return;
|
|
1466
|
+
while (select.options.length > 1) select.remove(1);
|
|
1467
|
+
const sorted = pipelines.slice().sort((a, b) =>
|
|
1468
|
+
(b.created_at || '').localeCompare(a.created_at || '')
|
|
1469
|
+
);
|
|
1470
|
+
sorted.forEach((p) => {
|
|
1471
|
+
const opt = document.createElement('option');
|
|
1472
|
+
opt.value = p.id;
|
|
1473
|
+
opt.textContent = (p.name || p.id) + ' (' + (p.status || 'unknown') + ')';
|
|
1474
|
+
select.appendChild(opt);
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
// ── Convoy Pipeline (Chaining) Render ────────────────────
|
|
1479
|
+
|
|
1480
|
+
function renderConvoyPipeline(pipeline, convoys) {
|
|
1481
|
+
const sectionEl = document.getElementById('convoy-pipeline-section');
|
|
1482
|
+
const descEl = document.getElementById('convoy-pipeline-desc');
|
|
1483
|
+
const bodyEl = document.getElementById('convoy-pipeline-body');
|
|
1484
|
+
if (!sectionEl || !bodyEl) return;
|
|
1485
|
+
|
|
1486
|
+
if (!pipeline) {
|
|
1487
|
+
sectionEl.style.display = 'none';
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
sectionEl.style.display = '';
|
|
1492
|
+
if (descEl) {
|
|
1493
|
+
descEl.textContent =
|
|
1494
|
+
(pipeline.name || pipeline.id) + ' \u2014 ' + (pipeline.branch || 'no branch');
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
const convoyIds = pipeline.convoy_ids || [];
|
|
1498
|
+
const pipelineConvoys = convoyIds
|
|
1499
|
+
.map((id) => convoys.find((c) => c.id === id))
|
|
1500
|
+
.filter(Boolean);
|
|
1501
|
+
|
|
1502
|
+
const total = pipelineConvoys.length;
|
|
1503
|
+
const done = pipelineConvoys.filter((c) => c.status === 'done').length;
|
|
1504
|
+
const failed = pipelineConvoys.filter(
|
|
1505
|
+
(c) => c.status === 'failed' || c.status === 'gate-failed'
|
|
1506
|
+
).length;
|
|
1507
|
+
const totalTasks = pipelineConvoys.reduce((sum, c) => {
|
|
1508
|
+
const s = c.summary || {};
|
|
1509
|
+
return sum + (s.total || (c.tasks ? c.tasks.length : 0));
|
|
1510
|
+
}, 0);
|
|
1511
|
+
const doneTasks = pipelineConvoys.reduce((sum, c) => {
|
|
1512
|
+
const s = c.summary || {};
|
|
1513
|
+
return sum + (s.done || 0);
|
|
1514
|
+
}, 0);
|
|
1515
|
+
const totalTokens = pipelineConvoys.reduce((sum, c) => sum + (c.total_tokens || 0), 0);
|
|
1516
|
+
|
|
1517
|
+
const pct =
|
|
1518
|
+
totalTasks > 0
|
|
1519
|
+
? Math.round((doneTasks / totalTasks) * 100)
|
|
1520
|
+
: total > 0
|
|
1521
|
+
? Math.round((done / total) * 100)
|
|
1522
|
+
: 0;
|
|
1523
|
+
|
|
1524
|
+
const statusClass =
|
|
1525
|
+
pipeline.status === 'done'
|
|
1526
|
+
? 'success'
|
|
1527
|
+
: pipeline.status === 'failed' || pipeline.status === 'gate-failed'
|
|
1528
|
+
? 'failed'
|
|
1529
|
+
: pipeline.status === 'running'
|
|
1530
|
+
? 'partial'
|
|
1531
|
+
: '';
|
|
1532
|
+
|
|
1533
|
+
let html = '<div class="convoy-overview">';
|
|
1534
|
+
html +=
|
|
1535
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Status</span>' +
|
|
1536
|
+
'<span class="outcome-badge outcome-badge--' + statusClass + '">' +
|
|
1537
|
+
escapeHtml(pipeline.status || 'unknown') + '</span></div>';
|
|
1538
|
+
html +=
|
|
1539
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Branch</span>' +
|
|
1540
|
+
'<span class="convoy-stat__value">' + escapeHtml(pipeline.branch || '\u2014') + '</span></div>';
|
|
1541
|
+
html +=
|
|
1542
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Convoys</span>' +
|
|
1543
|
+
'<span class="convoy-stat__value">' + done + '/' + total + '</span></div>';
|
|
1544
|
+
if (totalTasks > 0) {
|
|
1545
|
+
html +=
|
|
1546
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Tasks</span>' +
|
|
1547
|
+
'<span class="convoy-stat__value">' + doneTasks + '/' + totalTasks + '</span></div>';
|
|
1548
|
+
}
|
|
1549
|
+
if (totalTokens > 0) {
|
|
1550
|
+
html +=
|
|
1551
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Tokens</span>' +
|
|
1552
|
+
'<span class="convoy-stat__value">' + formatTokens(totalTokens) + '</span></div>';
|
|
1553
|
+
}
|
|
1554
|
+
html +=
|
|
1555
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Started</span>' +
|
|
1556
|
+
'<span class="convoy-stat__value">' +
|
|
1557
|
+
(pipeline.started_at ? formatTime(pipeline.started_at) : '\u2014') + '</span></div>';
|
|
1558
|
+
if (pipeline.finished_at) {
|
|
1559
|
+
html +=
|
|
1560
|
+
'<div class="convoy-stat"><span class="convoy-stat__label">Finished</span>' +
|
|
1561
|
+
'<span class="convoy-stat__value">' + formatTime(pipeline.finished_at) + '</span></div>';
|
|
1562
|
+
}
|
|
1563
|
+
html += '</div>';
|
|
1564
|
+
|
|
1565
|
+
// Convoy chain visualization
|
|
1566
|
+
html += '<div class="convoy-chain">';
|
|
1567
|
+
pipelineConvoys.forEach((convoy, i) => {
|
|
1568
|
+
const cs = convoy.summary || {};
|
|
1569
|
+
const cDone = cs.done || 0;
|
|
1570
|
+
const cTotal = cs.total || (convoy.tasks ? convoy.tasks.length : 0);
|
|
1571
|
+
const cTokens = convoy.total_tokens || 0;
|
|
1572
|
+
const isActive =
|
|
1573
|
+
(pipeline.current_convoy_id && pipeline.current_convoy_id === convoy.id) ||
|
|
1574
|
+
convoy.status === 'running';
|
|
1575
|
+
const nodeStatusClass =
|
|
1576
|
+
convoy.status === 'done'
|
|
1577
|
+
? 'done'
|
|
1578
|
+
: convoy.status === 'failed' || convoy.status === 'gate-failed'
|
|
1579
|
+
? 'failed'
|
|
1580
|
+
: isActive
|
|
1581
|
+
? 'active'
|
|
1582
|
+
: 'pending';
|
|
1583
|
+
const badgeClass =
|
|
1584
|
+
convoy.status === 'done'
|
|
1585
|
+
? 'success'
|
|
1586
|
+
: convoy.status === 'failed' || convoy.status === 'gate-failed'
|
|
1587
|
+
? 'failed'
|
|
1588
|
+
: convoy.status === 'running'
|
|
1589
|
+
? 'partial'
|
|
1590
|
+
: '';
|
|
1591
|
+
|
|
1592
|
+
if (i > 0) {
|
|
1593
|
+
html += '<div class="convoy-chain__connector">\u2192</div>';
|
|
1594
|
+
}
|
|
1595
|
+
html +=
|
|
1596
|
+
'<div class="convoy-chain__node convoy-chain__node--' + nodeStatusClass +
|
|
1597
|
+
'" data-convoy-id="' + escapeHtml(convoy.id) + '" title="Click to filter to this convoy">';
|
|
1598
|
+
html += '<div class="convoy-chain__node-name">' + escapeHtml(convoy.name || convoy.id) + '</div>';
|
|
1599
|
+
html +=
|
|
1600
|
+
'<span class="outcome-badge outcome-badge--' + badgeClass + '">' +
|
|
1601
|
+
escapeHtml(convoy.status) + '</span>';
|
|
1602
|
+
if (cTotal > 0) {
|
|
1603
|
+
html += '<div class="convoy-chain__node-meta">' + cDone + '/' + cTotal + ' tasks</div>';
|
|
1604
|
+
}
|
|
1605
|
+
if (cTokens > 0) {
|
|
1606
|
+
html += '<div class="convoy-chain__node-meta">' + formatTokens(cTokens) + ' tokens</div>';
|
|
1607
|
+
}
|
|
1608
|
+
html += '</div>';
|
|
1609
|
+
});
|
|
1610
|
+
html += '</div>';
|
|
1611
|
+
|
|
1612
|
+
// Progress bar
|
|
1613
|
+
html += '<div class="convoy-progress">';
|
|
1614
|
+
html +=
|
|
1615
|
+
'<div class="convoy-progress__bar">' +
|
|
1616
|
+
'<div class="convoy-progress__fill" style="width:' + pct + '%"></div></div>';
|
|
1617
|
+
html +=
|
|
1618
|
+
'<span class="convoy-progress__label">' + pct + '% complete' +
|
|
1619
|
+
(failed > 0 ? ' \u00B7 ' + failed + ' failed' : '') + '</span>';
|
|
1620
|
+
html += '</div>';
|
|
1621
|
+
|
|
1622
|
+
bodyEl.innerHTML = html;
|
|
1623
|
+
|
|
1624
|
+
// Click handlers for convoy drill-down
|
|
1625
|
+
bodyEl.querySelectorAll('.convoy-chain__node').forEach((node) => {
|
|
1626
|
+
node.addEventListener('click', () => {
|
|
1627
|
+
const convoyId = node.dataset.convoyId;
|
|
1628
|
+
const sel = document.getElementById('filter-convoy');
|
|
1629
|
+
if (sel && convoyId) {
|
|
1630
|
+
sel.value = convoyId;
|
|
1631
|
+
applyFilters();
|
|
1632
|
+
}
|
|
1633
|
+
});
|
|
1634
|
+
});
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1419
1637
|
async function main() {
|
|
1420
1638
|
const events = await loadNdjson(base + 'data/events.ndjson');
|
|
1421
1639
|
const convoys = await loadNdjson(base + 'data/convoys.ndjson');
|
|
1640
|
+
const pipelines = await loadNdjson(base + 'data/pipelines.ndjson');
|
|
1422
1641
|
|
|
1423
1642
|
const sessions = events.filter((e) => e.type === 'session');
|
|
1424
1643
|
const delegations = events.filter((e) => e.type === 'delegation');
|
|
@@ -1430,9 +1649,11 @@ const base = import.meta.env.BASE_URL;
|
|
|
1430
1649
|
rawPanels = panels;
|
|
1431
1650
|
rawReviews = reviews;
|
|
1432
1651
|
rawConvoys = convoys;
|
|
1652
|
+
rawPipelines = pipelines;
|
|
1433
1653
|
|
|
1434
1654
|
populateAgentFilter(sessions, delegations, reviews);
|
|
1435
1655
|
populateConvoyFilter(convoys);
|
|
1656
|
+
populatePipelineFilter(pipelines);
|
|
1436
1657
|
|
|
1437
1658
|
// ── Read URL params ───────────────────────────────────
|
|
1438
1659
|
const urlParams = new URLSearchParams(window.location.search);
|
|
@@ -1461,12 +1682,14 @@ const base = import.meta.env.BASE_URL;
|
|
|
1461
1682
|
document.getElementById('filter-agent')?.addEventListener('change', applyFilters);
|
|
1462
1683
|
document.getElementById('filter-outcome')?.addEventListener('change', applyFilters);
|
|
1463
1684
|
document.getElementById('filter-convoy')?.addEventListener('change', applyFilters);
|
|
1685
|
+
document.getElementById('filter-pipeline')?.addEventListener('change', applyFilters);
|
|
1464
1686
|
document.getElementById('filter-reset')?.addEventListener('click', () => {
|
|
1465
1687
|
document.getElementById('filter-date-from').value = '';
|
|
1466
1688
|
document.getElementById('filter-date-to').value = '';
|
|
1467
1689
|
document.getElementById('filter-agent').value = '';
|
|
1468
1690
|
document.getElementById('filter-outcome').value = '';
|
|
1469
1691
|
document.getElementById('filter-convoy').value = '';
|
|
1692
|
+
document.getElementById('filter-pipeline').value = '';
|
|
1470
1693
|
applyFilters();
|
|
1471
1694
|
});
|
|
1472
1695
|
|
|
@@ -1477,15 +1700,21 @@ const base = import.meta.env.BASE_URL;
|
|
|
1477
1700
|
refreshInterval = setInterval(async () => {
|
|
1478
1701
|
const freshEvents = await loadNdjson(base + 'data/events.ndjson');
|
|
1479
1702
|
const freshConvoys = await loadNdjson(base + 'data/convoys.ndjson');
|
|
1703
|
+
const freshPipelines = await loadNdjson(base + 'data/pipelines.ndjson');
|
|
1480
1704
|
rawSessions = freshEvents.filter((e) => e.type === 'session');
|
|
1481
1705
|
rawDelegations = freshEvents.filter((e) => e.type === 'delegation');
|
|
1482
1706
|
rawPanels = freshEvents.filter((e) => e.type === 'panel');
|
|
1483
1707
|
rawReviews = freshEvents.filter((e) => e.type === 'review');
|
|
1484
1708
|
rawConvoys = freshConvoys;
|
|
1709
|
+
rawPipelines = freshPipelines;
|
|
1485
1710
|
const currentValue = document.getElementById('filter-convoy')?.value;
|
|
1711
|
+
const currentPipelineValue = document.getElementById('filter-pipeline')?.value;
|
|
1486
1712
|
populateConvoyFilter(freshConvoys);
|
|
1713
|
+
populatePipelineFilter(freshPipelines);
|
|
1487
1714
|
const sel = document.getElementById('filter-convoy');
|
|
1488
1715
|
if (sel && currentValue) sel.value = currentValue;
|
|
1716
|
+
const pSel = document.getElementById('filter-pipeline');
|
|
1717
|
+
if (pSel && currentPipelineValue) pSel.value = currentPipelineValue;
|
|
1489
1718
|
applyFilters();
|
|
1490
1719
|
}, 5000);
|
|
1491
1720
|
}
|
|
@@ -1593,3 +1593,119 @@ body {
|
|
|
1593
1593
|
.convoy-tasks {
|
|
1594
1594
|
margin-top: 8px;
|
|
1595
1595
|
}
|
|
1596
|
+
|
|
1597
|
+
/* ---------- Convoy Chain / Pipeline Section ---------- */
|
|
1598
|
+
.convoy-chain {
|
|
1599
|
+
display: flex;
|
|
1600
|
+
align-items: stretch;
|
|
1601
|
+
gap: 0;
|
|
1602
|
+
overflow-x: auto;
|
|
1603
|
+
padding: 1rem 0 1.5rem;
|
|
1604
|
+
scrollbar-width: thin;
|
|
1605
|
+
scrollbar-color: var(--border-color) transparent;
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
.convoy-chain::-webkit-scrollbar {
|
|
1609
|
+
height: 4px;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
.convoy-chain::-webkit-scrollbar-track {
|
|
1613
|
+
background: transparent;
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
.convoy-chain::-webkit-scrollbar-thumb {
|
|
1617
|
+
background: var(--border-color);
|
|
1618
|
+
border-radius: 2px;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
.convoy-chain__connector {
|
|
1622
|
+
display: flex;
|
|
1623
|
+
align-items: center;
|
|
1624
|
+
padding: 0 0.5rem;
|
|
1625
|
+
color: var(--text-tertiary);
|
|
1626
|
+
font-size: 1.1rem;
|
|
1627
|
+
flex-shrink: 0;
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
.convoy-chain__node {
|
|
1631
|
+
display: flex;
|
|
1632
|
+
flex-direction: column;
|
|
1633
|
+
align-items: center;
|
|
1634
|
+
gap: 6px;
|
|
1635
|
+
padding: 12px 16px;
|
|
1636
|
+
background: var(--bg-tertiary);
|
|
1637
|
+
border: 1px solid var(--border-color);
|
|
1638
|
+
border-radius: 10px;
|
|
1639
|
+
min-width: 140px;
|
|
1640
|
+
cursor: pointer;
|
|
1641
|
+
transition:
|
|
1642
|
+
background var(--transition-fast),
|
|
1643
|
+
border-color var(--transition-fast),
|
|
1644
|
+
transform var(--transition-fast),
|
|
1645
|
+
box-shadow var(--transition-fast);
|
|
1646
|
+
flex-shrink: 0;
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
.convoy-chain__node:hover {
|
|
1650
|
+
background: var(--bg-card-hover);
|
|
1651
|
+
transform: translateY(-2px);
|
|
1652
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
.convoy-chain__node-name {
|
|
1656
|
+
font-size: 0.8rem;
|
|
1657
|
+
font-weight: 600;
|
|
1658
|
+
color: var(--text-primary);
|
|
1659
|
+
text-align: center;
|
|
1660
|
+
word-break: break-word;
|
|
1661
|
+
max-width: 120px;
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
.convoy-chain__node-meta {
|
|
1665
|
+
font-size: 0.72rem;
|
|
1666
|
+
color: var(--text-tertiary);
|
|
1667
|
+
text-align: center;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
.convoy-chain__node--active {
|
|
1671
|
+
border-color: var(--accent-purple);
|
|
1672
|
+
box-shadow: 0 0 0 1px var(--accent-purple), 0 0 12px rgba(167, 139, 250, 0.2);
|
|
1673
|
+
animation: convoy-pulse 2s ease-in-out infinite;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
.convoy-chain__node--done {
|
|
1677
|
+
border-color: rgba(34, 197, 94, 0.3);
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
.convoy-chain__node--failed {
|
|
1681
|
+
border-color: rgba(239, 68, 68, 0.3);
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
.convoy-chain__node--pending {
|
|
1685
|
+
opacity: 0.6;
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
@keyframes convoy-pulse {
|
|
1689
|
+
0%, 100% {
|
|
1690
|
+
box-shadow: 0 0 0 1px var(--accent-purple), 0 0 8px rgba(167, 139, 250, 0.15);
|
|
1691
|
+
}
|
|
1692
|
+
50% {
|
|
1693
|
+
box-shadow: 0 0 0 1px var(--accent-purple), 0 0 18px rgba(167, 139, 250, 0.35);
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
@media (max-width: 768px) {
|
|
1698
|
+
.convoy-chain {
|
|
1699
|
+
flex-wrap: wrap;
|
|
1700
|
+
gap: 8px;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
.convoy-chain__connector {
|
|
1704
|
+
display: none;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
.convoy-chain__node {
|
|
1708
|
+
flex: 1 1 calc(50% - 4px);
|
|
1709
|
+
min-width: 120px;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
@@ -14,7 +14,7 @@ Tracked issues, limitations, and accepted risks discovered during agent sessions
|
|
|
14
14
|
|
|
15
15
|
| Issue ID | Status | Severity | Summary | Evidence | Root Cause | Solution Options |
|
|
16
16
|
|----------|--------|----------|---------|----------|------------|------------------|
|
|
17
|
-
| KI-001 | Open | Medium |
|
|
17
|
+
| KI-001 | Open | Medium | Convoy engine run()/resume() don't catch unexpected errors from runConvoy() — convoy DB records can get stuck in 'running' status | `src/cli/convoy/engine.ts` lines 452-510 (run) and 520-570 (resume): if `runConvoy()` throws, the convoy record is never updated to 'failed' | The try/finally block exports and closes the store but doesn't catch to update convoy status | Add a catch block before finally that calls `store.updateConvoyStatus(convoyId, 'failed', ...)` before rethrowing |
|
|
18
18
|
|
|
19
19
|
### Status Values
|
|
20
20
|
|
|
@@ -47,6 +47,7 @@ What to build/change and why. 1-3 sentences max.
|
|
|
47
47
|
### Context
|
|
48
48
|
- Key files to read first: [list]
|
|
49
49
|
- Related patterns to follow: [file:line references]
|
|
50
|
+
- Prior phase output (compacted): [summary from Context Compaction protocol if this task depends on a prior phase]
|
|
50
51
|
- Relevant lessons: [LES-XXX references from LESSONS-LEARNED.md]
|
|
51
52
|
|
|
52
53
|
### Constraints
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: orchestration-protocols
|
|
3
|
-
description: "Runtime orchestration patterns for the Team Lead: parallel research spawning, agent health monitoring, active steering, background agent management, and escalation paths."
|
|
3
|
+
description: "Runtime orchestration patterns for the Team Lead: parallel research spawning, agent health monitoring, active steering, background agent management, Context Compaction, Agent Circuit Breaker, and escalation paths."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Orchestration Protocols
|
|
@@ -89,6 +89,25 @@ When multiple background agents complete work simultaneously, batch similar revi
|
|
|
89
89
|
- If multiple outputs share the same file partition boundary, review them sequentially to catch integration issues
|
|
90
90
|
- For panel reviews, combine related artifacts into a single panel question when they share acceptance criteria
|
|
91
91
|
|
|
92
|
+
## Context Compaction
|
|
93
|
+
|
|
94
|
+
Between phases, summarize prior agent output before passing it to the next agent. Never paste raw sub-agent results into a downstream prompt.
|
|
95
|
+
|
|
96
|
+
**When:** Multi-phase chains where the next agent only needs outcomes, not full reasoning traces. Skip for single-phase work or when raw detail is needed (e.g., code review).
|
|
97
|
+
|
|
98
|
+
**How:** After a sub-agent returns, extract only: files changed, key decisions, verification results (pass/fail), and blockers. Discard raw tool output, reasoning traces, and failed attempts.
|
|
99
|
+
|
|
100
|
+
**Template for delegation prompts:**
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
### Prior Phase Output
|
|
104
|
+
**Phase [N] — [Agent Name] — [Task Title]**
|
|
105
|
+
- Files changed: [list with one-line descriptions]
|
|
106
|
+
- Decisions: [key decisions that affect downstream work]
|
|
107
|
+
- Verification: [lint ✅ | types ✅ | tests ✅]
|
|
108
|
+
- Blockers: [none | list]
|
|
109
|
+
```
|
|
110
|
+
|
|
92
111
|
## Agent Health-Check Protocol
|
|
93
112
|
|
|
94
113
|
Monitor delegated agents for failure signals. Intervene early rather than waiting for completion.
|
|
@@ -148,3 +167,15 @@ Common failure modes and how to recover:
|
|
|
148
167
|
|
|
149
168
|
**Symptom:** Tests pass individually but fail when multiple agent outputs are merged.
|
|
150
169
|
**Recovery:** (1) Run affected tests to identify which projects break. (2) Check for import conflicts, duplicate definitions, or state pollution. (3) Delegate fix to the agent whose changes are most likely the cause.
|
|
170
|
+
|
|
171
|
+
## Agent Circuit Breaker
|
|
172
|
+
|
|
173
|
+
Track per-agent failure counts across the session (not just per-task). If the same agent keeps failing, the problem is likely systemic.
|
|
174
|
+
|
|
175
|
+
| Threshold | Action |
|
|
176
|
+
|-----------|--------|
|
|
177
|
+
| **2 failures** | Warning — investigate: same error class? Model endpoint healthy? Prompt pattern issue? |
|
|
178
|
+
| **3 failures** | Open circuit — stop delegating to that agent. Reassign tasks to an overlapping agent, try a different model tier, or checkpoint and escalate to the user. |
|
|
179
|
+
| **Next session** | Half-open — circuit resets. If the agent fails again immediately, re-open and add a lesson via **self-improvement**. |
|
|
180
|
+
|
|
181
|
+
This is a judgment-based pattern, not a hard gate. 3 failures on similar tasks with the same error is more concerning than 3 unrelated failures.
|