@desplega.ai/agent-swarm 1.145.0 → 1.147.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 (221) hide show
  1. package/README.md +2 -1
  2. package/dist/{acp-adapter-580t41c0.js → acp-adapter-9n319wqc.js} +61 -6
  3. package/dist/{actions-m662tjng.js → actions-2vxqvpr9.js} +9 -8
  4. package/dist/{app-zb3rndm8.js → app-w066xfy0.js} +6 -5
  5. package/dist/assistant-kt31dj2h.js +236 -0
  6. package/dist/{boot-reembed-072x00vn.js → boot-reembed-az5rassp.js} +7 -6
  7. package/dist/{boot-reembed-65zz2smt.js → boot-reembed-j3mm3rfz.js} +8 -7
  8. package/dist/{boot-scrub-logs-yz0ams04.js → boot-scrub-logs-b6h54817.js} +4 -4
  9. package/dist/{claude-adapter-paj270y2.js → claude-adapter-w1z04ann.js} +8 -6
  10. package/dist/{claude-managed-setup-w619jncn.js → claude-managed-setup-f5pmsyrp.js} +24 -3
  11. package/dist/{claude-sdk-session-swt80j9z.js → claude-sdk-session-f0cc1kec.js} +8 -6
  12. package/dist/{cli-dt553ktb.js → cli-0b6y7kxm.js} +1 -1
  13. package/dist/{cli-bxdhw615.js → cli-12fz972k.js} +4 -4
  14. package/dist/{cli-s2f20r5w.js → cli-1th1728g.js} +2 -2
  15. package/dist/{cli-rs6ec3b9.js → cli-3tgwnf43.js} +3 -3
  16. package/dist/{cli-gxnzc6wh.js → cli-4nr988h6.js} +1 -1
  17. package/dist/{cli-axs8e6d4.js → cli-53s590z8.js} +1 -1
  18. package/dist/{cli-ygbjp3z8.js → cli-54wwve05.js} +5 -4
  19. package/dist/{cli-v0asr5yv.js → cli-719k9j2c.js} +2 -2
  20. package/dist/{cli-anktweqr.js → cli-89xfd7f9.js} +21 -47
  21. package/dist/{cli-q34a0e10.js → cli-8v0g1yc8.js} +1 -1
  22. package/dist/cli-9d8ntetj.js +42 -0
  23. package/dist/{cli-z9fprcrf.js → cli-atcve9y8.js} +881 -738
  24. package/dist/{cli-jmb7g47h.js → cli-b5bq9crk.js} +14 -31
  25. package/dist/cli-d8brzxjb.js +190 -0
  26. package/dist/{cli-gzky0gkr.js → cli-de14znh8.js} +2 -2
  27. package/dist/{cli-xytwff7f.js → cli-dttph1bw.js} +2 -2
  28. package/dist/cli-ep19k3mb.js +19 -0
  29. package/dist/{cli-m1xa8be7.js → cli-f146mn5s.js} +7 -50
  30. package/dist/{cli-1fj0chdk.js → cli-f7dsy61y.js} +5 -3
  31. package/dist/{cli-f567d5c1.js → cli-ftht3zzj.js} +2782 -2589
  32. package/dist/{cli-a0g1gbt5.js → cli-hbv0kq6w.js} +2 -2
  33. package/dist/{cli-fhsz3twr.js → cli-jsp14b6c.js} +171 -1
  34. package/dist/{cli-7fnkj1hj.js → cli-kpv03zhj.js} +21 -17
  35. package/dist/{cli-m4j6trn4.js → cli-m8yrsg97.js} +2 -2
  36. package/dist/cli-m9sxbkhm.js +779 -0
  37. package/dist/cli-mmemxxdc.js +823 -0
  38. package/dist/{cli-tqtvj5pt.js → cli-n8508nre.js} +1 -1
  39. package/dist/{cli-z96t0thj.js → cli-p1d5b073.js} +37 -2
  40. package/dist/{cli-gh8y8f36.js → cli-rw51bq3j.js} +13 -10
  41. package/dist/{cli-59ej1c07.js → cli-smby5m17.js} +7 -6
  42. package/dist/{cli-65vqzz3v.js → cli-tzvk9haz.js} +94 -372
  43. package/dist/{cli-dc9k2ba9.js → cli-w9kb3bk1.js} +1 -1
  44. package/dist/{cli-kpev657q.js → cli-y6b6fb76.js} +25 -3
  45. package/dist/{cli-123q2get.js → cli-yz3djrm0.js} +9 -9
  46. package/dist/{cli-wvp6bvy4.js → cli-zhjmqxzh.js} +1 -1
  47. package/dist/cli.js +13 -13
  48. package/dist/{codex-adapter-k98vaw2r.js → codex-adapter-zw4dwsx7.js} +2 -2
  49. package/dist/{codex-hook-9pf19cks.js → codex-hook-bw8p5nh4.js} +2 -2
  50. package/dist/{codex-session-runner-tngtphx7.js → codex-session-runner-k981s65v.js} +2 -2
  51. package/dist/{commands-y8nbr3fv.js → commands-sykrxx7e.js} +4 -4
  52. package/dist/{db-30p4h2t1.js → db-sfbsc8wt.js} +6 -4
  53. package/dist/handlers-0aspcejm.js +603 -0
  54. package/dist/{hook-dcw4jfbj.js → hook-4nvqj2sb.js} +7 -5
  55. package/dist/{hook-21jexvfx.js → hook-hxccs7m5.js} +24 -49
  56. package/dist/{http-r4kq5g8d.js → http-y06z517d.js} +230 -94
  57. package/dist/{index-q3qja6ta.js → index-hssww7kj.js} +15 -14
  58. package/dist/{index-gay66b9w.js → index-k8znfx0z.js} +13 -12
  59. package/dist/{index-53zyht4z.js → index-tce1rss4.js} +371 -110
  60. package/dist/{index-nqvf26za.js → index-x5j894zf.js} +14 -13
  61. package/dist/{keepalive-xs8fa55y.js → keepalive-w733ax66.js} +6 -6
  62. package/dist/{lead-d9m2t4s0.js → lead-75bjqa9d.js} +29 -27
  63. package/dist/{maintenance-3zh82g6z.js → maintenance-w4f1zjck.js} +8 -7
  64. package/dist/{oauth-refresh-sweep-03snsye5.js → oauth-refresh-sweep-wdetky26.js} +5 -5
  65. package/dist/{onboard-0cg1925x.js → onboard-bb5net8s.js} +2 -2
  66. package/dist/{otel-impl-0ab95z27.js → otel-impl-0w7c14ap.js} +1 -1
  67. package/dist/{pi-mono-adapter-dtkz4e7j.js → pi-mono-adapter-2has4gnp.js} +12 -2
  68. package/dist/{pricing-refresh-e5jhzz4j.js → pricing-refresh-9nzsrgcq.js} +6 -6
  69. package/dist/{rbac-roles-p1mf40z3.js → rbac-roles-r3hqjp09.js} +5 -5
  70. package/dist/{rbac-roles-2w3cmrkc.js → rbac-roles-z1jrffbt.js} +4 -4
  71. package/dist/{registry-9kdck5ye.js → registry-v5wytg0s.js} +1 -2
  72. package/dist/{render-v2-xhawry3k.js → render-v2-vbr89fnb.js} +6 -5
  73. package/dist/{seed-pricing-t223sw91.js → seed-pricing-g62hy1pk.js} +7 -5
  74. package/dist/{setup-zcs0rce7.js → setup-gnfqnptp.js} +2 -2
  75. package/dist/{worker-qnp2ka62.js → worker-kznxp4qm.js} +29 -27
  76. package/openapi.json +263 -12
  77. package/package.json +1 -1
  78. package/plugin/commands/start-worker.md +4 -9
  79. package/plugin/pi-skills/start-worker/SKILL.md +4 -9
  80. package/src/be/db/agents.ts +556 -0
  81. package/src/be/db/context-versions.ts +117 -0
  82. package/src/be/db/runtime.ts +406 -0
  83. package/src/be/db/tasks/read.ts +1167 -0
  84. package/src/be/db/tasks/write.ts +953 -0
  85. package/src/be/db.ts +584 -3429
  86. package/src/be/migrations/147_scheduled_tasks_parent_task.sql +7 -0
  87. package/src/be/migrations/148_pages_svg.sql +123 -0
  88. package/src/be/migrations/149_session_tokens.sql +24 -0
  89. package/src/be/scripts/typecheck.ts +1 -0
  90. package/src/be/seed-pricing.ts +13 -8
  91. package/src/be/seed-scripts/catalog/ops-catalog-audit.inline.ts +1 -1
  92. package/src/be/seed-scripts/catalog/ops-catalog-audit.ts +1 -1
  93. package/src/be/seed-scripts/catalog/star-history-refresh.ts +101 -0
  94. package/src/be/seed-scripts/catalog/star-history-renderer.ts +119 -0
  95. package/src/be/seed-scripts/index.ts +17 -0
  96. package/src/be/seed-skills/index.ts +14 -0
  97. package/src/be/swarm-config-guard.ts +5 -2
  98. package/src/be/task-attachment-store.ts +70 -0
  99. package/src/be/users.ts +77 -0
  100. package/src/commands/attachments-section.ts +37 -0
  101. package/src/commands/claude-managed-setup.ts +45 -3
  102. package/src/commands/claude-md-session.ts +408 -0
  103. package/src/commands/context-preamble.ts +15 -3
  104. package/src/commands/profile-sync.ts +205 -5
  105. package/src/commands/provider-credentials.ts +60 -27
  106. package/src/commands/runner.ts +63 -58
  107. package/src/commands/templates.ts +25 -2
  108. package/src/hooks/hook.ts +26 -67
  109. package/src/http/agents.ts +40 -1
  110. package/src/http/auth.ts +13 -1
  111. package/src/http/fs.ts +21 -51
  112. package/src/http/index.ts +2 -0
  113. package/src/http/mcp.ts +32 -0
  114. package/src/http/pages-public.ts +20 -4
  115. package/src/http/pages.ts +11 -3
  116. package/src/http/poll.ts +4 -0
  117. package/src/http/repos.ts +3 -3
  118. package/src/http/sessions.ts +82 -0
  119. package/src/http/tasks.ts +10 -2
  120. package/src/http/utils.ts +79 -1
  121. package/src/prompts/session-templates.ts +12 -8
  122. package/src/providers/acp-adapter.ts +62 -8
  123. package/src/providers/pi-mono-adapter.ts +23 -6
  124. package/src/providers/pricing-sources.md +11 -0
  125. package/src/scheduler/scheduler.test.ts +49 -2
  126. package/src/scheduler/scheduler.ts +4 -0
  127. package/src/scripts-runtime/sdk-allowlist.ts +1 -0
  128. package/src/scripts-runtime/types/stdlib.d.ts +8 -0
  129. package/src/scripts-runtime/types/swarm-sdk.d.ts +8 -0
  130. package/src/server.ts +2 -0
  131. package/src/slack/assistant.ts +87 -46
  132. package/src/slack/handlers.test.ts +1 -3
  133. package/src/slack/handlers.ts +102 -87
  134. package/src/slack/inbound-files.ts +466 -0
  135. package/src/slack/templates.ts +14 -0
  136. package/src/tasks/task-terminal-effects.ts +158 -0
  137. package/src/tests/acp-adapter.test.ts +369 -117
  138. package/src/tests/budget-claim-gate.test.ts +1 -0
  139. package/src/tests/build-pi-skills.test.ts +5 -7
  140. package/src/tests/claude-managed-setup.test.ts +52 -4
  141. package/src/tests/claude-md-session.test.ts +603 -0
  142. package/src/tests/codex-skill-resolver.test.ts +19 -0
  143. package/src/tests/context-versioning.test.ts +107 -0
  144. package/src/tests/cors-allowlist.test.ts +309 -0
  145. package/src/tests/credential-check.test.ts +157 -14
  146. package/src/tests/db-agents.test.ts +91 -0
  147. package/src/tests/db-context-versions.test.ts +37 -0
  148. package/src/tests/db-extraction-contract.test.ts +45 -0
  149. package/src/tests/db-runtime.test.ts +70 -0
  150. package/src/tests/db-task-read-contract.test.ts +624 -0
  151. package/src/tests/db-task-write-contract.test.ts +653 -0
  152. package/src/tests/db-tasks-read.test.ts +183 -0
  153. package/src/tests/db-tasks-write.test.ts +230 -0
  154. package/src/tests/defer-task.test.ts +389 -0
  155. package/src/tests/docs-index-footprint.test.js +2 -2
  156. package/src/tests/e2e-visuals-stage.test.ts +151 -0
  157. package/src/tests/file-lock.test.ts +144 -0
  158. package/src/tests/fixtures/file-lock-holder.ts +13 -0
  159. package/src/tests/fixtures/hold-file-lock.ts +25 -0
  160. package/src/tests/heartbeat-expiry.test.ts +188 -0
  161. package/src/tests/http-api-integration.test.ts +78 -1
  162. package/src/tests/pages-public-html.test.ts +43 -0
  163. package/src/tests/pages-svg-migration.test.ts +42 -0
  164. package/src/tests/preload.ts +4 -1
  165. package/src/tests/profile-sync-warning.test.ts +16 -0
  166. package/src/tests/profile-sync.test.ts +126 -0
  167. package/src/tests/prompt-template-session.test.ts +20 -4
  168. package/src/tests/provider-registration.test.ts +93 -0
  169. package/src/tests/rbac-e2e-helpers.test.ts +53 -0
  170. package/src/tests/rbac-e2e-helpers.ts +19 -2
  171. package/src/tests/reload-config.test.ts +26 -0
  172. package/src/tests/routing-affinity-inventory.test.ts +1 -1
  173. package/src/tests/runner-attachments-section.test.ts +22 -2
  174. package/src/tests/runner-context-preamble.test.ts +30 -0
  175. package/src/tests/runner-deployment-resume.test.ts +107 -0
  176. package/src/tests/runner-repo-autostash.test.ts +12 -0
  177. package/src/tests/script-connections.test.ts +4 -0
  178. package/src/tests/seed-scripts.test.ts +2 -2
  179. package/src/tests/session-tokens.test.ts +279 -0
  180. package/src/tests/slack-file-tools-attachments.test.ts +408 -0
  181. package/src/tests/slack-inbound-files.test.ts +847 -0
  182. package/src/tests/star-history-refresh.test.ts +102 -0
  183. package/src/tests/swarm-config-reserved-keys.test.ts +21 -0
  184. package/src/tests/swarm-repos.test.ts +20 -0
  185. package/src/tests/tool-annotations.test.ts +4 -3
  186. package/src/tests/ui-logs-parser.test.ts +176 -0
  187. package/src/tools/create-page.ts +4 -2
  188. package/src/tools/defer-task.ts +239 -0
  189. package/src/tools/repos/update-repo.ts +2 -2
  190. package/src/tools/schedules/create-schedule.ts +1 -0
  191. package/src/tools/schedules/list-schedules.ts +1 -0
  192. package/src/tools/schedules/patch-schedule.ts +1 -0
  193. package/src/tools/schedules/update-schedule.ts +1 -0
  194. package/src/tools/slack-download-file.ts +60 -29
  195. package/src/tools/slack-read.ts +73 -32
  196. package/src/tools/store-progress.ts +16 -146
  197. package/src/tools/tool-config.ts +1 -0
  198. package/src/tools/utils.ts +21 -0
  199. package/src/types.ts +37 -4
  200. package/src/utils/acp-session-token.ts +56 -0
  201. package/src/utils/file-lock.ts +111 -0
  202. package/src/utils/heartbeat-expiry.ts +78 -0
  203. package/src/utils/request-auth-context.ts +2 -0
  204. package/src/utils/task-attachment-links.ts +22 -0
  205. package/templates/skills/code-quality/content.md +8 -5
  206. package/templates/skills/download-task-attachment/content.md +2 -1
  207. package/{plugin/pi-skills → templates/skills}/review-offered-task/SKILL.md +5 -5
  208. package/templates/skills/review-offered-task/config.json +14 -0
  209. package/{plugin/commands/review-offered-task.md → templates/skills/review-offered-task/content.md} +3 -8
  210. package/templates/skills/scheduling/content.md +4 -0
  211. package/templates/skills/slack-interaction/content.md +2 -2
  212. package/templates/skills/work-on-task/SKILL.md +16 -0
  213. package/templates/skills/work-on-task/config.json +14 -0
  214. package/templates/skills/work-on-task/content.md +11 -0
  215. package/dist/assistant-0qt42nzg.js +0 -212
  216. package/dist/cli-fs1kkqgr.js +0 -317
  217. package/dist/cli-jnf5zghe.js +0 -269
  218. package/dist/cli-n1q8q14d.js +0 -177
  219. package/dist/handlers-yfp1qn81.js +0 -592
  220. package/plugin/commands/work-on-task.md +0 -39
  221. package/plugin/pi-skills/work-on-task/SKILL.md +0 -39
