@desplega.ai/agent-swarm 1.135.2 → 1.136.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 (97) hide show
  1. package/dist/{actions-3az2vwwn.js → actions-agcbc8nd.js} +6 -6
  2. package/dist/{app-vygnfvrh.js → app-g2s78xya.js} +3 -3
  3. package/dist/{assistant-2jr2frrm.js → assistant-yd3jkb9d.js} +8 -8
  4. package/dist/{boot-reembed-y7r9cxt0.js → boot-reembed-6spqw4q0.js} +3 -3
  5. package/dist/{boot-reembed-ncbg16rb.js → boot-reembed-b22s9w5x.js} +4 -4
  6. package/dist/{boot-scrub-logs-t82rwa0y.js → boot-scrub-logs-6h3cqkc0.js} +2 -2
  7. package/dist/{claude-adapter-vvx2aw3v.js → claude-adapter-ng5y8zd7.js} +4 -4
  8. package/dist/{cli-mfa2eaef.js → cli-35jknh9e.js} +5 -5
  9. package/dist/{cli-cv2vjg2y.js → cli-3y553gws.js} +1 -1
  10. package/dist/{cli-nhvym0d2.js → cli-4gzv54ss.js} +15 -6
  11. package/dist/{cli-4dakdn30.js → cli-4r4jkqep.js} +6 -6
  12. package/dist/{cli-83razmqg.js → cli-54ht104h.js} +3 -3
  13. package/dist/{cli-6290n4yz.js → cli-5bnz1t86.js} +1 -1
  14. package/dist/{cli-6bz2hzvw.js → cli-68vayryq.js} +2 -2
  15. package/dist/{cli-1z01xdqh.js → cli-6gwgzdgw.js} +2 -2
  16. package/dist/{cli-1dfatkzm.js → cli-84vrhesc.js} +1 -1
  17. package/dist/{cli-jfrh963q.js → cli-8v57p983.js} +10 -10
  18. package/dist/{cli-3f0tnh34.js → cli-ads0hfw2.js} +81 -23
  19. package/dist/{cli-fmha74ga.js → cli-bnq8h7ea.js} +3 -3
  20. package/dist/{cli-j3xnd5b4.js → cli-d5ygfv18.js} +7 -6
  21. package/dist/{cli-8f4h27gm.js → cli-edwrx42s.js} +1 -1
  22. package/dist/{cli-r5vwg1ma.js → cli-fpjmcbhz.js} +4 -4
  23. package/dist/{cli-w0ygcv43.js → cli-gpdtxzar.js} +6 -4
  24. package/dist/{cli-4rdjdddh.js → cli-hz5hp6wn.js} +1 -1
  25. package/dist/{cli-6mmwmy45.js → cli-j7qp8gtf.js} +1 -1
  26. package/dist/{cli-5a5nrq3g.js → cli-jjhnma34.js} +5 -5
  27. package/dist/{cli-ey09krp2.js → cli-m3z53bed.js} +1 -1
  28. package/dist/{cli-cf6vq6qa.js → cli-mgef08pc.js} +1 -1
  29. package/dist/{cli-0jhyxtdj.js → cli-qckgdqmr.js} +2 -2
  30. package/dist/{cli-a1zrc2g6.js → cli-qhfkxrpg.js} +108 -33
  31. package/dist/{cli-yw2z5kj9.js → cli-spf767vc.js} +1 -1
  32. package/dist/{cli-1857msnd.js → cli-tee8w7tq.js} +1 -1
  33. package/dist/{cli-qxn3g3yx.js → cli-tmn19cdz.js} +61 -6
  34. package/dist/{cli-7ccy0h4r.js → cli-y16cesaq.js} +2 -2
  35. package/dist/{cli-cm4z7w7w.js → cli-z6e8eqrm.js} +2 -2
  36. package/dist/cli.js +16 -16
  37. package/dist/{codex-adapter-6p290yq3.js → codex-adapter-kw11ps3j.js} +2 -2
  38. package/dist/{codex-session-runner-7b3dhpmx.js → codex-session-runner-sffb69v7.js} +2 -2
  39. package/dist/{commands-wxg1g4nq.js → commands-0xxp4tz8.js} +2 -2
  40. package/dist/{db-8fqeheve.js → db-0npp39zd.js} +6 -2
  41. package/dist/{handlers-gwtqp17c.js → handlers-5p7a1jx6.js} +15 -9
  42. package/dist/{hook-gd9fwfp0.js → hook-hpefr0a8.js} +2 -2
  43. package/dist/{hook-mrqygs7p.js → hook-jjpxn4se.js} +3 -3
  44. package/dist/{http-x4mc1mqg.js → http-wfp33653.js} +322 -61
  45. package/dist/{index-yd654kac.js → index-17h657rg.js} +12 -8
  46. package/dist/{index-pzgasj16.js → index-m2p7ctyh.js} +10 -10
  47. package/dist/{index-2mdqrd0n.js → index-racb4wfq.js} +9 -9
  48. package/dist/{index-4djjkp9z.js → index-zh66wm65.js} +8 -8
  49. package/dist/{keepalive-3tycspcy.js → keepalive-wxjd633a.js} +4 -4
  50. package/dist/{lead-js1h3z7d.js → lead-359ec2z0.js} +23 -23
  51. package/dist/{maintenance-y91ry8q4.js → maintenance-rr03qjtb.js} +4 -4
  52. package/dist/{mistral-conversations-hdmnkf6h.js → mistral-conversations-qdrnmrb8.js} +1 -1
  53. package/dist/{oauth-refresh-sweep-s33gtxrw.js → oauth-refresh-sweep-jwj22yb8.js} +3 -3
  54. package/dist/{onboard-vndj64mb.js → onboard-asnhchcv.js} +2 -2
  55. package/dist/{openai-completions-cwy2kkzg.js → openai-completions-yzftqrft.js} +33 -4
  56. package/dist/{otel-impl-d2p84k6e.js → otel-impl-54cra6mw.js} +18 -4
  57. package/dist/{pi-mono-adapter-1phspz2y.js → pi-mono-adapter-29g7axgj.js} +669 -335
  58. package/dist/{pricing-refresh-c2bwsyk5.js → pricing-refresh-mkyy7c2y.js} +4 -4
  59. package/dist/{rbac-roles-2pedz5e9.js → rbac-roles-ak56tr75.js} +2 -2
  60. package/dist/{rbac-roles-reef5y2d.js → rbac-roles-kb3afm95.js} +3 -3
  61. package/dist/{render-v2-zd5r5wgf.js → render-v2-434asg49.js} +3 -3
  62. package/dist/{seed-pricing-2kyk1vhg.js → seed-pricing-nbmd7ah8.js} +3 -3
  63. package/dist/{setup-5ys9pwyr.js → setup-wh4qmjs4.js} +2 -2
  64. package/dist/{worker-nb1f7k04.js → worker-j1d27tjv.js} +23 -23
  65. package/openapi.json +167 -2
  66. package/package.json +6 -6
  67. package/src/be/db-retention.ts +275 -0
  68. package/src/be/db.ts +82 -7
  69. package/src/be/swarm-config-guard.ts +30 -0
  70. package/src/heartbeat/heartbeat.ts +21 -0
  71. package/src/http/index.ts +33 -33
  72. package/src/http/route-def.ts +93 -4
  73. package/src/http/stats.ts +37 -1
  74. package/src/http/tasks.ts +93 -0
  75. package/src/http/utils.ts +94 -0
  76. package/src/otel-impl.ts +21 -3
  77. package/src/otel.ts +15 -4
  78. package/src/slack/blocks.ts +1 -0
  79. package/src/slack/handlers.ts +7 -0
  80. package/src/tasks/sibling-awareness.ts +1 -0
  81. package/src/tasks/sibling-block.ts +17 -4
  82. package/src/tests/artifact-sdk.test.ts +20 -15
  83. package/src/tests/db-retention.test.ts +344 -0
  84. package/src/tests/docs-index-footprint.test.js +4 -5
  85. package/src/tests/draft-task-dispatch-race.test.ts +189 -0
  86. package/src/tests/events-http.test.ts +70 -27
  87. package/src/tests/otel-abort-span.test.ts +156 -0
  88. package/src/tests/otel-span-kind.test.ts +59 -0
  89. package/src/tests/promote-draft-task-route.test.ts +175 -0
  90. package/src/tests/route-def-find-route.test.ts +90 -4
  91. package/src/tests/sibling-block.test.ts +29 -1
  92. package/src/tests/slack-assistant-comention-production.test.ts +7 -1
  93. package/src/tests/steering-enabled.test.ts +6 -0
  94. package/src/tests/swarm-config-reserved-keys.test.ts +27 -0
  95. package/src/types.ts +2 -1
  96. package/templates/skills/swarm-scripts/SKILL.md +4 -0
  97. package/templates/skills/swarm-scripts/content.md +4 -0
