@desplega.ai/agent-swarm 1.153.0 → 1.154.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.
Files changed (143) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-ahmjxhek.js → acp-adapter-eb2aj8xy.js} +1 -1
  3. package/dist/{actions-jzrfpkmn.js → actions-kpnwp1kz.js} +18 -18
  4. package/dist/{app-03na2vwb.js → app-zk1apkf6.js} +6 -6
  5. package/dist/{assistant-hfkxvhgt.js → assistant-kwq4y50q.js} +19 -19
  6. package/dist/{boot-reembed-c98xrad3.js → boot-reembed-22hd3jjn.js} +7 -7
  7. package/dist/{boot-reembed-zt3qm9xn.js → boot-reembed-qe168424.js} +8 -8
  8. package/dist/{boot-scrub-logs-jcqd8ksj.js → boot-scrub-logs-pkdpsrjd.js} +5 -5
  9. package/dist/{claude-adapter-mgryg8g3.js → claude-adapter-3fx90nww.js} +10 -10
  10. package/dist/{claude-sdk-session-jjf4zss1.js → claude-sdk-session-z7fahf1k.js} +10 -10
  11. package/dist/{cli-1hwnb4hc.js → cli-09y3tjxz.js} +1 -1
  12. package/dist/{cli-b2g6mzjc.js → cli-0e31nm4n.js} +1 -1
  13. package/dist/{cli-5mbmvxnn.js → cli-1jpjafw4.js} +5 -5
  14. package/dist/{cli-bw0dfwkr.js → cli-243tzws8.js} +1 -1
  15. package/dist/{cli-rj7de4b2.js → cli-24k806sc.js} +1 -1
  16. package/dist/{cli-7g9s78jf.js → cli-3bkz2p7j.js} +7 -6
  17. package/dist/{cli-zcsyfw2z.js → cli-4k7jazkq.js} +4 -0
  18. package/dist/{cli-s5s1f2yn.js → cli-5vs0nh43.js} +25 -20
  19. package/dist/{cli-qrqhc31j.js → cli-6r3cgpk2.js} +94 -52
  20. package/dist/{cli-pgj4a5fb.js → cli-71cj99hx.js} +4 -3
  21. package/dist/{cli-d6hk10xx.js → cli-8sea27q4.js} +2 -2
  22. package/dist/{cli-a9scg8sv.js → cli-913yakhv.js} +22 -7
  23. package/dist/{cli-pf9q3696.js → cli-927erqqt.js} +5 -2
  24. package/dist/{cli-zy5w9gpt.js → cli-95jnpnqg.js} +1 -1
  25. package/dist/{cli-cdq08v3r.js → cli-abp3g4ax.js} +15 -2
  26. package/dist/{cli-nq0kgyxe.js → cli-acy6bfhr.js} +10 -7
  27. package/dist/{cli-n0q9b7j4.js → cli-c1v10xb2.js} +157 -52
  28. package/dist/{cli-tdh4hjr2.js → cli-e0pg4zeh.js} +1 -1
  29. package/dist/{cli-83wkg402.js → cli-e31ehqwy.js} +1 -1
  30. package/dist/{cli-m04pt18h.js → cli-e3229na9.js} +3 -3
  31. package/dist/{cli-ysc1kbet.js → cli-e3cyf59d.js} +2 -2
  32. package/dist/{cli-mzgyhxbe.js → cli-fdzg6jhf.js} +2 -2
  33. package/dist/{cli-0d9nbqxf.js → cli-g2h29qar.js} +2 -2
  34. package/dist/{cli-djvxhnc4.js → cli-ge67p080.js} +124 -26
  35. package/dist/{cli-7pnz2v6s.js → cli-hws0vn86.js} +2 -2
  36. package/dist/{cli-3bcmp015.js → cli-kp3qs53m.js} +2 -2
  37. package/dist/{cli-ybpp1srm.js → cli-myaxtgh8.js} +2 -1
  38. package/dist/{cli-r8tdds6s.js → cli-n62atwh9.js} +1 -1
  39. package/dist/{cli-6ks9xf1n.js → cli-pf1v8xhb.js} +4 -4
  40. package/dist/{cli-5taqtpze.js → cli-q85qhckh.js} +6 -6
  41. package/dist/{cli-eazstkad.js → cli-r1d3dzt6.js} +2 -2
  42. package/dist/{cli-ja7mrygn.js → cli-rxkqvngf.js} +2 -2
  43. package/dist/{cli-vw03hg5t.js → cli-stwsmd6k.js} +2 -2
  44. package/dist/{cli-z61ykvam.js → cli-wg04s9kr.js} +4 -3
  45. package/dist/cli.js +13 -12
  46. package/dist/{codex-adapter-8548daap.js → codex-adapter-ttdm995v.js} +5 -5
  47. package/dist/{codex-hook-8jexc34x.js → codex-hook-8gx7bcz0.js} +3 -3
  48. package/dist/{codex-session-runner-2dad8p4x.js → codex-session-runner-3v8nh4c8.js} +5 -5
  49. package/dist/{commands-355dbpa8.js → commands-1cxwbhhq.js} +5 -5
  50. package/dist/{db-4jjvwz1s.js → db-y9zwsr79.js} +23 -5
  51. package/dist/{dispatcher-ca590nkz.js → dispatcher-9m9zss36.js} +17 -17
  52. package/dist/{dsh-adapter-rgvj6ykp.js → dsh-adapter-gsb2qqf9.js} +2 -2
  53. package/dist/{google-generative-ai-xtw7tggr.js → google-generative-ai-gwwrnzqn.js} +1 -1
  54. package/dist/{google-vertex-zdqpms6n.js → google-vertex-5wfawpwz.js} +1 -1
  55. package/dist/{handlers-2y6dqpvf.js → handlers-36fm1bwn.js} +20 -20
  56. package/dist/{hook-0s8knepr.js → hook-pntw4r8h.js} +8 -8
  57. package/dist/{hook-k0gec254.js → hook-vwq8y26p.js} +9 -9
  58. package/dist/{http-jp2nb4zw.js → http-20jesakk.js} +89 -56
  59. package/dist/{index-42s7eezq.js → index-6artrehg.js} +17 -17
  60. package/dist/{index-3mq6ce93.js → index-9n5z2492.js} +17 -17
  61. package/dist/{index-0wzg3sp3.js → index-j5wrf1yw.js} +11 -11
  62. package/dist/{index-s37dbevy.js → index-m2xqpz5r.js} +18 -18
  63. package/dist/{index-b56xkbc7.js → index-m9ks8a7t.js} +7 -7
  64. package/dist/{keepalive-9pfw7t02.js → keepalive-pwxvxd2c.js} +7 -7
  65. package/dist/{lead-7vcmcdq4.js → lead-m789wqa3.js} +26 -26
  66. package/dist/{maintenance-x277jbpd.js → maintenance-bvg6w7e2.js} +8 -8
  67. package/dist/{oauth-refresh-sweep-5fwa7th2.js → oauth-refresh-sweep-6v4bd737.js} +6 -6
  68. package/dist/{onboard-17sv0f51.js → onboard-snckpcj1.js} +14 -2
  69. package/dist/{otel-impl-srjy4be4.js → otel-impl-e0ytens5.js} +1 -1
  70. package/dist/{pi-mono-adapter-946a0sdd.js → pi-mono-adapter-c4ggemhz.js} +6 -6
  71. package/dist/{pricing-refresh-vetcm563.js → pricing-refresh-52g2ywrw.js} +7 -7
  72. package/dist/{rbac-roles-cmxaddmy.js → rbac-roles-5455kfdn.js} +5 -5
  73. package/dist/{rbac-roles-cfzgr6r1.js → rbac-roles-hbf0xa52.js} +6 -6
  74. package/dist/{render-v2-f9hzff72.js → render-v2-npm8xdzh.js} +12 -8
  75. package/dist/{seed-pricing-jggk6rsy.js → seed-pricing-650wbr1n.js} +6 -6
  76. package/dist/{setup-8mfceb9t.js → setup-k1mew5rf.js} +2 -2
  77. package/dist/{virtual-modules-ax661xp0.js → virtual-modules-2q5b2pk4.js} +2 -2
  78. package/dist/{work-objects-vdsdcczj.js → work-objects-2ea3kvwg.js} +20 -20
  79. package/dist/{worker-cd0nhyv1.js → worker-ec6hvc4m.js} +26 -26
  80. package/openapi.json +74 -3
  81. package/package.json +2 -1
  82. package/plugin/opencode-plugins/lib/memory-raters.ts +7 -0
  83. package/src/be/db/agents.ts +75 -2
  84. package/src/be/db/tasks/read.ts +2 -0
  85. package/src/be/db/tasks/write.ts +7 -1
  86. package/src/be/db.ts +140 -18
  87. package/src/be/memory/raters/llm.ts +2 -6
  88. package/src/be/memory/raters/noop.ts +2 -3
  89. package/src/be/memory/raters/registry.ts +4 -10
  90. package/src/be/migrations/157_defer_provenance_and_marker.sql +27 -0
  91. package/src/be/seed/agent-fs-provision.ts +23 -0
  92. package/src/commands/onboard/compose-generator.ts +10 -0
  93. package/src/commands/onboard/env-generator.ts +8 -0
  94. package/src/commands/runner.ts +18 -2
  95. package/src/extensions/identity.ts +15 -7
  96. package/src/hooks/codex-hook.ts +7 -1
  97. package/src/http/agents.ts +10 -2
  98. package/src/http/poll.ts +7 -0
  99. package/src/http/schedules.ts +10 -0
  100. package/src/http/script-runs.ts +35 -26
  101. package/src/http/status.ts +2 -1
  102. package/src/http/tasks.ts +6 -1
  103. package/src/prompts/memories.ts +5 -7
  104. package/src/prompts/session-templates.ts +3 -2
  105. package/src/prompts/steering-delivery.ts +2 -0
  106. package/src/providers/codex-adapter.ts +3 -6
  107. package/src/providers/pi-mono-extension.ts +2 -5
  108. package/src/slack/ack.ts +43 -8
  109. package/src/slack/handlers.ts +7 -1
  110. package/src/slack/render-v2.ts +186 -17
  111. package/src/slack/responses.ts +1 -3
  112. package/src/slack/task-output.ts +66 -8
  113. package/src/slack/thread-buffer.ts +27 -3
  114. package/src/tests/agent-fs-provision-seeder.test.ts +56 -2
  115. package/src/tests/codex-steering-hook.test.ts +2 -2
  116. package/src/tests/db-task-read-contract.test.ts +9 -0
  117. package/src/tests/db-task-write-contract.test.ts +9 -0
  118. package/src/tests/defer-task.test.ts +115 -16
  119. package/src/tests/extension-agent-visibility.test.ts +474 -0
  120. package/src/tests/extensions-lifecycle.test.ts +3 -1
  121. package/src/tests/fetch-resolved-env.test.ts +43 -0
  122. package/src/tests/memory-rate-tool.test.ts +7 -10
  123. package/src/tests/memory-rater-defaults.test.ts +23 -0
  124. package/src/tests/memory-rater-e2e.test.ts +2 -3
  125. package/src/tests/script-connections.test.ts +3 -0
  126. package/src/tests/slack-render-v2.test.ts +446 -16
  127. package/src/tests/slack-steering.test.ts +69 -1
  128. package/src/tests/slack-task-output.test.ts +33 -12
  129. package/src/tests/steering-core.test.ts +35 -0
  130. package/src/tests/steering-delivery.test.ts +39 -0
  131. package/src/tests/steering-transport.test.ts +2 -2
  132. package/src/tests/workflow-live-recovery.test.ts +126 -0
  133. package/src/tools/defer-task.ts +64 -26
  134. package/src/tools/join-swarm.ts +1 -1
  135. package/src/tools/schedules/create-schedule.ts +11 -1
  136. package/src/tools/schedules/patch-schedule.ts +5 -0
  137. package/src/tools/schedules/update-schedule.ts +5 -0
  138. package/src/tools/send-task.ts +6 -0
  139. package/src/tools/utils.ts +1 -1
  140. package/src/types.ts +13 -0
  141. package/src/utils/memory-raters.ts +3 -0
  142. package/src/workflows/engine.ts +28 -0
  143. package/src/workflows/recovery.ts +7 -4