@@ -11,17 +11,17 @@ import {
11
11
  import {
12
12
  calculateNextRun,
13
13
  runScheduleNow
14
- } from "./cli-59ej1c07.js";
14
+ } from "./cli-smby5m17.js";
15
15
  import {
16
16
  startPricingRefreshLoop
17
- } from "./cli-m4j6trn4.js";
17
+ } from "./cli-m8yrsg97.js";
18
18
  import {
19
19
  seedPricingFromModelsDev
20
- } from "./cli-gh8y8f36.js";
20
+ } from "./cli-rw51bq3j.js";
21
21
  import {
22
22
  ensureRbacSeedsSynced,
23
23
  getUserGrant
24
- } from "./cli-q34a0e10.js";
24
+ } from "./cli-8v0g1yc8.js";
25
25
  import {
26
26
  can,
27
27
  decideAdmission,
@@ -48,7 +48,7 @@ import {
48
48
  runSavedScriptAsAgent,
49
49
  updateApp,
50
50
  upgradeAppDefinition
51
- } from "./cli-gzky0gkr.js";
51
+ } from "./cli-de14znh8.js";
52
52
  import {
53
53
  require_dist as require_dist2
54
54
  } from "./cli-qgm2pfpq.js";
@@ -72,7 +72,7 @@ import {
72
72
  updateTrackerSync,
73
73
  updateTrackerSyncSwarmId,
74
74
  upsertSwarmConfigWithPolicyMirror
75
- } from "./cli-1fj0chdk.js";
75
+ } from "./cli-f7dsy61y.js";
76
76
  import {
77
77
  isMultiRuntimeEnabled
78
78
  } from "./cli-07jd68a1.js";
@@ -86,7 +86,7 @@ import {
86
86
  snapshotWorkflow,
87
87
  startWorkflowExecution,
88
88
  validateJsonSchema
89
- } from "./cli-123q2get.js";
89
+ } from "./cli-yz3djrm0.js";
90
90
  import {
91
91
  ConnectionAuthInputSchema,
92
92
  SCRIPT_LONG_TIMEOUT_HINT_MS,
@@ -109,7 +109,7 @@ import {
109
109
  upsertCredentialBinding,
110
110
  upsertScriptConnection,
111
111
  validateDefinition
112
- } from "./cli-rs6ec3b9.js";
112
+ } from "./cli-3tgwnf43.js";
113
113
  import {
114
114
  CANDIDATE_SET_MULTIPLIER,
115
115
  computeScore,
@@ -121,7 +121,7 @@ import {
121
121
  isGraphExpansionEnabled,
122
122
  rerank,
123
123
  rowToCandidate
124
- } from "./cli-s2f20r5w.js";
124
+ } from "./cli-1th1728g.js";
125
125
  import {
126
126
  getApiKey
127
127
  } from "./cli-f14fvzag.js";
@@ -139,22 +139,29 @@ import {
139
139
  listAuthorizationsForApp,
140
140
  onAuthorizationRefreshed,
141
141
  upsertOAuthApp
142
- } from "./cli-wvp6bvy4.js";
142
+ } from "./cli-zhjmqxzh.js";
143
143
  import {
144
144
  ZodFirstPartyTypeKind,
145
145
  objectType
146
146
  } from "./cli-fad8m16k.js";
147
- import {
148
- AgentFsProvider
149
- } from "./cli-fhsz3twr.js";
150
147
  import {
151
148
  require_dist
152
149
  } from "./cli-51tf7ac3.js";