@@ -155,10 +155,11 @@ import {
155
155
  verifyAgentMailWebhook,
156
156
  verifyGitLabWebhook,
157
157
  verifyWebhookSignature,
158
+ wireHttpSpanLifecycle,
158
159
  withRemoteContext,
159
160
  withSpanContext,
160
161
  writeSkillsToFilesystem
161
- } from "./cli-3f0tnh34.js";
162
+ } from "./cli-ads0hfw2.js";
162
163
  import"./cli-mnm7w46e.js";
163
164
  import {
164
165
  Anthropic
@@ -179,7 +180,7 @@ import {
179
180
  checkHeartbeatChecklist,
180
181
  runHeartbeatSweep,
181
182
  stopHeartbeat
182
- } from "./cli-nhvym0d2.js";
183
+ } from "./cli-4gzv54ss.js";
183
184
  import {
184
185
  AGENT_MAX_TASKS_CONFIG_KEY,
185
186
  createResumeFollowUp,
@@ -194,7 +195,7 @@ import {
194
195
  touchRuntimeInstance,
195
196
  upsertRuntimeInstance,
196
197
  upsertSwarmConfigWithPolicyMirror
197
- } from "./cli-6290n4yz.js";
198
+ } from "./cli-5bnz1t86.js";
198
199
  import {
199
200
  isMultiRuntimeEnabled
200
201
  } from "./cli-qh4sqfws.js";