@@ -1,71 +1,71 @@
1
1
  import {
2
2
  runAgent
3
- } from "./cli-s5s1f2yn.js";
4
- import"./cli-pgj4a5fb.js";
3
+ } from "./cli-5vs0nh43.js";
4
+ import"./cli-71cj99hx.js";
5
5
  import"./cli-scwq51gn.js";
6
6
  import"./cli-9b13ggd1.js";
7
7
  import"./cli-18amys3y.js";
8
- import"./cli-zy5w9gpt.js";
8
+ import"./cli-95jnpnqg.js";
9
9
  import"./cli-5bfdm1ah.js";
10
- import"./cli-5taqtpze.js";
10
+ import"./cli-q85qhckh.js";
11
11
  import"./cli-hsxj0yar.js";
12
12
  import"./cli-r94z9p1z.js";
13
13
  import"./cli-2djtr51b.js";
14
- import"./cli-pf9q3696.js";
14
+ import"./cli-927erqqt.js";
15
15
  import"./cli-j490egb5.js";
16
- import"./cli-3bcmp015.js";
17
- import"./cli-5mbmvxnn.js";
18
- import"./cli-1hwnb4hc.js";
16
+ import"./cli-kp3qs53m.js";
17
+ import"./cli-1jpjafw4.js";
18
+ import"./cli-09y3tjxz.js";
19
19
  import"./cli-tng3131n.js";
