@desplega.ai/agent-swarm 1.102.0 → 1.103.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 (107) hide show
  1. package/dist/{actions-j9399ktm.js → actions-7txktrdj.js} +6 -6
  2. package/dist/{app-tnq1pz27.js → app-xm3xsdye.js} +3 -3
  3. package/dist/{assistant-c7y92gkw.js → assistant-qpv63wk6.js} +9 -9
  4. package/dist/{boot-reembed-k7e6fc1p.js → boot-reembed-9cxqka3e.js} +3 -3
  5. package/dist/{boot-reembed-b97r699t.js → boot-reembed-chxhrwv8.js} +4 -4
  6. package/dist/{boot-scrub-logs-14kbc61y.js → boot-scrub-logs-8qtfkcz8.js} +2 -2
  7. package/dist/{claude-managed-adapter-g07dbz3b.js → claude-managed-adapter-z29hjgzz.js} +3 -3
  8. package/dist/{cli-tsz1q7gk.js → cli-2307phk1.js} +375 -23
  9. package/dist/{cli-g5px3d7x.js → cli-2957pqpj.js} +24 -1
  10. package/dist/{cli-9qascwj7.js → cli-2qynerth.js} +1 -1
  11. package/dist/{cli-k1ghyj8b.js → cli-4fnp2tc3.js} +1 -1
  12. package/dist/{cli-hc4rd6sv.js → cli-85pf4z38.js} +1 -1
  13. package/dist/{cli-zk4gn40w.js → cli-8hyv6c2v.js} +6 -14
  14. package/dist/{cli-k81y1cjb.js → cli-8w95v19d.js} +1 -1
  15. package/dist/{cli-7xdq3jg3.js → cli-92fqyjcv.js} +1 -1
  16. package/dist/{cli-zctkpdmd.js → cli-dz3d6zjg.js} +1 -1
  17. package/dist/{cli-d0t4854c.js → cli-fedn86nz.js} +213 -476
  18. package/dist/{cli-g861fwjp.js → cli-fwxdt7kt.js} +3 -3
  19. package/dist/{cli-2aaa9mqr.js → cli-fygaw191.js} +2 -2
  20. package/dist/{cli-qbc6mncp.js → cli-gzepjz54.js} +2 -2
  21. package/dist/{cli-r68m8arr.js → cli-jt9d9fjw.js} +1 -1
  22. package/dist/{cli-axtg1zaa.js → cli-khe4x17a.js} +1 -1
  23. package/dist/{cli-sygq3fhn.js → cli-kk51f3tf.js} +5 -5
  24. package/dist/{cli-dgab5x2h.js → cli-krvxq8bc.js} +1 -1
  25. package/dist/{cli-xde8vhhp.js → cli-ksq38x4n.js} +2 -2
  26. package/dist/{cli-stqqf5kh.js → cli-m8f6qzck.js} +1 -1
  27. package/dist/{cli-ap4md0gc.js → cli-ns0r7mkr.js} +30 -5
  28. package/dist/{cli-t2jk33ta.js → cli-rttgde5f.js} +18 -6
  29. package/dist/{cli-mhj07xbq.js → cli-rvae030h.js} +3 -3
  30. package/dist/{cli-q6jzg6wj.js → cli-s14sb64w.js} +4 -4
  31. package/dist/{cli-zmf7refz.js → cli-v9283nma.js} +1 -1
  32. package/dist/{cli-fjx4x7nn.js → cli-xmtsan9k.js} +1 -1
  33. package/dist/{cli-vgck9mqq.js → cli-yeemwevj.js} +155 -37
  34. package/dist/{cli-5bqa41fd.js → cli-yfwwjeft.js} +1 -1
  35. package/dist/{cli-s8jw5bmg.js → cli-yp2krx5r.js} +2 -2
  36. package/dist/cli.js +9 -9
  37. package/dist/{codex-adapter-wf119mnw.js → codex-adapter-w0xharsg.js} +3 -3
  38. package/dist/{codex-session-runner-1gknw7mh.js → codex-session-runner-kzbjcm2k.js} +3 -3
  39. package/dist/{commands-2wyn3swb.js → commands-aqn63mcw.js} +2 -2
  40. package/dist/{db-567ntpxv.js → db-azrvwsnj.js} +2 -2
  41. package/dist/{handlers-wvwpk2kj.js → handlers-hf61har3.js} +9 -9
  42. package/dist/{hook-fatkywc0.js → hook-306p3yz4.js} +2 -2
  43. package/dist/{http-eq6wxve6.js → http-zts4haq7.js} +81 -62
  44. package/dist/{index-400x6p3j.js → index-29vg51x6.js} +6 -6
  45. package/dist/{index-9wqh5352.js → index-3c651yfk.js} +10 -10
  46. package/dist/{index-6aj8966p.js → index-bfh9hgek.js} +5 -5
  47. package/dist/{index-d1rm4ea3.js → index-h2yqjyk0.js} +8 -8
  48. package/dist/{keepalive-6x9nx92g.js → keepalive-a0dg5pds.js} +4 -4
  49. package/dist/{lead-5fgqwe13.js → lead-7mcxedkc.js} +21 -21
  50. package/dist/{maintenance-eajx5k1k.js → maintenance-mrzqd53t.js} +4 -4
  51. package/dist/{onboard-jc1w1edg.js → onboard-4dkpv9wa.js} +2 -2
  52. package/dist/{otel-impl-8k375amf.js → otel-impl-jt7gpyp9.js} +1 -1
  53. package/dist/{pi-mono-adapter-hf8sw7hs.js → pi-mono-adapter-zf7dt1wg.js} +1 -1
  54. package/dist/{pricing-refresh-zed6916t.js → pricing-refresh-xqnzh8dt.js} +4 -4
  55. package/dist/{seed-pricing-5805qzkz.js → seed-pricing-56tjm1fj.js} +3 -3
  56. package/dist/{setup-wz05vxh0.js → setup-tbwk8j10.js} +2 -2
  57. package/dist/{worker-j359graf.js → worker-e03za92t.js} +21 -21
  58. package/openapi.json +70 -1
  59. package/package.json +1 -1
  60. package/src/be/db.ts +83 -13
  61. package/src/be/migrations/098_repo_hooks_config.sql +3 -0
  62. package/src/be/task-lifecycle-events.ts +42 -0
  63. package/src/commands/runner.ts +174 -25
  64. package/src/github/task-reactions.ts +21 -0
  65. package/src/hooks/tool-loop-detection.test.ts +40 -0
  66. package/src/hooks/tool-loop-detection.ts +37 -1
  67. package/src/http/agents.ts +7 -0
  68. package/src/http/index.ts +16 -2
  69. package/src/http/prompt-templates.ts +1 -1
  70. package/src/http/repos.ts +5 -1
  71. package/src/http/schedules.ts +1 -1
  72. package/src/http/session-data.ts +2 -0
  73. package/src/http/tasks.ts +2 -1
  74. package/src/http/workflows.ts +1 -0
  75. package/src/prompts/resolver.ts +1 -1
  76. package/src/scheduler/scheduler.ts +25 -2
  77. package/src/server-runtime-counters.ts +12 -0
  78. package/src/server-user.ts +1 -2
  79. package/src/server.ts +5 -0
  80. package/src/telemetry.ts +18 -1
  81. package/src/tests/http-api-integration.test.ts +4 -0
  82. package/src/tests/model-control.test.ts +6 -6
  83. package/src/tests/swarm-repos.test.ts +25 -2
  84. package/src/tests/task-lifecycle-events.test.ts +53 -0
  85. package/src/tests/task-lifecycle-telemetry.test.ts +37 -1
  86. package/src/tests/telemetry-init.test.ts +32 -0
  87. package/src/tools/prompt-templates/preview.ts +1 -1
  88. package/src/tools/repos/update-repo.ts +6 -1
  89. package/src/tools/schedules/create-schedule.ts +1 -1
  90. package/src/tools/schedules/update-schedule.ts +1 -1
  91. package/src/tools/send-task.ts +7 -2
  92. package/src/tools/task-action.ts +6 -2
  93. package/src/types.ts +155 -1
  94. package/src/utils/template.ts +127 -0
  95. package/src/workflows/engine.ts +7 -0
  96. package/src/workflows/executors/agent-task.ts +1 -2
  97. package/src/workflows/template.ts +12 -121
  98. package/src/workflows/triggers.ts +6 -2
  99. package/templates/community/code-health-reports/PLAYBOOK.md +355 -0
  100. package/templates/community/code-health-reports/README.md +38 -0
  101. package/templates/community/code-health-reports/lead-prompt.md +52 -0
  102. package/templates/community/code-health-reports/report.mjs +378 -0
  103. package/templates/community/code-health-reports/run.sh +143 -0
  104. package/templates/schedules/weekly-code-health-reports/config.json +13 -0
  105. package/templates/schedules/weekly-code-health-reports/content.md +60 -0
  106. package/src/model-tiers.ts +0 -140
  107. package/templates/community/.gitkeep +0 -0