153
150
  import {
151
+ DEFAULT_DOWNLOAD_DIR,
152
+ MAX_FILE_SIZE,
153
+ attachSlackFilesForAgent,
154
+ attachableTask,
154
155
  createAdditiveBuffer,
156
+ downloadFile,
155
157
  extractSlackMessageText,
156
- parseSlackTs
157
- } from "./cli-jnf5zghe.js";
158
+ getFileInfo,
159
+ parseSlackTs,
160
+ uploadFile
161
+ } from "./cli-mmemxxdc.js";
162
+ import {
163
+ AgentFsProvider
164
+ } from "./cli-jsp14b6c.js";
158
165
  import {
159
166
  findOrCreateUserByEmail,
160
167
  findUserByExternalId,
@@ -166,14 +173,15 @@ import {
166
173
  recordIdentityEvent,
167
174
  recordUnmappedIdentity,
168
175
  renderIdentity,
176
+ resolveBySessionToken,
169
177
  resolveIdentity,
170
178
  resolveIdentityByEmail,
171
179
  resolveUserByToken,
172
180
  unlinkIdentity
173
- } from "./cli-z96t0thj.js";
181
+ } from "./cli-p1d5b073.js";
174
182
  import {
175
183
  createTaskWithSiblingAwareness
176
- } from "./cli-axs8e6d4.js";
184
+ } from "./cli-53s590z8.js";
177
185
  import {
178
186
  ensure,
179
187
  getAgentDisplayName,
@@ -184,7 +192,7 @@ import {
184
192
  startSlackApp,
185
193
  stopSlackApp,
186
194
  withSpan
187
- } from "./cli-jmb7g47h.js";
195
+ } from "./cli-b5bq9crk.js";
188
196
  import {
189
197
  $OpenAPIRegistry,
190
198
  $OpenApiGeneratorV31,
@@ -215,7 +223,7 @@ import {
215
223
  PromptTemplateStateSchema,
216
224
  ProviderNameSchema,
217
225
  ReasoningEffortSchema,
218
- RepoGuidelinesSchema,
226
+ RepoGuidelinesInputSchema,
219
227
  RepoHooksSchema,
220
228
  ScheduledTaskTargetTypeSchema,
221
229
  ScriptRunStatusSchema,
@@ -431,13 +439,13 @@ import {
431
439
  upsertPromptTemplate,
432
440
  upsertService,
433
441
  validateConfigValue
434
- } from "./cli-f567d5c1.js";
442
+ } from "./cli-ftht3zzj.js";
435
443
  import {
436
444
  generateDefaultClaudeMd,
437
445
  generateDefaultIdentityMd,
438
446
  generateDefaultSoulMd,
439
447
  init_defaults
440
- } from "./cli-kpev657q.js";
448
+ } from "./cli-y6b6fb76.js";
441
449
  import {
442
450
  getTemplateDefinition,
443
451
  init_registry,
@@ -446,7 +454,7 @@ import {
446
454
  interpolate,
447
455
  registerTemplate,
448
456
  resolveTemplate
449
- } from "./cli-7fnkj1hj.js";
457
+ } from "./cli-kpv03zhj.js";
450
458
  import {
451
459
  MAX_PROFILE_FILE_LENGTH,
452
460
  getAppUrl,
@@ -507,7 +515,7 @@ import {
507
515
  import {
508
516
  init_package,
509
517
  package_default
510
- } from "./cli-dc9k2ba9.js";
518
+ } from "./cli-w9kb3bk1.js";
511
519
  import {
512
520
  init_secret_scrubber,
513
521
  refreshSecretScrubberCache,
@@ -22295,7 +22303,7 @@ async function notifySlack(text) {
22295
22303
  return;
22296
22304
  }
22297
22305
  try {
22298
- const { getSlackApp: getSlackApp2 } = await import("./app-zb3rndm8.js");
22306
+ const { getSlackApp: getSlackApp2 } = await import("./app-w066xfy0.js");
22299
22307
  const app = getSlackApp2();
22300
22308
  if (!app) {
22301
22309
  console.warn("[Jira webhook keepalive] Slack not available, cannot send notification");
@@ -22366,7 +22374,7 @@ async function deleteJiraWebhook(webhookId) {
22366
22374
  console.log(`[Jira webhook keepalive] Deleted webhook id=${webhookId}`);
22367
22375
  }
22368
22376
  async function overwriteWebhookIds(next) {
22369
- const { getDbClient: getDbClient2 } = await import("./db-30p4h2t1.js");
22377
+ const { getDbClient: getDbClient2 } = await import("./db-sfbsc8wt.js");
22370
22378
  await getDbClient2().transaction(async (tx) => {
22371
22379
  const row = await tx.get("SELECT metadata FROM oauth_apps WHERE provider = 'jira'");
22372
22380
  if (!row) {
@@ -95048,156 +95056,6 @@ function warnIfMcpBaseUrlLooksLikeAppUrl2() {
95048
95056
  console.warn(`[Linear] WARNING: MCP_BASE_URL (${mcp}) equals APP_URL — surfaced webhook URL points at the dashboard host, not the API. Configure Linear with this URL only if the dashboard host also serves /api/*.`);
95049
95057
  }
95050
95058
  }
95051
- // src/slack/files.ts
95052
- import { createWriteStream } from "node:fs";
95053
- import { mkdir } from "node:fs/promises";
95054
- import { dirname } from "node:path";
95055
- var MAX_FILE_SIZE = 1073741824;
95056
- var DEFAULT_DOWNLOAD_DIR = `/workspace/shared/downloads/${process.env.AGENT_ID || "default"}/slack`;
95057
- async function uploadFile(client, options) {
95058
- const { file, filename, channelId, threadTs, initialComment, title } = options;
95059
- try {
95060
- if (Buffer.isBuffer(file) && file.length > MAX_FILE_SIZE) {
95061
- return {
95062
- success: false,
95063
- error: `File size ${file.length} bytes exceeds maximum of ${MAX_FILE_SIZE} bytes (1 GB)`
95064
- };
95065
- }
95066
- if (typeof file === "string") {
95067
- const bunFile = Bun.file(file);
95068
- const size = bunFile.size;
95069
- if (size > MAX_FILE_SIZE) {
95070
- return {
95071
- success: false,
95072
- error: `File size ${size} bytes exceeds maximum of ${MAX_FILE_SIZE} bytes (1 GB)`
95073
- };
95074
- }
95075
- }
95076
- const uploadArgs = {
95077
- file,
95078
- filename,
95079
- title: title || filename
95080
- };
95081
- if (channelId) {
95082
- uploadArgs.channel_id = channelId;
95083
- if (threadTs) {
95084
- uploadArgs.thread_ts = threadTs;
95085
- }
95086
- if (initialComment) {
95087
- uploadArgs.initial_comment = initialComment;
95088
- }
95089
- }
95090
- const result = await client.filesUploadV2(uploadArgs);
95091
- const uploadedFile = result.files?.[0];
95092
- const fileId = uploadedFile?.files?.[0]?.id;
95093
- if (!fileId) {
95094
- return {
95095
- success: false,
95096
- error: "Upload succeeded but no file ID returned"
95097
- };
95098
- }
95099
- return {
95100
- success: true,
95101
- fileId
95102
- };
95103
- } catch (error) {
95104
- const errorMsg = error instanceof Error ? error.message : String(error);
95105
- return {
95106
- success: false,
95107
- error: errorMsg
95108
- };
95109
- }
95110
- }
95111
- async function downloadFile(options) {
95112
- const { file, savePath, token } = options;
95113
- try {
95114
- const downloadUrl = typeof file === "string" ? file : file.url_private_download;
95115
- if (!downloadUrl) {
95116
- return {
95117
- success: false,
95118
- error: "No download URL available for this file"
95119
- };
95120
- }
95121
- let finalPath = savePath;
95122
- if (typeof file !== "string" && (savePath.endsWith("/") || !savePath.includes("."))) {
95123
- finalPath = savePath.endsWith("/") ? `${savePath}${file.name}` : `${savePath}/${file.name}`;
95124
- }
95125
- await mkdir(dirname(finalPath), { recursive: true });
95126
- const response = await fetch(downloadUrl, {
95127
- headers: {
95128
- Authorization: `Bearer ${token}`
95129
- }
95130
- });
95131
- if (!response.ok) {
95132
- return {
95133
- success: false,
95134
- error: `HTTP error ${response.status}: ${response.statusText}`
95135
- };
95136
- }
95137
- const body = response.body;
95138
- if (!body) {
95139
- return {
95140
- success: false,
95141
- error: "No response body"
95142
- };
95143
- }
95144
- const writer = createWriteStream(finalPath);
95145
- const reader = body.getReader();
95146
- try {
95147
- while (true) {
95148
- const { done, value } = await reader.read();
95149
- if (done)
95150
- break;
95151
- writer.write(value);
95152
- }
95153
- writer.end();
95154
- } finally {
95155
- reader.releaseLock();
95156
- }
95157
- await new Promise((resolve, reject) => {
95158
- writer.on("finish", resolve);
95159
- writer.on("error", reject);
95160
- });
95161
- return {
95162
- success: true,
95163
- savedPath: finalPath
95164
- };
95165
- } catch (error) {
95166
- const errorMsg = error instanceof Error ? error.message : String(error);
95167
- return {
95168
- success: false,
95169
- error: errorMsg
95170
- };
95171
- }
95172
- }
95173
- async function getFileInfo(client, fileId) {
95174
- try {
95175
- const result = await client.files.info({ file: fileId });
95176
- if (!result.file) {
95177
- return null;
95178
- }
95179
- const f = result.file;
95180
- return {
95181
- id: f.id,
95182
- name: f.name,
95183
- title: f.title,
95184
- mimetype: f.mimetype,
95185
- filetype: f.filetype,
95186
- size: f.size,
95187
- url_private: f.url_private,
95188
- url_private_download: f.url_private_download,
95189
- thumb_64: f.thumb_64,
95190
- thumb_80: f.thumb_80,
95191
- thumb_160: f.thumb_160,
95192
- thumb_360: f.thumb_360,
95193
- thumb_480: f.thumb_480,
95194
- user: f.user,
95195
- created: f.created
95196
- };
95197
- } catch {
95198
- return null;
95199
- }
95200
- }
95201
95059
  // src/http/core.ts
95202
95060
  init_request_auth_context();
95203
95061
  init_secret_scrubber();
@@ -95421,6 +95279,12 @@ async function resolveHttpRequestAuth(req, apiKey) {
95421
95279
  return { kind: "user", userId: user.id, user };
95422
95280
  }
95423
95281
  }
95282
+ if (bearer.startsWith("aseph_")) {
95283
+ const principal = await resolveBySessionToken(bearer);
95284
+ if (principal) {
95285
+ return { kind: "agent", agentId: principal.agentId, taskId: principal.taskId };
95286
+ }
95287
+ }
95424
95288
  return null;
95425
95289
  }
95426
95290
  function isActiveUser(user) {
@@ -95438,14 +95302,68 @@ init_secret_scrubber();
95438
95302
 
95439
95303
  // src/http/utils.ts
95440
95304
  init_db();
95305
+ init_env_flag();
95441
95306
  init_secret_scrubber();
95307
+ var DEFAULT_ALLOWED_ORIGINS = [
95308
+ "https://*.agent-swarm.dev",
95309
+ "https://*.agent-swarm.cloud",
95310
+ "http://localhost:5274",
95311
+ "http://127.0.0.1:5274",
95312
+ "http://[::1]:5274",
95313
+ "https://ui.swarm.localhost:1355"
95314
+ ];
95315
+ var warnedAboutAllowAnyOrigin = false;
95316
+ function warnIfCorsAllowsAnyOrigin() {
95317
+ if (isEnvFlagEnabled("CORS_ALLOW_ANY_ORIGIN", false) && !warnedAboutAllowAnyOrigin) {
95318
+ warnedAboutAllowAnyOrigin = true;
95319
+ console.warn("[CORS] CORS_ALLOW_ANY_ORIGIN=true: any request origin can receive non-credentialed responses; cookie-authenticated responses still require CORS_ALLOWED_ORIGINS. Set CORS_ALLOWED_ORIGINS and disable CORS_ALLOW_ANY_ORIGIN to restrict access.");
95320
+ }
95321
+ }
95322
+ function getAllowedOrigins() {
95323
+ const raw = process.env.CORS_ALLOWED_ORIGINS;
95324
+ if (!raw || !raw.trim())
95325
+ return DEFAULT_ALLOWED_ORIGINS;
95326
+ return raw.split(",").map((entry) => entry.trim()).filter(Boolean);
95327
+ }
95328
+ function isOriginAllowedForCredentials(origin) {
95329
+ const allowed = getAllowedOrigins().some((entry) => {
95330
+ if (!entry.includes("*"))
95331
+ return entry === origin;
95332
+ const pattern = /^([a-zA-Z][a-zA-Z0-9+.-]*):\/\/\*\.([a-zA-Z0-9.-]+)(:\d+)?$/.exec(entry);
95333
+ const candidate = /^([a-zA-Z][a-zA-Z0-9+.-]*):\/\/([a-zA-Z0-9.-]+)(:\d+)?$/.exec(origin);
95334
+ if (!pattern || !candidate)
95335
+ return false;
95336
+ if (pattern[1] !== candidate[1] || pattern[3] !== candidate[3])
95337
+ return false;
95338
+ const suffix = pattern[2].toLowerCase();
95339
+ const hostname = candidate[2].toLowerCase();
95340
+ const validLabel = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
95341
+ if (![...suffix.split("."), ...hostname.split(".")].every((label) => validLabel.test(label))) {
95342
+ return false;
95343
+ }
95344
+ return hostname.endsWith(`.${suffix}`);
95345
+ });
95346
+ if (!allowed) {
95347
+ console.warn(`[CORS] Denied credentialed origin ${scrubSecrets(JSON.stringify(origin.slice(0, 512)))}; add the trusted SPA origin to CORS_ALLOWED_ORIGINS (custom values replace hosted/dev defaults).`);
95348
+ }
95349
+ return allowed;
95350
+ }
95442
95351
  function setCorsHeaders(req, res) {
95443
95352
  const rawOrigin = req.headers.origin;
95444
95353
  const origin = Array.isArray(rawOrigin) ? rawOrigin[0] : rawOrigin;
95354
+ const allowCredentials = origin ? isOriginAllowedForCredentials(origin) : false;
95355
+ const allowAnyOrigin = isEnvFlagEnabled("CORS_ALLOW_ANY_ORIGIN", false);
95356
+ if (allowAnyOrigin)
95357
+ warnIfCorsAllowsAnyOrigin();
95358
+ if (origin && !allowCredentials && !allowAnyOrigin) {
95359
+ res.setHeader("Vary", "Origin");
95360
+ return;
95361
+ }
95445
95362
  if (origin) {
95446
95363
  res.setHeader("Access-Control-Allow-Origin", origin);
95447
95364
  res.setHeader("Vary", "Origin");
95448
- res.setHeader("Access-Control-Allow-Credentials", "true");
95365
+ if (allowCredentials)
95366
+ res.setHeader("Access-Control-Allow-Credentials", "true");
95449
95367
  const reqHeaders = req.headers["access-control-request-headers"];
95450
95368
  const askedHeaders = Array.isArray(reqHeaders) ? reqHeaders.join(", ") : reqHeaders;
95451
95369
  res.setHeader("Access-Control-Allow-Headers", askedHeaders ?? "Authorization, Content-Type, X-Agent-ID, X-Requested-With");
@@ -95962,7 +95880,7 @@ async function reloadGlobalConfigsAndIntegrations() {
95962
95880
  }
95963
95881
  async function reloadGlobalConfigsAndIntegrationsInner() {
95964
95882
  const updated = await loadGlobalConfigsIntoEnv(true);
95965
- const { resetFileStorageProvider } = await import("./registry-9kdck5ye.js");
95883
+ const { resetFileStorageProvider } = await import("./registry-v5wytg0s.js");
95966
95884
  resetFileStorageProvider();
95967
95885
  const integrations = [];
95968
95886
  resetAgentMail();
@@ -96418,6 +96336,14 @@ var scriptRunNudge = (r) => {
96418
96336
  const body = r.data?.data;
96419
96337
  return !r.ok && body?.error === "timeout" ? SCRIPT_RUN_TIMEOUT_NUDGE : scriptAuthoringNudge(r);
96420
96338
  };
96339
+ var SLACK_API_DISK_NUDGE = "That path is on the API server's disk, not in your container — call this from a task you own (or pass its taskId) to get the file as a task attachment with a fetchCommand.";
96340
+ var slackDownloadFileNudge = (r) => r.ok && r.data?.savedPath ? SLACK_API_DISK_NUDGE : undefined;
96341
+ var slackReadNudge = (r) => {
96342
+ if (!r.ok)
96343
+ return;
96344
+ const messages = r.data?.messages;
96345
+ return messages?.some((m) => m.files?.some((f) => Boolean(f.localPath))) ? SLACK_API_DISK_NUDGE : undefined;
96346
+ };
96421
96347
  var workflowLongScriptTimeoutNudge = (r) => {
96422
96348
  if (!r.ok)
96423
96349
  return;
@@ -96425,6 +96351,7 @@ var workflowLongScriptTimeoutNudge = (r) => {
96425
96351
  return hint ? WORKFLOW_LONG_SCRIPT_TIMEOUT_NUDGE : undefined;
96426
96352
  };
96427
96353
  var NUDGES = {
96354
+ "defer-task": (r) => r.ok ? "Stop working on this task now; the wake-up task will carry your note." : undefined,
96428
96355
  "script-run": scriptRunNudge,
96429
96356
  "script-upsert": scriptAuthoringNudge,
96430
96357
  "launch-script-run": scriptAuthoringNudge,
@@ -96433,6 +96360,8 @@ var NUDGES = {
96433
96360
  "update-workflow": workflowLongScriptTimeoutNudge,
96434
96361
  "patch-workflow": workflowLongScriptTimeoutNudge,
96435
96362
  "patch-workflow-node": workflowLongScriptTimeoutNudge,
96363
+ "slack-download-file": slackDownloadFileNudge,
96364
+ "slack-read": slackReadNudge,
96436
96365
  "script-search": (r) => {
96437
96366
  if (!r.ok)
96438
96367
  return;
@@ -101974,8 +101903,8 @@ var registerCreatePageTool = (server) => {
101974
101903
  key: AssetKeySchema.optional().describe("Logical namespace. Defaults to a shared/page:<id>/ resource key."),
101975
101904
  title: string().min(1).describe("Human-readable title shown in listings."),
101976
101905
  slug: string().min(1).optional().describe("URL slug. Defaults to the kebab-cased title. Same slug → updates the existing row."),
101977
- body: string().min(1).describe("Full page body (HTML document or JSON-render spec, per contentType)."),
101978
- contentType: PageContentTypeSchema.describe("'text/html' renders directly at /p/:id; 'application/json' is rendered by the SPA."),
101906
+ body: string().min(1).describe("Full page body (HTML document, SVG image, or JSON-render spec, per contentType)."),
101907
+ contentType: PageContentTypeSchema.describe("'text/html' and 'image/svg+xml' render directly at /p/:id; 'application/json' is rendered by the SPA."),
101979
101908
  authMode: PageAuthModeSchema.default("authed").describe("'authed' — requires page-session cookie (default); 'public' — no gate and must be explicit; 'password' — requires key."),
101980
101909
  password: string().min(1).optional().describe("Plaintext password, hashed before storage. Only meaningful for authMode='password'."),
101981
101910
  description: string().optional().describe("Optional short description, used in listings + OG-tag unfurl."),
@@ -102674,6 +102603,688 @@ ${result.total} rows in ${result.elapsed}ms`;
102674
102603
  });
102675
102604
  };
102676
102605
 
102606
+ // src/tools/defer-task.ts
102607
+ init_zod();
102608
+ init_db();
102609
+
102610
+ // src/tasks/task-terminal-effects.ts
102611
+ init_db();
102612
+
102613
+ // src/be/memory/raters/retrieval.ts
102614
+ init_db();
102615
+ function dedupeMemoryDocumentIds(memories) {
102616
+ const documents = new Map;
102617
+ for (const memory of memories) {
102618
+ const identity = memory.sourcePath ?? memory.key;
102619
+ if (identity == null)
102620
+ continue;
102621
+ const documentKey = JSON.stringify([memory.agentId, memory.scope, identity]);
102622
+ if (!documents.has(documentKey))
102623
+ documents.set(documentKey, memory.id);
102624
+ }
102625
+ return [...documents.values()];
102626
+ }
102627
+ async function recordMemoryAccesses(memoryIds) {
102628
+ const ids = [...new Set(memoryIds)].filter(Boolean);
102629
+ if (ids.length === 0)
102630
+ return;
102631
+ const now = new Date().toISOString();
102632
+ await getDbClient().transaction(async (tx) => {
102633
+ for (const id of ids) {
102634
+ await tx.run("UPDATE agent_memory SET accessedAt = ?, accessCount = accessCount + 1 WHERE id = ?", [now, id]);
102635
+ }
102636
+ });
102637
+ }
102638
+ async function recordRetrievals(taskId, agentId, results, sessionId, extras) {
102639
+ if (!taskId || results.length === 0)
102640
+ return;
102641
+ const insertSql = `INSERT INTO memory_retrieval
102642
+ (id, taskId, agentId, sessionId, memoryId, similarity, retrievedAt, contextKey, intent, eventType, retrievalId, rank, retrievalSource)
102643
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
102644
+ const now = new Date().toISOString();
102645
+ const retrievalId = crypto.randomUUID();
102646
+ const contextKey = extras?.contextKey ?? null;
102647
+ const intent = extras?.intent ?? null;
102648
+ const eventType = extras?.eventType ?? "search";
102649
+ await getDbClient().transaction(async (tx) => {
102650
+ for (const [rank, r] of results.entries()) {
102651
+ await tx.run(insertSql, [
102652
+ crypto.randomUUID(),
102653
+ taskId,
102654
+ agentId,
102655
+ sessionId ?? null,
102656
+ r.memoryId,
102657
+ r.similarity,
102658
+ now,
102659
+ contextKey,
102660
+ intent,
102661
+ eventType,
102662
+ retrievalId,
102663
+ rank,
102664
+ r.retrievalSource ?? null
102665
+ ]);
102666
+ }
102667
+ });
102668
+ ensure({
102669
+ id: "memory_retrieved",
102670
+ flow: "task",
102671
+ runId: taskId,
102672
+ data: {
102673
+ count: results.length,
102674
+ taskId,
102675
+ agentId
102676
+ },
102677
+ validator: (data) => typeof data.count === "number" && data.count > 0 && typeof data.taskId === "string" && data.taskId.length > 0 && typeof data.agentId === "string" && data.agentId.length > 0
102678
+ });
102679
+ }
102680
+ async function getRetrievalsForTask(taskId) {
102681
+ return getDbClient().query("SELECT memoryId, similarity FROM memory_retrieval WHERE taskId = ?", [taskId]);
102682
+ }
102683
+
102684
+ // src/be/memory/raters/explicit-self.ts
102685
+ class ExplicitSelfRatingRater {
102686
+ name = "explicit-self";
102687
+ async rate() {
102688
+ return [];
102689
+ }
102690
+ }
102691
+
102692
+ // src/be/memory/raters/implicit-citation.ts
102693
+ class ImplicitCitationRater {
102694
+ name = "implicit-citation";
102695
+ async rate(ctx) {
102696
+ if (ctx.retrievedMemoryIds.length === 0)
102697
+ return [];
102698
+ const evidence = ctx.evidence ?? "";
102699
+ const events = [];
102700
+ for (const memoryId of ctx.retrievedMemoryIds) {
102701
+ if (evidence.length > 0 && evidence.includes(memoryId)) {
102702
+ events.push({ memoryId, signal: 1, weight: 0.5, source: "" });
102703
+ } else {
102704
+ events.push({ memoryId, signal: -1, weight: 0.25, source: "" });
102705
+ }
102706
+ }
102707
+ return events;
102708
+ }
102709
+ }
102710
+
102711
+ // src/be/memory/raters/noop.ts
102712
+ class NoopRater {
102713
+ name = "noop";
102714
+ async rate() {
102715
+ return [];
102716
+ }
102717
+ }
102718
+
102719
+ // src/be/memory/raters/registry.ts
102720
+ var FACTORIES = {
102721
+ noop: () => new NoopRater,
102722
+ "implicit-citation": () => new ImplicitCitationRater,
102723
+ "explicit-self": () => new ExplicitSelfRatingRater,
102724
+ llm: () => new LlmRater
102725
+ };
102726
+ var SERVER_RATERS = new Set(["implicit-citation"]);
102727
+ function getRegisteredRaters() {
102728
+ const raw = process.env.MEMORY_RATERS;
102729
+ if (!raw || raw.trim() === "") {
102730
+ return [new NoopRater];
102731
+ }
102732
+ const names = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
102733
+ const raters = [];
102734
+ for (const name of names) {
102735
+ const factory = FACTORIES[name];
102736
+ if (!factory) {
102737
+ console.warn(`[memory-rater] Unknown rater "${name}" in MEMORY_RATERS — skipping`);
102738
+ continue;
102739
+ }
102740
+ raters.push(factory());
102741
+ }
102742
+ if (raters.length === 0) {
102743
+ return [new NoopRater];
102744
+ }
102745
+ return raters;
102746
+ }
102747
+ function getRaterWeightMultiplier(name) {
102748
+ const raw = process.env.MEMORY_RATER_WEIGHTS;
102749
+ if (!raw || raw.trim() === "")
102750
+ return 1;
102751
+ for (const pair of raw.split(",")) {
102752
+ const trimmed = pair.trim();
102753
+ if (trimmed === "")
102754
+ continue;
102755
+ const [rawName, rawMult] = trimmed.split(":");
102756
+ if (!rawName || !rawMult)
102757
+ continue;
102758
+ if (rawName.trim() !== name)
102759
+ continue;
102760
+ const mult = Number(rawMult);
102761
+ if (Number.isFinite(mult) && mult >= 0)
102762
+ return mult;
102763
+ }
102764
+ return 1;
102765
+ }
102766
+
102767
+ // src/be/memory/raters/store.ts
102768
+ init_db();
102769
+ class ExplicitSelfDuplicateError extends Error {
102770
+ event;
102771
+ constructor(message, event) {
102772
+ super(message);
102773
+ this.event = event;
102774
+ this.name = "ExplicitSelfDuplicateError";
102775
+ }
102776
+ }
102777
+ async function applyRating(events, ctx = {}) {
102778
+ if (events.length === 0) {
102779
+ return { applied: 0, rejected: [] };
102780
+ }
102781
+ const accepted = [];
102782
+ const rejected = [];
102783
+ for (const event of events) {
102784
+ const reason = validate(event);
102785
+ if (reason) {
102786
+ rejected.push({ event, reason });
102787
+ continue;
102788
+ }
102789
+ let sanitizedReferencesSource = null;
102790
+ if (event.referencesSource !== undefined) {
102791
+ if (event.referencesSource.length === 0) {
102792
+ rejected.push({ event, reason: "referencesSource must be non-empty" });
102793
+ continue;
102794
+ }
102795
+ if (event.referencesSource.length > REFERENCES_SOURCE_MAX_LENGTH) {
102796
+ rejected.push({
102797
+ event,
102798
+ reason: `referencesSource exceeds ${REFERENCES_SOURCE_MAX_LENGTH} chars`
102799
+ });
102800
+ continue;
102801
+ }
102802
+ sanitizedReferencesSource = sanitizeReferencesSource(event.referencesSource);
102803
+ if (sanitizedReferencesSource === null) {
102804
+ rejected.push({
102805
+ event,
102806
+ reason: "referencesSource contains a NUL byte or strips to empty"
102807
+ });
102808
+ continue;
102809
+ }
102810
+ }
102811
+ accepted.push({ event, sanitizedReferencesSource });
102812
+ }
102813
+ if (accepted.length === 0) {
102814
+ return { applied: 0, rejected };
102815
+ }
102816
+ const UPDATE_MEMORY_SQL = "UPDATE agent_memory SET alpha = alpha + ?, beta = beta + ? WHERE id = ?";
102817
+ const CHECK_EXISTS_SQL = "SELECT id FROM agent_memory WHERE id = ?";
102818
+ const INSERT_RATING_SQL = `INSERT INTO memory_rating
102819
+ (id, memoryId, taskId, source, signal, weight, reasoning, createdAt, contextKey)
102820
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`;
102821
+ const UPSERT_EDGE_SQL = `INSERT INTO agent_memory_edge (from_id, to_id, type, alpha, beta, createdAt)
102822
+ VALUES (?, ?, 'references-source', ?, ?, ?)
102823
+ ON CONFLICT(from_id, to_id, type) DO UPDATE SET
102824
+ alpha = alpha + excluded.alpha - 1.0,
102825
+ beta = beta + excluded.beta - 1.0`;
102826
+ const { applied, lateRejects, appliedEvents } = await getDbClient().transaction(async (tx) => {
102827
+ let applied2 = 0;
102828
+ const lateRejects2 = [];
102829
+ const appliedEvents2 = [];
102830
+ for (const { event, sanitizedReferencesSource } of accepted) {
102831
+ const exists = await tx.get(CHECK_EXISTS_SQL, [event.memoryId]);
102832
+ if (!exists) {
102833
+ lateRejects2.push({ event, reason: "memoryId not found in agent_memory" });
102834
+ continue;
102835
+ }
102836
+ const alphaDelta = Math.max(0, event.signal) * event.weight;
102837
+ const betaDelta = Math.max(0, -event.signal) * event.weight;
102838
+ await tx.run(UPDATE_MEMORY_SQL, [alphaDelta, betaDelta, event.memoryId]);
102839
+ try {
102840
+ await tx.run(INSERT_RATING_SQL, [
102841
+ crypto.randomUUID(),
102842
+ event.memoryId,
102843
+ ctx.taskId ?? null,
102844
+ event.source,
102845
+ event.signal,
102846
+ event.weight,
102847
+ event.reasoning ?? null,
102848
+ new Date().toISOString(),
102849
+ ctx.contextKey ?? null
102850
+ ]);
102851
+ } catch (err) {
102852
+ if (isUniqueConstraintError(err)) {
102853
+ throw new ExplicitSelfDuplicateError(`duplicate explicit-self rating for memoryId=${event.memoryId} taskId=${ctx.taskId}`, event);
102854
+ }
102855
+ throw err;
102856
+ }
102857
+ if (sanitizedReferencesSource !== null) {
102858
+ await tx.run(UPSERT_EDGE_SQL, [
102859
+ event.memoryId,
102860
+ sanitizedReferencesSource,
102861
+ 1 + alphaDelta,
102862
+ 1 + betaDelta,
102863
+ new Date().toISOString()
102864
+ ]);
102865
+ }
102866
+ appliedEvents2.push({ event, sanitizedReferencesSource });
102867
+ applied2 += 1;
102868
+ }
102869
+ return { applied: applied2, lateRejects: lateRejects2, appliedEvents: appliedEvents2 };
102870
+ });
102871
+ if (ctx.taskId && appliedEvents.length > 0) {
102872
+ for (const { event, sanitizedReferencesSource } of appliedEvents) {
102873
+ ensure({
102874
+ id: "memory_rated",
102875
+ flow: "task",
102876
+ runId: ctx.taskId,
102877
+ data: {
102878
+ memoryId: event.memoryId,
102879
+ source: event.source,
102880
+ signal: event.signal,
102881
+ weight: event.weight,
102882
+ hasReferencesSource: sanitizedReferencesSource !== null
102883
+ },
102884
+ validator: (data) => typeof data.memoryId === "string" && data.memoryId.length > 0 && typeof data.source === "string" && data.source.length > 0 && typeof data.signal === "number" && data.signal >= -1 && data.signal <= 1 && typeof data.weight === "number" && data.weight >= 0 && data.weight <= 1
102885
+ });
102886
+ }
102887
+ }
102888
+ return { applied, rejected: [...rejected, ...lateRejects] };
102889
+ }
102890
+ function validate(event) {
102891
+ if (!event.source || event.source.trim() === "") {
102892
+ return "source is required";
102893
+ }
102894
+ if (!Number.isFinite(event.signal) || event.signal < -1 || event.signal > 1) {
102895
+ return "signal must be in [-1, +1]";
102896
+ }
102897
+ if (!Number.isFinite(event.weight) || event.weight < 0 || event.weight > 1) {
102898
+ return "weight must be in [0, 1]";
102899
+ }
102900
+ if (!event.memoryId) {
102901
+ return "memoryId is required";
102902
+ }
102903
+ return null;
102904
+ }
102905
+ function isUniqueConstraintError(err) {
102906
+ if (!(err instanceof Error))
102907
+ return false;
102908
+ return /UNIQUE constraint failed|SQLITE_CONSTRAINT/i.test(err.message);
102909
+ }
102910
+
102911
+ // src/be/memory/raters/run-server-raters.ts
102912
+ async function runServerRaters(input, deps = {}) {
102913
+ const result = { ratersFired: 0, outcomes: [] };
102914
+ if (input.retrievedMemoryIds.length === 0)
102915
+ return result;
102916
+ const allRaters = deps.raters ?? getRegisteredRaters();
102917
+ const allowed = deps.serverRaterNames ?? SERVER_RATERS;
102918
+ const weightFor = deps.weightMultiplierFor ?? getRaterWeightMultiplier;
102919
+ const applyFn = deps.applyRating ?? applyRating;
102920
+ const serverRaters = allRaters.filter((r) => allowed.has(r.name));
102921
+ for (const rater of serverRaters) {
102922
+ const events = await rater.rate({
102923
+ taskId: input.taskId,
102924
+ agentId: input.agentId,
102925
+ retrievedMemoryIds: input.retrievedMemoryIds,
102926
+ evidence: input.evidence
102927
+ });
102928
+ if (events.length === 0)
102929
+ continue;
102930
+ const multiplier = weightFor(rater.name);
102931
+ const stamped = events.map((e) => ({
102932
+ ...e,
102933
+ source: rater.name,
102934
+ weight: Math.max(0, Math.min(1, e.weight * multiplier))
102935
+ }));
102936
+ const applied = await applyFn(stamped, { taskId: input.taskId });
102937
+ result.ratersFired += 1;
102938
+ result.outcomes.push({ rater: rater.name, events: stamped, result: applied });
102939
+ }
102940
+ return result;
102941
+ }
102942
+
102943
+ // src/memory/automatic-task-gate.ts
102944
+ var SCHEDULE_TAG_PREFIX = "schedule:";
102945
+ var AUTOMATIC_TASK_TYPES = new Set([
102946
+ "boot-triage",
102947
+ "heartbeat",
102948
+ "heartbeat-checklist",
102949
+ "health-check",
102950
+ "health-probe",
102951
+ "monitor",
102952
+ "monitoring"
102953
+ ]);
102954
+ function isAutomaticOrRecurringTaskCompletion(task) {
102955
+ const tags = task.tags ?? [];
102956
+ const taskType = task.taskType?.toLowerCase();
102957
+ return task.source === "schedule" || task.source === "system" || tags.includes("scheduled") || tags.includes("auto-generated") || tags.some((tag) => tag.startsWith(SCHEDULE_TAG_PREFIX)) || taskType !== undefined && (AUTOMATIC_TASK_TYPES.has(taskType) || taskType.endsWith("-monitor") || taskType.endsWith("-digest"));
102958
+ }
102959
+ function shouldPersistAutomaticTaskMemory(task, persistMemory) {
102960
+ if (persistMemory)
102961
+ return true;
102962
+ return !isAutomaticOrRecurringTaskCompletion(task);
102963
+ }
102964
+ var shouldPersistTaskCompletionMemory = shouldPersistAutomaticTaskMemory;
102965
+
102966
+ // src/tasks/task-terminal-effects.ts
102967
+ init_secret_scrubber();
102968
+ async function runTaskTerminalEffects(args) {
102969
+ const { task, status, output, failureReason, agentId, persistMemory } = args;
102970
+ const taskId = task.id;
102971
+ if (shouldPersistTaskCompletionMemory(task, persistMemory)) {
102972
+ (async () => {
102973
+ try {
102974
+ const taskContent = status === "completed" ? `Task: ${task.task}
102975
+
102976
+ Output:
102977
+ ${output || "(no output)"}` : `Task: ${task.task}
102978
+
102979
+ Failure reason:
102980
+ ${failureReason || "No reason provided"}
102981
+
102982
+ This task failed. Learn from this to avoid repeating the mistake.`;
102983
+ if (taskContent.length < 30)
102984
+ return;
102985
+ const store = getMemoryStore();
102986
+ const provider = getEmbeddingProvider();
102987
+ const memory = await store.store({
102988
+ agentId: agentId ?? null,
102989
+ content: taskContent,
102990
+ name: `Task: ${task.task.slice(0, 80)}`,
102991
+ scope: "agent",
102992
+ source: "task_completion",
102993
+ sourceTaskId: taskId
102994
+ });
102995
+ const embedding = await provider.embed(taskContent);
102996
+ if (embedding) {
102997
+ await store.updateEmbedding(memory.id, embedding, provider.name);
102998
+ }
102999
+ const shouldShareWithSwarm = status === "completed" && (task.taskType === "research" || task.tags?.includes("knowledge") || task.tags?.includes("shared"));
103000
+ if (shouldShareWithSwarm) {
103001
+ try {
103002
+ const swarmMemory = await store.store({
103003
+ agentId: agentId ?? null,
103004
+ scope: "swarm",
103005
+ name: `Shared: ${task.task.slice(0, 80)}`,
103006
+ content: `Task completed by agent ${agentId}:
103007
+
103008
+ ${taskContent}`,
103009
+ source: "task_completion",
103010
+ sourceTaskId: taskId
103011
+ });
103012
+ const swarmEmbedding = await provider.embed(taskContent);
103013
+ if (swarmEmbedding) {
103014
+ await store.updateEmbedding(swarmMemory.id, swarmEmbedding, provider.name);
103015
+ }
103016
+ } catch {}
103017
+ }
103018
+ } catch {}
103019
+ })().catch((err) => console.error("[task-terminal-effects] task completion memory write failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
103020
+ }
103021
+ (async () => {
103022
+ try {
103023
+ const retrievals = await getRetrievalsForTask(taskId);
103024
+ if (retrievals.length === 0)
103025
+ return;
103026
+ const retrievedMemoryIds = retrievals.map((r) => r.memoryId);
103027
+ const logs = await getSessionLogsByTaskId(taskId);
103028
+ const evidence = logs.map((l) => l.content).join(`
103029
+ `);
103030
+ await runServerRaters({
103031
+ taskId,
103032
+ agentId: agentId ?? "",
103033
+ retrievedMemoryIds,
103034
+ evidence
103035
+ });
103036
+ } catch (err) {
103037
+ console.error("[task-terminal-effects] server-rater fire failed:", err instanceof Error ? err.message : String(err));
103038
+ }
103039
+ })().catch((err) => console.error("[task-terminal-effects] server rater run failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
103040
+ if (!task.workflowRunId) {
103041
+ try {
103042
+ const followUp = await createWorkerTaskFollowUp({ task, status, output, failureReason });
103043
+ if (followUp) {
103044
+ console.log(`[task-terminal-effects] Created follow-up task ${followUp.id.slice(0, 8)} for ${status} task ${taskId.slice(0, 8)}`);
103045
+ }
103046
+ } catch (err) {
103047
+ console.warn(`[task-terminal-effects] Failed to create follow-up task: ${err}`);
103048
+ }
103049
+ }
103050
+ }
103051
+
103052
+ // src/tasks/terminal-result-guard.ts
103053
+ init_db();
103054
+ init_types();
103055
+ init_secret_scrubber();
103056
+ function getTaskOutputValidationError(outputSchema, output) {
103057
+ if (!outputSchema || typeof outputSchema !== "object")
103058
+ return;
103059
+ const schema = outputSchema;
103060
+ if (!output) {
103061
+ return `Task has an outputSchema but no output was provided. You must call store-progress with a valid JSON output matching this schema:
103062
+ ${JSON.stringify(schema, null, 2)}`;
103063
+ }
103064
+ let parsed;
103065
+ try {
103066
+ parsed = JSON.parse(output);
103067
+ } catch {
103068
+ return `Task output must be valid JSON matching the outputSchema. Got invalid JSON. Schema:
103069
+ ${JSON.stringify(schema, null, 2)}`;
103070
+ }
103071
+ let validationErrors;
103072
+ try {
103073
+ validationErrors = validateJsonSchema(schema, parsed);
103074
+ } catch (error) {
103075
+ const detail = error instanceof Error ? error.message : String(error);
103076
+ return `Task outputSchema is malformed and cannot be validated (${detail}). Ask an operator to correct the task's outputSchema, or force-complete with store-progress force: true.`;
103077
+ }
103078
+ if (validationErrors.length > 0) {
103079
+ return `Task output does not match the outputSchema. Errors:
103080
+ ${validationErrors.join(`
103081
+ `)}
103082
+
103083
+ Expected schema:
103084
+ ${JSON.stringify(schema, null, 2)}
103085
+
103086
+ Please fix your output and retry.`;
103087
+ }
103088
+ return;
103089
+ }
103090
+ async function guardTerminalTaskResultWrite(task, write) {
103091
+ if (!isTerminalTaskStatus(task.status) || !write.status && !write.force) {
103092
+ return { handled: false };
103093
+ }
103094
+ const scrubbedOutput = write.output !== undefined ? scrubSecrets(write.output) : undefined;
103095
+ const scrubbedFailureReason = write.failureReason !== undefined ? scrubSecrets(write.failureReason) : undefined;
103096
+ const hasDifferingOutput = scrubbedOutput !== undefined && scrubbedOutput !== task.output;
103097
+ const hasDifferingFailureReason = scrubbedFailureReason !== undefined && scrubbedFailureReason !== task.failureReason;
103098
+ const hasDifferingResultText = hasDifferingOutput || hasDifferingFailureReason;
103099
+ if (hasDifferingResultText && write.force) {
103100
+ const outputValidationError = hasDifferingOutput ? getTaskOutputValidationError(task.outputSchema, write.output) : undefined;
103101
+ if (outputValidationError) {
103102
+ return { handled: true, success: false, message: outputValidationError, task };
103103
+ }
103104
+ const overwrittenTask = await overwriteTerminalTaskResultText(task.id, {
103105
+ ...write.output !== undefined ? { output: write.output } : {},
103106
+ ...write.failureReason !== undefined ? { failureReason: write.failureReason } : {}
103107
+ });
103108
+ if (!overwrittenTask) {
103109
+ return {
103110
+ handled: true,
103111
+ success: false,
103112
+ message: `Task "${task.id}" terminal result text could not be overwritten.`,
103113
+ task
103114
+ };
103115
+ }
103116
+ return {
103117
+ handled: true,
103118
+ success: true,
103119
+ message: `Task "${task.id}" is already ${task.status}; force-overwrote terminal result text ` + "without replaying completion side effects.",
103120
+ task: overwrittenTask,
103121
+ wasForcedOverwrite: true
103122
+ };
103123
+ }
103124
+ if (hasDifferingResultText) {
103125
+ return {
103126
+ handled: true,
103127
+ success: false,
103128
+ message: `Discarded write for already-${task.status} task "${task.id}"; ` + "existing output/failureReason and finishedAt were preserved. Retry with force: true " + "to overwrite terminal result text without replaying completion side effects.",
103129
+ task
103130
+ };
103131
+ }
103132
+ return {
103133
+ handled: true,
103134
+ success: true,
103135
+ message: `Task "${task.id}" is already ${task.status}; treating as no-op. ` + "Existing output preserved (first-call-wins).",
103136
+ task,
103137
+ wasNoOp: true
103138
+ };
103139
+ }
103140
+
103141
+ // src/tools/defer-task.ts
103142
+ init_types();
103143
+
103144
+ class DeferAbortedError extends Error {
103145
+ }
103146
+ function renderChecks(checks2) {
103147
+ if (!checks2 || checks2.length === 0)
103148
+ return "";
103149
+ return `
103150
+
103151
+ Checks:
103152
+ ${checks2.map((c) => `- ${c}`).join(`
103153
+ `)}`;
103154
+ }
103155
+ var registerDeferTaskTool = (server) => {
103156
+ createToolRegistrar(server)("defer-task", {
103157
+ title: "Defer Task",
103158
+ annotations: { destructiveHint: false, idempotentHint: false },
103159
+ description: "Completes this task now with status `completed` and books a wake-up for you. Use when the result needs time: a build, a deploy, a reply. The task reaches its final state on this call; the lead sees your summary as its output. A one-off schedule wakes you up later with a child task that carries this task as its parent. Provide delayMs or runAt, a summary of what you did, and a note that says what is pending and what to check.",
103160
+ inputSchema: object({
103161
+ taskId: string().describe("The ID of the task you are working on."),
103162
+ delayMs: number().int().positive().optional().describe("Wake up after this many milliseconds (e.g. 1800000 for 30 min)."),
103163
+ runAt: string().datetime().optional().describe("Wake up at this ISO datetime (e.g. '2026-03-06T15:00:00Z'). Must be future."),
103164
+ summary: string().min(1).max(4000).describe("What you did so far and where things stand. This becomes the task's output; the lead and your wake-up run both read it."),
103165
+ note: string().min(1).max(2000).describe("What is pending, and what to check on wake-up."),
103166
+ checks: array(string().min(1)).max(20).optional().describe("Concrete things to verify on wake-up, one per entry.")
103167
+ }),
103168
+ outputSchema: swarmToolOutputSchema({
103169
+ yourAgentId: string().optional(),
103170
+ taskId: string().optional(),
103171
+ scheduleId: string().optional(),
103172
+ nextRunAt: string().optional()
103173
+ })
103174
+ }, async ({ taskId, delayMs, runAt, summary, note, checks: checks2 }, requestInfo, _meta) => {
103175
+ if (!requestInfo.agentId) {
103176
+ return toolErr('Agent ID not found. Set the "X-Agent-ID" header.');
103177
+ }
103178
+ const agent = await getAgentById(requestInfo.agentId);
103179
+ if (!agent) {
103180
+ return toolErr(`Agent not found: ${requestInfo.agentId}`);
103181
+ }
103182
+ const task = await getTaskById(taskId);
103183
+ if (!task) {
103184
+ return toolErr(`Task with ID "${taskId}" not found.`);
103185
+ }
103186
+ const forbidden = assertOwnsTask(ownerCtx(requestInfo), task);
103187
+ if (forbidden)
103188
+ return forbidden;
103189
+ if (task.agentId !== requestInfo.agentId) {
103190
+ return toolErr(`Task "${taskId}" is not assigned to you.`);
103191
+ }
103192
+ if (isTerminalTaskStatus(task.status)) {
103193
+ return toolErr(`Task ${taskId} is already ${task.status}; nothing to defer.`);
103194
+ }
103195
+ if (task.workflowRunId) {
103196
+ return toolErr(`Task ${taskId} is owned by workflow run ${task.workflowRunId}; workflow-owned tasks cannot be deferred.`);
103197
+ }
103198
+ if (!delayMs && !runAt) {
103199
+ return toolErr("Provide either delayMs or runAt.");
103200
+ }
103201
+ if (delayMs && runAt) {
103202
+ return toolErr("Provide either delayMs or runAt, not both.");
103203
+ }
103204
+ if (runAt && new Date(runAt).getTime() <= Date.now()) {
103205
+ return toolErr("runAt must be in the future.");
103206
+ }
103207
+ const nextRunAt = delayMs ? new Date(Date.now() + delayMs).toISOString() : runAt;
103208
+ const checksBlock = renderChecks(checks2);
103209
+ const taskTemplate = `Resume task ${taskId}: ${note}${checksBlock}`;
103210
+ const createdBy = await resolveTaskAuditUserId(requestInfo.sourceTaskId, requestInfo.agentId) ?? undefined;
103211
+ const previewOutput = `${summary}
103212
+
103213
+ Deferred until ${nextRunAt} (schedule pending). Pending: ${note}${checksBlock}`;
103214
+ const outputValidationError = getTaskOutputValidationError(task.outputSchema, previewOutput);
103215
+ if (outputValidationError) {
103216
+ return toolErr(`Task ${taskId} has an outputSchema; its terminal output must satisfy it, but a deferral note cannot. ${outputValidationError}`);
103217
+ }
103218
+ try {
103219
+ const committed = await getDbClient().transaction(async () => {
103220
+ const schedule = await createScheduledTask({
103221
+ name: `deferred-${taskId.slice(0, 8)}-${Date.now()}-${crypto.randomUUID()}`,
103222
+ description: note,
103223
+ taskTemplate,
103224
+ targetType: "agent-task",
103225
+ scheduleType: "one_time",
103226
+ nextRunAt,
103227
+ targetAgentId: requestInfo.agentId,
103228
+ createdByAgentId: requestInfo.agentId,
103229
+ taskType: "deferred",
103230
+ tags: ["deferred"],
103231
+ priority: task.priority,
103232
+ modelTier: task.modelTier,
103233
+ parentTaskId: taskId,
103234
+ createdBy
103235
+ });
103236
+ const output = `${summary}
103237
+
103238
+ Deferred until ${nextRunAt} (schedule ${schedule.id}). Pending: ${note}${checksBlock}`;
103239
+ const completed = await completeTask(taskId, output);
103240
+ if (!completed) {
103241
+ throw new DeferAbortedError(`Task ${taskId} reached a terminal state before this deferral committed.`);
103242
+ }
103243
+ getDbClient().afterCommit(() => {
103244
+ ensure({
103245
+ id: "completed",
103246
+ flow: "task",
103247
+ runId: taskId,
103248
+ depIds: task.wasPaused ? ["started", "resumed"] : ["started"],
103249
+ data: {
103250
+ taskId,
103251
+ agentId: task.agentId,
103252
+ previousStatus: task.status,
103253
+ hasOutput: true
103254
+ },
103255
+ validator: (data) => data.previousStatus === "in_progress",
103256
+ filter: ({}, ctx) => ctx.deps.length > 0,
103257
+ conditions: [{ timeout_ms: 3600000 }]
103258
+ });
103259
+ });
103260
+ if (task.agentId) {
103261
+ await updateAgentStatusFromCapacity(task.agentId);
103262
+ }
103263
+ return { scheduleId: schedule.id, output, completed };
103264
+ });
103265
+ await runTaskTerminalEffects({
103266
+ task: committed.completed,
103267
+ status: "completed",
103268
+ output: committed.output,
103269
+ agentId: requestInfo.agentId
103270
+ });
103271
+ return toolOk(`Task ${taskId} completed and deferred. Wake-up at ${nextRunAt} (schedule ${committed.scheduleId}). This task is final; the wake-up task continues the work.`, {
103272
+ data: {
103273
+ yourAgentId: requestInfo.agentId,
103274
+ taskId,
103275
+ scheduleId: committed.scheduleId,
103276
+ nextRunAt
103277
+ }
103278
+ });
103279
+ } catch (error) {
103280
+ const message = error instanceof Error ? error.message : "Unknown error";
103281
+ return toolErr(`Failed to defer task: ${message}`, {
103282
+ data: { yourAgentId: requestInfo.agentId, taskId }
103283
+ });
103284
+ }
103285
+ });
103286
+ };
103287
+
102677
103288
  // src/tools/delete-channel.ts
102678
103289
  init_zod();
102679
103290
  init_db();
@@ -104837,77 +105448,6 @@ async function getLinksForMemory(memoryId, options = {}) {
104837
105448
  return { links, backlinks };
104838
105449
  }
104839
105450
 
104840
- // src/be/memory/raters/retrieval.ts
104841
- init_db();
104842
- function dedupeMemoryDocumentIds(memories) {
104843
- const documents = new Map;
104844
- for (const memory of memories) {
104845
- const identity = memory.sourcePath ?? memory.key;
104846
- if (identity == null)
104847
- continue;
104848
- const documentKey = JSON.stringify([memory.agentId, memory.scope, identity]);
104849
- if (!documents.has(documentKey))
104850
- documents.set(documentKey, memory.id);
104851
- }
104852
- return [...documents.values()];
104853
- }
104854
- async function recordMemoryAccesses(memoryIds) {
104855
- const ids = [...new Set(memoryIds)].filter(Boolean);
104856
- if (ids.length === 0)
104857
- return;
104858
- const now = new Date().toISOString();
104859
- await getDbClient().transaction(async (tx) => {
104860
- for (const id of ids) {
104861
- await tx.run("UPDATE agent_memory SET accessedAt = ?, accessCount = accessCount + 1 WHERE id = ?", [now, id]);
104862
- }
104863
- });
104864
- }
104865
- async function recordRetrievals(taskId, agentId, results, sessionId, extras) {
104866
- if (!taskId || results.length === 0)
104867
- return;
104868
- const insertSql = `INSERT INTO memory_retrieval
104869
- (id, taskId, agentId, sessionId, memoryId, similarity, retrievedAt, contextKey, intent, eventType, retrievalId, rank, retrievalSource)
104870
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
104871
- const now = new Date().toISOString();
104872
- const retrievalId = crypto.randomUUID();
104873
- const contextKey = extras?.contextKey ?? null;
104874
- const intent = extras?.intent ?? null;
104875
- const eventType = extras?.eventType ?? "search";
104876
- await getDbClient().transaction(async (tx) => {
104877
- for (const [rank, r] of results.entries()) {
104878
- await tx.run(insertSql, [
104879
- crypto.randomUUID(),
104880
- taskId,
104881
- agentId,
104882
- sessionId ?? null,
104883
- r.memoryId,
104884
- r.similarity,
104885
- now,
104886
- contextKey,
104887
- intent,
104888
- eventType,
104889
- retrievalId,
104890
- rank,
104891
- r.retrievalSource ?? null
104892
- ]);
104893
- }
104894
- });
104895
- ensure({
104896
- id: "memory_retrieved",
104897
- flow: "task",
104898
- runId: taskId,
104899
- data: {
104900
- count: results.length,
104901
- taskId,
104902
- agentId
104903
- },
104904
- validator: (data) => typeof data.count === "number" && data.count > 0 && typeof data.taskId === "string" && data.taskId.length > 0 && typeof data.agentId === "string" && data.agentId.length > 0
104905
- });
104906
- }
104907
- async function getRetrievalsForTask(taskId) {
104908
- return getDbClient().query("SELECT memoryId, similarity FROM memory_retrieval WHERE taskId = ?", [taskId]);
104909
- }
104910
-
104911
105451
  // src/tools/memory-get.ts
104912
105452
  init_types();
104913
105453
  var NUDGE_ELIGIBLE_SOURCES = new Set(["manual", "file_index"]);
@@ -107062,7 +107602,7 @@ var registerUpdateRepoTool = (server) => {
107062
107602
  defaultBranch: string().optional().describe("New default branch."),
107063
107603
  autoClone: boolean().optional().describe("Whether to auto-clone."),
107064
107604
  hooks: RepoHooksSchema.nullable().optional().describe("Repository hook install config. Set { enabled: true } to opt into best-effort worker hook installation, or null to disable."),
107065
- guidelines: RepoGuidelinesSchema.nullable().optional().describe("Repository guidelines: prChecks (commands before PR), mergeChecks (conditions before merge), allowMerge (default false), review (guidance for reviewers). Pass null to clear.")
107605
+ guidelines: RepoGuidelinesInputSchema.nullable().optional().describe("Repository guidelines: prChecks (commands before PR), mergeChecks (conditions before merge), allowMerge (default false), review (guidance for reviewers). Pass null to clear.")
107066
107606
  }),
107067
107607
  outputSchema: swarmToolOutputSchema({
107068
107608
  repo: swarmRepoOutputShape2.nullable().optional()
@@ -113654,6 +114194,7 @@ var scheduleDataShape = {
113654
114194
  lastRunAt: string().optional(),
113655
114195
  nextRunAt: string().optional(),
113656
114196
  createdByAgentId: string().optional(),
114197
+ parentTaskId: string().optional(),
113657
114198
  timezone: string().optional(),
113658
114199
  model: string().optional(),
113659
114200
  modelTier: ModelTierSchema.optional(),
@@ -114066,6 +114607,7 @@ var scheduleRowShape = {
114066
114607
  lastRunAt: string().optional(),
114067
114608
  nextRunAt: string().optional(),
114068
114609
  createdByAgentId: string().optional(),
114610
+ parentTaskId: string().optional(),
114069
114611
  timezone: string().optional(),
114070
114612
  consecutiveErrors: number().optional(),
114071
114613
  lastErrorAt: string().optional(),
@@ -114204,6 +114746,7 @@ var scheduleDataShape2 = {
114204
114746
  lastRunAt: string().optional(),
114205
114747
  nextRunAt: string().optional(),
114206
114748
  createdByAgentId: string().optional(),
114749
+ parentTaskId: string().optional(),
114207
114750
  timezone: string().optional(),
114208
114751
  model: string().optional(),
114209
114752
  modelTier: ModelTierSchema.optional(),
@@ -114490,6 +115033,7 @@ var scheduleDataShape3 = {
114490
115033
  lastRunAt: string().optional(),
114491
115034
  nextRunAt: string().optional(),
114492
115035
  createdByAgentId: string().optional(),
115036
+ parentTaskId: string().optional(),
114493
115037
  timezone: string().optional(),
114494
115038
  model: string().optional(),
114495
115039
  modelTier: ModelTierSchema.optional(),
@@ -117046,19 +117590,26 @@ var registerSlackDeleteTool = (server) => {
117046
117590
  // src/tools/slack-download-file.ts
117047
117591
  init_zod();
117048
117592
  init_db();
117593
+ function fileIdFromUrl(url) {
117594
+ return /\/files-pri\/[A-Z0-9]+-([A-Z0-9]+)\//.exec(url)?.[1];
117595
+ }
117049
117596
  var registerSlackDownloadFileTool = (server) => {
117050
117597
  createToolRegistrar(server)("slack-download-file", {
117051
117598
  title: "Download file from Slack",
117052
- description: "Download a file from Slack by file ID or URL. Files are saved to the agent's download directory on the shared disk by default.",
117053
- annotations: { readOnlyHint: true, openWorldHint: true },
117599
+ description: "Download a file from Slack by file ID or URL. From a task, the file is stored as an attachment of that task and the result carries a ready-to-run `fetchCommand` to get the bytes into your container. Without a task, the file is saved on the API server's disk, which your container usually can't read.",
117600
+ annotations: { readOnlyHint: false, openWorldHint: true },
117054
117601
  inputSchema: object({
117055
117602
  fileId: string().optional().describe("The Slack file ID to download (e.g., 'F0RDC39U1')."),
117056
117603
  url: string().url().optional().describe("Direct URL to download (url_private_download from a file object)."),
117057
- savePath: string().optional().describe("Where to save the file. Can be a directory or full path. Defaults to /workspace/shared/downloads/{agentId}/slack/"),
117604
+ taskId: uuid().optional().describe("Task to attach the file to. Defaults to the task you are working on; must be a task you own or created."),
117605
+ savePath: string().optional().describe("Only without a task: where to save the file on the API server (directory or full path). Defaults to /workspace/shared/downloads/{agentId}/slack/."),
117058
117606
  filename: string().optional().describe("Filename to use when saving. Only used if savePath is a directory.")
117059
117607
  }),
117060
117608
  outputSchema: swarmToolOutputSchema({
117061
- savedPath: string().optional(),
117609
+ taskId: string().optional(),
117610
+ attachmentId: string().optional(),
117611
+ fetchCommand: string().optional(),
117612
+ savedPath: string().optional().describe("Only without a task: the path on the API server's disk, not in your container."),
117062
117613
  fileInfo: looseObject({
117063
117614
  id: string().optional(),
117064
117615
  name: string().optional(),
@@ -117066,7 +117617,7 @@ var registerSlackDownloadFileTool = (server) => {
117066
117617
  size: number().optional()
117067
117618
  }).optional()
117068
117619
  })
117069
- }, async ({ fileId, url, savePath, filename }, requestInfo, _meta) => {
117620
+ }, async ({ fileId, url, taskId, savePath, filename }, requestInfo, _meta) => {
117070
117621
  if (!requestInfo.agentId) {
117071
117622
  return toolErr("Agent ID not found.");
117072
117623
  }
@@ -117085,22 +117636,33 @@ var registerSlackDownloadFileTool = (server) => {
117085
117636
  if (!token) {
117086
117637
  return toolErr("Slack bot token not configured.");
117087
117638
  }
117639
+ const task = await attachableTask(agent.id, taskId ?? requestInfo.sourceTaskId);
117640
+ if (taskId && !task) {
117641
+ return toolErr("You don't have context for this task.");
117642
+ }
117088
117643
  try {
117089
- let downloadUrl = url;
117090
- let fileInfo;
117091
- if (fileId) {
117092
- const info = await getFileInfo(app.client, fileId);
117644
+ const id2 = fileId ?? (url ? fileIdFromUrl(url) : undefined);
117645
+ const info = id2 ? await getFileInfo(app.client, id2) : null;
117646
+ if (fileId && !info) {
117647
+ return toolErr(`File not found: ${fileId}`);
117648
+ }
117649
+ const fileInfo = info ? { id: info.id, name: info.name, mimetype: info.mimetype, size: info.size } : undefined;
117650
+ if (task) {
117093
117651
  if (!info) {
117094
- return toolErr(`File not found: ${fileId}`);
117652
+ return toolErr("Could not identify the Slack file in that URL; pass fileId instead.");
117095
117653
  }
117096
- downloadUrl = info.url_private_download;
117097
- fileInfo = {
117098
- id: info.id,
117099
- name: info.name,
117100
- mimetype: info.mimetype,
117101
- size: info.size
117102
- };
117654
+ const outcome = (await attachSlackFilesForAgent(app.client, task, [info], agent.id)).get(info.id);
117655
+ if (!outcome || "reason" in outcome) {
117656
+ return toolErr(`Failed to attach file: ${outcome?.reason ?? "unknown error"}`);
117657
+ }
117658
+ const { attachment, fetchCommand } = outcome;
117659
+ return toolOk(`Attached ${attachment.name} to task ${task.id} (attachment ${attachment.id}).`, {
117660
+ details: `Get it into your container with:
117661
+ ${fetchCommand}`,
117662
+ data: { taskId: task.id, attachmentId: attachment.id, fetchCommand, fileInfo }
117663
+ });
117103
117664
  }
117665
+ const downloadUrl = info?.url_private_download ?? url;
117104
117666
  if (!downloadUrl) {
117105
117667
  return toolErr("No download URL available.");
117106
117668
  }
@@ -117117,8 +117679,9 @@ var registerSlackDownloadFileTool = (server) => {
117117
117679
  if (!result.success) {
117118
117680
  return toolErr(`Failed to download file: ${result.error}`);
117119
117681
  }
117120
- const successMsg = `File downloaded successfully to ${result.savedPath}`;
117121
- return toolOk(successMsg, { data: { savedPath: result.savedPath, fileInfo } });
117682
+ return toolOk(`File saved on the API server at ${result.savedPath}.`, {
117683
+ data: { savedPath: result.savedPath, fileInfo }
117684
+ });
117122
117685
  } catch (error) {
117123
117686
  const errorMsg = error instanceof Error ? error.message : String(error);
117124
117687
  return toolErr(`Failed to download file: ${errorMsg}`);
@@ -117389,7 +117952,10 @@ var SlackFileSchema = looseObject({
117389
117952
  filetype: string().optional(),
117390
117953
  size: number().optional(),
117391
117954
  url_private_download: string().optional(),
117392
- localPath: string().optional()
117955
+ attachmentId: string().optional(),
117956
+ fetchCommand: string().optional(),
117957
+ notAttached: string().optional(),
117958
+ localPath: string().optional().describe("Only without a task: the path on the API server's disk, not in your container.")
117393
117959
  });
117394
117960
  var SlackMessageSchema = looseObject({
117395
117961
  user: string().optional(),
@@ -117402,15 +117968,15 @@ var SlackMessageSchema = looseObject({
117402
117968
  var registerSlackReadTool = (server) => {
117403
117969
  createToolRegistrar(server)("slack-read", {
117404
117970
  title: "Read Slack thread/channel history",
117405
- description: "Read messages from a Slack thread or channel. Use inboxMessageId or taskId to read from a thread you have context for, or provide channelId directly for channel history (leads only).",
117406
- annotations: { readOnlyHint: true, openWorldHint: true },
117971
+ description: "Read messages from a Slack thread or channel. Use inboxMessageId or taskId to read from a thread you have context for, or provide channelId directly for channel history (leads only). From a task, files in the messages are stored as attachments of that task, each with a ready-to-run `fetchCommand`.",
117972
+ annotations: { readOnlyHint: false, openWorldHint: true },
117407
117973
  inputSchema: object({
117408
117974
  inboxMessageId: uuid().optional().describe("Read thread history for an inbox message."),
117409
117975
  taskId: uuid().optional().describe("Read thread history for a task."),
117410
117976
  channelId: string().optional().describe("Slack channel ID to read from (requires lead privileges)."),
117411
117977
  threadTs: string().optional().describe("Thread timestamp (required with channelId for thread history)."),
117412
117978
  limit: number().int().min(1).max(100).default(20).describe("Maximum number of messages to retrieve (default: 20, max: 100)."),
117413
- includeFiles: boolean().default(true).describe("Include file attachments in the response (default: true).")
117979
+ includeFiles: boolean().default(true).describe("Include file attachments in the response (default: true). From a task, they are also stored as attachments of that task.")
117414
117980
  }),
117415
117981
  outputSchema: swarmToolOutputSchema({
117416
117982
  channelId: string().optional(),
@@ -117427,6 +117993,7 @@ var registerSlackReadTool = (server) => {
117427
117993
  }
117428
117994
  let slackChannelId = channelId;
117429
117995
  let slackThreadTs = threadTs;
117996
+ let contextTask = null;
117430
117997
  if (inboxMessageId) {
117431
117998
  const inboxMsg = await getInboxMessageById(inboxMessageId);
117432
117999
  if (!inboxMsg) {
@@ -117447,6 +118014,7 @@ var registerSlackReadTool = (server) => {
117447
118014
  }
117448
118015
  slackChannelId = task.slackChannelId;
117449
118016
  slackThreadTs = task.slackThreadTs;
118017
+ contextTask = task;
117450
118018
  } else if (channelId) {
117451
118019
  const decision = can({
117452
118020
  principal: { kind: "agent", agentId: agent.id, isLead: agent.isLead },
@@ -117500,6 +118068,11 @@ var registerSlackReadTool = (server) => {
117500
118068
  }
117501
118069
  }
117502
118070
  const token = process.env.SLACK_BOT_TOKEN;
118071
+ const attachTo = contextTask ?? await attachableTask(agent.id, taskId ?? requestInfo.sourceTaskId);
118072
+ if (taskId && !attachTo) {
118073
+ return toolErr("You don't have context for this task.", { data: { messages: [] } });
118074
+ }
118075
+ const toAttach = [];
117503
118076
  const messages = [];
117504
118077
  for (const m of rawMessages) {
117505
118078
  const extractedText = extractSlackMessageText(m);
@@ -117524,7 +118097,9 @@ var registerSlackReadTool = (server) => {
117524
118097
  size: f.size,
117525
118098
  url_private_download: f.url_private_download
117526
118099
  };
117527
- if (token && f.url_private_download) {
118100
+ if (attachTo) {
118101
+ toAttach.push({ raw: f, info: fileInfo });
118102
+ } else if (token && f.url_private_download) {
117528
118103
  const savePath = `${AUTO_DOWNLOAD_DIR}/${f.id}_${f.name}`;
117529
118104
  try {
117530
118105
  const downloadResult = await downloadFile({
@@ -117549,13 +118124,29 @@ var registerSlackReadTool = (server) => {
117549
118124
  files
117550
118125
  });
117551
118126
  }
118127
+ if (attachTo && toAttach.length > 0) {
118128
+ const outcomes = await attachSlackFilesForAgent(client, attachTo, toAttach.map(({ raw }) => raw), agent.id);
118129
+ for (const { info } of toAttach) {
118130
+ const outcome = outcomes.get(info.id);
118131
+ if (outcome && "attachment" in outcome) {
118132
+ info.attachmentId = outcome.attachment.id;
118133
+ info.fetchCommand = outcome.fetchCommand;
118134
+ } else {
118135
+ info.notAttached = outcome?.reason ?? "not downloaded";
118136
+ }
118137
+ }
118138
+ }
117552
118139
  const textOutput = messages.map((m) => {
117553
118140
  let text = `[${m.username || m.user || "Unknown"}]: ${m.text}`;
117554
118141
  if (m.files && m.files.length > 0) {
117555
118142
  const fileList = m.files.map((f) => {
117556
118143
  let line = ` - ${f.name} (${f.mimetype}, ${Math.round(f.size / 1024)} KB)`;
117557
- if (f.localPath) {
117558
- line += ` [Downloaded: ${f.localPath}]`;
118144
+ if (f.fetchCommand) {
118145
+ line += ` [Task attachment ${f.attachmentId}: ${f.fetchCommand}]`;
118146
+ } else if (f.notAttached) {
118147
+ line += ` [Not attached: ${f.notAttached}]`;
118148
+ } else if (f.localPath) {
118149
+ line += ` [Downloaded on the API server: ${f.localPath}]`;
117559
118150
  }
117560
118151
  return line;
117561
118152
  }).join(`
@@ -118168,379 +118759,6 @@ var registerSteerTaskTool = (server) => {
118168
118759
  // src/tools/store-progress.ts
118169
118760
  init_zod();
118170
118761
  init_db();
118171
-
118172
- // src/be/memory/raters/explicit-self.ts
118173
- class ExplicitSelfRatingRater {
118174
- name = "explicit-self";
118175
- async rate() {
118176
- return [];
118177
- }
118178
- }
118179
-
118180
- // src/be/memory/raters/implicit-citation.ts
118181
- class ImplicitCitationRater {
118182
- name = "implicit-citation";
118183
- async rate(ctx) {
118184
- if (ctx.retrievedMemoryIds.length === 0)
118185
- return [];
118186
- const evidence = ctx.evidence ?? "";
118187
- const events = [];
118188
- for (const memoryId of ctx.retrievedMemoryIds) {
118189
- if (evidence.length > 0 && evidence.includes(memoryId)) {
118190
- events.push({ memoryId, signal: 1, weight: 0.5, source: "" });
118191
- } else {
118192
- events.push({ memoryId, signal: -1, weight: 0.25, source: "" });
118193
- }
118194
- }
118195
- return events;
118196
- }
118197
- }
118198
-
118199
- // src/be/memory/raters/noop.ts
118200
- class NoopRater {
118201
- name = "noop";
118202
- async rate() {
118203
- return [];
118204
- }
118205
- }
118206
-
118207
- // src/be/memory/raters/registry.ts
118208
- var FACTORIES = {
118209
- noop: () => new NoopRater,
118210
- "implicit-citation": () => new ImplicitCitationRater,
118211
- "explicit-self": () => new ExplicitSelfRatingRater,
118212
- llm: () => new LlmRater
118213
- };
118214
- var SERVER_RATERS = new Set(["implicit-citation"]);
118215
- function getRegisteredRaters() {
118216
- const raw = process.env.MEMORY_RATERS;
118217
- if (!raw || raw.trim() === "") {
118218
- return [new NoopRater];
118219
- }
118220
- const names = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
118221
- const raters = [];
118222
- for (const name of names) {
118223
- const factory = FACTORIES[name];
118224
- if (!factory) {
118225
- console.warn(`[memory-rater] Unknown rater "${name}" in MEMORY_RATERS — skipping`);
118226
- continue;
118227
- }
118228
- raters.push(factory());
118229
- }
118230
- if (raters.length === 0) {
118231
- return [new NoopRater];
118232
- }
118233
- return raters;
118234
- }
118235
- function getRaterWeightMultiplier(name) {
118236
- const raw = process.env.MEMORY_RATER_WEIGHTS;
118237
- if (!raw || raw.trim() === "")
118238
- return 1;
118239
- for (const pair of raw.split(",")) {
118240
- const trimmed = pair.trim();
118241
- if (trimmed === "")
118242
- continue;
118243
- const [rawName, rawMult] = trimmed.split(":");
118244
- if (!rawName || !rawMult)
118245
- continue;
118246
- if (rawName.trim() !== name)
118247
- continue;
118248
- const mult = Number(rawMult);
118249
- if (Number.isFinite(mult) && mult >= 0)
118250
- return mult;
118251
- }
118252
- return 1;
118253
- }
118254
-
118255
- // src/be/memory/raters/store.ts
118256
- init_db();
118257
- class ExplicitSelfDuplicateError extends Error {
118258
- event;
118259
- constructor(message, event) {
118260
- super(message);
118261
- this.event = event;
118262
- this.name = "ExplicitSelfDuplicateError";
118263
- }
118264
- }
118265
- async function applyRating(events, ctx = {}) {
118266
- if (events.length === 0) {
118267
- return { applied: 0, rejected: [] };
118268
- }
118269
- const accepted = [];
118270
- const rejected = [];
118271
- for (const event of events) {
118272
- const reason = validate(event);
118273
- if (reason) {
118274
- rejected.push({ event, reason });
118275
- continue;
118276
- }
118277
- let sanitizedReferencesSource = null;
118278
- if (event.referencesSource !== undefined) {
118279
- if (event.referencesSource.length === 0) {
118280
- rejected.push({ event, reason: "referencesSource must be non-empty" });
118281
- continue;
118282
- }
118283
- if (event.referencesSource.length > REFERENCES_SOURCE_MAX_LENGTH) {
118284
- rejected.push({
118285
- event,
118286
- reason: `referencesSource exceeds ${REFERENCES_SOURCE_MAX_LENGTH} chars`
118287
- });
118288
- continue;
118289
- }
118290
- sanitizedReferencesSource = sanitizeReferencesSource(event.referencesSource);
118291
- if (sanitizedReferencesSource === null) {
118292
- rejected.push({
118293
- event,
118294
- reason: "referencesSource contains a NUL byte or strips to empty"
118295
- });
118296
- continue;
118297
- }
118298
- }
118299
- accepted.push({ event, sanitizedReferencesSource });
118300
- }
118301
- if (accepted.length === 0) {
118302
- return { applied: 0, rejected };
118303
- }
118304
- const UPDATE_MEMORY_SQL = "UPDATE agent_memory SET alpha = alpha + ?, beta = beta + ? WHERE id = ?";
118305
- const CHECK_EXISTS_SQL = "SELECT id FROM agent_memory WHERE id = ?";
118306
- const INSERT_RATING_SQL = `INSERT INTO memory_rating
118307
- (id, memoryId, taskId, source, signal, weight, reasoning, createdAt, contextKey)
118308
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`;
118309
- const UPSERT_EDGE_SQL = `INSERT INTO agent_memory_edge (from_id, to_id, type, alpha, beta, createdAt)
118310
- VALUES (?, ?, 'references-source', ?, ?, ?)
118311
- ON CONFLICT(from_id, to_id, type) DO UPDATE SET
118312
- alpha = alpha + excluded.alpha - 1.0,
118313
- beta = beta + excluded.beta - 1.0`;
118314
- const { applied, lateRejects, appliedEvents } = await getDbClient().transaction(async (tx) => {
118315
- let applied2 = 0;
118316
- const lateRejects2 = [];
118317
- const appliedEvents2 = [];
118318
- for (const { event, sanitizedReferencesSource } of accepted) {
118319
- const exists = await tx.get(CHECK_EXISTS_SQL, [event.memoryId]);
118320
- if (!exists) {
118321
- lateRejects2.push({ event, reason: "memoryId not found in agent_memory" });
118322
- continue;
118323
- }
118324
- const alphaDelta = Math.max(0, event.signal) * event.weight;
118325
- const betaDelta = Math.max(0, -event.signal) * event.weight;
118326
- await tx.run(UPDATE_MEMORY_SQL, [alphaDelta, betaDelta, event.memoryId]);
118327
- try {
118328
- await tx.run(INSERT_RATING_SQL, [
118329
- crypto.randomUUID(),
118330
- event.memoryId,
118331
- ctx.taskId ?? null,
118332
- event.source,
118333
- event.signal,
118334
- event.weight,
118335
- event.reasoning ?? null,
118336
- new Date().toISOString(),
118337
- ctx.contextKey ?? null
118338
- ]);
118339
- } catch (err) {
118340
- if (isUniqueConstraintError(err)) {
118341
- throw new ExplicitSelfDuplicateError(`duplicate explicit-self rating for memoryId=${event.memoryId} taskId=${ctx.taskId}`, event);
118342
- }
118343
- throw err;
118344
- }
118345
- if (sanitizedReferencesSource !== null) {
118346
- await tx.run(UPSERT_EDGE_SQL, [
118347
- event.memoryId,
118348
- sanitizedReferencesSource,
118349
- 1 + alphaDelta,
118350
- 1 + betaDelta,
118351
- new Date().toISOString()
118352
- ]);
118353
- }
118354
- appliedEvents2.push({ event, sanitizedReferencesSource });
118355
- applied2 += 1;
118356
- }
118357
- return { applied: applied2, lateRejects: lateRejects2, appliedEvents: appliedEvents2 };
118358
- });
118359
- if (ctx.taskId && appliedEvents.length > 0) {
118360
- for (const { event, sanitizedReferencesSource } of appliedEvents) {
118361
- ensure({
118362
- id: "memory_rated",
118363
- flow: "task",
118364
- runId: ctx.taskId,
118365
- data: {
118366
- memoryId: event.memoryId,
118367
- source: event.source,
118368
- signal: event.signal,
118369
- weight: event.weight,
118370
- hasReferencesSource: sanitizedReferencesSource !== null
118371
- },
118372
- validator: (data) => typeof data.memoryId === "string" && data.memoryId.length > 0 && typeof data.source === "string" && data.source.length > 0 && typeof data.signal === "number" && data.signal >= -1 && data.signal <= 1 && typeof data.weight === "number" && data.weight >= 0 && data.weight <= 1
118373
- });
118374
- }
118375
- }
118376
- return { applied, rejected: [...rejected, ...lateRejects] };
118377
- }
118378
- function validate(event) {
118379
- if (!event.source || event.source.trim() === "") {
118380
- return "source is required";
118381
- }
118382
- if (!Number.isFinite(event.signal) || event.signal < -1 || event.signal > 1) {
118383
- return "signal must be in [-1, +1]";
118384
- }
118385
- if (!Number.isFinite(event.weight) || event.weight < 0 || event.weight > 1) {
118386
- return "weight must be in [0, 1]";
118387
- }
118388
- if (!event.memoryId) {
118389
- return "memoryId is required";
118390
- }
118391
- return null;
118392
- }
118393
- function isUniqueConstraintError(err) {
118394
- if (!(err instanceof Error))
118395
- return false;
118396
- return /UNIQUE constraint failed|SQLITE_CONSTRAINT/i.test(err.message);
118397
- }
118398
-
118399
- // src/be/memory/raters/run-server-raters.ts
118400
- async function runServerRaters(input, deps = {}) {
118401
- const result = { ratersFired: 0, outcomes: [] };
118402
- if (input.retrievedMemoryIds.length === 0)
118403
- return result;
118404
- const allRaters = deps.raters ?? getRegisteredRaters();
118405
- const allowed = deps.serverRaterNames ?? SERVER_RATERS;
118406
- const weightFor = deps.weightMultiplierFor ?? getRaterWeightMultiplier;
118407
- const applyFn = deps.applyRating ?? applyRating;
118408
- const serverRaters = allRaters.filter((r) => allowed.has(r.name));
118409
- for (const rater of serverRaters) {
118410
- const events = await rater.rate({
118411
- taskId: input.taskId,
118412
- agentId: input.agentId,
118413
- retrievedMemoryIds: input.retrievedMemoryIds,
118414
- evidence: input.evidence
118415
- });
118416
- if (events.length === 0)
118417
- continue;
118418
- const multiplier = weightFor(rater.name);
118419
- const stamped = events.map((e) => ({
118420
- ...e,
118421
- source: rater.name,
118422
- weight: Math.max(0, Math.min(1, e.weight * multiplier))
118423
- }));
118424
- const applied = await applyFn(stamped, { taskId: input.taskId });
118425
- result.ratersFired += 1;
118426
- result.outcomes.push({ rater: rater.name, events: stamped, result: applied });
118427
- }
118428
- return result;
118429
- }
118430
-
118431
- // src/memory/automatic-task-gate.ts
118432
- var SCHEDULE_TAG_PREFIX = "schedule:";
118433
- var AUTOMATIC_TASK_TYPES = new Set([
118434
- "boot-triage",
118435
- "heartbeat",
118436
- "heartbeat-checklist",
118437
- "health-check",
118438
- "health-probe",
118439
- "monitor",
118440
- "monitoring"
118441
- ]);
118442
- function isAutomaticOrRecurringTaskCompletion(task) {
118443
- const tags = task.tags ?? [];
118444
- const taskType = task.taskType?.toLowerCase();
118445
- return task.source === "schedule" || task.source === "system" || tags.includes("scheduled") || tags.includes("auto-generated") || tags.some((tag) => tag.startsWith(SCHEDULE_TAG_PREFIX)) || taskType !== undefined && (AUTOMATIC_TASK_TYPES.has(taskType) || taskType.endsWith("-monitor") || taskType.endsWith("-digest"));
118446
- }
118447
- function shouldPersistAutomaticTaskMemory(task, persistMemory) {
118448
- if (persistMemory)
118449
- return true;
118450
- return !isAutomaticOrRecurringTaskCompletion(task);
118451
- }
118452
- var shouldPersistTaskCompletionMemory = shouldPersistAutomaticTaskMemory;
118453
-
118454
- // src/tasks/terminal-result-guard.ts
118455
- init_db();
118456
- init_types();
118457
- init_secret_scrubber();
118458
- function getTaskOutputValidationError(outputSchema, output) {
118459
- if (!outputSchema || typeof outputSchema !== "object")
118460
- return;
118461
- const schema = outputSchema;
118462
- if (!output) {
118463
- return `Task has an outputSchema but no output was provided. You must call store-progress with a valid JSON output matching this schema:
118464
- ${JSON.stringify(schema, null, 2)}`;
118465
- }
118466
- let parsed;
118467
- try {
118468
- parsed = JSON.parse(output);
118469
- } catch {
118470
- return `Task output must be valid JSON matching the outputSchema. Got invalid JSON. Schema:
118471
- ${JSON.stringify(schema, null, 2)}`;
118472
- }
118473
- let validationErrors;
118474
- try {
118475
- validationErrors = validateJsonSchema(schema, parsed);
118476
- } catch (error) {
118477
- const detail = error instanceof Error ? error.message : String(error);
118478
- return `Task outputSchema is malformed and cannot be validated (${detail}). Ask an operator to correct the task's outputSchema, or force-complete with store-progress force: true.`;
118479
- }
118480
- if (validationErrors.length > 0) {
118481
- return `Task output does not match the outputSchema. Errors:
118482
- ${validationErrors.join(`
118483
- `)}
118484
-
118485
- Expected schema:
118486
- ${JSON.stringify(schema, null, 2)}
118487
-
118488
- Please fix your output and retry.`;
118489
- }
118490
- return;
118491
- }
118492
- async function guardTerminalTaskResultWrite(task, write2) {
118493
- if (!isTerminalTaskStatus(task.status) || !write2.status && !write2.force) {
118494
- return { handled: false };
118495
- }
118496
- const scrubbedOutput = write2.output !== undefined ? scrubSecrets(write2.output) : undefined;
118497
- const scrubbedFailureReason = write2.failureReason !== undefined ? scrubSecrets(write2.failureReason) : undefined;
118498
- const hasDifferingOutput = scrubbedOutput !== undefined && scrubbedOutput !== task.output;
118499
- const hasDifferingFailureReason = scrubbedFailureReason !== undefined && scrubbedFailureReason !== task.failureReason;
118500
- const hasDifferingResultText = hasDifferingOutput || hasDifferingFailureReason;
118501
- if (hasDifferingResultText && write2.force) {
118502
- const outputValidationError = hasDifferingOutput ? getTaskOutputValidationError(task.outputSchema, write2.output) : undefined;
118503
- if (outputValidationError) {
118504
- return { handled: true, success: false, message: outputValidationError, task };
118505
- }
118506
- const overwrittenTask = await overwriteTerminalTaskResultText(task.id, {
118507
- ...write2.output !== undefined ? { output: write2.output } : {},
118508
- ...write2.failureReason !== undefined ? { failureReason: write2.failureReason } : {}
118509
- });
118510
- if (!overwrittenTask) {
118511
- return {
118512
- handled: true,
118513
- success: false,
118514
- message: `Task "${task.id}" terminal result text could not be overwritten.`,
118515
- task
118516
- };
118517
- }
118518
- return {
118519
- handled: true,
118520
- success: true,
118521
- message: `Task "${task.id}" is already ${task.status}; force-overwrote terminal result text ` + "without replaying completion side effects.",
118522
- task: overwrittenTask,
118523
- wasForcedOverwrite: true
118524
- };
118525
- }
118526
- if (hasDifferingResultText) {
118527
- return {
118528
- handled: true,
118529
- success: false,
118530
- message: `Discarded write for already-${task.status} task "${task.id}"; ` + "existing output/failureReason and finishedAt were preserved. Retry with force: true " + "to overwrite terminal result text without replaying completion side effects.",
118531
- task
118532
- };
118533
- }
118534
- return {
118535
- handled: true,
118536
- success: true,
118537
- message: `Task "${task.id}" is already ${task.status}; treating as no-op. ` + "Existing output preserved (first-call-wins).",
118538
- task,
118539
- wasNoOp: true
118540
- };
118541
- }
118542
-
118543
- // src/tools/store-progress.ts
118544
118762
  init_types();
118545
118763
  init_secret_scrubber();
118546
118764
  var storeProgressOutputSchema = swarmToolOutputSchema({
@@ -118760,91 +118978,15 @@ var registerStoreProgressTool = (server) => {
118760
118978
  };
118761
118979
  });
118762
118980
  const shouldRunTerminalSideEffects = (status === "completed" || status === "failed") && result.success && result.task && !(("wasNoOp" in result) && result.wasNoOp) && !(("wasForcedOverwrite" in result) && result.wasForcedOverwrite);
118763
- if (shouldRunTerminalSideEffects && shouldPersistTaskCompletionMemory(result.task, persistMemory)) {
118764
- (async () => {
118765
- try {
118766
- const taskContent = status === "completed" ? `Task: ${result.task.task}
118767
-
118768
- Output:
118769
- ${output || "(no output)"}` : `Task: ${result.task.task}
118770
-
118771
- Failure reason:
118772
- ${failureReason || "No reason provided"}
118773
-
118774
- This task failed. Learn from this to avoid repeating the mistake.`;
118775
- if (taskContent.length < 30)
118776
- return;
118777
- const store = getMemoryStore();
118778
- const provider = getEmbeddingProvider();
118779
- const memory = await store.store({
118780
- agentId: requestInfo.agentId ?? null,
118781
- content: taskContent,
118782
- name: `Task: ${result.task.task.slice(0, 80)}`,
118783
- scope: "agent",
118784
- source: "task_completion",
118785
- sourceTaskId: taskId
118786
- });
118787
- const embedding = await provider.embed(taskContent);
118788
- if (embedding) {
118789
- await store.updateEmbedding(memory.id, embedding, provider.name);
118790
- }
118791
- const shouldShareWithSwarm = status === "completed" && (result.task.taskType === "research" || result.task.tags?.includes("knowledge") || result.task.tags?.includes("shared"));
118792
- if (shouldShareWithSwarm) {
118793
- try {
118794
- const swarmMemory = await store.store({
118795
- agentId: requestInfo.agentId ?? null,
118796
- scope: "swarm",
118797
- name: `Shared: ${result.task.task.slice(0, 80)}`,
118798
- content: `Task completed by agent ${requestInfo.agentId}:
118799
-
118800
- ${taskContent}`,
118801
- source: "task_completion",
118802
- sourceTaskId: taskId
118803
- });
118804
- const swarmEmbedding = await provider.embed(taskContent);
118805
- if (swarmEmbedding) {
118806
- await store.updateEmbedding(swarmMemory.id, swarmEmbedding, provider.name);
118807
- }
118808
- } catch {}
118809
- }
118810
- } catch {}
118811
- })().catch((err) => console.error("[store-progress] task completion memory write failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
118812
- }
118813
- if (shouldRunTerminalSideEffects) {
118814
- (async () => {
118815
- try {
118816
- const retrievals = await getRetrievalsForTask(taskId);
118817
- if (retrievals.length === 0)
118818
- return;
118819
- const retrievedMemoryIds = retrievals.map((r) => r.memoryId);
118820
- const logs = await getSessionLogsByTaskId(taskId);
118821
- const evidence = logs.map((l) => l.content).join(`
118822
- `);
118823
- await runServerRaters({
118824
- taskId,
118825
- agentId: requestInfo.agentId ?? "",
118826
- retrievedMemoryIds,
118827
- evidence
118828
- });
118829
- } catch (err) {
118830
- console.error("[store-progress] server-rater fire failed:", err instanceof Error ? err.message : String(err));
118831
- }
118832
- })().catch((err) => console.error("[store-progress] server rater run failed:", scrubSecrets(err instanceof Error ? err.message : String(err))));
118833
- }
118834
- if (status && result.success && result.task && !result.task.workflowRunId && !(("wasNoOp" in result) && result.wasNoOp) && !(("wasForcedOverwrite" in result) && result.wasForcedOverwrite)) {
118835
- try {
118836
- const followUp = await createWorkerTaskFollowUp({
118837
- task: result.task,
118838
- status,
118839
- output,
118840
- failureReason
118841
- });
118842
- if (followUp) {
118843
- console.log(`[store-progress] Created follow-up task ${followUp.id.slice(0, 8)} for ${status} task ${taskId.slice(0, 8)}`);
118844
- }
118845
- } catch (err) {
118846
- console.warn(`[store-progress] Failed to create follow-up task: ${err}`);
118847
- }
118981
+ if (shouldRunTerminalSideEffects && status) {
118982
+ await runTaskTerminalEffects({
118983
+ task: result.task,
118984
+ status,
118985
+ output,
118986
+ failureReason,
118987
+ agentId: requestInfo.agentId,
118988
+ persistMemory
118989
+ });
118848
118990
  }
118849
118991
  const { success, message } = result;
118850
118992
  const task = result.task ? {
@@ -121296,6 +121438,7 @@ async function createServer(opts = {}) {
121296
121438
  if (hasCapability2("scheduling")) {
121297
121439
  registerListSchedulesTool(server);
121298
121440
  registerCreateScheduleTool(server);
121441
+ registerDeferTaskTool(server);
121299
121442
  registerUpdateScheduleTool(server);
121300
121443
  registerPatchScheduleTool(server);
121301
121444
  registerDeleteScheduleTool(server);
@@ -121456,7 +121599,7 @@ function isExplicitSelfRaterEnabled() {
121456
121599
 
121457
121600
  // src/utils/skill-fs-writer.ts
121458
121601
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
121459
- import { dirname as dirname2, join as join3 } from "node:path";
121602
+ import { dirname, join as join3 } from "node:path";
121460
121603
  var SWARM_MARKER_FILE = ".swarm-managed";
121461
121604
  function reconcileManagedSkillFiles(skillDir, currentRelativeFiles) {
121462
121605
  if (!existsSync2(join3(skillDir, SWARM_MARKER_FILE)))
@@ -121560,7 +121703,7 @@ function writeSkillsToFilesystem(entries, harnessType = "all", home) {
121560
121703
  }
121561
121704
  const targetPath = join3(skillDir, file.path);
121562
121705
  try {
121563
- mkdirSync2(dirname2(targetPath), { recursive: true });
121706
+ mkdirSync2(dirname(targetPath), { recursive: true });
121564
121707
  writeFileSync2(targetPath, file.content, "utf-8");
121565
121708
  } catch (err) {
121566
121709
  const msg = err instanceof Error ? err.message : "Unknown error";
@@ -121593,4 +121736,4 @@ function writeSkillsToFilesystem(entries, harnessType = "all", home) {
121593
121736
  return { synced, removed, errors };
121594
121737
  }
121595
121738
 
121596
- export { safeParseAsync2 as safeParseAsync, normalizeObjectSchema, getParseErrorMessage, DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature, isAgentMailEnabled, initAgentMail, verifyAgentMailWebhook, isInboxAllowed, isSenderAllowed, handleMessageReceived, enqueueAuditRow, enqueueAdmissionRow, flushAuditBuffer, startAuditWriter, stopAuditWriter, startAuditGc, stopAuditGc, handlePullRequest, handleIssue, handleComment, handlePullRequestReview, handleCheckRun, handleCheckSuite, handleWorkflowRun, isGitLabEnabled, initGitLab, verifyGitLabWebhook, handleMergeRequest, handleIssue2 as handleIssue1, handleNote, handlePipeline, getJiraMetadata, updateJiraMetadata, clearJiraMetadata, registerJiraWebhook, deleteJiraWebhook, isJiraEnabled, initJira, handleJiraWebhook, handleAgentSessionEvent, handleIssueUpdate, handleIssueDelete, handleAgentSessionPrompted, isLinearEnabled, initLinear, parseCookieHeader, extractAndVerifyCookie, issuePageSessionCookie, resolveHttpRequestAuth, setCorsHeaders, parseQueryParams, getPathSegments, wireHttpSpanLifecycle, safeRequestUrlForLog, agentWithCapacity, parseBody, BODY_TOO_LARGE, enforceContentLengthCap, json, jsonError, triggerSchemaErrorResponse, deriveApiBaseUrl, httpServerSemconvAttributes, runtimeInstanceHeader, describeRequestRoute, route, loadGlobalConfigsIntoEnv, reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload, handleCore, mcpOverflowAuthError, markScriptSdkRequestOrigin, toolErr, createToolRegistrar, userCtx, resolveTaskAuditUserId, resolveHttpAuditUserId, resolveHttpFavoriteOwner, handleApps, getUserCommsPrefs, getTaskDetailsInputSchema, getTaskDetailsOutputSchema, getTaskDetailsHandler, cancelTaskInputSchema, cancelTaskOutputSchema, cancelTaskHandler, executeReadOnlyQuery, assertSelectOnlyQuery, handleDbQuery, snapshotMetric, AssetKeyAuthorizationError, authorizeAssetKeyWrite, snapshotPage, assertOAuthAppUrlsSafe, assertOAuthEgressUrlSafe, listOAuthPresets, listOAuthPresetIds, getOAuthPreset, hydrateOAuthAppFromPreset, scopedResourceScopeIdSchema, resolveScopedResourceId, getTasksInputSchema, getTasksOutputSchema, getTasksHandler, reservedNamespaceError, reservedRoomKeyError, refreshLinks, canReadMemory, getLinksForMemory, dedupeMemoryDocumentIds, recordMemoryAccesses, recordRetrievals, expandCandidatesWithGraph, indexMemoryContent, markKapsoMessageRead, sendKapsoReaction, getKapsoConfig, getKapsoNumberMapping, markKapsoMessageSeen, resolveRoomNamespace, roomRequestInfo, authorizeRoomNamespace, RoomOperationSchema, removeAwarenessStates, roomTopic, decodeRoomSnapshot, roomView, getRoom, changeRoom, applyRoomUpdate, resetRoom, sweepRooms, closeRooms, removeNamespaceRooms, createEvent, createEventsBatch, getEventCountsFiltered, getEventsFiltered, mergeScheduleTiming, validateRecurringTiming, checkOutputSchemaShape, sendTaskOutputSchema, sendTaskHandler, parseSkillContent, steerTaskUserInputSchema, steerTaskOutputSchema, steerTaskHandler, ExplicitSelfDuplicateError, applyRating, shouldPersistAutomaticTaskMemory, guardTerminalTaskResultWrite, canClaim, emitBudgetRefusalSideEffects, taskActionInputSchema, taskActionOutputSchema, taskActionHandler, patchWorkflowDefinition, resolveScriptsOnlyMode, ALL_CAPABILITIES, hasCapability, getEnabledCapabilities, createServer, SIMILARITY_THRESHOLD, renderMemoriesPrompt, writeSkillsToFilesystem };
121739
+ export { safeParseAsync2 as safeParseAsync, normalizeObjectSchema, getParseErrorMessage, DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCRequest, isJSONRPCResultResponse, isJSONRPCErrorResponse, JSONRPCMessageSchema, isInitializeRequest, McpServer, isGitHubEnabled, initGitHub, verifyWebhookSignature, isAgentMailEnabled, initAgentMail, verifyAgentMailWebhook, isInboxAllowed, isSenderAllowed, handleMessageReceived, enqueueAuditRow, enqueueAdmissionRow, flushAuditBuffer, startAuditWriter, stopAuditWriter, startAuditGc, stopAuditGc, handlePullRequest, handleIssue, handleComment, handlePullRequestReview, handleCheckRun, handleCheckSuite, handleWorkflowRun, isGitLabEnabled, initGitLab, verifyGitLabWebhook, handleMergeRequest, handleIssue2 as handleIssue1, handleNote, handlePipeline, getJiraMetadata, updateJiraMetadata, clearJiraMetadata, registerJiraWebhook, deleteJiraWebhook, isJiraEnabled, initJira, handleJiraWebhook, handleAgentSessionEvent, handleIssueUpdate, handleIssueDelete, handleAgentSessionPrompted, isLinearEnabled, initLinear, parseCookieHeader, extractAndVerifyCookie, issuePageSessionCookie, resolveHttpRequestAuth, warnIfCorsAllowsAnyOrigin, isOriginAllowedForCredentials, setCorsHeaders, parseQueryParams, getPathSegments, wireHttpSpanLifecycle, safeRequestUrlForLog, agentWithCapacity, parseBody, BODY_TOO_LARGE, enforceContentLengthCap, json, jsonError, triggerSchemaErrorResponse, deriveApiBaseUrl, httpServerSemconvAttributes, runtimeInstanceHeader, describeRequestRoute, route, loadGlobalConfigsIntoEnv, reloadGlobalConfigsAndIntegrations, scheduleIntegrationsReload, handleCore, mcpOverflowAuthError, markScriptSdkRequestOrigin, toolErr, createToolRegistrar, userCtx, resolveTaskAuditUserId, resolveHttpAuditUserId, resolveHttpFavoriteOwner, handleApps, getUserCommsPrefs, getTaskDetailsInputSchema, getTaskDetailsOutputSchema, getTaskDetailsHandler, cancelTaskInputSchema, cancelTaskOutputSchema, cancelTaskHandler, executeReadOnlyQuery, assertSelectOnlyQuery, handleDbQuery, snapshotMetric, AssetKeyAuthorizationError, authorizeAssetKeyWrite, snapshotPage, assertOAuthAppUrlsSafe, assertOAuthEgressUrlSafe, listOAuthPresets, listOAuthPresetIds, getOAuthPreset, hydrateOAuthAppFromPreset, scopedResourceScopeIdSchema, resolveScopedResourceId, dedupeMemoryDocumentIds, recordMemoryAccesses, recordRetrievals, ExplicitSelfDuplicateError, applyRating, shouldPersistAutomaticTaskMemory, guardTerminalTaskResultWrite, getTasksInputSchema, getTasksOutputSchema, getTasksHandler, reservedNamespaceError, reservedRoomKeyError, refreshLinks, canReadMemory, getLinksForMemory, expandCandidatesWithGraph, indexMemoryContent, markKapsoMessageRead, sendKapsoReaction, getKapsoConfig, getKapsoNumberMapping, markKapsoMessageSeen, resolveRoomNamespace, roomRequestInfo, authorizeRoomNamespace, RoomOperationSchema, removeAwarenessStates, roomTopic, decodeRoomSnapshot, roomView, getRoom, changeRoom, applyRoomUpdate, resetRoom, sweepRooms, closeRooms, removeNamespaceRooms, createEvent, createEventsBatch, getEventCountsFiltered, getEventsFiltered, mergeScheduleTiming, validateRecurringTiming, checkOutputSchemaShape, sendTaskOutputSchema, sendTaskHandler, parseSkillContent, steerTaskUserInputSchema, steerTaskOutputSchema, steerTaskHandler, canClaim, emitBudgetRefusalSideEffects, taskActionInputSchema, taskActionOutputSchema, taskActionHandler, patchWorkflowDefinition, resolveScriptsOnlyMode, ALL_CAPABILITIES, hasCapability, getEnabledCapabilities, createServer, SIMILARITY_THRESHOLD, renderMemoriesPrompt, writeSkillsToFilesystem };