@desplega.ai/agent-swarm 1.157.0 → 1.158.0
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/{acp-adapter-qhqrk4q0.js → acp-adapter-xaq4n6pc.js} +1 -1
- package/dist/{actions-9rrg0zxm.js → actions-p9hz5yat.js} +15 -15
- package/dist/{app-enysy1zd.js → app-g26wdcz6.js} +4 -4
- package/dist/{artifact-td4q4dch.js → artifact-3v5t9jtg.js} +1 -1
- package/dist/{assistant-zegamy48.js → assistant-wydfqkb3.js} +16 -16
- package/dist/{boot-reembed-r6shx5qx.js → boot-reembed-g5ckg9yb.js} +6 -6
- package/dist/{boot-reembed-zfxb937k.js → boot-reembed-se8zmdcp.js} +5 -5
- package/dist/{boot-scrub-logs-k5y0se6r.js → boot-scrub-logs-wfxqan61.js} +3 -3
- package/dist/{seed-pricing-vqxa06qf.js → boot-seeds-s3q01xj3.js} +10 -10
- package/dist/{claude-adapter-5yc7hxwv.js → claude-adapter-tv2x4f36.js} +7 -7
- package/dist/{claude-managed-adapter-ea2aga6w.js → claude-managed-adapter-41b2s7fd.js} +2 -2
- package/dist/{claude-sdk-session-j4ywn3xf.js → claude-sdk-session-t442qz6f.js} +8 -8
- package/dist/{cli-e781c6f9.js → cli-0xjkj1j7.js} +1 -0
- package/dist/{cli-58rgvkt4.js → cli-1hkrch3k.js} +2 -2
- package/dist/{cli-yscm6cv8.js → cli-20cj37vt.js} +1866 -9
- package/dist/{cli-h0wdadsx.js → cli-4198qc9v.js} +7 -3
- package/dist/{cli-awwphhcs.js → cli-47m6dkd3.js} +362 -126
- package/dist/{cli-wb2zvbfg.js → cli-53sz8gkz.js} +1 -1
- package/dist/{cli-005pze6s.js → cli-5d10vd2m.js} +1 -1
- package/dist/{cli-v53rbqp3.js → cli-65hjmev5.js} +57 -17
- package/dist/{cli-scwq51gn.js → cli-68w09sjw.js} +7 -1
- package/dist/{cli-s98skd5r.js → cli-7gtvvpbh.js} +4 -4
- package/dist/{cli-y3nxwx0t.js → cli-7s3syk22.js} +18 -11
- package/dist/{cli-74h6f2bp.js → cli-8qmme6vd.js} +2 -2
- package/dist/{cli-wsed24mk.js → cli-987hg0aa.js} +2 -2
- package/dist/{cli-9n76jszt.js → cli-9httdpyq.js} +1 -1
- package/dist/{cli-f3va018d.js → cli-aky8tctm.js} +26 -93
- package/dist/{cli-sgyqyyxe.js → cli-c07r9a2m.js} +2 -1
- package/dist/{cli-c41wjx0r.js → cli-fgqxwrpv.js} +291 -12
- package/dist/{cli-01vfmq8c.js → cli-ftfvggzx.js} +607 -164
- package/dist/{cli-ytxs7mn1.js → cli-g8djp6qe.js} +17 -0
- package/dist/{cli-avkd6mqv.js → cli-h967nb6r.js} +551 -0
- package/dist/{cli-r9ee9c4w.js → cli-j55n64b6.js} +23 -22
- package/dist/{cli-9p33cz9h.js → cli-j57qkrpq.js} +86 -28
- package/dist/{cli-tjmghmm5.js → cli-q67y4wzm.js} +6 -3
- package/dist/{cli-n6zq3kbd.js → cli-rj19hc34.js} +1 -1
- package/dist/{cli-jytrw2na.js → cli-rjehvrts.js} +4 -4
- package/dist/{cli-tpv97m71.js → cli-rqz8qbw7.js} +245 -75
- package/dist/{cli-p37sg0a9.js → cli-s8eet254.js} +1 -1
- package/dist/cli-t1ze64h3.js +811 -0
- package/dist/{cli-6jjzxv3b.js → cli-ws6rqycm.js} +3 -2
- package/dist/{cli-xf5b7y1f.js → cli-wscdvcqz.js} +13 -5
- package/dist/{cli-5j7bm4tb.js → cli-x24pshtq.js} +5 -5
- package/dist/{cli-nbp6m6gp.js → cli-xberxa1r.js} +51 -26
- package/dist/{cli-vx9p3qdt.js → cli-xhaeg2nc.js} +1 -1
- package/dist/cli.js +29 -15
- package/dist/{codex-adapter-gns3s6c3.js → codex-adapter-cnm8wk11.js} +5 -5
- package/dist/{codex-session-runner-gqnxys5w.js → codex-session-runner-gfg547zj.js} +5 -5
- package/dist/{commands-hxy2y2sp.js → commands-e3bn0p75.js} +3 -3
- package/dist/{db-w8ghhsgf.js → db-03v9kzr2.js} +17 -3
- package/dist/{dispatcher-cp1rknjz.js → dispatcher-nrmg8yht.js} +14 -14
- package/dist/{dsh-adapter-1dwg97zv.js → dsh-adapter-k03nfqa6.js} +2 -2
- package/dist/{handlers-egfhr351.js → handlers-aqcedbyb.js} +17 -17
- package/dist/{hook-x4kftwzt.js → hook-7vkskkre.js} +19 -11
- package/dist/{hook-fbxjqfjz.js → hook-ybvmrmhq.js} +4 -4
- package/dist/{http-c7jfx990.js → http-2eqa8t24.js} +432 -195
- package/dist/{index-4k9hct21.js → index-1yks3qcr.js} +14 -14
- package/dist/{index-jtvpgb8f.js → index-a3vn96n8.js} +30 -27
- package/dist/{index-dc2ek6bw.js → index-c6zsv1bd.js} +5 -5
- package/dist/{index-yy07ef2s.js → index-chgdkq36.js} +14 -14
- package/dist/{index-r6bty6tb.js → index-x71bvq0p.js} +15 -15
- package/dist/{keepalive-f7ekefyc.js → keepalive-vtkf5n99.js} +5 -5
- package/dist/{lead-h053syts.js → lead-h3sp357x.js} +26 -26
- package/dist/{maintenance-a3w6zs54.js → maintenance-jzeqtk3q.js} +6 -6
- package/dist/{oauth-refresh-sweep-vra1dhkd.js → oauth-refresh-sweep-qp3dzmdp.js} +4 -4
- package/dist/{onboard-mfgzeqxs.js → onboard-tmsp0qbz.js} +278 -81
- package/dist/{opencode-adapter-z64xjzec.js → opencode-adapter-x6x2da1z.js} +3 -3
- package/dist/{otel-impl-2ez6xk57.js → otel-impl-9mz73q65.js} +416 -301
- package/dist/{pi-mono-adapter-2b7mw16r.js → pi-mono-adapter-m6dvv0dz.js} +2 -2
- package/dist/{pricing-refresh-6sw65tck.js → pricing-refresh-v1cbr9te.js} +5 -5
- package/dist/{rbac-roles-nm6924sy.js → rbac-roles-c9wqz83x.js} +4 -4
- package/dist/{render-v2-f026j6c4.js → render-v2-gryrh9h8.js} +4 -4
- package/dist/{setup-w606fr1q.js → setup-q9720bt6.js} +2 -2
- package/dist/{virtual-modules-8qheft18.js → virtual-modules-3htpgn8x.js} +1 -1
- package/dist/{work-objects-ezmggdne.js → work-objects-b76x7deb.js} +17 -17
- package/dist/{worker-1mbyv29k.js → worker-6vrxbv41.js} +26 -26
- package/openapi.json +1626 -629
- package/package.json +2 -1
- package/src/apps/catalog.generated.json +229 -0
- package/src/apps/page-validator.ts +71 -16
- package/src/apps/row-store.ts +66 -11
- package/src/apps/sync.ts +59 -17
- package/src/artifact-sdk/browser-sdk.ts +436 -2
- package/src/be/approval-sweeps.ts +109 -0
- package/src/be/boot-seeds.ts +40 -0
- package/src/be/chunking.ts +1 -1
- package/src/be/db/agents.ts +20 -0
- package/src/be/db/approvals.ts +78 -0
- package/src/be/db/tasks/read.ts +197 -39
- package/src/be/db/tasks/write.ts +41 -9
- package/src/be/db-client.ts +107 -48
- package/src/be/db.ts +219 -76
- package/src/be/events.ts +33 -1
- package/src/be/memory/graph-expansion.ts +10 -3
- package/src/be/memory/providers/sqlite-store.ts +55 -13
- package/src/be/memory/raters/retrieval.ts +5 -2
- package/src/be/memory/reranker.ts +26 -2
- package/src/be/memory/types.ts +2 -0
- package/src/be/migrations/166_approval_request_auto_cancellation.sql +9 -0
- package/src/be/migrations/171_memory_retrieval_relevance.sql +8 -0
- package/src/be/migrations/175_workflow_runs_list_index.sql +11 -0
- package/src/be/migrations/177_events_event_agent_created_index.sql +11 -0
- package/src/be/models-catalog.ts +2 -0
- package/src/be/modelsdev-cache.json +1857 -0
- package/src/be/modelsdev-cache.ts +14 -1
- package/src/be/pricing-normalize.ts +2 -0
- package/src/be/scripts/typecheck.ts +1 -0
- package/src/be/seed-pricing.ts +3 -1
- package/src/be/seed-skills/bundled-files.generated.json +1 -1
- package/src/be/steering.ts +53 -3
- package/src/be/swarm-config-guard.ts +3 -0
- package/src/be/task-citations.ts +29 -0
- package/src/cli.tsx +14 -1
- package/src/commands/onboard/compose-generator.ts +8 -3
- package/src/commands/onboard/container-engine.ts +220 -0
- package/src/commands/onboard/manifest.ts +1 -0
- package/src/commands/onboard/steps/health-check.tsx +4 -1
- package/src/commands/onboard/steps/prereq-check.tsx +50 -54
- package/src/commands/onboard/steps/start.tsx +31 -16
- package/src/commands/onboard/types.ts +7 -2
- package/src/commands/onboard.tsx +39 -4
- package/src/commands/profile-sync.ts +79 -26
- package/src/commands/runner.ts +8 -1
- package/src/extensions/catalog.generated.json +17 -0
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/heartbeat/heartbeat.ts +263 -103
- package/src/hooks/hook.ts +21 -12
- package/src/http/agents.ts +35 -0
- package/src/http/approval-requests.ts +136 -64
- package/src/http/apps.ts +14 -3
- package/src/http/config.ts +15 -1
- package/src/http/events.ts +62 -2
- package/src/http/index.ts +6 -4
- package/src/http/memory.ts +21 -7
- package/src/http/schedules.ts +1 -1
- package/src/http/session-data.ts +9 -4
- package/src/http/sessions.ts +25 -18
- package/src/http/stats.ts +19 -7
- package/src/http/status.ts +11 -1
- package/src/http/tasks.ts +40 -8
- package/src/http/webhooks.ts +67 -46
- package/src/http/workflows.ts +15 -20
- package/src/linear/outbound.ts +37 -15
- package/src/otel-impl.ts +151 -1
- package/src/otel.ts +14 -3
- package/src/prompts/memories.ts +19 -2
- package/src/providers/claude-managed-models.ts +8 -0
- package/src/providers/modelsdev-reasoning.json +551 -0
- package/src/rbac/legacy-policy.ts +16 -0
- package/src/rbac/permissions.ts +4 -0
- package/src/scheduler/schedule-task.ts +3 -0
- package/src/scripts-runtime/sdk-allowlist.ts +1 -0
- package/src/scripts-runtime/swarm-sdk.ts +9 -0
- package/src/scripts-runtime/types/stdlib.d.ts +1 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +1 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +1 -0
- package/src/server.ts +12 -7
- package/src/slack/app.ts +35 -4
- package/src/slack/connection-state.ts +17 -0
- package/src/tasks/context-key.ts +1 -0
- package/src/tasks/worker-follow-up.ts +6 -2
- package/src/tests/agent-task-activity.test.ts +74 -0
- package/src/tests/agents-list-model-display.test.ts +6 -1
- package/src/tests/approval-auto-cancellation-migration.test.ts +104 -0
- package/src/tests/approval-requests.test.ts +395 -0
- package/src/tests/approval-sweeps-config.test.ts +47 -0
- package/src/tests/approval-sweeps.test.ts +508 -0
- package/src/tests/apps-kibo-blocks.test.ts +77 -0
- package/src/tests/apps-spike.test.ts +56 -1
- package/src/tests/apps-sync-engine.test.ts +20 -9
- package/src/tests/boot-seeds.test.ts +170 -0
- package/src/tests/cancel-approval-request-tool.test.ts +115 -0
- package/src/tests/claude-managed-adapter.test.ts +6 -0
- package/src/tests/config-key-filter.test.ts +80 -0
- package/src/tests/context-window.test.ts +1 -0
- package/src/tests/db-client-busy-retry.test.ts +96 -0
- package/src/tests/db-client.test.ts +60 -1
- package/src/tests/db-task-read-contract.test.ts +10 -0
- package/src/tests/db-task-write-contract.test.ts +9 -0
- package/src/tests/docs-index-footprint.test.js +3 -3
- package/src/tests/events-http.test.ts +103 -0
- package/src/tests/extensions-catalog.test.ts +22 -17
- package/src/tests/extensions-pre-task.test.ts +107 -0
- package/src/tests/fixtures/kibo-blocks-definition.json.txt +105 -0
- package/src/tests/follow-up-config-inheritance.test.ts +260 -0
- package/src/tests/heartbeat-orphan-resume.test.ts +84 -0
- package/src/tests/heartbeat-reboot-live.test.ts +95 -0
- package/src/tests/heartbeat-stall-cas.test.ts +80 -0
- package/src/tests/heartbeat.test.ts +99 -3
- package/src/tests/hook-mcp-config.test.ts +29 -0
- package/src/tests/http-api-integration.test.ts +16 -2
- package/src/tests/kv-storage.test.ts +62 -0
- package/src/tests/linear-outbound-sync.test.ts +120 -5
- package/src/tests/list-endpoint-slimming.test.ts +91 -0
- package/src/tests/memory-graph-organic-route.test.ts +155 -0
- package/src/tests/memory-http-recall-gating.test.ts +14 -4
- package/src/tests/memory-hybrid.test.ts +161 -1
- package/src/tests/memory-prompt-recall-crowdout.test.ts +297 -0
- package/src/tests/memory.test.ts +22 -0
- package/src/tests/onboard-container-engine.test.ts +240 -0
- package/src/tests/otel-event-loop-and-logs.test.ts +99 -0
- package/src/tests/pricing-routes.test.ts +14 -0
- package/src/tests/profile-sync-warning.test.ts +8 -4
- package/src/tests/promote-draft-task-route.test.ts +19 -0
- package/src/tests/provider-registration.test.ts +296 -42
- package/src/tests/rbac-engine.test.ts +30 -0
- package/src/tests/reasoning-effort.test.ts +8 -0
- package/src/tests/script-connections.test.ts +7 -0
- package/src/tests/sdk-allowlist.test.ts +39 -0
- package/src/tests/session-costs-model-key-normalize.test.ts +1 -0
- package/src/tests/sessions-detail-batch.test.ts +250 -0
- package/src/tests/sessions.test.ts +118 -0
- package/src/tests/slack-config.test.ts +22 -0
- package/src/tests/sonnet-5-5-registry.test.ts +44 -0
- package/src/tests/status.test.ts +36 -1
- package/src/tests/swarm-diff.test.ts +316 -10
- package/src/tests/task-completion-idempotency.test.ts +2 -1
- package/src/tests/tasks-requested-by-filter.test.ts +3 -1
- package/src/tests/tool-annotations.test.ts +1 -1
- package/src/tests/ui-list-slim-projections.test.ts +158 -0
- package/src/tests/webhooks-task-blocked.test.ts +127 -0
- package/src/tests/workflow-approval-recovery.test.ts +203 -0
- package/src/tests/workflow-hitl-routing.test.ts +22 -1
- package/src/tests/workflow-hitl-slack-card.test.ts +52 -0
- package/src/tests/workflow-http-v2.test.ts +99 -8
- package/src/tests/workflow-retry-validation.test.ts +56 -0
- package/src/tests/workflow-tla-races.test.ts +389 -0
- package/src/tests/workflow-validation-port-routing.test.ts +113 -1
- package/src/tools/cancel-approval-request.ts +57 -0
- package/src/tools/memory-search.ts +1 -0
- package/src/tools/request-human-input.ts +4 -2
- package/src/tools/send-task.ts +4 -0
- package/src/tools/templates.ts +19 -0
- package/src/tools/tool-config.ts +2 -1
- package/src/tools/workflows/list-workflow-runs.ts +1 -0
- package/src/types.ts +38 -0
- package/src/utils/context-window.ts +1 -0
- package/src/workflows/approval-cancel.ts +152 -0
- package/src/workflows/approval-notifications.ts +84 -0
- package/src/workflows/checkpoint.ts +10 -5
- package/src/workflows/definition.ts +21 -0
- package/src/workflows/engine.ts +152 -21
- package/src/workflows/executors/human-in-the-loop.ts +1 -1
- package/src/workflows/recovery.ts +100 -45
- package/src/workflows/resume.ts +49 -18
- package/src/workflows/retry-poller.ts +71 -21
- package/templates/extensions/README.md +1 -0
- package/templates/extensions/github-sender-allowlist/README.md +18 -0
- package/templates/extensions/github-sender-allowlist/hooks.ts +55 -0
- package/templates/extensions/github-sender-allowlist/manifest.json +8 -0
- package/templates/skills/apps/content.md +20 -1
- package/templates/skills/code-quality/content.md +26 -1
- package/templates/skills/pages/content.md +16 -4
- package/templates/skills/pages/files/examples/multiplayer-board.html +3 -12
- package/dist/cli-2daksqps.js +0 -378
- package/dist/rbac-roles-3gxmnb20.js +0 -37
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
REBOOT_RETRY_PIN_TAG,
|
|
3
3
|
agentsWithLiveRuntime,
|
|
4
|
+
cancelApprovalRequestAndRun,
|
|
4
5
|
countActiveRuntimeInstancesForAgent,
|
|
6
|
+
createApprovalFollowUpTask,
|
|
5
7
|
createPoolStarvationDecisionTask,
|
|
6
8
|
createRerouteDecisionTask,
|
|
7
9
|
createResumeFollowUp,
|
|
@@ -15,7 +17,7 @@ import {
|
|
|
15
17
|
recoverIncompleteRuns,
|
|
16
18
|
repointTrackerSyncBySwarmId,
|
|
17
19
|
resolveLeadOnlyRecoveryAssignment
|
|
18
|
-
} from "./cli-
|
|
20
|
+
} from "./cli-ftfvggzx.js";
|
|
19
21
|
import {
|
|
20
22
|
isMultiRuntimeEnabled
|
|
21
23
|
} from "./cli-re8z5p8p.js";
|
|
@@ -24,6 +26,7 @@ import {
|
|
|
24
26
|
assignUnassignedTaskPending,
|
|
25
27
|
backfillSupersedeTaskResumeTaskId,
|
|
26
28
|
buildRoutingAffinityFromAgent,
|
|
29
|
+
cascadeFailDependents,
|
|
27
30
|
cleanupStaleSessions,
|
|
28
31
|
createLogEntry,
|
|
29
32
|
createTaskExtended,
|
|
@@ -34,15 +37,19 @@ import {
|
|
|
34
37
|
getActiveTaskCount,
|
|
35
38
|
getAllAgents,
|
|
36
39
|
getDbClient,
|
|
40
|
+
getDependentTasks,
|
|
41
|
+
getExpiredPendingApprovals,
|
|
37
42
|
getIdleWorkersWithCapacity,
|
|
38
43
|
getLeadAgent,
|
|
39
44
|
getPendingSteeringForTask,
|
|
40
45
|
getRecentCompletedCount,
|
|
41
46
|
getRecentFailedCount,
|
|
42
47
|
getRecentFailedTasks,
|
|
48
|
+
getStaleApprovalRequests,
|
|
43
49
|
getStalePinnedResumes,
|
|
44
50
|
getStaleUnassignedAffinityTasks,
|
|
45
51
|
getStalledInProgressTasks,
|
|
52
|
+
getSupersededTasksWithoutResume,
|
|
46
53
|
getTaskById,
|
|
47
54
|
getTaskStats,
|
|
48
55
|
getTasksByStatus,
|
|
@@ -59,9 +66,10 @@ import {
|
|
|
59
66
|
releaseStaleOfferedTasksForOfflineAgents,
|
|
60
67
|
releaseStaleProcessingInbox,
|
|
61
68
|
releaseStaleReviewingTasks,
|
|
69
|
+
resolveApprovalRequest,
|
|
62
70
|
supersedeTask,
|
|
63
71
|
updateAgentStatus
|
|
64
|
-
} from "./cli-
|
|
72
|
+
} from "./cli-47m6dkd3.js";
|
|
65
73
|
import {
|
|
66
74
|
init_registry,
|
|
67
75
|
init_resolver,
|
|
@@ -73,6 +81,73 @@ import {
|
|
|
73
81
|
scrubSecrets
|
|
74
82
|
} from "./cli-r2ap2czm.js";
|
|
75
83
|
|
|
84
|
+
// src/be/approval-sweeps.ts
|
|
85
|
+
init_db();
|
|
86
|
+
var DEFAULT_APPROVAL_REQUEST_AUTO_CANCELLATION_DAYS = 7;
|
|
87
|
+
function approvalRequestAutoCancellationDays() {
|
|
88
|
+
const raw = process.env.APPROVAL_REQUEST_AUTO_CANCELLATION_DAYS;
|
|
89
|
+
if (raw != null && /^\d+$/.test(raw.trim())) {
|
|
90
|
+
return Number.parseInt(raw.trim(), 10);
|
|
91
|
+
}
|
|
92
|
+
return DEFAULT_APPROVAL_REQUEST_AUTO_CANCELLATION_DAYS;
|
|
93
|
+
}
|
|
94
|
+
async function autoCancelStaleApprovalRequests(now = new Date) {
|
|
95
|
+
const days = approvalRequestAutoCancellationDays();
|
|
96
|
+
if (days === 0)
|
|
97
|
+
return { cancelled: [], runsCancelled: [] };
|
|
98
|
+
const cutoff = new Date(now.getTime() - days * 86400000).toISOString();
|
|
99
|
+
const stale = await getStaleApprovalRequests({ cutoff });
|
|
100
|
+
const reason = `Auto-cancelled by the approval sweep after ${days} days with no response`;
|
|
101
|
+
const cancelled = [];
|
|
102
|
+
const runsCancelled = [];
|
|
103
|
+
for (const row of stale) {
|
|
104
|
+
try {
|
|
105
|
+
const result = await cancelApprovalRequestAndRun(row.id, {
|
|
106
|
+
reason,
|
|
107
|
+
resolvedBy: null,
|
|
108
|
+
slackReason: "auto-cancelled with no response"
|
|
109
|
+
});
|
|
110
|
+
if (!result || "timedOut" in result)
|
|
111
|
+
continue;
|
|
112
|
+
cancelled.push(result.request);
|
|
113
|
+
if (result.runCancelled && result.request.workflowRunId) {
|
|
114
|
+
runsCancelled.push(result.request.workflowRunId);
|
|
115
|
+
}
|
|
116
|
+
} catch (err) {
|
|
117
|
+
console.error(`[approval-sweep] could not cancel approval request ${row.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (cancelled.length > 0) {
|
|
121
|
+
console.log(`[approval-sweep] auto-cancelled ${cancelled.length} stale approval requests and ${runsCancelled.length} workflow runs`);
|
|
122
|
+
}
|
|
123
|
+
return { cancelled, runsCancelled };
|
|
124
|
+
}
|
|
125
|
+
async function timeoutExpiredApprovalRequests(now = new Date) {
|
|
126
|
+
const expired = await getExpiredPendingApprovals({ now: now.toISOString() });
|
|
127
|
+
const timedOut = [];
|
|
128
|
+
for (const row of expired) {
|
|
129
|
+
try {
|
|
130
|
+
const updated = await getDbClient().transaction(async () => {
|
|
131
|
+
const request = await resolveApprovalRequest(row.id, {
|
|
132
|
+
status: "timeout",
|
|
133
|
+
resolutionReason: `Timed out by the approval sweep: no answer before ${row.expiresAt}`
|
|
134
|
+
});
|
|
135
|
+
if (request)
|
|
136
|
+
await createApprovalFollowUpTask(request, "hitl.timeout");
|
|
137
|
+
return request;
|
|
138
|
+
});
|
|
139
|
+
if (updated)
|
|
140
|
+
timedOut.push(updated);
|
|
141
|
+
} catch (err) {
|
|
142
|
+
console.error(`[approval-sweep] could not time out approval request ${row.id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (timedOut.length > 0) {
|
|
146
|
+
console.log(`[approval-sweep] timed out ${timedOut.length} expired approval requests`);
|
|
147
|
+
}
|
|
148
|
+
return { timedOut };
|
|
149
|
+
}
|
|
150
|
+
|
|
76
151
|
// src/heartbeat/heartbeat.ts
|
|
77
152
|
init_db();
|
|
78
153
|
init_steering();
|
|
@@ -260,12 +335,15 @@ async function codeLevelTriage() {
|
|
|
260
335
|
workflowRuns: 0,
|
|
261
336
|
staleRuntimes: 0,
|
|
262
337
|
staleOfferedTasks: 0,
|
|
263
|
-
abandonedDraftTasks: 0
|
|
338
|
+
abandonedDraftTasks: 0,
|
|
339
|
+
approvalAutoCancelled: 0,
|
|
340
|
+
approvalTimedOut: 0
|
|
264
341
|
}
|
|
265
342
|
};
|
|
266
343
|
findings.staleCleanup.staleRuntimes = (await expireStaleRuntimeInstances()).expired;
|
|
267
344
|
findings.staleCleanup.staleOfferedTasks = await releaseStaleOfferedTasksForOfflineAgents();
|
|
268
345
|
await detectAndRemediateStalledTasks(findings);
|
|
346
|
+
await repairSupersededWithoutResume(findings);
|
|
269
347
|
await checkWorkerHealth(findings);
|
|
270
348
|
await autoAssignPoolTasks(findings);
|
|
271
349
|
await cleanupStaleResources(findings);
|
|
@@ -361,6 +439,29 @@ async function detectAndRemediateStalledTasks(findings) {
|
|
|
361
439
|
await remediateCrashedWorkerTask(findings, task, remediationOpts, proposed);
|
|
362
440
|
}
|
|
363
441
|
}
|
|
442
|
+
var ORPHAN_SUPERSEDE_MIN_AGE_MS = 60 * 1000;
|
|
443
|
+
var ORPHAN_SUPERSEDE_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
444
|
+
async function repairSupersededWithoutResume(findings) {
|
|
445
|
+
const now = Date.now();
|
|
446
|
+
const orphans = await getSupersededTasksWithoutResume(new Date(now - ORPHAN_SUPERSEDE_MIN_AGE_MS).toISOString(), new Date(now - ORPHAN_SUPERSEDE_MAX_AGE_MS).toISOString());
|
|
447
|
+
for (const task of orphans) {
|
|
448
|
+
if (!task.agentId)
|
|
449
|
+
continue;
|
|
450
|
+
if (getNextResumeGeneration(task) > maxResumeGenerations())
|
|
451
|
+
continue;
|
|
452
|
+
const resume = await createResumeFollowUp({ parentId: task.id, reason: "crash_recovery" });
|
|
453
|
+
if (resume.kind !== "created")
|
|
454
|
+
continue;
|
|
455
|
+
await backfillSupersedeTaskResumeTaskId(task.id, resume.task.id);
|
|
456
|
+
findings.autoResumedTasks.push({
|
|
457
|
+
taskId: task.id,
|
|
458
|
+
resumeTaskId: resume.task.id,
|
|
459
|
+
agentId: task.agentId,
|
|
460
|
+
reason: "repaired superseded task without resume"
|
|
461
|
+
});
|
|
462
|
+
console.log(`[Heartbeat] Created missing resume ${resume.task.id.slice(0, 8)} for superseded task ${task.id.slice(0, 8)}`);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
364
465
|
function isRemediationAction(value) {
|
|
365
466
|
return typeof value === "string" && REMEDIATION_ACTIONS.has(value);
|
|
366
467
|
}
|
|
@@ -393,7 +494,9 @@ async function remediateCrashedWorkerTask(findings, task, opts, decision) {
|
|
|
393
494
|
if (!task.agentId)
|
|
394
495
|
return;
|
|
395
496
|
if (decision.action === "fail") {
|
|
396
|
-
const failed = await failTask(task.id, decision.reason
|
|
497
|
+
const failed = await failTask(task.id, decision.reason, {
|
|
498
|
+
expectedLastUpdatedAt: task.lastUpdatedAt
|
|
499
|
+
});
|
|
397
500
|
if (failed) {
|
|
398
501
|
findings.autoFailedTasks.push({
|
|
399
502
|
taskId: task.id,
|
|
@@ -416,7 +519,8 @@ async function remediateCrashedWorkerTask(findings, task, opts, decision) {
|
|
|
416
519
|
await beforeHeartbeatSupersedeForTests?.(task);
|
|
417
520
|
const superseded = await supersedeTask(task.id, {
|
|
418
521
|
reason: decision.reason,
|
|
419
|
-
resumeTaskId: null
|
|
522
|
+
resumeTaskId: null,
|
|
523
|
+
expectedLastUpdatedAt: task.lastUpdatedAt
|
|
420
524
|
});
|
|
421
525
|
if (!superseded) {
|
|
422
526
|
return;
|
|
@@ -510,94 +614,144 @@ async function runRebootSweep() {
|
|
|
510
614
|
if (sessionLastSeen >= bootEpoch - BOOT_EPOCH_SKEW_MS) {
|
|
511
615
|
continue;
|
|
512
616
|
}
|
|
617
|
+
if (Date.now() - sessionLastSeen < stallThresholdStaleHeartbeatMin() * 60 * 1000) {
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
513
620
|
}
|
|
514
621
|
if (session)
|
|
515
622
|
await deleteActiveSession(task.id);
|
|
516
|
-
const failed = await failTask(task.id, reason);
|
|
623
|
+
const failed = await failTask(task.id, reason, { cascadeDependents: false });
|
|
517
624
|
if (!failed)
|
|
518
625
|
continue;
|
|
519
|
-
if (await getActiveTaskCount(task.agentId) === 0) {
|
|
520
|
-
await restoreAgentIdleAfterRemediation(task.agentId);
|
|
521
|
-
}
|
|
522
|
-
if (SKIP_AUTO_RESUME_TYPES.has(task.taskType ?? "")) {
|
|
523
|
-
rebootAffectedTasks.push({ original: failed, retryTaskId: null });
|
|
524
|
-
continue;
|
|
525
|
-
}
|
|
526
626
|
let retryTaskId = null;
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
627
|
+
try {
|
|
628
|
+
if (await getActiveTaskCount(task.agentId) === 0) {
|
|
629
|
+
await restoreAgentIdleAfterRemediation(task.agentId);
|
|
630
|
+
}
|
|
631
|
+
if (SKIP_AUTO_RESUME_TYPES.has(task.taskType ?? "")) {
|
|
632
|
+
rebootAffectedTasks.push({ original: failed, retryTaskId: null });
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
if (task.routingAffinityInvalid) {
|
|
636
|
+
console.error(`[Heartbeat] Reboot retry suppressed for ${task.id.slice(0, 8)}: invalid routing affinity`);
|
|
637
|
+
rebootAffectedTasks.push({ original: failed, retryTaskId: null });
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
const existingRetry = await getDbClient().get(`SELECT id FROM agent_tasks
|
|
533
641
|
WHERE parentTaskId = ?
|
|
534
642
|
AND status NOT IN ('completed', 'failed', 'cancelled')
|
|
535
643
|
LIMIT 1`, [task.id]);
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
644
|
+
if (!existingRetry) {
|
|
645
|
+
try {
|
|
646
|
+
let preferredAgentId;
|
|
647
|
+
let sourceCandidate = await getPinCandidateAgent(task.agentId);
|
|
648
|
+
if (sourceCandidate) {
|
|
649
|
+
const activeCount = await getActiveTaskCount(sourceCandidate.id);
|
|
650
|
+
const maxTasks = sourceCandidate.maxTasks ?? 1;
|
|
651
|
+
const hasCap = activeCount < maxTasks;
|
|
652
|
+
if (hasCap) {
|
|
653
|
+
preferredAgentId = sourceCandidate.id;
|
|
654
|
+
} else {
|
|
655
|
+
sourceCandidate = null;
|
|
656
|
+
console.warn(`[Heartbeat] Reboot retry for task ${task.id.slice(0, 8)} NOT pinned: agent ${task.agentId.slice(0, 8)} at capacity (${activeCount}/${maxTasks}); falling back to affinity-gated pool`);
|
|
657
|
+
}
|
|
549
658
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
parentTaskId: task.id,
|
|
566
|
-
agentId: preferredAgentId,
|
|
567
|
-
routingReason: preferredAgentId === undefined ? undefined : preferredAgentId === task.agentId ? "continuity" : "reroute_fault",
|
|
568
|
-
routingSource: preferredAgentId === undefined ? undefined : "engine_default",
|
|
569
|
-
tags,
|
|
570
|
-
priority: task.priority,
|
|
571
|
-
source: task.source,
|
|
572
|
-
taskType: task.taskType ?? undefined,
|
|
573
|
-
routingAffinity
|
|
574
|
-
});
|
|
575
|
-
if (authorization.decision) {
|
|
576
|
-
await createLogEntry({
|
|
577
|
-
eventType: "task_recovery_authorization",
|
|
578
|
-
taskId: retryTask.id,
|
|
659
|
+
const leadOnly = task.routingAffinity?.leadOnly === true;
|
|
660
|
+
const authorization = await resolveLeadOnlyRecoveryAssignment(task, sourceCandidate);
|
|
661
|
+
if (leadOnly)
|
|
662
|
+
preferredAgentId = authorization.agentId;
|
|
663
|
+
const tags = ["reboot-retry", "auto-generated"];
|
|
664
|
+
if (preferredAgentId !== undefined)
|
|
665
|
+
tags.push(REBOOT_RETRY_PIN_TAG);
|
|
666
|
+
const sourceAffinity = await buildRoutingAffinityFromAgent(task.agentId) ?? undefined;
|
|
667
|
+
const routingAffinity = leadOnly ? {
|
|
668
|
+
...sourceAffinity ?? task.routingAffinity,
|
|
669
|
+
capabilities: task.routingAffinity?.capabilities ?? sourceAffinity?.capabilities ?? [],
|
|
670
|
+
leadOnly: true
|
|
671
|
+
} : sourceAffinity;
|
|
672
|
+
const retryTask = await createTaskExtended(task.task, {
|
|
673
|
+
parentTaskId: task.id,
|
|
579
674
|
agentId: preferredAgentId,
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
675
|
+
routingReason: preferredAgentId === undefined ? undefined : preferredAgentId === task.agentId ? "continuity" : "reroute_fault",
|
|
676
|
+
routingSource: preferredAgentId === undefined ? undefined : "engine_default",
|
|
677
|
+
tags,
|
|
678
|
+
priority: task.priority,
|
|
679
|
+
source: task.source,
|
|
680
|
+
taskType: task.taskType ?? undefined,
|
|
681
|
+
inheritParentFollowUpConfig: true,
|
|
682
|
+
routingAffinity
|
|
586
683
|
});
|
|
684
|
+
if (authorization.decision) {
|
|
685
|
+
await createLogEntry({
|
|
686
|
+
eventType: "task_recovery_authorization",
|
|
687
|
+
taskId: retryTask.id,
|
|
688
|
+
agentId: preferredAgentId,
|
|
689
|
+
metadata: {
|
|
690
|
+
leadOnly: true,
|
|
691
|
+
parentTaskId: task.id,
|
|
692
|
+
sourceAgentId: task.agentId,
|
|
693
|
+
decision: authorization.decision
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
retryTaskId = retryTask.id;
|
|
698
|
+
console.log(`[Heartbeat] Reboot retry created: ${retryTaskId} (parent: ${task.id})`);
|
|
699
|
+
} catch (err) {
|
|
700
|
+
console.error(`[Heartbeat] Failed to create retry task for ${task.id}:`, err);
|
|
587
701
|
}
|
|
588
|
-
retryTaskId = retryTask.id;
|
|
589
|
-
console.log(`[Heartbeat] Reboot retry created: ${retryTaskId} (parent: ${task.id})`);
|
|
590
|
-
} catch (err) {
|
|
591
|
-
console.error(`[Heartbeat] Failed to create retry task for ${task.id}:`, err);
|
|
592
702
|
}
|
|
703
|
+
rebootAffectedTasks.push({ original: failed, retryTaskId });
|
|
704
|
+
} finally {
|
|
705
|
+
await settleRebootSweptDependents(task.id, retryTaskId);
|
|
593
706
|
}
|
|
594
|
-
rebootAffectedTasks.push({ original: failed, retryTaskId });
|
|
595
707
|
}
|
|
596
708
|
console.log(`[Heartbeat] Reboot sweep complete: ${rebootAffectedTasks.length} task(s) auto-failed and retried`);
|
|
597
709
|
} finally {
|
|
598
710
|
isSweeping = false;
|
|
599
711
|
}
|
|
600
712
|
}
|
|
713
|
+
var NEVER_STARTED_STATUSES = new Set([
|
|
714
|
+
"draft",
|
|
715
|
+
"backlog",
|
|
716
|
+
"unassigned",
|
|
717
|
+
"offered",
|
|
718
|
+
"reviewing",
|
|
719
|
+
"pending"
|
|
720
|
+
]);
|
|
721
|
+
async function settleRebootSweptDependents(sweptId, retryTaskId) {
|
|
722
|
+
try {
|
|
723
|
+
if (retryTaskId) {
|
|
724
|
+
for (const dep of await getDependentTasks(sweptId)) {
|
|
725
|
+
if (!NEVER_STARTED_STATUSES.has(dep.status))
|
|
726
|
+
continue;
|
|
727
|
+
const dependsOn = [
|
|
728
|
+
...new Set(dep.dependsOn.map((id) => id === sweptId ? retryTaskId : id))
|
|
729
|
+
];
|
|
730
|
+
const row = await getDbClient().get(`UPDATE agent_tasks
|
|
731
|
+
SET dependsOn = ?, lastUpdatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now')
|
|
732
|
+
WHERE id = ? AND status = ?
|
|
733
|
+
AND EXISTS (SELECT 1 FROM json_each(agent_tasks.dependsOn) WHERE value = ?)
|
|
734
|
+
RETURNING id`, [JSON.stringify(dependsOn), dep.id, dep.status, sweptId]);
|
|
735
|
+
if (!row)
|
|
736
|
+
continue;
|
|
737
|
+
try {
|
|
738
|
+
await createLogEntry({
|
|
739
|
+
eventType: "task_dependency_repointed",
|
|
740
|
+
taskId: dep.id,
|
|
741
|
+
agentId: dep.agentId ?? undefined,
|
|
742
|
+
oldValue: sweptId,
|
|
743
|
+
newValue: retryTaskId,
|
|
744
|
+
metadata: { reason: "reboot_retry" }
|
|
745
|
+
});
|
|
746
|
+
} catch {}
|
|
747
|
+
console.log(`[Heartbeat] Reboot sweep: dependent ${dep.id.slice(0, 8)} re-pointed from ${sweptId.slice(0, 8)} to retry ${retryTaskId.slice(0, 8)}`);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
await cascadeFailDependents(sweptId, "failed");
|
|
751
|
+
} catch (err) {
|
|
752
|
+
console.error(`[Heartbeat] Reboot sweep: settling dependents of ${sweptId} failed:`, err);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
601
755
|
function getRebootAffectedTasks() {
|
|
602
756
|
return rebootAffectedTasks;
|
|
603
757
|
}
|
|
@@ -764,6 +918,18 @@ async function cleanupStaleResources(findings) {
|
|
|
764
918
|
} catch {
|
|
765
919
|
findings.staleCleanup.workflowRuns = 0;
|
|
766
920
|
}
|
|
921
|
+
try {
|
|
922
|
+
findings.staleCleanup.approvalTimedOut = (await timeoutExpiredApprovalRequests()).timedOut.length;
|
|
923
|
+
} catch (err) {
|
|
924
|
+
console.error("[heartbeat] approval timeout sweep failed:", err);
|
|
925
|
+
findings.staleCleanup.approvalTimedOut = 0;
|
|
926
|
+
}
|
|
927
|
+
try {
|
|
928
|
+
findings.staleCleanup.approvalAutoCancelled = (await autoCancelStaleApprovalRequests()).cancelled.length;
|
|
929
|
+
} catch (err) {
|
|
930
|
+
console.error("[heartbeat] approval auto-cancel sweep failed:", err);
|
|
931
|
+
findings.staleCleanup.approvalAutoCancelled = 0;
|
|
932
|
+
}
|
|
767
933
|
}
|
|
768
934
|
function isEffectivelyEmpty(content) {
|
|
769
935
|
const lines = content.split(`
|
|
@@ -970,7 +1136,9 @@ async function runHeartbeatSweep() {
|
|
|
970
1136
|
workflowRuns: 0,
|
|
971
1137
|
staleRuntimes: 0,
|
|
972
1138
|
staleOfferedTasks: 0,
|
|
973
|
-
abandonedDraftTasks: 0
|
|
1139
|
+
abandonedDraftTasks: 0,
|
|
1140
|
+
approvalAutoCancelled: 0,
|
|
1141
|
+
approvalTimedOut: 0
|
|
974
1142
|
}
|
|
975
1143
|
};
|
|
976
1144
|
cleanupOnlyFindings.staleCleanup.staleRuntimes = (await expireStaleRuntimeInstances()).expired;
|
|
@@ -1018,9 +1186,11 @@ function logFindings(findings) {
|
|
|
1018
1186
|
inboxProcessing,
|
|
1019
1187
|
workflowRuns,
|
|
1020
1188
|
staleOfferedTasks,
|
|
1021
|
-
abandonedDraftTasks
|
|
1189
|
+
abandonedDraftTasks,
|
|
1190
|
+
approvalAutoCancelled,
|
|
1191
|
+
approvalTimedOut
|
|
1022
1192
|
} = findings.staleCleanup;
|
|
1023
|
-
const totalCleanup = sessions + reviewingTasks + mentionProcessing + inboxProcessing + workflowRuns;
|
|
1193
|
+
const totalCleanup = sessions + reviewingTasks + mentionProcessing + inboxProcessing + workflowRuns + approvalAutoCancelled + approvalTimedOut;
|
|
1024
1194
|
if (totalCleanup > 0) {
|
|
1025
1195
|
parts.push(`stale_cleanup=${totalCleanup}`);
|
|
1026
1196
|
}
|
|
@@ -63160,7 +63160,7 @@ function getCreateJiti() {
|
|
|
63160
63160
|
}
|
|
63161
63161
|
var virtualModulesPromise;
|
|
63162
63162
|
function getVirtualModules() {
|
|
63163
|
-
virtualModulesPromise ??= import("./virtual-modules-
|
|
63163
|
+
virtualModulesPromise ??= import("./virtual-modules-3htpgn8x.js").then((module) => module.VIRTUAL_MODULES);
|
|
63164
63164
|
return virtualModulesPromise;
|
|
63165
63165
|
}
|
|
63166
63166
|
var _aliases = null;
|