@@ -8,13 +8,13 @@ import {
8
8
  authJsonToCredentialSelection,
9
9
  checkCodexCredentials,
10
10
  credentialsToAuthJson
11
- } from "./cli-axtg1zaa.js";
11
+ } from "./cli-khe4x17a.js";
12
12
  import {
13
13
  loadAllCodexOAuthSlots
14
14
  } from "./cli-4wmnp8q3.js";
15
15
  import {
16
16
  checkClaudeManagedCredentials
17
- } from "./cli-s8jw5bmg.js";
17
+ } from "./cli-yp2krx5r.js";
18
18
  import {
19
19
  checkDevinCredentials
20
20
  } from "./cli-tyfxrrdd.js";
@@ -29,7 +29,7 @@ import {
29
29
  withSpan,
30
30
  withSpanContext,
31
31
  writeSkillsToFilesystem
32
- } from "./cli-tsz1q7gk.js";
32
+ } from "./cli-2307phk1.js";
33
33
  import {
34
34
  checkClaudeCredentials
35
35
  } from "./cli-p04j6hjv.js";
@@ -49,10 +49,10 @@ import {
49
49
  import {
50
50
  ensure,
51
51
  initialize
52
- } from "./cli-ap4md0gc.js";
52
+ } from "./cli-ns0r7mkr.js";
53
53
  import {
54
54
  validateJsonSchema
55
- } from "./cli-t2jk33ta.js";
55
+ } from "./cli-rttgde5f.js";
56
56
  import {
57
57
  getMcpBaseUrl
58
58
  } from "./cli-dh55d5fg.js";