20
20
  import"./cli-b5b30yzk.js";
21
21
  import"./cli-zm7njwzd.js";
22
22
  import"./cli-e781c6f9.js";
23
- import"./cli-mzgyhxbe.js";
23
+ import"./cli-fdzg6jhf.js";
24
24
  import"./cli-hp1n6zq3.js";
25
25
  import"./cli-eree7rnv.js";
26
26
  import"./cli-avkd6mqv.js";
27
27
  import {
28
28
  getEnabledCapabilities
29
- } from "./cli-qrqhc31j.js";
29
+ } from "./cli-6r3cgpk2.js";
30
30
  import"./cli-0z2v4nhw.js";
31
- import"./cli-7g9s78jf.js";
31
+ import"./cli-3bkz2p7j.js";
32
32
  import"./cli-e7d20cty.js";
33
33
  import"./cli-re8z5p8p.js";
34
34
  import"./cli-3dpj7atn.js";
35
- import"./cli-d6hk10xx.js";
36
- import"./cli-vw03hg5t.js";
37
- import"./cli-tdh4hjr2.js";
38
- import"./cli-83wkg402.js";
35
+ import"./cli-8sea27q4.js";
36
+ import"./cli-stwsmd6k.js";
37
+ import"./cli-e0pg4zeh.js";
38
+ import"./cli-e31ehqwy.js";
39
39
  import"./cli-ytxs7mn1.js";