@@ -204,16 +205,16 @@ import {
204
205
  ensure,
205
206
  initialize,
206
207
  require_dist
207
- } from "./cli-r5vwg1ma.js";
208
+ } from "./cli-fpjmcbhz.js";
208
209
  import {
209
210
  getModelsCatalog
210
- } from "./cli-cm4z7w7w.js";
211
+ } from "./cli-z6e8eqrm.js";
211
212
  import {
212
213
  normalizeModelKey
213
- } from "./cli-1857msnd.js";
214
+ } from "./cli-tee8w7tq.js";
214
215
  import {
215
216
  getUserGrant
216
- } from "./cli-cv2vjg2y.js";
217
+ } from "./cli-3y553gws.js";
217
218
  import {
218
219
  can,
219
220
  clearAuditSink,
@@ -230,12 +231,12 @@ import {
230
231
  scriptSdkTypesWithGeneratedApis,
231
232
  scriptStdlibTypesWithGeneratedApis,
232
233
  typecheckScript
233
- } from "./cli-83razmqg.js";
234
+ } from "./cli-54ht104h.js";
234
235
  import {
235
236
  collectScriptReferences,
236
237
  getApp,
237
238
  listAppRecords
238
- } from "./cli-6bz2hzvw.js";
239
+ } from "./cli-68vayryq.js";
239
240
  import {
240
241
  RawLlmConfigSchema,
241
242
  RawLlmOutputSchema,
@@ -254,7 +255,7 @@ import {
254
255
  validateDefinition,
255
256
  validateJsonSchema,
256
257
  verifyHmacSignature
257
- } from "./cli-5a5nrq3g.js";
258
+ } from "./cli-jjhnma34.js";
258
259
  import"./cli-3dpj7atn.js";
259
260
  import {
260
261
  ConnectionAuthInputSchema,
@@ -327,14 +328,14 @@ import {
327
328
  upsertMcpOAuthToken,
328
329
  upsertScriptByName,
329
330
  upsertScriptConnection
330
- } from "./cli-fmha74ga.js";
331
+ } from "./cli-bnq8h7ea.js";
331
332
  import"./cli-epan13p1.js";
332
333
  import {
333
334
  getApiKey
334
335
  } from "./cli-f14fvzag.js";
335
336
  import {
336
337
  searchScripts
337
- } from "./cli-0jhyxtdj.js";
338
+ } from "./cli-qckgdqmr.js";
338
339
  import {
339
340
  CANDIDATE_SET_MULTIPLIER,
340
341
  getEmbeddingProvider,
@@ -342,7 +343,7 @@ import {
342
343
  init_constants as init_constants2,
343
344
  init_reranker,
344
345
  rerank
345
- } from "./cli-4rdjdddh.js";
346
+ } from "./cli-hz5hp6wn.js";
346
347
  import"./cli-dr5tcz68.js";
347
348
  import"./cli-vsap7a8d.js";
348
349
  import {
@@ -368,7 +369,7 @@ import {
368
369
  updateAuthorizationIdentity,
369
370
  updateOAuthAppById,
370
371
  upsertAuthorization
371
- } from "./cli-ey09krp2.js";
372
+ } from "./cli-m3z53bed.js";
372
373
  import"./cli-fad8m16k.js";
373
374
  import {
374
375
  getFileStorageProvider
@@ -377,7 +378,7 @@ import {
377
378
  FilesError,
378
379
  normalizeFilesError
379
380
  } from "./cli-fhsz3twr.js";
380
- import"./cli-1dfatkzm.js";
381
+ import"./cli-84vrhesc.js";
381
382
  import {
382
383
  findUserById,
383
384
  fingerprintApiKey,
@@ -393,15 +394,15 @@ import {
393
394
  resolveUserByToken,
394
395
  revokeToken,
395
396
  unlinkIdentity
396
- } from "./cli-yw2z5kj9.js";
397
+ } from "./cli-spf767vc.js";
397
398
  import {
398
399
  createTaskWithSiblingAwareness
399
- } from "./cli-w0ygcv43.js";
400
+ } from "./cli-gpdtxzar.js";
400
401
  import {
401
402
  getSlackApp,
402
403
  startSlackApp,
403
404
  stopSlackApp
404
- } from "./cli-j3xnd5b4.js";
405
+ } from "./cli-d5ygfv18.js";
405
406
  import"./cli-qf9kpsve.js";
406
407
  import"./cli-g2p9bd1z.js";
407
408
  import"./cli-5tnr64pm.js";