@@ -65,7 +65,6 @@ import {
65
65
  generateDefaultToolsMd,
66
66
  initTelemetry,
67
67
  init_defaults,
68
- init_model_tiers,
69
68
  init_resolver,
70
69
  init_session_templates,
71
70
  init_telemetry,
@@ -76,7 +75,7 @@ import {
76
75
  resolveTaskModelSelection,
77
76
  resolveTemplateAsync,
78
77
  telemetry
79
- } from "./cli-d0t4854c.js";
78
+ } from "./cli-fedn86nz.js";
80
79
  import {
81
80
  init_credentials,
82
81
  resolveCredentialPools
@@ -92,7 +91,6 @@ import {
92
91
  // src/commands/runner.ts
93
92
  import { existsSync, statSync } from "node:fs";
94
93
  import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
95
- init_model_tiers();
96
94
 
97
95
  // src/prompts/base-prompt.ts
98
96
  init_resolver();
@@ -441,15 +439,15 @@ async function createProviderAdapter(provider) {
441
439
  return new ClaudeAdapter;
442
440
  }
443
441
  case "pi": {
444
- const { PiMonoAdapter } = await import("./pi-mono-adapter-hf8sw7hs.js");
442
+ const { PiMonoAdapter } = await import("./pi-mono-adapter-zf7dt1wg.js");
445
443
  return new PiMonoAdapter;
446
444
  }
447
445
  case "codex": {
448
- const { CodexAdapter } = await import("./codex-adapter-wf119mnw.js");
446
+ const { CodexAdapter } = await import("./codex-adapter-w0xharsg.js");
449
447
  return new CodexAdapter;
450
448
  }
451
449
  case "claude-managed": {
452
- const { ClaudeManagedAdapter } = await import("./claude-managed-adapter-g07dbz3b.js");
450
+ const { ClaudeManagedAdapter } = await import("./claude-managed-adapter-z29hjgzz.js");
453
451
  return new ClaudeManagedAdapter;
454
452
  }
455
453
  case "devin": {
@@ -467,6 +465,7 @@ async function createProviderAdapter(provider) {
467
465
 
468
466
  // src/commands/runner.ts
469
467
  init_telemetry();
468
+ init_types();
470
469
 
471
470
  // src/utils/budget-backoff.ts
472
471
  var BUDGET_BACKOFF_CAP_MS = 5 * 60 * 1000;
@@ -802,6 +801,9 @@ async function refreshSkillsIfChanged(ctx, lastHashRef, homeOverride) {
802
801
  return { changed: true, summary };
803
802
  }
804
803
 
804
+ // src/commands/runner.ts
805
+ init_template();
806
+
805
807
  // src/vcs/index.ts
806
808
  function detectVcsProvider(url) {
807
809
  if (url.includes("gitlab.com") || url.includes("gitlab."))
@@ -811,9 +813,6 @@ function detectVcsProvider(url) {
811
813
  return null;
812
814
  }
813
815
 
814
- // src/commands/runner.ts
815
- init_template();
816
-
817
816
  // src/commands/context-preamble.ts
818
817
  init_secret_scrubber();
819
818
  var CONTEXT_PREAMBLE_MAX_TOKENS = Number(process.env.CONTEXT_PREAMBLE_MAX_TOKENS || "2000");
@@ -1108,7 +1107,7 @@ async function checkProviderCredentials(provider, env, opts) {
1108
1107
  case "opencode":
1109
1108
  return checkOpencodeCredentials(env, opts);
1110
1109
  case "pi": {
1111
- const { checkPiMonoCredentials } = await import("./pi-mono-adapter-hf8sw7hs.js");
1110
+ const { checkPiMonoCredentials } = await import("./pi-mono-adapter-zf7dt1wg.js");
1112
1111
  return checkPiMonoCredentials(env, opts);
1113
1112
  }
1114
1113
  default:
@@ -1588,6 +1587,24 @@ async function refreshExistingRepoForTask(repoConfig, role) {
1588
1587
  return `The repo "${name}" at ${clonePath} could not be refreshed from origin/${defaultBranch}: ${errorMsg}.${stashNote}`;
1589
1588
  }
1590
1589
  }
1590
+ function getInstallRepoHooksScriptPath() {
1591
+ const imagePath = "/usr/local/bin/install-repo-hooks.sh";
1592
+ if (existsSync(imagePath))
1593
+ return imagePath;
1594
+ return `${process.cwd()}/scripts/install-repo-hooks.sh`;
1595
+ }
1596
+ async function installRepoHooksForTask(repoConfig, role) {
1597
+ if (repoConfig.hooks?.enabled !== true)
1598
+ return;
1599
+ try {
1600
+ const scriptPath = getInstallRepoHooksScriptPath();
1601
+ await Bun.$`bash ${scriptPath} ${repoConfig.clonePath} ${repoConfig.name}`;
1602
+ console.log(`[${role}] Installed git hooks for ${repoConfig.name}`);
1603
+ } catch (err) {
1604
+ const errorMsg = scrubSecrets(err.message);
1605
+ console.warn(`[${role}] Could not install git hooks for ${repoConfig.name}: ${errorMsg}`);
1606
+ }
1607
+ }
1591
1608
  async function ensureRepoForTask(repoConfig, role) {
1592
1609
  const { url, name, clonePath, defaultBranch } = repoConfig;
1593
1610
  try {
@@ -1611,6 +1628,7 @@ async function ensureRepoForTask(repoConfig, role) {
1611
1628
  console.log(`[${role}] Repo ${name} already cloned at ${clonePath}`);
1612
1629
  warning = await refreshExistingRepoForTask({ name, clonePath, defaultBranch }, role);
1613
1630
  }
1631
+ await installRepoHooksForTask(repoConfig, role);
1614
1632
  const claudeMd = await readClaudeMd(clonePath, role);
1615
1633
  const autoStashes = await listSwarmAutostashes(clonePath, role);
1616
1634
  return { clonePath, claudeMd, warning, autoStashes };
@@ -2359,7 +2377,11 @@ function setupShutdownHandlers(role, apiConfig, getRunnerState) {
2359
2377
  }
2360
2378
  }
2361
2379
  if (apiConfig) {
2362
- telemetry.session("ended", { agentId: apiConfig.agentId });
2380
+ telemetry.session("ended", {
2381
+ agentId: apiConfig.agentId,
2382
+ durationMs: state ? Date.now() - state.startedAt : undefined,
2383
+ tasksProcessed: state?.tasksProcessed ?? 0
2384
+ });
2363
2385
  await closeAgent(apiConfig, role);
2364
2386
  }
2365
2387
  await savePm2State(role);
@@ -3023,6 +3045,18 @@ function providerEventAttributes(event) {
3023
3045
  return {};
3024
3046
  }
3025
3047
  }
3048
+ function normalizeSessionErrorCategory(category) {
3049
+ switch (category) {
3050
+ case "rate_limit":
3051
+ case "api_error":
3052
+ case "context_overflow":
3053
+ case "timeout":
3054
+ case "provider_error":
3055
+ return category;
3056
+ default:
3057
+ return "unknown";
3058
+ }
3059
+ }
3026
3060
  function implicitCloseActiveToolSpans(activeToolSpans, now = Date.now()) {
3027
3061
  let closed = 0;
3028
3062
  for (const [toolCallId, active] of activeToolSpans) {
@@ -3151,6 +3185,9 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
3151
3185
  const eventFlushTimer = setInterval(flushEvents, EVENT_FLUSH_INTERVAL_MS);
3152
3186
  const sessionStartTime = Date.now();
3153
3187
  let providerSessionId = session.sessionId;
3188
+ let pendingHarnessVariant;
3189
+ let pendingHarnessVariantMeta;
3190
+ let runningTaskForSessionInit;
3154
3191
  const activeToolSpans = new Map;
3155
3192
  if (providerSessionId) {
3156
3193
  sessionSpan.setAttribute("agentswarm.provider.session_id", providerSessionId);
@@ -3159,11 +3196,34 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
3159
3196
  let lastContextPostTime = 0;
3160
3197
  const CONTEXT_THROTTLE_MS = 30000;
3161
3198
  let cumulativeProgressOutputTokens = 0;
3199
+ function bufferSessionLogLine(content) {
3200
+ if (!shouldStream)
3201
+ return;
3202
+ logBuffer.lines.push(content);
3203
+ const shouldFlush = logBuffer.lines.length >= LOG_BUFFER_SIZE || Date.now() - logBuffer.lastFlush >= LOG_FLUSH_INTERVAL_MS;
3204
+ if (shouldFlush) {
3205
+ flushLogBuffer(logBuffer, {
3206
+ apiUrl: opts.apiUrl,
3207
+ apiKey: opts.apiKey,
3208
+ agentId: opts.agentId,
3209
+ sessionId: opts.runnerSessionId,
3210
+ iteration: opts.iteration,
3211
+ taskId: effectiveTaskId,
3212
+ cli: adapter.name
3213
+ }).catch(() => {});
3214
+ }
3215
+ }
3162
3216
  session.onEvent((event) => withSpanContext(sessionSpan, () => {
3163
3217
  sessionSpan.addEvent(`provider.${event.type}`, providerEventAttributes(event));
3164
3218
  switch (event.type) {
3165
3219
  case "session_init":
3166
3220
  providerSessionId = event.sessionId;
3221
+ pendingHarnessVariant = event.harnessVariant;
3222
+ pendingHarnessVariantMeta = event.harnessVariantMeta;
3223
+ if (runningTaskForSessionInit) {
3224
+ runningTaskForSessionInit.harnessVariant = event.harnessVariant;
3225
+ runningTaskForSessionInit.harnessVariantMeta = event.harnessVariantMeta;
3226
+ }
3167
3227
  sessionSpan.setAttributes({
3168
3228
  "agentswarm.provider.session_id": providerSessionId,
3169
3229
  "agentswarm.provider.name": event.provider,
@@ -3350,6 +3410,11 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
3350
3410
  break;
3351
3411
  }
3352
3412
  case "compaction": {
3413
+ telemetry.compaction("triggered", {
3414
+ compactTrigger: event.compactTrigger,
3415
+ preCompactTokens: event.preCompactTokens,
3416
+ contextTotalTokens: event.contextTotalTokens
3417
+ });
3353
3418
  fetch(`${opts.apiUrl}/api/tasks/${realTaskId}/context`, {
3354
3419
  method: "POST",
3355
3420
  headers: {
@@ -3369,24 +3434,15 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
3369
3434
  }
3370
3435
  case "raw_log":
3371
3436
  prettyPrintLine(event.content, opts.role);
3372
- if (shouldStream) {
3373
- logBuffer.lines.push(event.content);
3374
- const shouldFlush = logBuffer.lines.length >= LOG_BUFFER_SIZE || Date.now() - logBuffer.lastFlush >= LOG_FLUSH_INTERVAL_MS;
3375
- if (shouldFlush) {
3376
- flushLogBuffer(logBuffer, {
3377
- apiUrl: opts.apiUrl,
3378
- apiKey: opts.apiKey,
3379
- agentId: opts.agentId,
3380
- sessionId: opts.runnerSessionId,
3381
- iteration: opts.iteration,
3382
- taskId: effectiveTaskId,
3383
- cli: adapter.name
3384
- }).catch(() => {});
3385
- }
3386
- }
3437
+ bufferSessionLogLine(event.content);
3387
3438
  break;
3388
3439
  case "raw_stderr":
3389
3440
  prettyPrintStderr(event.content, opts.role);
3441
+ bufferSessionLogLine(JSON.stringify({
3442
+ type: "stderr",
3443
+ content: event.content,
3444
+ timestamp: new Date().toISOString()
3445
+ }));
3390
3446
  break;
3391
3447
  case "progress": {
3392
3448
  if (effectiveTaskId && opts.apiUrl) {
@@ -3454,6 +3510,21 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
3454
3510
  "gen_ai.usage.output_tokens": result.cost.outputTokens ?? 0,
3455
3511
  "agentswarm.cost.total_usd": result.cost.totalCostUsd ?? 0
3456
3512
  });
3513
+ telemetry.session("cost", {
3514
+ agentId: opts.agentId,
3515
+ model: result.cost.model,
3516
+ provider: result.cost.provider ?? opts.harnessProvider,
3517
+ inputTokens: result.cost.inputTokens ?? 0,
3518
+ outputTokens: result.cost.outputTokens ?? 0,
3519
+ cacheReadTokens: result.cost.cacheReadTokens,
3520
+ cacheWriteTokens: result.cost.cacheWriteTokens,
3521
+ reasoningOutputTokens: result.cost.reasoningOutputTokens,
3522
+ thinkingTokens: result.cost.thinkingTokens,
3523
+ totalCostUsd: result.cost.totalCostUsd,
3524
+ durationMs: result.cost.durationMs,
3525
+ numTurns: result.cost.numTurns,
3526
+ isError: result.cost.isError
3527
+ });
3457
3528
  try {
3458
3529
  await saveCostData({ ...result.cost, taskId: realTaskId, sessionId: opts.runnerSessionId }, opts.apiUrl, opts.apiKey);
3459
3530
  } catch (err) {
@@ -3530,8 +3601,16 @@ async function spawnProviderProcess(adapter, opts, logDir, isYolo) {
3530
3601
  result: null,
3531
3602
  credentialInfo,
3532
3603
  harnessProvider: opts.harnessProvider,
3533
- hasLocalEnvironment: adapter.traits.hasLocalEnvironment
3604
+ hasLocalEnvironment: adapter.traits.hasLocalEnvironment,
3605
+ model: model || undefined
3534
3606
  };
3607
+ runningTaskForSessionInit = runningTask;
3608
+ if (pendingHarnessVariant !== undefined) {
3609
+ runningTask.harnessVariant = pendingHarnessVariant;
3610
+ }
3611
+ if (pendingHarnessVariantMeta !== undefined) {
3612
+ runningTask.harnessVariantMeta = pendingHarnessVariantMeta;
3613
+ }
3535
3614
  promise.then((r) => {
3536
3615
  runningTask.result = r;
3537
3616
  }).catch(() => {
@@ -3552,7 +3631,11 @@ async function checkCompletedProcesses(state, role, apiConfig, cancelledSignaled
3552
3631
  workingDir: task.workingDir,
3553
3632
  credentialInfo: task.credentialInfo,
3554
3633
  harnessProvider: task.harnessProvider,
3555
- hasLocalEnvironment: task.hasLocalEnvironment
3634
+ hasLocalEnvironment: task.hasLocalEnvironment,
3635
+ harnessVariant: task.harnessVariant,
3636
+ harnessVariantMeta: task.harnessVariantMeta,
3637
+ model: task.model,
3638
+ durationMs: Date.now() - task.startTime.getTime()
3556
3639
  });
3557
3640
  }
3558
3641
  }
@@ -3562,7 +3645,11 @@ async function checkCompletedProcesses(state, role, apiConfig, cancelledSignaled
3562
3645
  cursorUpdates,
3563
3646
  workingDir,
3564
3647
  credentialInfo,
3565
- harnessProvider
3648
+ harnessProvider,
3649
+ harnessVariant,
3650
+ harnessVariantMeta,
3651
+ model,
3652
+ durationMs
3566
3653
  } of completedTasks) {
3567
3654
  state.activeTasks.delete(taskId);
3568
3655
  vcsDetectedTasks.delete(taskId);
@@ -3625,6 +3712,28 @@ async function checkCompletedProcesses(state, role, apiConfig, cancelledSignaled
3625
3712
  const bridgeFailureDiagnostics = bridgeDiagnostics?.paneTail != null ? `Claude bridge final tmux pane tail (${bridgeDiagnostics.artifactPath}):
3626
3713
  ${bridgeDiagnostics.paneTail}` : undefined;
3627
3714
  await ensureTaskFinished(apiConfig, role, taskId, result.exitCode, failureReason, result.output, harnessProvider, bridgeFailureDiagnostics);
3715
+ telemetry.taskEvent("session_completed", {
3716
+ taskId,
3717
+ agentId: apiConfig.agentId,
3718
+ provider: result.cost?.provider ?? harnessProvider,
3719
+ model: result.cost?.model ?? model,
3720
+ harnessVariant,
3721
+ harnessVersion: typeof harnessVariantMeta?.version === "string" || typeof harnessVariantMeta?.version === "number" ? String(harnessVariantMeta.version) : undefined,
3722
+ exitCode: result.exitCode,
3723
+ isError: result.exitCode !== 0,
3724
+ durationMs
3725
+ });
3726
+ if (result.exitCode !== 0 || result.isError) {
3727
+ telemetry.session("failure", {
3728
+ agentId: apiConfig.agentId,
3729
+ errorCategory: normalizeSessionErrorCategory(result.errorCategory),
3730
+ provider: result.cost?.provider ?? harnessProvider,
3731
+ model: result.cost?.model ?? model,
3732
+ durationMs: result.cost?.durationMs ?? durationMs,
3733
+ wasRateLimited: result.rateLimitResetAt != null
3734
+ });
3735
+ }
3736
+ state.tasksProcessed += 1;
3628
3737
  if (result.exitCode === 0 && credentialInfo) {
3629
3738
  reportKeyClearRateLimit(apiConfig.apiUrl, apiConfig.apiKey, credentialInfo.keyType, credentialInfo.keySuffix).catch(() => {});
3630
3739
  }
@@ -3733,10 +3842,12 @@ async function runAgent(config, opts) {
3733
3842
  const swarmUrl = process.env.SWARM_URL || "localhost";
3734
3843
  const apiKey = getApiKey();
3735
3844
  let bootProvider;
3845
+ let bootModel = process.env.MODEL_OVERRIDE || "";
3736
3846
  let bootCooldownMs = resolveCodexCreditsExhaustedCooldownMs(undefined);
3737
3847
  try {
3738
3848
  const bootEnv = await fetchResolvedEnv(apiUrl, apiKey, agentId);
3739
3849
  bootProvider = bootEnv.resolvedProvider;
3850
+ bootModel = bootEnv.env.MODEL_OVERRIDE || bootModel;
3740
3851
  bootCooldownMs = resolveCodexCreditsExhaustedCooldownMs(bootEnv.env.CODEX_CREDITS_EXHAUSTED_COOLDOWN_MS);
3741
3852
  } catch (err) {
3742
3853
  console.warn(`[runner] fetchResolvedEnv failed at boot, falling back to env for provider and the default cooldown: ${err}`);
@@ -3780,7 +3891,12 @@ async function runAgent(config, opts) {
3780
3891
  } catch {}
3781
3892
  });
3782
3893
  }
3783
- telemetry.session("started", { agentId });
3894
+ telemetry.session("started", {
3895
+ agentId,
3896
+ harnessProvider: bootProvider,
3897
+ model: bootModel || undefined,
3898
+ role
3899
+ });
3784
3900
  let capabilities = config.capabilities;
3785
3901
  let agentSoulMd;
3786
3902
  let agentIdentityMd;
@@ -3889,6 +4005,8 @@ ${additionalSystemPrompt}` : basePrompt;
3889
4005
  const state = {
3890
4006
  activeTasks: new Map,
3891
4007
  maxConcurrent,
4008
+ startedAt: Date.now(),
4009
+ tasksProcessed: 0,
3892
4010
  harnessProvider: bootProvider,
3893
4011
  codexCreditsExhaustedCooldownMs: bootCooldownMs
3894
4012
  };
@@ -4309,7 +4427,7 @@ ${additionalSystemPrompt}` : basePrompt;
4309
4427
  const effectiveConfig = repoConfig ?? {
4310
4428
  url: task.vcsRepo,
4311
4429
  name: task.vcsRepo.split("/").pop() || task.vcsRepo,
4312
- clonePath: `/workspace/repos/${task.vcsRepo.split("/").pop() || task.vcsRepo}`,
4430
+ clonePath: `/workspace/personal/repos/${task.vcsRepo.split("/").pop() || task.vcsRepo}`,
4313
4431
  defaultBranch: "main"
4314
4432
  };
4315
4433
  const repoContext = await ensureRepoForTask(effectiveConfig, role);
@@ -4537,7 +4655,7 @@ ${additionalSystemPrompt}` : basePrompt;
4537
4655
  const effectiveConfig = repoConfig ?? {
4538
4656
  url: taskVcsRepo,
4539
4657
  name: taskVcsRepo.split("/").pop() || taskVcsRepo,
4540
- clonePath: `/workspace/repos/${taskVcsRepo.split("/").pop() || taskVcsRepo}`,
4658
+ clonePath: `/workspace/personal/repos/${taskVcsRepo.split("/").pop() || taskVcsRepo}`,
4541
4659
  defaultBranch: "main"
4542
4660
  };
4543
4661
  const repoResult = await ensureRepoForTask(effectiveConfig, role);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getDb,
3
3
  init_db
4
- } from "./cli-d0t4854c.js";
4
+ } from "./cli-fedn86nz.js";
5
5
 
6
6
  // src/be/users.ts
7
7
  init_db();
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  createSwarmEventHandler
3
- } from "./cli-7xdq3jg3.js";
3
+ } from "./cli-92fqyjcv.js";
4
4
  import {
5
5
  checkToolLoop
6
- } from "./cli-g5px3d7x.js";
6
+ } from "./cli-2957pqpj.js";
7
7
  import {
8
8
  readPkgVersion
9
9
  } from "./cli-d6n0thxw.js";
package/dist/cli.js CHANGED
@@ -62,7 +62,7 @@ var import_react = __toESM(require_react(), 1);
62
62
  // package.json
63
63
  var package_default = {
64
64
  name: "@desplega.ai/agent-swarm",
65
- version: "1.102.0",
65
+ version: "1.103.0",
66
66
  description: "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
67
67
  license: "MIT",
68
68
  author: "desplega.sh <contact@desplega.sh>",
@@ -616,7 +616,7 @@ function McpServer({ port, apiKey, dbPath }) {
616
616
  if (dbPath) {
617
617
  process.env.DATABASE_PATH = dbPath;
618
618
  }
619
- import("./http-eq6wxve6.js").then(() => {
619
+ import("./http-zts4haq7.js").then(() => {
620
620
  setStatus("running");
621
621
  }).catch((err) => {
622
622
  setStatus("error");
@@ -702,7 +702,7 @@ function WorkerRunner({
702
702
  }) {
703
703
  const { exit } = use_app_default();
704
704
  import_react.useEffect(() => {
705
- import("./worker-j359graf.js").then(({ runWorker }) => runWorker({
705
+ import("./worker-e03za92t.js").then(({ runWorker }) => runWorker({
706
706
  prompt: prompt || undefined,
707
707
  yolo,
708
708
  systemPrompt: systemPrompt || undefined,
@@ -719,7 +719,7 @@ function WorkerRunner({
719
719
  function LeadRunner({ prompt, yolo, systemPrompt, systemPromptFile, additionalArgs }) {
720
720
  const { exit } = use_app_default();
721
721
  import_react.useEffect(() => {
722
- import("./lead-5fgqwe13.js").then(({ runLead }) => runLead({
722
+ import("./lead-7mcxedkc.js").then(({ runLead }) => runLead({
723
723
  prompt: prompt || undefined,
724
724
  yolo,
725
725
  systemPrompt: systemPrompt || undefined,
@@ -759,8 +759,8 @@ function LazyComponent({
759
759
  }
760
760
  return import_react.createElement(Component, props);
761
761
  }
762
- var loadOnboard = () => import("./onboard-jc1w1edg.js").then(({ Onboard }) => Onboard);
763
- var loadConnect = () => import("./setup-wz05vxh0.js").then(({ Setup }) => Setup);
762
+ var loadOnboard = () => import("./onboard-4dkpv9wa.js").then(({ Onboard }) => Onboard);
763
+ var loadConnect = () => import("./setup-tbwk8j10.js").then(({ Setup }) => Setup);
764
764
  function UnknownCommand({ command }) {
765
765
  const { exit } = use_app_default();
766
766
  import_react.useEffect(() => {
@@ -873,7 +873,7 @@ ${binName} docs \u2014 v${package_default.version}
873
873
  }
874
874
  process.exit(0);
875
875
  } else if (args.command === "hook") {
876
- const { runHook } = await import("./hook-fatkywc0.js");
876
+ const { runHook } = await import("./hook-306p3yz4.js");
877
877
  await runHook();
878
878
  } else if (args.command === "artifact") {
879
879
  const artifactArgs = process.argv.slice(process.argv.indexOf("artifact") + 1);
@@ -893,7 +893,7 @@ ${binName} docs \u2014 v${package_default.version}
893
893
  printHelp("scripts");
894
894
  process.exit(scriptsArgs[0] === "reembed" || args.showHelp ? 0 : 1);
895
895
  }
896
- const { runScriptsMaintenanceCommand } = await import("./maintenance-eajx5k1k.js");
896
+ const { runScriptsMaintenanceCommand } = await import("./maintenance-mrzqd53t.js");
897
897
  await runScriptsMaintenanceCommand(scriptsArgs);
898
898
  console.log("Scripts re-embedded.");
899
899
  } else if (args.command === "codex-login") {
@@ -901,7 +901,7 @@ ${binName} docs \u2014 v${package_default.version}
901
901
  const codexLoginArgs = process.argv.slice(process.argv.indexOf("codex-login") + 1);
902
902
  await runCodexLogin(codexLoginArgs);
903
903
  } else if (args.command === "codex-session-runner") {
904
- const { runCodexSessionRunner } = await import("./codex-session-runner-1gknw7mh.js");
904
+ const { runCodexSessionRunner } = await import("./codex-session-runner-kzbjcm2k.js");
905
905
  await runCodexSessionRunner();
906
906
  } else if (args.command === "claude-managed-setup") {
907
907
  const { runClaudeManagedSetup } = await import("./claude-managed-setup-ftbmvmvx.js");
@@ -5,11 +5,11 @@ import {
5
5
  checkCodexCredentials,
6
6
  createInProcessCodexSession,
7
7
  resolveCodexRunnerArgv
8
- } from "./cli-axtg1zaa.js";
8
+ } from "./cli-khe4x17a.js";
9
9
  import"./cli-p03mawph.js";
10
10
  import"./cli-4wmnp8q3.js";
11
- import"./cli-7xdq3jg3.js";
12
- import"./cli-g5px3d7x.js";
11
+ import"./cli-92fqyjcv.js";
12
+ import"./cli-2957pqpj.js";
13
13
  import"./cli-r94z9p1z.js";
14
14
  import"./cli-d6n0thxw.js";
15
15
  import"./cli-hx1dcevq.js";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createInProcessCodexSession
3
- } from "./cli-axtg1zaa.js";
3
+ } from "./cli-khe4x17a.js";
4
4
  import"./cli-p03mawph.js";
5
5
  import"./cli-4wmnp8q3.js";
6
- import"./cli-7xdq3jg3.js";
7
- import"./cli-g5px3d7x.js";
6
+ import"./cli-92fqyjcv.js";
7
+ import"./cli-2957pqpj.js";
8
8
  import"./cli-r94z9p1z.js";
9
9
  import"./cli-d6n0thxw.js";
10
10
  import"./cli-hx1dcevq.js";
@@ -2,11 +2,11 @@ import {
2
2
  getAllAgents,
3
3
  getAllTasks,
4
4
  init_db
5
- } from "./cli-d0t4854c.js";
5
+ } from "./cli-fedn86nz.js";
6
6
  import"./cli-z2zcxes1.js";
7
7
  import"./cli-q21d49ac.js";
8
8
  import"./cli-anrj584m.js";
9
- import"./cli-hc4rd6sv.js";
9
+ import"./cli-85pf4z38.js";
10
10
  import"./cli-3pp1362w.js";
11
11
  import"./cli-p9swy5t3.js";
12
12
 
@@ -376,11 +376,11 @@ import {
376
376
  upsertSkillFile,
377
377
  upsertSkillFiles,
378
378
  upsertSwarmConfig
379
- } from "./cli-d0t4854c.js";
379
+ } from "./cli-fedn86nz.js";
380
380
  import"./cli-z2zcxes1.js";
381
381
  import"./cli-q21d49ac.js";
382
382
  import"./cli-anrj584m.js";
383
- import"./cli-hc4rd6sv.js";
383
+ import"./cli-85pf4z38.js";
384
384
  import"./cli-3pp1362w.js";
385
385
  import"./cli-p9swy5t3.js";
386
386
  init_db();
@@ -3,26 +3,26 @@ import {
3
3
  getBufferMessageCount,
4
4
  instantFlush,
5
5
  wasEventSeen
6
- } from "./cli-q6jzg6wj.js";
6
+ } from "./cli-s14sb64w.js";
7
7
  import {
8
8
  extractTaskFromMessage,
9
9
  hasOtherUserMention,
10
10
  routeMessage
11
- } from "./cli-zctkpdmd.js";
11
+ } from "./cli-dz3d6zjg.js";
12
12
  import {
13
13
  extractSlackMessageText
14
14
  } from "./cli-2deg0cen.js";
15
15
  import {
16
16
  registerTreeMessage
17
- } from "./cli-sygq3fhn.js";
17
+ } from "./cli-kk51f3tf.js";
18
18
  import"./cli-fete3y1e.js";
19
19
  import"./cli-b0p7rfnd.js";
20
20
  import {
21
21
  enrichSlackUserEmail,
22
22
  resolveSlackUserId
23
- } from "./cli-mhj07xbq.js";
24
- import"./cli-9qascwj7.js";
25
- import"./cli-5bqa41fd.js";
23
+ } from "./cli-rvae030h.js";
24
+ import"./cli-2qynerth.js";
25
+ import"./cli-yfwwjeft.js";
26
26
  import {
27
27
  buildTreeBlocks
28
28
  } from "./cli-z92pkwzn.js";
@@ -30,7 +30,7 @@ import"./cli-dh55d5fg.js";
30
30
  import {
31
31
  createTaskWithSiblingAwareness,
32
32
  slackContextKey
33
- } from "./cli-r68m8arr.js";
33
+ } from "./cli-jt9d9fjw.js";
34
34
  import {
35
35
  getAgentById,
36
36
  getAgentWorkingOnThread,
@@ -40,11 +40,11 @@ import {
40
40
  init_db,
41
41
  init_resolver,
42
42
  resolveTemplate
43
- } from "./cli-d0t4854c.js";
43
+ } from "./cli-fedn86nz.js";
44
44
  import"./cli-z2zcxes1.js";
45
45
  import"./cli-q21d49ac.js";
46
46
  import"./cli-anrj584m.js";
47
- import"./cli-hc4rd6sv.js";
47
+ import"./cli-85pf4z38.js";
48
48
  import"./cli-3pp1362w.js";
49
49
  import"./cli-e15jhafb.js";
50
50
  import {
@@ -9,7 +9,7 @@ import"./cli-4wmnp8q3.js";
9
9
  import {
10
10
  checkToolLoop,
11
11
  clearToolHistory
12
- } from "./cli-g5px3d7x.js";
12
+ } from "./cli-2957pqpj.js";
13
13
  import"./cli-hx1dcevq.js";
14
14
  import {
15
15
  buildRatingsFromLlm,
@@ -29,7 +29,7 @@ import"./cli-anrj584m.js";
29
29
  import {
30
30
  init_package,
31
31
  package_default
32
- } from "./cli-hc4rd6sv.js";
32
+ } from "./cli-85pf4z38.js";
33
33
  import"./cli-3pp1362w.js";
34
34
  import"./cli-xw7p4wkq.js";
35
35
  import"./cli-4wgngmwv.js";