40
- import"./cli-6ks9xf1n.js";
40
+ import"./cli-pf1v8xhb.js";
41
41
  import"./cli-epan13p1.js";
42
42
  import"./cli-y89t4nca.js";
43
43
  import"./cli-f14fvzag.js";
44
- import"./cli-r8tdds6s.js";
44
+ import"./cli-n62atwh9.js";
45
45
  import"./cli-bsakbbkm.js";
46
46
  import"./cli-fad8m16k.js";
47
47
  import"./cli-jsp14b6c.js";
48
- import"./cli-ysc1kbet.js";
49
- import"./cli-7pnz2v6s.js";
50
- import"./cli-0d9nbqxf.js";
48
+ import"./cli-e3cyf59d.js";
49
+ import"./cli-hws0vn86.js";
50
+ import"./cli-g2h29qar.js";
51
51
  import"./cli-aehm1rbq.js";
52
52
  import"./cli-51tf7ac3.js";
53
- import"./cli-n0q9b7j4.js";
53
+ import"./cli-c1v10xb2.js";
54
54
  import"./cli-q51yprfq.js";
55
55
  import"./cli-3er6gcsn.js";
56
56
  import"./cli-yatxqynm.js";
57
57
  import"./cli-2658f6at.js";
58
- import"./cli-djvxhnc4.js";
59
- import"./cli-zcsyfw2z.js";
60
- import"./cli-b2g6mzjc.js";
61
- import"./cli-z61ykvam.js";
58
+ import"./cli-ge67p080.js";
59
+ import"./cli-4k7jazkq.js";
60
+ import"./cli-0e31nm4n.js";
61
+ import"./cli-wg04s9kr.js";
62
62
  import"./cli-v4en75c5.js";
