@desplega.ai/agent-swarm 1.147.0 → 1.149.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/README.md +13 -1
- package/dist/{acp-adapter-9n319wqc.js → acp-adapter-4jncb126.js} +12 -5
- package/dist/{actions-2vxqvpr9.js → actions-31vp3ae7.js} +10 -9
- package/dist/{app-w066xfy0.js → app-1hh67x8w.js} +6 -6
- package/dist/{assistant-kt31dj2h.js → assistant-z66dmz6p.js} +13 -11
- package/dist/{boot-reembed-az5rassp.js → boot-reembed-fqzxxzjh.js} +7 -7
- package/dist/{boot-reembed-j3mm3rfz.js → boot-reembed-wxa8ya0s.js} +8 -8
- package/dist/{boot-scrub-logs-b6h54817.js → boot-scrub-logs-jnyndh79.js} +5 -5
- package/dist/{claude-adapter-w1z04ann.js → claude-adapter-3qpa9w0j.js} +9 -9
- package/dist/{claude-managed-adapter-sactwn31.js → claude-managed-adapter-qvsmh6mv.js} +2 -2
- package/dist/{claude-sdk-session-f0cc1kec.js → claude-sdk-session-2yxgjs5d.js} +9 -9
- package/dist/{cli-y6b6fb76.js → cli-08b07b4r.js} +1 -1
- package/dist/{cli-8fc8de14.js → cli-0z2v4nhw.js} +1 -1
- package/dist/{cli-de14znh8.js → cli-19f354qr.js} +2 -2
- package/dist/{cli-hbv0kq6w.js → cli-2qts1hys.js} +3 -3
- package/dist/{cli-kpv03zhj.js → cli-3apbzgyk.js} +27 -15
- package/dist/{cli-1th1728g.js → cli-3q5ejx9p.js} +2 -2
- package/dist/{cli-d8brzxjb.js → cli-4wtq5jjv.js} +2 -2
- package/dist/{cli-ct0et58h.js → cli-5my3bjsd.js} +1 -1
- package/dist/{cli-cn6mmc7f.js → cli-6664w7y4.js} +1 -1
- package/dist/{cli-yz3djrm0.js → cli-6pqcb4q0.js} +53 -13
- package/dist/{cli-719k9j2c.js → cli-7smrsr25.js} +3 -3
- package/dist/{cli-rw51bq3j.js → cli-9fy6nk6g.js} +1 -1
- package/dist/{cli-zhjmqxzh.js → cli-9hspd3dp.js} +2 -2
- package/dist/{cli-3tgwnf43.js → cli-aae6hz6a.js} +4 -4
- package/dist/{cli-89xfd7f9.js → cli-cr12paw2.js} +5 -5
- package/dist/{cli-b5bq9crk.js → cli-d8ftsp62.js} +8 -8
- package/dist/{cli-4nr988h6.js → cli-e95cx1eb.js} +3 -3
- package/dist/{cli-n8508nre.js → cli-gjhjfeeg.js} +1 -1
- package/dist/{cli-p1d5b073.js → cli-gv88e1vf.js} +1 -1
- package/dist/{cli-rvqz34y5.js → cli-jecc01cb.js} +1 -1
- package/dist/{cli-8v0g1yc8.js → cli-k0cr4kat.js} +1 -1
- package/dist/{cli-mmemxxdc.js → cli-kgz4np97.js} +4 -4
- package/dist/{cli-w9kb3bk1.js → cli-kjwt6hdf.js} +3 -1
- package/dist/{cli-f7dsy61y.js → cli-mnmsfd1w.js} +6 -2
- package/dist/{cli-54wwve05.js → cli-n3dz2942.js} +37 -26
- package/dist/{cli-12fz972k.js → cli-nye12xk5.js} +8 -5
- package/dist/{cli-tzvk9haz.js → cli-phsxnkp6.js} +20 -20
- package/dist/{cli-53s590z8.js → cli-q50ef8g0.js} +1 -1
- package/dist/{cli-f146mn5s.js → cli-qaacms9y.js} +7 -6
- package/dist/{cli-xqcq9y5e.js → cli-r2ap2czm.js} +1 -0
- package/dist/{cli-m8yrsg97.js → cli-sd5pv3b1.js} +3 -3
- package/dist/{cli-0b6y7kxm.js → cli-xm87hzbw.js} +1 -1
- package/dist/{cli-ftht3zzj.js → cli-yab68w40.js} +285 -11
- package/dist/{cli-atcve9y8.js → cli-yb9qhqam.js} +227 -59
- package/dist/{cli-smby5m17.js → cli-ygweqcn4.js} +133 -22
- package/dist/{cli-dttph1bw.js → cli-ykxrnd1q.js} +2 -2
- package/dist/{cli-m9sxbkhm.js → cli-zvz62chv.js} +3 -3
- package/dist/cli.js +16 -14
- package/dist/{codex-adapter-zw4dwsx7.js → codex-adapter-8meawydj.js} +4 -4
- package/dist/{codex-hook-bw8p5nh4.js → codex-hook-hfrt9shr.js} +2 -2
- package/dist/{codex-session-runner-k981s65v.js → codex-session-runner-gjgxyp5j.js} +4 -4
- package/dist/{commands-sykrxx7e.js → commands-hz3nb95f.js} +5 -5
- package/dist/{db-sfbsc8wt.js → db-ggz97zbm.js} +5 -5
- package/dist/{e2b-6hb103d8.js → e2b-p04vmtx0.js} +1 -1
- package/dist/{handlers-0aspcejm.js → handlers-nbzdzn9k.js} +14 -11
- package/dist/{hook-hxccs7m5.js → hook-bks2q1f6.js} +7 -7
- package/dist/{hook-4nvqj2sb.js → hook-kq9wp0ep.js} +8 -8
- package/dist/{http-y06z517d.js → http-hrf77v87.js} +96 -45
- package/dist/{index-tce1rss4.js → index-6nsbg88z.js} +443 -144
- package/dist/{index-x5j894zf.js → index-8hmeg8j1.js} +14 -14
- package/dist/{index-k8znfx0z.js → index-cqtebbhb.js} +13 -13
- package/dist/{index-hssww7kj.js → index-n28pw1zt.js} +15 -15
- package/dist/{keepalive-w733ax66.js → keepalive-dxc12gvg.js} +7 -7
- package/dist/{lead-75bjqa9d.js → lead-yckfn18d.js} +32 -32
- package/dist/{maintenance-w4f1zjck.js → maintenance-6kfb2m5e.js} +8 -8
- package/dist/{oauth-refresh-sweep-wdetky26.js → oauth-refresh-sweep-1x1ac722.js} +6 -6
- package/dist/{onboard-bb5net8s.js → onboard-dcyt1609.js} +4 -3
- package/dist/{opencode-adapter-fef1mrn2.js → opencode-adapter-dce4wskd.js} +2 -2
- package/dist/{otel-impl-0w7c14ap.js → otel-impl-tbk3e5dr.js} +2 -2
- package/dist/{pi-mono-adapter-2has4gnp.js → pi-mono-adapter-zvshk5cj.js} +2 -2
- package/dist/{pricing-refresh-9nzsrgcq.js → pricing-refresh-kaqg567e.js} +7 -7
- package/dist/{rbac-roles-z1jrffbt.js → rbac-roles-ammq6rd2.js} +5 -5
- package/dist/{rbac-roles-r3hqjp09.js → rbac-roles-cf97v1vd.js} +6 -6
- package/dist/{render-v2-vbr89fnb.js → render-v2-80w603vy.js} +6 -6
- package/dist/{seed-pricing-g62hy1pk.js → seed-pricing-zbrn83xv.js} +6 -6
- package/dist/{setup-gnfqnptp.js → setup-fe66kczs.js} +2 -2
- package/dist/{worker-kznxp4qm.js → worker-qmb2d1e2.js} +32 -32
- package/dist/{x-n2phr5vm.js → x-n3e0v3xa.js} +2 -2
- package/openapi.json +46 -4
- package/package.json +3 -1
- package/src/agentmail/handlers.ts +5 -0
- package/src/automation-preflight-alert.ts +41 -0
- package/src/be/automation-preflight.ts +3 -3
- package/src/be/budget-refusal-notify.ts +1 -0
- package/src/be/db/tasks/read.ts +5 -0
- package/src/be/db.ts +132 -2
- package/src/be/migrations/150_deferred_task_waits.sql +18 -0
- package/src/be/migrations/151_repair_scheduled_task_required_params.sql +39 -0
- package/src/be/migrations/152_routing_decisions.sql +44 -0
- package/src/be/scripts/typecheck.ts +33 -22
- package/src/be/seed-scripts/catalog/delegate.ts +5 -1
- package/src/be/seed-skills/bundled-files.generated.json +10 -0
- package/src/be/seed-skills/index.ts +3 -0
- package/src/be/steering.ts +1 -0
- package/src/be/swarm-config-guard.ts +11 -0
- package/src/commands/onboard/steps/post-task.tsx +1 -0
- package/src/github/handlers.ts +9 -0
- package/src/gitlab/handlers.ts +4 -0
- package/src/heartbeat/heartbeat.ts +8 -0
- package/src/http/approval-requests.ts +1 -0
- package/src/http/apps.ts +1 -0
- package/src/http/config.ts +15 -6
- package/src/http/mcp.ts +31 -4
- package/src/http/script-runs.ts +6 -0
- package/src/http/tasks.ts +52 -30
- package/src/integrations/kapso/inbound.ts +1 -0
- package/src/jira/sync.ts +2 -0
- package/src/linear/sync.ts +2 -0
- package/src/prompts/session-templates.ts +29 -15
- package/src/scheduler/deferred-task-waits.ts +123 -0
- package/src/scheduler/schedule-task.ts +42 -0
- package/src/scheduler/scheduler.ts +22 -31
- package/src/script-workflows/workflow-ctx.ts +2 -0
- package/src/scripts-runtime/types/stdlib.d.ts +38 -24
- package/src/scripts-runtime/types/swarm-sdk.d.ts +38 -24
- package/src/server.ts +10 -1
- package/src/slack/actions.ts +1 -0
- package/src/slack/assistant.ts +2 -0
- package/src/slack/handlers.ts +3 -0
- package/src/slack/thread-buffer.ts +2 -0
- package/src/tasks/worker-follow-up.ts +9 -0
- package/src/tests/acp-adapter.test.ts +35 -6
- package/src/tests/acp-session-token.test.ts +67 -0
- package/src/tests/asset-key-api.test.ts +15 -2
- package/src/tests/asset-key-mcp.test.ts +2 -0
- package/src/tests/automation-preflight-alert.test.ts +91 -0
- package/src/tests/claude-worker-parity.test.ts +3 -0
- package/src/tests/config-session-auth.test.ts +143 -0
- package/src/tests/defer-task.test.ts +117 -6
- package/src/tests/deferred-task-wake.test.ts +456 -0
- package/src/tests/heartbeat-reroute-decision.test.ts +1 -0
- package/src/tests/http-api-integration.test.ts +33 -4
- package/src/tests/mcp-input-ergonomics.test.ts +386 -0
- package/src/tests/model-control.test.ts +18 -5
- package/src/tests/opencode-adapter.test.ts +2 -2
- package/src/tests/promote-draft-task-route.test.ts +4 -0
- package/src/tests/prompt-template-session.test.ts +13 -4
- package/src/tests/rbac-wire-e2e.test.ts +2 -2
- package/src/tests/routing-decision-persistence.test.ts +520 -0
- package/src/tests/routing-reason-contract.test.ts +89 -0
- package/src/tests/routing-reason-inventory.test.ts +55 -0
- package/src/tests/schedule-target-type.test.ts +48 -1
- package/src/tests/scheduled-task-required-params-migration.test.ts +182 -0
- package/src/tests/scheduled-tasks.test.ts +9 -5
- package/src/tests/script-connections.test.ts +4 -0
- package/src/tests/script-runs-http.test.ts +31 -0
- package/src/tests/scripts-typecheck.test.ts +11 -0
- package/src/tests/secret-scrubber.test.ts +12 -0
- package/src/tests/send-task-output-schema.test.ts +66 -1
- package/src/tests/send-task-requested-by.test.ts +1 -0
- package/src/tests/send-task-slack-routing-guard.test.ts +2 -0
- package/src/tests/store-progress-blocked-waiting-gate.test.ts +151 -0
- package/src/tests/swarm-tool-result-gate.test.ts +24 -0
- package/src/tests/task-tool-manifest.test.ts +47 -0
- package/src/tests/task-tool-preload-mcp.test.ts +125 -0
- package/src/tests/task-tools-ctx.test.ts +2 -0
- package/src/tests/tool-output-agent-id.test.ts +1 -0
- package/src/tests/ui-followup-lead-delegation.test.ts +6 -1
- package/src/tests/workflow-agent-task.test.ts +24 -1
- package/src/tests/workflow-engine-v2.test.ts +58 -2
- package/src/tools/accept-steer.ts +0 -1
- package/src/tools/defer-task.ts +73 -21
- package/src/tools/memory-get.ts +10 -3
- package/src/tools/memory-rate.ts +19 -7
- package/src/tools/memory-search.ts +2 -1
- package/src/tools/memory-store.ts +25 -5
- package/src/tools/send-task.ts +40 -2
- package/src/tools/skills/skill-publish.ts +1 -0
- package/src/tools/store-progress.ts +78 -4
- package/src/tools/templates.ts +2 -1
- package/src/tools/utils.ts +33 -2
- package/src/types.ts +14 -1
- package/src/utils/acp-session-token.ts +14 -4
- package/src/utils/secret-scrubber.ts +2 -0
- package/src/utils/task-tool-manifest.ts +33 -0
- package/src/workflows/engine.ts +4 -1
- package/src/workflows/executors/agent-task.ts +7 -1
- package/templates/ai-toolbox.manifest.json +6 -1
- package/templates/skills/comms/config.json +18 -0
- package/templates/skills/comms/content.md +74 -0
- package/templates/skills/comms/files/references/ste-rules.md +73 -0
- package/templates/skills/comms/files/references/visual-shapes.md +112 -0
- package/templates/skills/swarm-scripts/SKILL.md +3 -2
- package/templates/skills/swarm-scripts/content.md +3 -2
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runAgent
|
|
3
|
-
} from "./cli-
|
|
4
|
-
import"./cli-
|
|
5
|
-
import"./cli-
|
|
6
|
-
import"./cli-
|
|
3
|
+
} from "./cli-phsxnkp6.js";
|
|
4
|
+
import"./cli-xm87hzbw.js";
|
|
5
|
+
import"./cli-e95cx1eb.js";
|
|
6
|
+
import"./cli-6664w7y4.js";
|
|
7
7
|
import"./cli-hsxj0yar.js";
|
|
8
8
|
import"./cli-9b13ggd1.js";
|
|
9
|
-
import"./cli-
|
|
9
|
+
import"./cli-5my3bjsd.js";
|
|
10
10
|
import"./cli-5bfdm1ah.js";
|
|
11
11
|
import"./cli-r94z9p1z.js";
|
|
12
12
|
import"./cli-2djtr51b.js";
|
|
13
13
|
import {
|
|
14
14
|
getEnabledCapabilities
|
|
15
|
-
} from "./cli-
|
|
16
|
-
import"./cli-
|
|
15
|
+
} from "./cli-yb9qhqam.js";
|
|
16
|
+
import"./cli-0z2v4nhw.js";
|
|
17
17
|
import"./cli-j490egb5.js";
|
|
18
|
-
import"./cli-
|
|
19
|
-
import"./cli-
|
|
20
|
-
import"./cli-
|
|
18
|
+
import"./cli-7smrsr25.js";
|
|
19
|
+
import"./cli-cr12paw2.js";
|
|
20
|
+
import"./cli-4wtq5jjv.js";
|
|
21
21
|
import"./cli-b5b30yzk.js";
|
|
22
|
-
import"./cli-
|
|
22
|
+
import"./cli-jecc01cb.js";
|
|
23
23
|
import"./cli-hp1n6zq3.js";
|
|
24
24
|
import"./cli-tng3131n.js";
|
|
25
25
|
import"./cli-zm7njwzd.js";
|
|
@@ -27,49 +27,49 @@ import"./cli-s25avqg9.js";
|
|
|
27
27
|
import"./cli-eree7rnv.js";
|
|
28
28
|
import"./cli-xvkmedgn.js";
|
|
29
29
|
import"./cli-4yc5d8fk.js";
|
|
30
|
-
import"./cli-
|
|
31
|
-
import"./cli-
|
|
32
|
-
import"./cli-
|
|
33
|
-
import"./cli-
|
|
30
|
+
import"./cli-ygweqcn4.js";
|
|
31
|
+
import"./cli-sd5pv3b1.js";
|
|
32
|
+
import"./cli-9fy6nk6g.js";
|
|
33
|
+
import"./cli-k0cr4kat.js";
|
|
34
34
|
import"./cli-cmp8g3sw.js";
|
|
35
|
-
import"./cli-
|
|
35
|
+
import"./cli-19f354qr.js";
|
|
36
36
|
import"./cli-qgm2pfpq.js";
|
|
37
|
-
import"./cli-
|
|
37
|
+
import"./cli-mnmsfd1w.js";
|
|
38
38
|
import"./cli-07jd68a1.js";
|
|
39
|
-
import"./cli-
|
|
39
|
+
import"./cli-6pqcb4q0.js";
|
|
40
40
|
import"./cli-1ebpar1q.js";
|
|
41
41
|
import"./cli-e7d20cty.js";
|
|
42
42
|
import"./cli-3dpj7atn.js";
|
|
43
|
-
import"./cli-
|
|
43
|
+
import"./cli-aae6hz6a.js";
|
|
44
44
|
import"./cli-epan13p1.js";
|
|
45
|
-
import"./cli-
|
|
46
|
-
import"./cli-
|
|
45
|
+
import"./cli-2qts1hys.js";
|
|
46
|
+
import"./cli-3q5ejx9p.js";
|
|
47
47
|
import"./cli-y89t4nca.js";
|
|
48
48
|
import"./cli-f14fvzag.js";
|
|
49
|
-
import"./cli-
|
|
50
|
-
import"./cli-
|
|
49
|
+
import"./cli-zvz62chv.js";
|
|
50
|
+
import"./cli-9hspd3dp.js";
|
|
51
51
|
import"./cli-fad8m16k.js";
|
|
52
52
|
import"./cli-aehm1rbq.js";
|
|
53
53
|
import"./cli-bsakbbkm.js";
|
|
54
54
|
import"./cli-51tf7ac3.js";
|
|
55
|
-
import"./cli-
|
|
55
|
+
import"./cli-kgz4np97.js";
|
|
56
56
|
import"./cli-jsp14b6c.js";
|
|
57
|
-
import"./cli-
|
|
58
|
-
import"./cli-
|
|
59
|
-
import"./cli-
|
|
57
|
+
import"./cli-gv88e1vf.js";
|
|
58
|
+
import"./cli-q50ef8g0.js";
|
|
59
|
+
import"./cli-d8ftsp62.js";
|
|
60
60
|
import"./cli-q51yprfq.js";
|
|
61
61
|
import"./cli-9d8ntetj.js";
|
|
62
62
|
import"./cli-yatxqynm.js";
|
|
63
|
-
import"./cli-
|
|
64
|
-
import"./cli-
|
|
65
|
-
import"./cli-
|
|
63
|
+
import"./cli-yab68w40.js";
|
|
64
|
+
import"./cli-08b07b4r.js";
|
|
65
|
+
import"./cli-3apbzgyk.js";
|
|
66
66
|
import"./cli-e29gmdmw.js";
|
|
67
67
|
import"./cli-c2mk1kgf.js";
|
|
68
68
|
import"./cli-ej6gbxfb.js";
|
|
69
69
|
import"./cli-sd0mxa3c.js";
|
|
70
70
|
import"./cli-w5e1d1vv.js";
|
|
71
|
-
import"./cli-
|
|
72
|
-
import"./cli-
|
|
71
|
+
import"./cli-kjwt6hdf.js";
|
|
72
|
+
import"./cli-r2ap2czm.js";
|
|
73
73
|
import"./cli-pzxba7gw.js";
|
|
74
74
|
import"./cli-f7kvq46p.js";
|
|
75
75
|
import"./cli-zf8jjwex.js";
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
executeComposioRequest,
|
|
4
4
|
formatComposioResultForCli,
|
|
5
5
|
parseComposioArgs
|
|
6
|
-
} from "./cli-
|
|
6
|
+
} from "./cli-0z2v4nhw.js";
|
|
7
7
|
import {
|
|
8
8
|
init_secret_scrubber,
|
|
9
9
|
scrubSecrets
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-r2ap2czm.js";
|
|
11
11
|
import"./cli-bc05qbss.js";
|
|
12
12
|
|
|
13
13
|
// src/commands/x.ts
|
package/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Agent Swarm API",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.149.0",
|
|
6
6
|
"description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
|
|
7
7
|
},
|
|
8
8
|
"servers": [
|
|
@@ -174,6 +174,20 @@
|
|
|
174
174
|
],
|
|
175
175
|
"default": "mcp"
|
|
176
176
|
},
|
|
177
|
+
"routingReason": {
|
|
178
|
+
"type": "string",
|
|
179
|
+
"enum": [
|
|
180
|
+
"skill",
|
|
181
|
+
"continuity",
|
|
182
|
+
"overflow",
|
|
183
|
+
"human_pinned",
|
|
184
|
+
"reroute_fault"
|
|
185
|
+
]
|
|
186
|
+
},
|
|
187
|
+
"routingNote": {
|
|
188
|
+
"type": "string",
|
|
189
|
+
"maxLength": 200
|
|
190
|
+
},
|
|
177
191
|
"taskType": {
|
|
178
192
|
"type": "string",
|
|
179
193
|
"maxLength": 50
|
|
@@ -4065,7 +4079,7 @@
|
|
|
4065
4079
|
"config": {
|
|
4066
4080
|
"type": "object",
|
|
4067
4081
|
"additionalProperties": {},
|
|
4068
|
-
"description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
|
|
4082
|
+
"description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, routingReason?, routingNote?, tags?, priority?, dir?, vcsRepo?, model? }; configured agentId defaults routingReason to human_pinned. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
|
|
4069
4083
|
},
|
|
4070
4084
|
"next": {
|
|
4071
4085
|
"anyOf": [
|
|
@@ -4494,7 +4508,7 @@
|
|
|
4494
4508
|
"config": {
|
|
4495
4509
|
"type": "object",
|
|
4496
4510
|
"additionalProperties": {},
|
|
4497
|
-
"description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
|
|
4511
|
+
"description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, routingReason?, routingNote?, tags?, priority?, dir?, vcsRepo?, model? }; configured agentId defaults routingReason to human_pinned. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
|
|
4498
4512
|
},
|
|
4499
4513
|
"next": {
|
|
4500
4514
|
"anyOf": [
|
|
@@ -33207,6 +33221,20 @@
|
|
|
33207
33221
|
"agentId": {
|
|
33208
33222
|
"type": "string"
|
|
33209
33223
|
},
|
|
33224
|
+
"routingReason": {
|
|
33225
|
+
"type": "string",
|
|
33226
|
+
"enum": [
|
|
33227
|
+
"skill",
|
|
33228
|
+
"continuity",
|
|
33229
|
+
"overflow",
|
|
33230
|
+
"human_pinned",
|
|
33231
|
+
"reroute_fault"
|
|
33232
|
+
]
|
|
33233
|
+
},
|
|
33234
|
+
"routingNote": {
|
|
33235
|
+
"type": "string",
|
|
33236
|
+
"maxLength": 200
|
|
33237
|
+
},
|
|
33210
33238
|
"tags": {
|
|
33211
33239
|
"type": "array",
|
|
33212
33240
|
"items": {
|
|
@@ -40188,6 +40216,20 @@
|
|
|
40188
40216
|
"agentId": {
|
|
40189
40217
|
"type": "string"
|
|
40190
40218
|
},
|
|
40219
|
+
"routingReason": {
|
|
40220
|
+
"type": "string",
|
|
40221
|
+
"enum": [
|
|
40222
|
+
"skill",
|
|
40223
|
+
"continuity",
|
|
40224
|
+
"overflow",
|
|
40225
|
+
"human_pinned",
|
|
40226
|
+
"reroute_fault"
|
|
40227
|
+
]
|
|
40228
|
+
},
|
|
40229
|
+
"routingNote": {
|
|
40230
|
+
"type": "string",
|
|
40231
|
+
"maxLength": 200
|
|
40232
|
+
},
|
|
40191
40233
|
"taskType": {
|
|
40192
40234
|
"type": "string"
|
|
40193
40235
|
},
|
|
@@ -46726,7 +46768,7 @@
|
|
|
46726
46768
|
"config": {
|
|
46727
46769
|
"type": "object",
|
|
46728
46770
|
"additionalProperties": {},
|
|
46729
|
-
"description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, tags?, priority?, dir?, vcsRepo?, model? }. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
|
|
46771
|
+
"description": "Executor-specific config. For agent-task: { template, outputSchema?, agentId?, routingReason?, routingNote?, tags?, priority?, dir?, vcsRepo?, model? }; configured agentId defaults routingReason to human_pinned. For script: { runtime, script, args?, timeout? }. For swarm-script: { scriptName, scope?, pinHash?, args?, fsMode?, timeoutMs? (1000-300000) }. Agent-task templates and ordinary config values support {{interpolation}} from the node's inputs context, including trigger and declared upstream aliases. SECURITY: executable source for script/swarm-script nodes does not interpolate trigger.* or upstream node outputs; only input/workflow/swarm/run values are allowed in inline script source, and named swarm-script source is not workflow-interpolated. Pass dynamic values through config.args instead (inline script receives them as argv; swarm-script receives its args object). NOTE: config.outputSchema on agent-task nodes validates the AGENT's raw JSON output, while node-level outputSchema validates the EXECUTOR's return value ({taskId, taskOutput})."
|
|
46730
46772
|
},
|
|
46731
46773
|
"next": {
|
|
46732
46774
|
"anyOf": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@desplega.ai/agent-swarm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.149.0",
|
|
4
4
|
"description": "agent-swarm.dev — an open-source operating system for AI work: a lead agent breaks goals into tasks, routes them to specialized workers such as Claude Code or Codex, runs each worker in an isolated container, and preserves shared memory, tools, schedules, and review gates so delegated work compounds across sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-swarm.dev",
|
|
@@ -111,6 +111,8 @@
|
|
|
111
111
|
"prepare-release": "bun scripts/prepare-release.ts",
|
|
112
112
|
"refresh:vendored-openapi": "bun scripts/refresh-vendored-openapi.ts",
|
|
113
113
|
"sync-chart-version": "bun scripts/sync-chart-version.ts",
|
|
114
|
+
"sync-plugin-versions": "bun scripts/sync-plugin-versions.ts",
|
|
115
|
+
"check:plugin-versions": "bun scripts/sync-plugin-versions.ts --check",
|
|
114
116
|
"bump:agent-fs": "bun scripts/bump-agent-fs.ts",
|
|
115
117
|
"check-chart-version": "bun scripts/sync-chart-version.ts --check-if-package-version-changed",
|
|
116
118
|
"cli": "bun src/cli.tsx",
|
|
@@ -49,6 +49,7 @@ const agentmailBuffer = createIngressBuffer<BufferedAgentMailMessage>({
|
|
|
49
49
|
if (followupResult.skipped) return;
|
|
50
50
|
const task = await createTaskWithSiblingAwareness(followupResult.text, {
|
|
51
51
|
agentId: first.agentId,
|
|
52
|
+
routingReason: "continuity",
|
|
52
53
|
source: "agentmail",
|
|
53
54
|
taskType: "agentmail-reply",
|
|
54
55
|
agentmailInboxId: first.inboxId,
|
|
@@ -249,6 +250,7 @@ export async function handleMessageReceived(
|
|
|
249
250
|
|
|
250
251
|
const task = await createTaskWithSiblingAwareness(followupResult.text, {
|
|
251
252
|
agentId: existingTask.agentId,
|
|
253
|
+
routingReason: existingTask.agentId ? "continuity" : undefined,
|
|
252
254
|
source: "agentmail",
|
|
253
255
|
taskType: "agentmail-reply",
|
|
254
256
|
agentmailInboxId: inbox_id,
|
|
@@ -288,6 +290,7 @@ export async function handleMessageReceived(
|
|
|
288
290
|
|
|
289
291
|
const task = await createTaskWithSiblingAwareness(leadResult.text, {
|
|
290
292
|
agentId: agent.id,
|
|
293
|
+
routingReason: "human_pinned",
|
|
291
294
|
source: "agentmail",
|
|
292
295
|
taskType: "agentmail-message",
|
|
293
296
|
agentmailInboxId: inbox_id,
|
|
@@ -318,6 +321,7 @@ export async function handleMessageReceived(
|
|
|
318
321
|
|
|
319
322
|
const task = await createTaskWithSiblingAwareness(workerResult.text, {
|
|
320
323
|
agentId: agent.id,
|
|
324
|
+
routingReason: "human_pinned",
|
|
321
325
|
source: "agentmail",
|
|
322
326
|
taskType: "agentmail-message",
|
|
323
327
|
agentmailInboxId: inbox_id,
|
|
@@ -352,6 +356,7 @@ export async function handleMessageReceived(
|
|
|
352
356
|
|
|
353
357
|
const task = await createTaskWithSiblingAwareness(unmappedResult.text, {
|
|
354
358
|
agentId: lead.id,
|
|
359
|
+
routingReason: "skill",
|
|
355
360
|
source: "agentmail",
|
|
356
361
|
taskType: "agentmail-message",
|
|
357
362
|
agentmailInboxId: inbox_id,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AutomationPreflightResult } from "./be/automation-preflight";
|
|
2
|
+
import { getAppUrl } from "./utils/constants";
|
|
3
|
+
import { scrubSecrets } from "./utils/secret-scrubber";
|
|
4
|
+
|
|
5
|
+
/** Best-effort alert; callers gate this on a newly recorded preflight refusal. */
|
|
6
|
+
export async function notifyAutomationPreflightFailure(
|
|
7
|
+
preflight: AutomationPreflightResult,
|
|
8
|
+
): Promise<void> {
|
|
9
|
+
const channel = process.env.SLACK_ALERTS_CHANNEL?.trim();
|
|
10
|
+
if (!channel) {
|
|
11
|
+
console.warn("[Automation Preflight] SLACK_ALERTS_CHANNEL not set; skipping alert");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const { getSlackApp } = await import("./slack/app");
|
|
17
|
+
const app = getSlackApp();
|
|
18
|
+
if (!app) {
|
|
19
|
+
console.warn("[Automation Preflight] Slack not available, cannot send notification");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
await app.client.chat.postMessage({
|
|
23
|
+
channel,
|
|
24
|
+
text: scrubSecrets(
|
|
25
|
+
`⚠️ Automation needs setup\n` +
|
|
26
|
+
`Automation: ${preflight.kind} "${preflight.name}"\n` +
|
|
27
|
+
`Missing params: ${preflight.missing.params.join(", ") || "none"}\n` +
|
|
28
|
+
`Missing integrations: ${preflight.missing.integrations.join(", ") || "none"}\n` +
|
|
29
|
+
`Fire SKIPPED. It was not retried or queued.\n` +
|
|
30
|
+
`Fix setup: ${getAppUrl()}${preflight.fixUrl}`,
|
|
31
|
+
),
|
|
32
|
+
unfurl_links: false,
|
|
33
|
+
unfurl_media: false,
|
|
34
|
+
});
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error(
|
|
37
|
+
"[Automation Preflight] Failed to send Slack notification:",
|
|
38
|
+
scrubSecrets(error instanceof Error ? error.message : String(error)),
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -380,7 +380,7 @@ export async function recordWorkflowPreflightFailure(input: {
|
|
|
380
380
|
failureReason: string;
|
|
381
381
|
createdBy?: string;
|
|
382
382
|
now?: Date;
|
|
383
|
-
}): Promise<string> {
|
|
383
|
+
}): Promise<{ runId: string; recorded: boolean }> {
|
|
384
384
|
const now = input.now ?? new Date();
|
|
385
385
|
const bounds = utcDayBounds(now);
|
|
386
386
|
return await getDbClient().transaction(async (tx) => {
|
|
@@ -392,7 +392,7 @@ export async function recordWorkflowPreflightFailure(input: {
|
|
|
392
392
|
ORDER BY startedAt ASC LIMIT 1`,
|
|
393
393
|
[input.workflowId, bounds.start, bounds.end],
|
|
394
394
|
);
|
|
395
|
-
if (existing) return existing.id;
|
|
395
|
+
if (existing) return { runId: existing.id, recorded: false };
|
|
396
396
|
|
|
397
397
|
const runId = crypto.randomUUID();
|
|
398
398
|
const timestamp = now.toISOString();
|
|
@@ -413,6 +413,6 @@ export async function recordWorkflowPreflightFailure(input: {
|
|
|
413
413
|
timestamp,
|
|
414
414
|
],
|
|
415
415
|
);
|
|
416
|
-
return runId;
|
|
416
|
+
return { runId, recorded: true };
|
|
417
417
|
});
|
|
418
418
|
}
|
package/src/be/db/tasks/read.ts
CHANGED
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
ProviderName,
|
|
10
10
|
ReasoningEffort,
|
|
11
11
|
RoutingAffinity,
|
|
12
|
+
RoutingReason,
|
|
12
13
|
} from "../../../types";
|
|
13
14
|
import {
|
|
14
15
|
FollowUpConfigSchema,
|
|
@@ -45,6 +46,8 @@ export type AgentTaskRow = {
|
|
|
45
46
|
title: string | null;
|
|
46
47
|
status: AgentTaskStatus;
|
|
47
48
|
source: AgentTaskSource;
|
|
49
|
+
routing_reason: RoutingReason | null;
|
|
50
|
+
routing_note: string | null;
|
|
48
51
|
taskType: string | null;
|
|
49
52
|
tags: string | null;
|
|
50
53
|
priority: number;
|
|
@@ -165,6 +168,8 @@ export function rowToAgentTask(row: AgentTaskRow): AgentTask {
|
|
|
165
168
|
title: row.title ?? undefined,
|
|
166
169
|
status: row.status,
|
|
167
170
|
source: row.source,
|
|
171
|
+
routingReason: row.routing_reason ?? undefined,
|
|
172
|
+
routingNote: row.routing_note ?? undefined,
|
|
168
173
|
taskType: row.taskType ?? undefined,
|
|
169
174
|
tags: row.tags ? JSON.parse(row.tags) : [],
|
|
170
175
|
priority: row.priority ?? 50,
|
package/src/be/db.ts
CHANGED
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
AgentLogEventType,
|
|
19
19
|
AgentMcpServer,
|
|
20
20
|
AgentSkill,
|
|
21
|
+
AgentStatus,
|
|
21
22
|
AgentTask,
|
|
22
23
|
AgentTaskStatus,
|
|
23
24
|
AgentTaskSummary,
|
|
@@ -2051,6 +2052,103 @@ export async function findRecentSimilarTasks(opts: {
|
|
|
2051
2052
|
return rows.map(rowToAgentTask);
|
|
2052
2053
|
}
|
|
2053
2054
|
|
|
2055
|
+
type RoutingDecisionWorkerStatus = {
|
|
2056
|
+
agentId: string;
|
|
2057
|
+
status: AgentStatus;
|
|
2058
|
+
activeTaskCount: number;
|
|
2059
|
+
openTaskCount: number;
|
|
2060
|
+
};
|
|
2061
|
+
|
|
2062
|
+
type RoutingDecisionCandidate = {
|
|
2063
|
+
taskId: string;
|
|
2064
|
+
agentId: string;
|
|
2065
|
+
};
|
|
2066
|
+
|
|
2067
|
+
type RoutingDecisionSnapshot = {
|
|
2068
|
+
capturedAt: string;
|
|
2069
|
+
workerStatuses: RoutingDecisionWorkerStatus[];
|
|
2070
|
+
continuityCandidates: {
|
|
2071
|
+
samePr: RoutingDecisionCandidate | null;
|
|
2072
|
+
sameThread: RoutingDecisionCandidate | null;
|
|
2073
|
+
sameRepo: RoutingDecisionCandidate | null;
|
|
2074
|
+
};
|
|
2075
|
+
};
|
|
2076
|
+
|
|
2077
|
+
const ROUTING_HOLDER_SQL = `CASE
|
|
2078
|
+
WHEN status IN ('draft', 'offered', 'reviewing') AND offeredTo IS NOT NULL THEN offeredTo
|
|
2079
|
+
ELSE COALESCE(agentId, offeredTo)
|
|
2080
|
+
END`;
|
|
2081
|
+
|
|
2082
|
+
async function findLatestRoutingCandidate(
|
|
2083
|
+
where: string,
|
|
2084
|
+
params: Array<string | number>,
|
|
2085
|
+
): Promise<RoutingDecisionCandidate | null> {
|
|
2086
|
+
const row = await getDbClient().get<RoutingDecisionCandidate>(
|
|
2087
|
+
`SELECT id AS taskId, ${ROUTING_HOLDER_SQL} AS agentId
|
|
2088
|
+
FROM agent_tasks
|
|
2089
|
+
WHERE ${where}
|
|
2090
|
+
AND ${ROUTING_HOLDER_SQL} IN (SELECT id FROM agents WHERE isLead = 0)
|
|
2091
|
+
ORDER BY createdAt DESC, rowid DESC
|
|
2092
|
+
LIMIT 1`,
|
|
2093
|
+
params,
|
|
2094
|
+
);
|
|
2095
|
+
return row ?? null;
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
async function captureRoutingDecisionSnapshot(
|
|
2099
|
+
options: CreateTaskOptions,
|
|
2100
|
+
): Promise<RoutingDecisionSnapshot> {
|
|
2101
|
+
const workerStatuses = await getDbClient().query<RoutingDecisionWorkerStatus>(
|
|
2102
|
+
`SELECT agent.id AS agentId, agent.status,
|
|
2103
|
+
COUNT(task.id) AS openTaskCount,
|
|
2104
|
+
SUM(CASE WHEN task.status IN ('in_progress', 'reviewing') THEN 1 ELSE 0 END) AS activeTaskCount
|
|
2105
|
+
FROM agents agent
|
|
2106
|
+
LEFT JOIN agent_tasks task ON
|
|
2107
|
+
(task.agentId = agent.id OR task.offeredTo = agent.id)
|
|
2108
|
+
AND task.status NOT IN ('completed', 'failed', 'cancelled', 'superseded')
|
|
2109
|
+
WHERE agent.isLead = 0
|
|
2110
|
+
GROUP BY agent.id, agent.status
|
|
2111
|
+
ORDER BY agent.id`,
|
|
2112
|
+
);
|
|
2113
|
+
|
|
2114
|
+
const samePr =
|
|
2115
|
+
options.vcsRepo && options.vcsNumber != null
|
|
2116
|
+
? await findLatestRoutingCandidate("vcsRepo = ? AND vcsNumber = ?", [
|
|
2117
|
+
options.vcsRepo,
|
|
2118
|
+
options.vcsNumber,
|
|
2119
|
+
])
|
|
2120
|
+
: null;
|
|
2121
|
+
|
|
2122
|
+
let sameThread: RoutingDecisionCandidate | null = null;
|
|
2123
|
+
if (options.slackChannelId && options.slackThreadTs) {
|
|
2124
|
+
sameThread = await findLatestRoutingCandidate("slackChannelId = ? AND slackThreadTs = ?", [
|
|
2125
|
+
options.slackChannelId,
|
|
2126
|
+
options.slackThreadTs,
|
|
2127
|
+
]);
|
|
2128
|
+
} else if (options.agentmailThreadId) {
|
|
2129
|
+
sameThread = await findLatestRoutingCandidate("agentmailThreadId = ?", [
|
|
2130
|
+
options.agentmailThreadId,
|
|
2131
|
+
]);
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
const sameRepo = options.vcsRepo
|
|
2135
|
+
? await findLatestRoutingCandidate("vcsRepo = ?", [options.vcsRepo])
|
|
2136
|
+
: null;
|
|
2137
|
+
|
|
2138
|
+
return {
|
|
2139
|
+
capturedAt: new Date().toISOString(),
|
|
2140
|
+
workerStatuses,
|
|
2141
|
+
continuityCandidates: { samePr, sameThread, sameRepo },
|
|
2142
|
+
};
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
function logRoutingDecisionFailure(taskId: string, stage: "capture" | "write", error: unknown) {
|
|
2146
|
+
console.warn(
|
|
2147
|
+
`[routing-decision] Failed to ${stage} snapshot for task ${taskId}:`,
|
|
2148
|
+
scrubSecrets(error instanceof Error ? error.message : String(error)),
|
|
2149
|
+
);
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2054
2152
|
export async function createTaskExtended(
|
|
2055
2153
|
task: string,
|
|
2056
2154
|
options?: CreateTaskOptions,
|
|
@@ -2417,9 +2515,16 @@ export async function createTaskExtended(
|
|
|
2417
2515
|
: await findExistingLinearTrackerContextWork(options?.contextKey);
|
|
2418
2516
|
if (existingTrackerWork) return { existing: existingTrackerWork };
|
|
2419
2517
|
|
|
2518
|
+
let routingDecisionSnapshot: RoutingDecisionSnapshot | null = null;
|
|
2519
|
+
try {
|
|
2520
|
+
routingDecisionSnapshot = await captureRoutingDecisionSnapshot(options);
|
|
2521
|
+
} catch (error) {
|
|
2522
|
+
logRoutingDecisionFailure(id, "capture", error);
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2420
2525
|
const inserted = await getDbClient().get<AgentTaskRow>(
|
|
2421
2526
|
`INSERT INTO agent_tasks (
|
|
2422
|
-
id, "key", agentId, creatorAgentId, task, status, source,
|
|
2527
|
+
id, "key", agentId, creatorAgentId, task, status, source, routing_reason, routing_note,
|
|
2423
2528
|
taskType, tags, priority, dependsOn, offeredTo, offeredAt,
|
|
2424
2529
|
slackChannelId, slackThreadTs, slackTriggerMessageTs, slackUserId,
|
|
2425
2530
|
vcsProvider, vcsRepo, vcsEventType, vcsNumber, vcsCommentId, vcsAuthor, vcsUrl,
|
|
@@ -2427,7 +2532,7 @@ export async function createTaskExtended(
|
|
|
2427
2532
|
agentmailInboxId, agentmailMessageId, agentmailThreadId,
|
|
2428
2533
|
mentionMessageId, mentionChannelId, dir, parentTaskId, model, modelTier, effort, scheduleId,
|
|
2429
2534
|
workflowRunId, workflowRunStepId, outputSchema, followUpConfig, requestedByUserId, requestedByUserIdInherited, contextKey, routingAffinity, swarmVersion, createdAt, lastUpdatedAt, created_by, updated_by
|
|
2430
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
|
|
2535
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`,
|
|
2431
2536
|
[
|
|
2432
2537
|
id,
|
|
2433
2538
|
assetKey,
|
|
@@ -2436,6 +2541,8 @@ export async function createTaskExtended(
|
|
|
2436
2541
|
task,
|
|
2437
2542
|
status,
|
|
2438
2543
|
options?.source ?? "mcp",
|
|
2544
|
+
options?.routingReason ?? null,
|
|
2545
|
+
options?.routingNote ?? null,
|
|
2439
2546
|
options?.taskType ?? null,
|
|
2440
2547
|
JSON.stringify(options?.tags ?? []),
|
|
2441
2548
|
options?.priority ?? 50,
|
|
@@ -2482,6 +2589,28 @@ export async function createTaskExtended(
|
|
|
2482
2589
|
],
|
|
2483
2590
|
);
|
|
2484
2591
|
if (!inserted) throw new Error("Failed to create task");
|
|
2592
|
+
|
|
2593
|
+
if (routingDecisionSnapshot) {
|
|
2594
|
+
try {
|
|
2595
|
+
await getDbClient().run(
|
|
2596
|
+
`INSERT INTO routing_decisions (
|
|
2597
|
+
task_id, selected_agent_id, captured_at, worker_statuses,
|
|
2598
|
+
continuity_candidates, created_by, updated_by
|
|
2599
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
2600
|
+
[
|
|
2601
|
+
id,
|
|
2602
|
+
options.offeredTo ?? options.agentId ?? null,
|
|
2603
|
+
routingDecisionSnapshot.capturedAt,
|
|
2604
|
+
JSON.stringify(routingDecisionSnapshot.workerStatuses),
|
|
2605
|
+
JSON.stringify(routingDecisionSnapshot.continuityCandidates),
|
|
2606
|
+
auditUserId,
|
|
2607
|
+
auditUserId,
|
|
2608
|
+
],
|
|
2609
|
+
);
|
|
2610
|
+
} catch (error) {
|
|
2611
|
+
logRoutingDecisionFailure(id, "write", error);
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2485
2614
|
return { row: inserted };
|
|
2486
2615
|
});
|
|
2487
2616
|
|
|
@@ -3520,6 +3649,7 @@ export async function postMessage(
|
|
|
3520
3649
|
|
|
3521
3650
|
const task = await createTaskExtended(taskDescription, {
|
|
3522
3651
|
agentId: mentionedAgentId, // Direct assignment
|
|
3652
|
+
routingReason: "human_pinned",
|
|
3523
3653
|
creatorAgentId: agentId ?? undefined,
|
|
3524
3654
|
source: "mcp",
|
|
3525
3655
|
taskType: "task",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- Task deferrals retain their one-time schedule as the deadline. This sibling
|
|
2
|
+
-- to workflow wait_states arbitrates event/deadline dispatch without inventing
|
|
3
|
+
-- a workflow run or step for an ordinary task.
|
|
4
|
+
CREATE TABLE IF NOT EXISTS deferred_task_waits (
|
|
5
|
+
scheduleId TEXT PRIMARY KEY REFERENCES scheduled_tasks(id) ON DELETE CASCADE,
|
|
6
|
+
taskId TEXT NOT NULL,
|
|
7
|
+
eventName TEXT NOT NULL CHECK (eventName IN ('task.completed', 'task.failed', 'settled')),
|
|
8
|
+
status TEXT NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'fired')),
|
|
9
|
+
firedBy TEXT,
|
|
10
|
+
childTaskId TEXT,
|
|
11
|
+
resolvedAt TEXT,
|
|
12
|
+
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
13
|
+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
14
|
+
created_by TEXT,
|
|
15
|
+
updated_by TEXT
|
|
16
|
+
);
|
|
17
|
+
CREATE INDEX IF NOT EXISTS idx_deferred_task_waits_pending
|
|
18
|
+
ON deferred_task_waits(taskId) WHERE status = 'pending';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
-- Migration 141 added requirements by canonical name even when an existing
|
|
2
|
+
-- schedule already contained concrete values instead of template placeholders.
|
|
3
|
+
-- Restore its unbound timezone first so TIMEZONE is pruned in the same pass
|
|
4
|
+
-- unless the task body still references it. Keep operator-supplied bindings.
|
|
5
|
+
UPDATE scheduled_tasks
|
|
6
|
+
SET timezone = 'UTC'
|
|
7
|
+
WHERE name = 'weekly-dependabot-triage'
|
|
8
|
+
AND timezone = '{{TIMEZONE}}'
|
|
9
|
+
AND json_extract(params, '$.TIMEZONE') IS NULL;
|
|
10
|
+
|
|
11
|
+
-- Only remove requirements that the row does not consume. Scope this repair to
|
|
12
|
+
-- the names backfilled by 141; leave custom schedules and integration gates alone.
|
|
13
|
+
-- The EXISTS guard also leaves already-correct JSON byte-for-byte unchanged.
|
|
14
|
+
UPDATE scheduled_tasks
|
|
15
|
+
SET requiredParams = (
|
|
16
|
+
SELECT json_group_array(value)
|
|
17
|
+
FROM json_each(scheduled_tasks.requiredParams)
|
|
18
|
+
WHERE instr(COALESCE(scheduled_tasks.taskTemplate, ''), '{{' || value || '}}') > 0
|
|
19
|
+
OR instr(COALESCE(scheduled_tasks.timezone, ''), '{{' || value || '}}') > 0
|
|
20
|
+
)
|
|
21
|
+
WHERE name IN (
|
|
22
|
+
'daily-blocker-digest',
|
|
23
|
+
'daily-compounding-reflection',
|
|
24
|
+
'daily-status-report',
|
|
25
|
+
'daily-workflow-health-audit',
|
|
26
|
+
'weekly-harness-upgrade-check',
|
|
27
|
+
'weekly-dependabot-triage',
|
|
28
|
+
'weekly-code-health-reports',
|
|
29
|
+
'weekly-dora-metrics',
|
|
30
|
+
'daily-hn-briefing',
|
|
31
|
+
'gtm-weekly-review',
|
|
32
|
+
'dream-daily'
|
|
33
|
+
)
|
|
34
|
+
AND EXISTS (
|
|
35
|
+
SELECT 1
|
|
36
|
+
FROM json_each(scheduled_tasks.requiredParams)
|
|
37
|
+
WHERE instr(COALESCE(scheduled_tasks.taskTemplate, ''), '{{' || value || '}}') = 0
|
|
38
|
+
AND instr(COALESCE(scheduled_tasks.timezone, ''), '{{' || value || '}}') = 0
|
|
39
|
+
);
|