@@ -449,6 +450,7 @@ import {
449
450
  KvNamespaceSchema,
450
451
  KvTypeCollisionError,
451
452
  KvValueTypeSchema,
453
+ MAX_DB_RETENTION_DAYS,
452
454
  McpAuthMethodSchema,
453
455
  McpServerSchema,
454
456
  McpServerWithInstallInfoSchema,
@@ -729,6 +731,7 @@ import {
729
731
  pageContextKey,
730
732
  pauseTask,
731
733
  placeholderForConfigKey,
734
+ promoteDraftTask,
732
735
  recordBudgetRefusalNotification,
733
736
  recordInlineScriptRun,
734
737
  recordKeyRateLimitWindows,
@@ -789,7 +792,7 @@ import {
789
792
  upsertSwarmConfig,
790
793
  validateConfigValue,
791
794
  withFavoriteFlags
792
- } from "./cli-qxn3g3yx.js";
795
+ } from "./cli-tmn19cdz.js";
793
796
  import {
794
797
  IDENTITY_FIELD_BUDGETS,
795
798
  IdentityFieldBudgetError,
@@ -831,7 +834,7 @@ import {
831
834
  import {
832
835
  init_package,
833
836
  package_default
834
- } from "./cli-4dakdn30.js";
837
+ } from "./cli-4r4jkqep.js";
835
838
  import {
836
839
  array,
837
840
  exports_external,
@@ -883,6 +886,189 @@ import {
883
886
  } from "node:http";
884
887
  init_db();
885
888
 
889
+ // src/be/db-retention.ts
890
+ init_env_flag();
891
+ init_db();
892
+ init_swarm_config_guard();
893
+ import { AsyncLocalStorage } from "node:async_hooks";
894
+ var DAY_MS = 24 * 60 * 60 * 1000;
895
+ var RETENTION_INTERVAL_MS = 60 * 60 * 1000;
896
+ var BATCH_SIZE = 5000;
897
+ var PER_TABLE_BATCH_CAP = 40;
898
+ var WALL_CLOCK_CAP_MS = 60000;
899
+ var YIELD_MS = 5;
900
+ var DB_RETENTION_TABLES = [
901
+ {
902
+ table: "session_logs",
903
+ timeColumn: "createdAt",
904
+ envKey: "SESSION_LOG_RETENTION_DAYS",
905
+ metricsKey: "sessionLogs"
906
+ },
907
+ {
908
+ table: "agent_log",
909
+ timeColumn: "createdAt",
910
+ envKey: "AGENT_LOG_RETENTION_DAYS",
911
+ metricsKey: "agentLog"
912
+ },
913
+ {
914
+ table: "events",
915
+ timeColumn: "createdAt",
916
+ envKey: "EVENTS_RETENTION_DAYS",
917
+ metricsKey: "events"
918
+ }
919
+ ];
920
+ var retentionTimer = null;
921
+ var retentionTickPromise = null;
922
+ var retentionAbortController = null;
923
+ var retentionStats = {};
924
+ var cumulativeRowsDeleted = {};
925
+ var scheduleContextFree = AsyncLocalStorage.snapshot();
926
+ function readPositiveIntEnv(key, env = process.env) {
927
+ const raw = env[key]?.trim();
928
+ if (!raw || !/^\d+$/.test(raw))
929
+ return null;
930
+ const value = Number(raw);
931
+ return Number.isSafeInteger(value) && value >= 1 && value <= MAX_DB_RETENTION_DAYS ? value : null;
932
+ }
933
+ function yieldTick() {
934
+ return new Promise((resolve) => setTimeout(resolve, YIELD_MS));
935
+ }
936
+ function retentionDays(table) {
937
+ return readPositiveIntEnv(table.envKey);
938
+ }
939
+ function dryRunEnabled(env = process.env) {
940
+ const raw = env.DB_RETENTION_DRY_RUN;
941
+ if (raw === undefined || raw.trim() === "")
942
+ return false;
943
+ return isEnvFlagEnabled("DB_RETENTION_DRY_RUN", true, env);
944
+ }
945
+ async function sweepTable(table, cutoff, dryRun, deadline, batchSize, perTableBatchCap, signal) {
946
+ const client = getDbClient();
947
+ let rowsDeleted = 0;
948
+ let batches = 0;
949
+ let pagesFetched = 0;
950
+ let cursor = null;
951
+ let complete = true;
952
+ let exhausted = false;
953
+ const pageLimit = dryRun ? Number.POSITIVE_INFINITY : perTableBatchCap;
954
+ while (!signal.aborted && pagesFetched < pageLimit && Date.now() < deadline) {
955
+ const page = await client.query(`SELECT id, ${table.timeColumn} AS createdAt
956
+ FROM ${table.table}
957
+ ${cursor === null ? "" : "WHERE id > ?"}
958
+ ORDER BY id
959
+ LIMIT ?`, cursor === null ? [batchSize] : [cursor, batchSize]);
960
+ pagesFetched += 1;
961
+ if (Date.now() >= deadline || signal.aborted) {
962
+ complete = false;
963
+ break;
964
+ }
965
+ if (page.length === 0) {
966
+ exhausted = true;
967
+ break;
968
+ }
969
+ cursor = page[page.length - 1]?.id ?? null;
970
+ const expiredIds = page.filter((row) => row.createdAt < cutoff).map((row) => row.id);
971
+ if (expiredIds.length > 0) {
972
+ if (dryRun) {
973
+ rowsDeleted += expiredIds.length;
974
+ } else {
975
+ const placeholders = expiredIds.map(() => "?").join(", ");
976
+ const result = await client.run(`DELETE FROM ${table.table} WHERE id IN (${placeholders})`, expiredIds);
977
+ rowsDeleted += result.changes;
978
+ }
979
+ batches += 1;
980
+ }
981
+ if (page.length < batchSize) {
982
+ exhausted = true;
983
+ break;
984
+ }
985
+ await yieldTick();
986
+ }
987
+ return { rowsDeleted, batches, complete: !dryRun || complete && exhausted };
988
+ }
989
+ function runDbRetentionTick(options = {}) {
990
+ if (retentionTickPromise)
991
+ return retentionTickPromise;
992
+ const abortController = new AbortController;
993
+ retentionAbortController = abortController;
994
+ const promise = Promise.resolve().then(async () => {
995
+ try {
996
+ const tickStartedAt = Date.now();
997
+ const cutoffBase = options.now ?? new Date(tickStartedAt);
998
+ const dryRun = dryRunEnabled();
999
+ const batchSize = options.batchSize ?? BATCH_SIZE;
1000
+ const perTableBatchCap = options.perTableBatchCap ?? PER_TABLE_BATCH_CAP;
1001
+ const deadline = tickStartedAt + (options.wallClockCapMs ?? WALL_CLOCK_CAP_MS);
1002
+ let deletedAny = false;
1003
+ for (const table of DB_RETENTION_TABLES) {
1004
+ if (abortController.signal.aborted || Date.now() >= deadline)
1005
+ break;
1006
+ const days = retentionDays(table);
1007
+ if (days === null)
1008
+ continue;
1009
+ const startedAt = Date.now();
1010
+ try {
1011
+ const cutoff = new Date(cutoffBase.getTime() - days * DAY_MS).toISOString();
1012
+ const result = await sweepTable(table, cutoff, dryRun, deadline, batchSize, perTableBatchCap, abortController.signal);
1013
+ if (dryRun && !result.complete) {
1014
+ throw new Error("dry-run count stopped before completion");
1015
+ }
1016
+ deletedAny ||= !dryRun && result.rowsDeleted > 0;
1017
+ const cumulative = (cumulativeRowsDeleted[table.metricsKey] ?? 0) + (dryRun ? 0 : result.rowsDeleted);
1018
+ cumulativeRowsDeleted[table.metricsKey] = cumulative;
1019
+ retentionStats[table.metricsKey] = {
1020
+ at: new Date().toISOString(),
1021
+ rowsDeleted: result.rowsDeleted,
1022
+ batches: result.batches,
1023
+ durationMs: Date.now() - startedAt,
1024
+ dryRun,
1025
+ cumulativeRowsDeleted: cumulative
1026
+ };
1027
+ if (result.rowsDeleted > 0) {
1028
+ console.log(`[db-retention] ${table.table}: ${dryRun ? "would delete" : "deleted"} ${result.rowsDeleted} row(s) in ${result.batches} batch(es) after ${Date.now() - startedAt}ms`);
1029
+ }
1030
+ } catch (err) {
1031
+ console.error(`[db-retention] ${table.table} sweep failed:`, err.message);
1032
+ }
1033
+ }
1034
+ if (deletedAny && !abortController.signal.aborted) {
1035
+ try {
1036
+ await getDbClient().run("PRAGMA incremental_vacuum(2000)");
1037
+ } catch (err) {
1038
+ console.error("[db-retention] incremental vacuum failed:", err.message);
1039
+ }
1040
+ }
1041
+ } finally {
1042
+ if (retentionAbortController === abortController)
1043
+ retentionAbortController = null;
1044
+ retentionTickPromise = null;
1045
+ }
1046
+ });
1047
+ retentionTickPromise = promise;
1048
+ return promise;
1049
+ }
1050
+ function getDbRetentionStats() {
1051
+ return { ...retentionStats };
1052
+ }
1053
+ async function startDbRetention(intervalMs = RETENTION_INTERVAL_MS) {
1054
+ if (retentionTimer)
1055
+ return;
1056
+ const configured = DB_RETENTION_TABLES.map((table) => `${table.table}=${retentionDays(table) ?? "disabled"}`).join(", ");
1057
+ console.log(`[db-retention] starting (${configured}, dryRun=${dryRunEnabled()})`);
1058
+ retentionTimer = scheduleContextFree(() => setInterval(() => void runDbRetentionTick(), intervalMs));
1059
+ if (typeof retentionTimer.unref === "function")
1060
+ retentionTimer.unref();
1061
+ await runDbRetentionTick();
1062
+ }
1063
+ async function stopDbRetention() {
1064
+ if (retentionTimer) {
1065
+ clearInterval(retentionTimer);
1066
+ retentionTimer = null;
1067
+ }
1068
+ retentionAbortController?.abort();
1069
+ await retentionTickPromise;
1070
+ }
1071
+
886
1072
  // src/be/scripts/retention.ts
887
1073
  init_db();
888
1074
  var SCRATCH_RETENTION_DAYS = 14;
@@ -18693,7 +18879,33 @@ var SwarmMetricsSchema = exports_external.object({
18693
18879
  workflows: exports_external.object({ total: exports_external.number(), enabled: exports_external.number() }),
18694
18880
  pages: exports_external.object({ total: exports_external.number() }),
18695
18881
  sessions: exports_external.object({ active: exports_external.number() }),
18696
- skills: exports_external.object({ total: exports_external.number() })
18882
+ skills: exports_external.object({ total: exports_external.number() }),
18883
+ retention: exports_external.object({
18884
+ sessionLogs: exports_external.object({
18885
+ at: exports_external.string(),
18886
+ rowsDeleted: exports_external.number(),
18887
+ batches: exports_external.number(),
18888
+ durationMs: exports_external.number(),
18889
+ dryRun: exports_external.boolean(),
18890
+ cumulativeRowsDeleted: exports_external.number()
18891
+ }).optional(),
18892
+ agentLog: exports_external.object({
18893
+ at: exports_external.string(),
18894
+ rowsDeleted: exports_external.number(),
18895
+ batches: exports_external.number(),
18896
+ durationMs: exports_external.number(),
18897
+ dryRun: exports_external.boolean(),
18898
+ cumulativeRowsDeleted: exports_external.number()
18899
+ }).optional(),
18900
+ events: exports_external.object({
18901
+ at: exports_external.string(),
18902
+ rowsDeleted: exports_external.number(),
18903
+ batches: exports_external.number(),
18904
+ durationMs: exports_external.number(),
18905
+ dryRun: exports_external.boolean(),
18906
+ cumulativeRowsDeleted: exports_external.number()
18907
+ }).optional()
18908
+ })
18697
18909
  });
18698
18910
  var ConcurrentContextSchema = exports_external.object({
18699
18911
  processingInboxMessages: exports_external.array(exports_external.object({
@@ -18848,7 +19060,10 @@ async function handleStats(req, res, pathSegments, queryParams, myAgentId) {
18848
19060
  return true;
18849
19061
  }
18850
19062
  if (getMetrics.match(req.method, pathSegments)) {
18851
- getMetrics.respond(res, 200, await getSwarmMetrics());
19063
+ getMetrics.respond(res, 200, {
19064
+ ...await getSwarmMetrics(),
19065
+ retention: getDbRetentionStats()
19066
+ });
18852
19067
  return true;
18853
19068
  }
18854
19069
  if (listServices.match(req.method, pathSegments)) {
@@ -19512,13 +19727,29 @@ var createTask = route({
19512
19727
  requestedByUserId: exports_external.string().optional(),
19513
19728
  model: exports_external.string().optional(),
19514
19729
  modelTier: ModelTierSchema.optional(),
19515
- effort: ReasoningEffortSchema.optional()
19730
+ effort: ReasoningEffortSchema.optional(),
19731
+ draft: exports_external.boolean().optional()
19516
19732
  }),
19517
19733
  responses: {
19518
19734
  201: { description: "Task created", schema: AgentTaskSchema },
19519
19735
  400: { description: "Validation error" }
19520
19736
  }
19521
19737
  });
19738
+ var promoteDraftTaskRoute = route({
19739
+ method: "post",
19740
+ path: "/api/tasks/{id}/promote-draft",
19741
+ pattern: ["api", "tasks", null, "promote-draft"],
19742
+ summary: "Promote a draft task out of the pre-dispatch draft state",
19743
+ description: "Transitions a `draft` task (#1240 — created with attachments still uploading) to its normal dispatch-eligible status: `offered` if it was offered to an agent, `pending` if it has an owning agent (the common case — UI-composer tasks default to Lead), otherwise `unassigned`. Called by the UI composer once its attachment upload batch settles, whether every file uploaded, some failed, or all failed — a draft must never be stranded by an upload error. Idempotent: calling it on a task that already left `draft` returns the current task unchanged rather than erroring, so a retried request is safe.",
19744
+ tags: ["Tasks"],
19745
+ params: exports_external.object({ id: exports_external.string() }),
19746
+ rbac: { permission: "task.action.own" },
19747
+ responses: {
19748
+ 200: { description: "Task promoted (or already out of draft)", schema: AgentTaskSchema },
19749
+ 403: { description: "Caller does not own this task" },
19750
+ 404: { description: "Task not found" }
19751
+ }
19752
+ });
19522
19753
  var updateSession = route({
19523
19754
  method: "put",
19524
19755
  path: "/api/tasks/{id}/session",
@@ -19867,6 +20098,30 @@ async function canSteerTask(req, myAgentId, task) {
19867
20098
  }
19868
20099
  return can({ principal, verb, resource, source: "http" }).allow;
19869
20100
  }
20101
+ async function canActOnOwnTask(req, myAgentId, task) {
20102
+ const resource = {
20103
+ kind: "task",
20104
+ taskId: task.id,
20105
+ requestedByUserId: task.requestedByUserId,
20106
+ creatorAgentId: task.creatorAgentId,
20107
+ agentId: task.agentId
20108
+ };
20109
+ let principal;
20110
+ const auth = getRequestAuth(req);
20111
+ if (auth?.kind === "operator") {
20112
+ principal = { kind: "operator" };
20113
+ } else if (auth?.kind === "user") {
20114
+ principal = { kind: "user", userId: auth.userId };
20115
+ } else {
20116
+ if (!myAgentId)
20117
+ return false;
20118
+ const agent = await getAgentById(myAgentId);
20119
+ if (!agent)
20120
+ return false;
20121
+ principal = { kind: "agent", agentId: myAgentId, isLead: agent.isLead };
20122
+ }
20123
+ return can({ principal, verb: "task.action.own", resource, source: "http" }).allow;
20124
+ }
19870
20125
  async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
19871
20126
  if (listTasks.match(req.method, pathSegments)) {
19872
20127
  const parsed = await listTasks.parse(req, res, pathSegments, queryParams);
@@ -19969,6 +20224,7 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
19969
20224
  outputSchema: parsed.body.outputSchema || undefined,
19970
20225
  contextKey: parsed.body.contextKey || undefined,
19971
20226
  requestedByUserId,
20227
+ status: parsed.body.draft ? "draft" : undefined,
19972
20228
  ...splitLegacyModelAlias({
19973
20229
  model: parsed.body.model,
19974
20230
  modelTier: parsed.body.modelTier
@@ -19997,6 +20253,28 @@ async function handleTasks(req, res, pathSegments, queryParams, myAgentId) {
19997
20253
  }
19998
20254
  return true;
19999
20255
  }
20256
+ if (promoteDraftTaskRoute.match(req.method, pathSegments)) {
20257
+ const parsed = await promoteDraftTaskRoute.parse(req, res, pathSegments, queryParams);
20258
+ if (!parsed)
20259
+ return true;
20260
+ const existingTask = await getTaskById(parsed.params.id);
20261
+ if (!existingTask) {
20262
+ jsonError(res, "Task not found", 404);
20263
+ return true;
20264
+ }
20265
+ const allowed = await canActOnOwnTask(req, myAgentId, existingTask);
20266
+ if (!allowed) {
20267
+ jsonError(res, "Not authorized to act on this task", 403);
20268
+ return true;
20269
+ }
20270
+ const promoted = existingTask.status === "draft" ? await promoteDraftTask(parsed.params.id) : existingTask;
20271
+ if (!promoted) {
20272
+ jsonError(res, "Task not found", 404);
20273
+ return true;
20274
+ }
20275
+ promoteDraftTaskRoute.respond(res, 200, promoted);
20276
+ return true;
20277
+ }
20000
20278
  if (updateSession.match(req.method, pathSegments)) {
20001
20279
  const parsed = await updateSession.parse(req, res, pathSegments, queryParams);
20002
20280
  if (!parsed)
@@ -23745,7 +24023,6 @@ var transportActivityUser = globalState.__transportActivityUser ?? {};
23745
24023
  var httpServer = createHttpServer(async (req, res) => {
23746
24024
  const startTime = performance.now();
23747
24025
  let statusCode = 200;
23748
- let spanEnded = false;
23749
24026
  const originalWriteHead = res.writeHead.bind(res);
23750
24027
  res.writeHead = (code, ...args) => {
23751
24028
  statusCode = code;
@@ -23763,8 +24040,10 @@ var httpServer = createHttpServer(async (req, res) => {
23763
24040
  await withRemoteContext(req.headers, async () => {
23764
24041
  const reqPath = req.url?.split("?")[0] ?? "";
23765
24042
  const pathSegments = getPathSegments(req.url || "");
24043
+ const hasQueryString = (req.url ?? "").includes("?");
24044
+ const hasTrailingSlash = reqPath.length > 1 && reqPath.endsWith("/");
23766
24045
  const skipSpan = reqPath === "/api/poll" && !isPollTracingEnabled();
23767
- const { spanName, httpRoute } = describeRequestRoute(req.method, pathSegments);
24046
+ const { spanName, httpRoute } = describeRequestRoute(req.method, pathSegments, hasQueryString, hasTrailingSlash);
23768
24047
  const semconv = httpServerSemconvAttributes(req);
23769
24048
  const span = skipSpan ? null : startSpan(spanName, {
23770
24049
  "http.request.method": req.method ?? "",
@@ -23776,29 +24055,9 @@ var httpServer = createHttpServer(async (req, res) => {
23776
24055
  "user_agent.original": semconv["user_agent.original"],
23777
24056
  "agent.id": req.headers["x-agent-id"],
23778
24057
  "agentswarm.component": "api"
23779
- });
24058
+ }, { kind: "server" });
23780
24059
  if (span) {
23781
- res.on("finish", () => {
23782
- if (spanEnded)
23783
- return;
23784
- spanEnded = true;
23785
- span.setAttributes({
23786
- "http.response.status_code": statusCode,
23787
- "agentswarm.http.duration_ms": Math.round((performance.now() - startTime) * 10) / 10
23788
- });
23789
- if (statusCode >= 500) {
23790
- span.setStatus({ code: 2, message: `HTTP ${statusCode}` });
23791
- }
23792
- span.end();
23793
- });
23794
- res.on("error", (err) => {
23795
- if (spanEnded)
23796
- return;
23797
- spanEnded = true;
23798
- span.recordException(err);
23799
- span.setStatus({ code: 2, message: err.message });
23800
- span.end();
23801
- });
24060
+ wireHttpSpanLifecycle(res, span, () => statusCode, startTime);
23802
24061
  }
23803
24062
  const handleRequest = async () => {
23804
24063
  setCorsHeaders(req, res);
@@ -23908,7 +24167,7 @@ async function shutdown() {
23908
24167
  sessionsProcessed: getServerSessionsProcessed()
23909
24168
  });
23910
24169
  if (hasCapability("scheduling")) {
23911
- const { stopScheduler } = await import("./index-2mdqrd0n.js");
24170
+ const { stopScheduler } = await import("./index-racb4wfq.js");
23912
24171
  stopScheduler();
23913
24172
  }
23914
24173
  stopHeartbeat();
@@ -23916,11 +24175,12 @@ async function shutdown() {
23916
24175
  await stopScriptRunSupervisor();
23917
24176
  await stopSlackApp();
23918
24177
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
23919
- const { stopOAuthKeepalive } = await import("./keepalive-3tycspcy.js");
24178
+ const { stopOAuthKeepalive } = await import("./keepalive-wxjd633a.js");
23920
24179
  await stopOAuthKeepalive();
23921
24180
  }
23922
24181
  stopOAuthPendingGc();
23923
24182
  stopMemoryGc();
24183
+ await stopDbRetention();
23924
24184
  stopScratchScriptGc();
23925
24185
  stopAuditGc();
23926
24186
  stopAuditWriter();
@@ -23980,15 +24240,15 @@ try {
23980
24240
  console.warn("[startup] CAPABILITIES upgrade seed failed (non-fatal):", err);
23981
24241
  }
23982
24242
  try {
23983
- const { seedPricingFromModelsDev } = await import("./seed-pricing-2kyk1vhg.js");
24243
+ const { seedPricingFromModelsDev } = await import("./seed-pricing-nbmd7ah8.js");
23984
24244
  seedPricingFromModelsDev();
23985
- const { startPricingRefreshLoop } = await import("./pricing-refresh-c2bwsyk5.js");
24245
+ const { startPricingRefreshLoop } = await import("./pricing-refresh-mkyy7c2y.js");
23986
24246
  startPricingRefreshLoop();
23987
24247
  } catch (err) {
23988
24248
  console.error("[startup] Failed to seed pricing rows:", err);
23989
24249
  }
23990
24250
  try {
23991
- const { ensureRbacSeedsSynced } = await import("./rbac-roles-reef5y2d.js");
24251
+ const { ensureRbacSeedsSynced } = await import("./rbac-roles-kb3afm95.js");
23992
24252
  ensureRbacSeedsSynced();
23993
24253
  } catch (err) {
23994
24254
  console.error("[startup] Failed to sync RBAC seed rows:", err);
@@ -23996,7 +24256,7 @@ try {
23996
24256
  throw err;
23997
24257
  }
23998
24258
  try {
23999
- const { runAllSeeders } = await import("./index-yd654kac.js");
24259
+ const { runAllSeeders } = await import("./index-17h657rg.js");
24000
24260
  await runAllSeeders({ scriptEmbeddingMode: "skip" });
24001
24261
  } catch (err) {
24002
24262
  console.error("[startup] Failed to seed built-in entities:", err);
@@ -24034,35 +24294,36 @@ httpServer.listen(port, async () => {
24034
24294
  await initWorkflows();
24035
24295
  await startScriptRunSupervisor(getMcpBaseUrl());
24036
24296
  if (hasCapability("scheduling")) {
24037
- const { startScheduler } = await import("./index-2mdqrd0n.js");
24038
- const { getExecutorRegistry: getExecutorRegistry2 } = await import("./index-4djjkp9z.js");
24297
+ const { startScheduler } = await import("./index-racb4wfq.js");
24298
+ const { getExecutorRegistry: getExecutorRegistry2 } = await import("./index-zh66wm65.js");
24039
24299
  const intervalMs = Number(process.env.SCHEDULER_INTERVAL_MS) || 1e4;
24040
24300
  startScheduler(getExecutorRegistry2(), intervalMs, {
24041
24301
  runId: globalState.__runId
24042
24302
  });
24043
24303
  }
24044
24304
  if (!isEnvFlagEnabled("HEARTBEAT_DISABLE", false)) {
24045
- const { startHeartbeat } = await import("./index-pzgasj16.js");
24305
+ const { startHeartbeat } = await import("./index-m2p7ctyh.js");
24046
24306
  const heartbeatMs = Number(process.env.HEARTBEAT_INTERVAL_MS) || 90000;
24047
24307
  startHeartbeat(heartbeatMs);
24048
24308
  }
24049
24309
  if (process.env.OAUTH_KEEPALIVE_DISABLE !== "true") {
24050
- const { startOAuthKeepalive } = await import("./keepalive-3tycspcy.js");
24310
+ const { startOAuthKeepalive } = await import("./keepalive-wxjd633a.js");
24051
24311
  startOAuthKeepalive();
24052
24312
  }
24053
24313
  if (process.env.OAUTH_REFRESH_SWEEP_DISABLE !== "true") {
24054
- const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-s33gtxrw.js");
24314
+ const { startOAuthRefreshSweep } = await import("./oauth-refresh-sweep-jwj22yb8.js");
24055
24315
  startOAuthRefreshSweep();
24056
24316
  }
24057
24317
  startOAuthPendingGc();
24058
24318
  await startMemoryGc();
24059
- import("./boot-reembed-y7r9cxt0.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
24319
+ await startDbRetention();
24320
+ import("./boot-reembed-6spqw4q0.js").then(({ runBootReembed }) => runBootReembed()).catch((err) => {
24060
24321
  console.error("[boot-reembed] startup backfill failed (non-fatal):", err);
24061
24322
  });
24062
- import("./boot-reembed-ncbg16rb.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
24323
+ import("./boot-reembed-b22s9w5x.js").then(({ runBootReembedScripts }) => runBootReembedScripts()).catch((err) => {
24063
24324
  console.error("[boot-reembed-scripts] startup backfill failed (non-fatal):", err);
24064
24325
  });
24065
- import("./boot-scrub-logs-t82rwa0y.js").then(({ runBootScrubLogs }) => runBootScrubLogs()).catch((err) => {
24326
+ import("./boot-scrub-logs-6h3cqkc0.js").then(({ runBootScrubLogs }) => runBootScrubLogs()).catch((err) => {
24066
24327
  console.error("[boot-scrub-logs] startup scrub failed (non-fatal):", err);
24067
24328
  });
24068
24329
  }).on("error", (err) => {