63
63
  import"./cli-dv6cdjs2.js";
64
64
  import"./cli-n7h1kqpf.js";
65
65
  import"./cli-ej6gbxfb.js";
66
66
  import"./cli-sd0mxa3c.js";
67
67
  import"./cli-w5e1d1vv.js";
68
- import"./cli-ybpp1srm.js";
68
+ import"./cli-myaxtgh8.js";
69
69
  import"./cli-r2ap2czm.js";
70
70
  import"./cli-5b6b62tz.js";
71
71
  import"./cli-btbzvq95.js";
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.153.0",
5
+ "version": "1.154.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": [
@@ -391,6 +391,10 @@
391
391
  "type": "boolean",
392
392
  "default": false
393
393
  },
394
+ "deferredAt": {
395
+ "type": "string",
396
+ "format": "date-time"
397
+ },
394
398
  "compactionCount": {
395
399
  "type": "integer",
396
400
  "minimum": 0
@@ -4207,6 +4211,9 @@
4207
4211
  "api"
4208
4212
  ]
4209
4213
  },
4214
+ "senderLabel": {
4215
+ "type": "string"
4216
+ },
4210
4217
  "createdByKind": {
4211
4218
  "type": "string",
4212
4219
  "enum": [
@@ -9553,7 +9560,7 @@
9553
9560
  },
9554
9561
  "get": {
9555
9562
  "summary": "List all agents",
9556
- "description": "Returns agents WITHOUT the six identity-markdown blobs (`claudeMd`/`soulMd`/`identityMd`/`toolsMd`/`heartbeatMd`/`setupScript`) by default — they bloat the list by ~16 KB/agent and the overview never renders them. Pass `fields=full` to restore them, or fetch a single agent via `GET /api/agents/{id}`.",
9563
+ "description": "Returns agents WITHOUT the six identity-markdown blobs (`claudeMd`/`soulMd`/`identityMd`/`toolsMd`/`heartbeatMd`/`setupScript`) by default — they bloat the list by ~16 KB/agent and the overview never renders them. Pass `fields=full` to restore them, or fetch a single agent via `GET /api/agents/{id}`. Extension identities (`ext:<name>`, role `extension`) are never listed; they are API principals, not workers.",
9557
9564
  "tags": [
9558
9565
  "Agents"
9559
9566
  ],
@@ -26692,6 +26699,14 @@
26692
26699
  "parentTaskId": {
26693
26700
  "type": "string"
26694
26701
  },
26702
+ "requestedDelayMs": {
26703
+ "type": "integer",
26704
+ "exclusiveMinimum": 0
26705
+ },
26706
+ "requestedRunAt": {
26707
+ "type": "string",
26708
+ "format": "date-time"
26709
+ },
26695
26710
  "timezone": {
26696
26711
  "type": "string",
26697
26712
  "default": "UTC"
@@ -27049,6 +27064,14 @@
27049
27064
  "parentTaskId": {
27050
27065
  "type": "string"
27051
27066
  },
27067
+ "requestedDelayMs": {
27068
+ "type": "integer",
27069
+ "exclusiveMinimum": 0
27070
+ },
27071
+ "requestedRunAt": {
27072
+ "type": "string",
27073
+ "format": "date-time"
27074
+ },
27052
27075
  "timezone": {
27053
27076
  "type": "string",
27054
27077
  "default": "UTC"
@@ -27233,6 +27256,14 @@
27233
27256
  "parentTaskId": {
27234
27257
  "type": "string"
27235
27258
  },
27259
+ "requestedDelayMs": {
27260
+ "type": "integer",
27261
+ "exclusiveMinimum": 0
27262
+ },
27263
+ "requestedRunAt": {
27264
+ "type": "string",
27265
+ "format": "date-time"
27266
+ },
27236
27267
  "timezone": {
27237
27268
  "type": "string",
27238
27269
  "default": "UTC"
@@ -27460,6 +27491,14 @@
27460
27491
  "parentTaskId": {
27461
27492
  "type": "string"
27462
27493
  },
27494
+ "requestedDelayMs": {
27495
+ "type": "integer",
27496
+ "exclusiveMinimum": 0
27497
+ },
27498
+ "requestedRunAt": {
27499
+ "type": "string",
27500
+ "format": "date-time"
27501
+ },
27463
27502
  "timezone": {
27464
27503
  "type": "string",
27465
27504
  "default": "UTC"
@@ -27702,6 +27741,14 @@
27702
27741
  "parentTaskId": {
27703
27742
  "type": "string"
27704
27743
  },
27744
+ "requestedDelayMs": {
27745
+ "type": "integer",
27746
+ "exclusiveMinimum": 0
27747
+ },
27748
+ "requestedRunAt": {
27749
+ "type": "string",
27750
+ "format": "date-time"
27751
+ },
27705
27752
  "timezone": {
27706
27753
  "type": "string",
27707
27754
  "default": "UTC"
@@ -28064,6 +28111,14 @@
28064
28111
  "parentTaskId": {
28065
28112
  "type": "string"
28066
28113
  },
28114
+ "requestedDelayMs": {
28115
+ "type": "integer",
28116
+ "exclusiveMinimum": 0
28117
+ },
28118
+ "requestedRunAt": {
28119
+ "type": "string",
28120
+ "format": "date-time"
28121
+ },
28067
28122
  "timezone": {
28068
28123
  "type": "string",
28069
28124
  "default": "UTC"
@@ -28447,6 +28502,14 @@
28447
28502
  "parentTaskId": {
28448
28503
  "type": "string"
28449
28504
  },
28505
+ "requestedDelayMs": {
28506
+ "type": "integer",
28507
+ "exclusiveMinimum": 0
28508
+ },
28509
+ "requestedRunAt": {
28510
+ "type": "string",
28511
+ "format": "date-time"
28512
+ },
28450
28513
  "timezone": {
28451
28514
  "type": "string",
28452
28515
  "default": "UTC"
@@ -40143,6 +40206,14 @@
40143
40206
  "parentTaskId": {
40144
40207
  "type": "string"
40145
40208
  },
40209
+ "requestedDelayMs": {
40210
+ "type": "integer",
40211
+ "exclusiveMinimum": 0
40212
+ },
40213
+ "requestedRunAt": {
40214
+ "type": "string",
40215
+ "format": "date-time"
40216
+ },
40146
40217
  "timezone": {
40147
40218
  "type": "string",
40148
40219
  "default": "UTC"
@@ -41422,7 +41493,7 @@
41422
41493
  }
41423
41494
  },
41424
41495
  "400": {
41425
- "description": "Validation error",
41496
+ "description": "Validation error, or agentId/offeredTo targets an extension identity",
41426
41497
  "content": {
41427
41498
  "application/json": {
41428
41499
  "schema": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desplega.ai/agent-swarm",
3
- "version": "1.153.0",
3
+ "version": "1.154.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",
@@ -41,6 +41,7 @@
41
41
  "plugin/commands/",
42
42
  "plugin/agents/",
43
43
  "plugin/pi-skills/",
44
+ "plugin/opencode-plugins/lib/memory-raters.ts",
44
45
  "templates/",
45
46
  "vendored-openapi/",
46
47
  "openapi.json"
@@ -0,0 +1,7 @@
1
+ /** Unset enables citation ratings and self-rating hints; an explicitly empty value disables all raters. */
2
+ export function getMemoryRaterNames(): string[] {
3
+ return (process.env.MEMORY_RATERS ?? "implicit-citation,explicit-self")
4
+ .split(",")
5
+ .map((name) => name.trim())
6
+ .filter(Boolean);
7
+ }
@@ -206,8 +206,79 @@ export async function getAgentById(id: string): Promise<Agent | null> {
206
206
  return row ? rowToAgent(row) : null;
207
207
  }
208
208
 
209
- export async function getAllAgents(opts?: { slim?: boolean }): Promise<Agent[]> {
210
- const rows = await getDbClient().query<AgentRow>("SELECT * FROM agents ORDER BY name");
209
+ /**
210
+ * Role stamped on the `ext:<name>` agent row an extension authenticates as
211
+ * (`src/extensions/identity.ts`). These rows are API identities, not workers:
212
+ * they are hidden from agent listings and can never be assigned, offered, or
213
+ * claim tasks. The rows themselves are kept so the extension can keep calling
214
+ * the API and re-enabling it finds the same identity.
215
+ */
216
+ export const EXTENSION_AGENT_ROLE = "extension";
217
+
218
+ /** SQL predicate that drops extension-identity rows from an `agents` scan. */
219
+ export const NOT_EXTENSION_AGENT_SQL = `COALESCE(role, '') != '${EXTENSION_AGENT_ROLE}'`;
220
+
221
+ export function isExtensionAgent(agent: Pick<Agent, "role"> | null | undefined): boolean {
222
+ return agent?.role === EXTENSION_AGENT_ROLE;
223
+ }
224
+
225
+ export function extensionAgentAssignmentError(agent: Pick<Agent, "id" | "name">): string {
226
+ return `Agent "${agent.name}" (${agent.id}) is an extension identity and cannot be assigned, offered, or scheduled tasks. Target a worker or lead agent instead.`;
227
+ }
228
+
229
+ /**
230
+ * Thrown when an ordinary registration or profile update tries to grant the
231
+ * reserved extension role, or to strip it from an extension identity. Only
232
+ * `ensureExtensionAgent` may set it.
233
+ */
234
+ export class ReservedAgentRoleError extends Error {
235
+ constructor(message: string) {
236
+ super(message);
237
+ this.name = "ReservedAgentRoleError";
238
+ }
239
+ }
240
+
241
+ /**
242
+ * Returns the reason a role change is refused, or null when it is allowed.
243
+ * `allowExtensionRole` is passed only by the extension identity lifecycle.
244
+ */
245
+ export function reservedRoleViolation(
246
+ currentRole: string | null | undefined,
247
+ nextRole: string | undefined,
248
+ opts?: { allowExtensionRole?: boolean },
249
+ ): string | null {
250
+ if (nextRole === undefined || nextRole === currentRole) return null;
251
+ if (currentRole === EXTENSION_AGENT_ROLE) {
252
+ return `Extension identities keep the "${EXTENSION_AGENT_ROLE}" role; it cannot be changed.`;
253
+ }
254
+ if (nextRole === EXTENSION_AGENT_ROLE && !opts?.allowExtensionRole) {
255
+ return `Role "${EXTENSION_AGENT_ROLE}" is reserved for extension identities.`;
256
+ }
257
+ return null;
258
+ }
259
+
260
+ /** Thrown by task creation when the assignee or offer target is an extension identity. */
261
+ export class ExtensionAgentAssignmentError extends Error {
262
+ constructor(agent: Pick<Agent, "id" | "name">) {
263
+ super(extensionAgentAssignmentError(agent));
264
+ this.name = "ExtensionAgentAssignmentError";
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Lists agents ordered by name. Extension identities are excluded unless
270
+ * `includeExtensions` is set; only the extension identity lifecycle and
271
+ * name-collision checks need them.
272
+ */
273
+ export async function getAllAgents(opts?: {
274
+ slim?: boolean;
275
+ includeExtensions?: boolean;
276
+ }): Promise<Agent[]> {
277
+ const rows = await getDbClient().query<AgentRow>(
278
+ opts?.includeExtensions
279
+ ? "SELECT * FROM agents ORDER BY name"
280
+ : `SELECT * FROM agents WHERE ${NOT_EXTENSION_AGENT_SQL} ORDER BY name`,
281
+ );
211
282
  return rows.map((row) => rowToAgent(row, opts?.slim ?? false));
212
283
  }
213
284
 
@@ -529,6 +600,8 @@ export function isAgentEligibleForTask(
529
600
  agent: Pick<Agent, "id" | "isLead" | "role" | "capabilities">,
530
601
  task: Pick<AgentTask, "routingAffinity" | "routingAffinityInvalid">,
531
602
  ): boolean {
603
+ // Extension identities are API principals, never task executors.
604
+ if (isExtensionAgent(agent)) return false;
532
605
  const affinity = task.routingAffinity;
533
606
  // A malformed persisted blob is a security boundary failure, not an
534
607
  // untagged task. Quarantine it from every assignment/claim path.
@@ -103,6 +103,7 @@ export type AgentTaskRow = {
103
103
  peakContextTokens: number | null;
104
104
  contextWindowSize: number | null;
105
105
  was_paused: number;
106
+ deferredAt: string | null;
106
107
  credentialKeySuffix: string | null;
107
108
  credentialKeyType: string | null;
108
109
  requestedByUserId: string | null;
@@ -228,6 +229,7 @@ export function rowToAgentTask(row: AgentTaskRow): AgentTask {
228
229
  output: row.output ?? undefined,
229
230
  progress: row.progress ?? undefined,
230
231
  wasPaused: !!row.was_paused,
232
+ deferredAt: row.deferredAt ?? undefined,
231
233
  credentialKeySuffix: row.credentialKeySuffix ?? undefined,
232
234
  credentialKeyType: row.credentialKeyType ?? undefined,
233
235
  requestedByUserId: row.requestedByUserId ?? undefined,
@@ -326,7 +326,7 @@ export async function updateTaskTitle(
326
326
  export async function completeTask(
327
327
  id: string,
328
328
  output?: string,
329
- options?: { addTags?: string[] },
329
+ options?: { addTags?: string[]; deferredAt?: string },
330
330
  ): Promise<AgentTask | null> {
331
331
  const oldTask = await getTaskById(id);
332
332
  if (!oldTask) return null;
@@ -364,6 +364,12 @@ export async function completeTask(
364
364
  [JSON.stringify(nextTags), id],
365
365
  );
366
366
  }
367
+ if (completed && options?.deferredAt) {
368
+ completed = await getDbClient().get<AgentTaskRow>(
369
+ "UPDATE agent_tasks SET deferredAt = ?, lastUpdatedAt = strftime('%Y-%m-%dT%H:%M:%fZ', 'now') WHERE id = ? RETURNING *",
370
+ [options.deferredAt, id],
371
+ );
372
+ }
367
373
  if (completed) {
368
374
  await dependencies.reconcileTaskPullRequestAttachments(id, completed.agentId, [
369
375
  completed.output,