@desplega.ai/agent-swarm 2.4.0 → 2.4.2

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 (239) hide show
  1. package/README.md +1 -1
  2. package/dist/{acp-adapter-kedstxx6.js → acp-adapter-dv7hmx4r.js} +9 -9
  3. package/dist/{actions-vget6r1k.js → actions-51nc1gny.js} +21 -21
  4. package/dist/{amp-adapter-xeb5mktv.js → amp-adapter-abp5tdx8.js} +4 -4
  5. package/dist/{app-mqap8t8m.js → app-9h14qvr6.js} +3 -3
  6. package/dist/{assistant-h0gv97mv.js → assistant-wv1gz3mt.js} +22 -22
  7. package/dist/{boot-reembed-qr8a894z.js → boot-reembed-6yn53ms9.js} +1 -1
  8. package/dist/{boot-reembed-rj85jjhw.js → boot-reembed-7fcka4z5.js} +1 -1
  9. package/dist/{boot-scrub-sweep-eyfvn6v9.js → boot-scrub-sweep-pm1580ax.js} +4 -4
  10. package/dist/{boot-seeds-xs9a8dx1.js → boot-seeds-g5hfc1x8.js} +4 -4
  11. package/dist/{claude-adapter-bm23cye7.js → claude-adapter-gf3kxhf0.js} +9 -9
  12. package/dist/{claude-managed-adapter-1mwrsm9d.js → claude-managed-adapter-h2y889ge.js} +2 -2
  13. package/dist/{claude-managed-setup-gkfgks4j.js → claude-managed-setup-h00hsgtz.js} +2 -2
  14. package/dist/{claude-sdk-session-apb4ypz3.js → claude-sdk-session-s2k1qd8y.js} +13 -13
  15. package/dist/{cli-tj4j2ts4.js → cli-02qm7src.js} +8 -8
  16. package/dist/{cli-1cevz46c.js → cli-0qvtffe9.js} +6 -6
  17. package/dist/{cli-avmqhatn.js → cli-10hhg0km.js} +8 -8
  18. package/dist/{cli-7gh7020n.js → cli-1dmcq2eh.js} +1 -1
  19. package/dist/{cli-kz116kvw.js → cli-239yjk27.js} +7 -7
  20. package/dist/{cli-7ayprxp7.js → cli-2dfbv8qr.js} +8 -0
  21. package/dist/{cli-a49vpbf3.js → cli-5kqnemen.js} +1 -1
  22. package/dist/{cli-x719j3vs.js → cli-5rk36sjf.js} +442 -205
  23. package/dist/{cli-fb6t92v8.js → cli-6x9ma5w5.js} +1 -1
  24. package/dist/{cli-c8fwpgqb.js → cli-7225gwj7.js} +2 -2
  25. package/dist/{cli-5s5hx57y.js → cli-7awf1fp8.js} +1 -1
  26. package/dist/{cli-bn26xbcs.js → cli-8nyhf7za.js} +1 -1
  27. package/dist/{cli-ywyrffff.js → cli-8sxqsbbq.js} +1 -1
  28. package/dist/{cli-rsd7ga7v.js → cli-8zwe9mpk.js} +11 -11
  29. package/dist/{cli-y83zk5sb.js → cli-a0kcty51.js} +4 -4
  30. package/dist/{cli-8b9wvjps.js → cli-a4gvwttf.js} +4 -4
  31. package/dist/{cli-jhp7w1fy.js → cli-a5ebc95n.js} +2 -2
  32. package/dist/{cli-mvg2hf8p.js → cli-ahtpy9kf.js} +14 -7
  33. package/dist/{cli-x1p5dhq2.js → cli-bcj753sq.js} +3 -3
  34. package/dist/{cli-p22zdvnt.js → cli-bn0rewsy.js} +3 -3
  35. package/dist/{cli-p1m2b6gc.js → cli-d2mb5s8a.js} +7 -7
  36. package/dist/{cli-rg7ntypm.js → cli-d3qqdy4c.js} +456 -94
  37. package/dist/{cli-c5sbmw1v.js → cli-d82btycs.js} +94 -15
  38. package/dist/{cli-02vhhssk.js → cli-efaqv1c7.js} +5 -5
  39. package/dist/{cli-vjfpshn3.js → cli-ejs3m1sx.js} +1 -1
  40. package/dist/{cli-kk2r80n5.js → cli-faypxz7q.js} +4 -4
  41. package/dist/{cli-a1esmmee.js → cli-fpmsqq59.js} +7 -2
  42. package/dist/{cli-wrv09v7q.js → cli-ftyypbg5.js} +1 -1
  43. package/dist/{cli-zvze9rbm.js → cli-fyzjmseb.js} +3 -3
  44. package/dist/{cli-8rwvksbc.js → cli-g0hgtz4p.js} +5 -5
  45. package/dist/{cli-nrrg0fvy.js → cli-h38rjv87.js} +133 -12
  46. package/dist/{cli-tg9ksbn8.js → cli-h93c9vb3.js} +2 -2
  47. package/dist/{cli-eqgfs202.js → cli-hqhzg1qq.js} +2 -2
  48. package/dist/{cli-bhwa8rzc.js → cli-hyfw2j1e.js} +13 -12
  49. package/dist/{cli-3wjs22x3.js → cli-j4rqdf2n.js} +2 -2
  50. package/dist/{cli-6ftrrwm1.js → cli-n85dqg6d.js} +5 -5
  51. package/dist/{cli-8cxkw1f5.js → cli-nmqdc2t3.js} +2 -2
  52. package/dist/{cli-4fhyq711.js → cli-nn47d7e8.js} +13 -13
  53. package/dist/{cli-x3en6ct3.js → cli-nwyw3zhg.js} +1 -1
  54. package/dist/{cli-3avfh5az.js → cli-pemywhfq.js} +2 -2
  55. package/dist/{cli-xfe63zx3.js → cli-pkht5hap.js} +2 -2
  56. package/dist/{cli-sppc0cmw.js → cli-pnp2j5zg.js} +2 -2
  57. package/dist/{cli-wk8ccrz6.js → cli-pw7v69vp.js} +2 -2
  58. package/dist/{cli-tgvpmnwz.js → cli-r99kc9yq.js} +5 -5
  59. package/dist/{cli-bfc3k1x5.js → cli-rdyw3mct.js} +9 -9
  60. package/dist/{cli-b80a1100.js → cli-s6vr7r2d.js} +2 -2
  61. package/dist/{cli-zv4vy2b0.js → cli-s95dknxh.js} +1 -1
  62. package/dist/{cli-ttaz6c7m.js → cli-saw9a6f6.js} +6 -5
  63. package/dist/{cli-mz1ezzzh.js → cli-shvfedvm.js} +3 -3
  64. package/dist/{cli-rdr166ht.js → cli-smvcw9z5.js} +1 -1
  65. package/dist/{cli-2rwet3r7.js → cli-sv5gb0yb.js} +1 -1
  66. package/dist/{cli-5ff2sjyt.js → cli-t30yj95q.js} +2 -2
  67. package/dist/{cli-ptkpaqfy.js → cli-wt645v7q.js} +1 -1
  68. package/dist/{cli-f3nx1h8z.js → cli-wxbn3yfx.js} +2 -2
  69. package/dist/{cli-wyrr38xm.js → cli-x5mq1fyq.js} +1 -1
  70. package/dist/{cli-ccn0eybf.js → cli-xbzvet96.js} +6 -6
  71. package/dist/{cli-4mkvwgzr.js → cli-xf234ws8.js} +1 -1
  72. package/dist/{cli-nme7wery.js → cli-y2x52gs2.js} +46 -13
  73. package/dist/{cli-ffbrkh1r.js → cli-y8n5k515.js} +46 -38
  74. package/dist/{cli-ecshf504.js → cli-z4wd2ftv.js} +7 -7
  75. package/dist/{cli-dsgj3e7a.js → cli-zfg9enh9.js} +2 -2
  76. package/dist/{cli-yxqag76b.js → cli-zw88zjba.js} +1 -1
  77. package/dist/cli.js +20 -20
  78. package/dist/{codex-adapter-pp2gq8gr.js → codex-adapter-ttygw382.js} +6 -6
  79. package/dist/{codex-hook-qwzccd64.js → codex-hook-x7nejyrr.js} +7 -4
  80. package/dist/{codex-login-35p4sk85.js → codex-login-m819c41r.js} +1 -1
  81. package/dist/{codex-session-runner-0vzn09t8.js → codex-session-runner-60b58vv3.js} +7 -7
  82. package/dist/{commands-psqhkttb.js → commands-edmdwa4x.js} +2 -2
  83. package/dist/{controller-t20vz2k8.js → controller-m263fg43.js} +4 -4
  84. package/dist/{controllers-connect-gkxmqw9d.js → controllers-connect-5fym8sw1.js} +23 -23
  85. package/dist/{cursor-adapter-3v542qe5.js → cursor-adapter-cz6nm6mj.js} +3 -3
  86. package/dist/{db-nc1rd869.js → db-2y0mgstc.js} +3 -3
  87. package/dist/{db-2xbyenjr.js → db-nn0hcmx5.js} +6 -2
  88. package/dist/{devin-adapter-7egzmt0k.js → devin-adapter-zgqadvnm.js} +1 -1
  89. package/dist/{dispatcher-ewceb8ts.js → dispatcher-0a9wwjcx.js} +20 -20
  90. package/dist/{docker-njavd3fb.js → docker-fkgtr75t.js} +2 -2
  91. package/dist/{dsh-adapter-75xwh78t.js → dsh-adapter-3n3net33.js} +3 -3
  92. package/dist/{e2b-5r6a5jeb.js → e2b-7am6tmq6.js} +2 -2
  93. package/dist/{e2b-pw1nvtmh.js → e2b-thdcxtjd.js} +2 -2
  94. package/dist/{easter-egg-3d-xsc47jwf.js → easter-egg-3d-5cgynaja.js} +1 -1
  95. package/dist/{event-bus-101fenkh.js → event-bus-9vpk8gmq.js} +1 -1
  96. package/dist/{execute-gzmw1mnw.js → execute-t4e6m3rw.js} +1 -1
  97. package/dist/{external-channel-a5dsmxn4.js → external-channel-zhvt95n3.js} +2 -2
  98. package/dist/{grok-adapter-vj88xr23.js → grok-adapter-qnr1hp2y.js} +10 -10
  99. package/dist/handlers-dkcarkd0.js +39 -0
  100. package/dist/{heartbeat-t2m9r3wa.js → heartbeat-gz97r7ac.js} +23 -23
  101. package/dist/{hook-xa677f8r.js → hook-1mmdgjqs.js} +16 -9
  102. package/dist/{hook-8femx1bg.js → hook-x8rthca4.js} +6 -6
  103. package/dist/{http-xpmmq028.js → http-r8f85xr9.js} +274 -160
  104. package/dist/index-5jecgp3n.js +41 -0
  105. package/dist/index-aex0eba9.js +40 -0
  106. package/dist/{index-syztqdt6.js → index-g6tbb6ve.js} +1 -1
  107. package/dist/{index-cdzyfrsp.js → index-smxyk04s.js} +1 -1
  108. package/dist/{index-dg2tmj99.js → index-vzvfqzfj.js} +20 -20
  109. package/dist/{index-s7ckdajq.js → index-y7rbcrc1.js} +10 -10
  110. package/dist/{keepalive-3nr4st3r.js → keepalive-64c0f34c.js} +4 -4
  111. package/dist/lead-b1da0f97.js +78 -0
  112. package/dist/{maintenance-verwpe2c.js → maintenance-mnxpar12.js} +1 -1
  113. package/dist/{oauth-refresh-sweep-9q2t0y3q.js → oauth-refresh-sweep-36hs2v4h.js} +3 -3
  114. package/dist/{onboard-aytqedmq.js → onboard-xes8de61.js} +3 -3
  115. package/dist/{opencode-adapter-f4hryjny.js → opencode-adapter-3s7ax02e.js} +7 -7
  116. package/dist/{otel-impl-hckw4wt1.js → otel-impl-fzc57kcq.js} +2 -2
  117. package/dist/{pi-mono-adapter-hxby0ce1.js → pi-mono-adapter-ytp7gz8b.js} +22 -11
  118. package/dist/{pricing-refresh-5nvme3sm.js → pricing-refresh-1nek2w7b.js} +3 -3
  119. package/dist/{rbac-roles-vbpy21mg.js → rbac-roles-sqefb5hw.js} +2 -2
  120. package/dist/{rbac-roles-pd8c26m1.js → rbac-roles-ttyfaep2.js} +1 -1
  121. package/dist/{render-v2-7nqgvk2q.js → render-v2-vb527jwn.js} +3 -3
  122. package/dist/{resume-b6djcj3c.js → resume-jcdzg1bn.js} +10 -8
  123. package/dist/{runtime-txrxc9za.js → runtime-xe3aqy4x.js} +1 -1
  124. package/dist/{session-access-fc3f9y12.js → session-access-zsp4wsp0.js} +4 -4
  125. package/dist/{setup-n39szm6b.js → setup-1nb2zqd3.js} +1 -1
  126. package/dist/{virtual-modules-wyp2k6z3.js → virtual-modules-4r3zkc20.js} +2 -2
  127. package/dist/{work-objects-jem2fre0.js → work-objects-61w08fwr.js} +23 -23
  128. package/dist/worker-c1e68hpa.js +78 -0
  129. package/dist/{x-8ewt8gxn.js → x-y45mthwn.js} +2 -2
  130. package/openapi.json +491 -52
  131. package/package.json +3 -3
  132. package/src/apps/action-runner.ts +146 -0
  133. package/src/apps/catalog.generated.json +3 -2
  134. package/src/apps/definition.ts +152 -4
  135. package/src/apps/row-store.ts +23 -9
  136. package/src/apps/schema-migrate.ts +14 -6
  137. package/src/apps/script-types.ts +2 -1
  138. package/src/apps/sync.ts +20 -19
  139. package/src/be/db/tasks/read.ts +112 -0
  140. package/src/be/db.ts +16 -4
  141. package/src/be/fleet-benchmark-stats.ts +10 -5
  142. package/src/be/models-catalog.ts +4 -0
  143. package/src/be/onboarding.ts +6 -0
  144. package/src/be/scripts/typecheck.ts +13 -0
  145. package/src/be/swarm-config-guard.ts +25 -1
  146. package/src/be/telemetry-enable.ts +1 -1
  147. package/src/commands/provider-credentials.ts +12 -2
  148. package/src/commands/runner.ts +3 -0
  149. package/src/heartbeat/heartbeat.ts +2 -2
  150. package/src/hooks/codex-hook.ts +6 -2
  151. package/src/hooks/hook.ts +7 -0
  152. package/src/hooks/pr-body-guard.ts +38 -11
  153. package/src/hooks/pr-room-guard.ts +88 -0
  154. package/src/http/agents.ts +1 -0
  155. package/src/http/apps.ts +99 -183
  156. package/src/http/fleet-benchmark.ts +79 -30
  157. package/src/http/global-config.ts +7 -0
  158. package/src/http/ranking.ts +24 -40
  159. package/src/http/status.ts +49 -43
  160. package/src/http/tasks.ts +49 -1
  161. package/src/http/telemetry-ui.ts +1 -1
  162. package/src/http/used-by.ts +55 -19
  163. package/src/http/users.ts +2 -2
  164. package/src/providers/acp-targets.ts +1 -1
  165. package/src/providers/amp-adapter.ts +1 -1
  166. package/src/providers/pi-mono-adapter.ts +15 -0
  167. package/src/providers/reasoning-effort.ts +2 -1
  168. package/src/providers/types.ts +2 -0
  169. package/src/ranking/telemetry-ranking.ts +5 -33
  170. package/src/scripts-runtime/sdk-allowlist.ts +7 -0
  171. package/src/scripts-runtime/types/stdlib.d.ts +31 -0
  172. package/src/scripts-runtime/types/swarm-sdk.d.ts +31 -0
  173. package/src/server.ts +4 -0
  174. package/src/telemetry-context.ts +19 -1
  175. package/src/telemetry-contract/EVENTS.md +42 -8
  176. package/src/telemetry-contract/SOURCE.json +6 -5
  177. package/src/telemetry-contract/catalog.json +225 -5
  178. package/src/telemetry-contract/ranking/fixtures/valid/no-claim.json +10 -0
  179. package/src/telemetry-contract/ranking/listing.v1.schema.json +2 -2
  180. package/src/telemetry-contract/types.gen.ts +225 -27
  181. package/src/telemetry-identity.ts +47 -9
  182. package/src/telemetry-snapshot.ts +9 -1
  183. package/src/telemetry-ui-events.ts +9 -2
  184. package/src/telemetry.ts +29 -6
  185. package/src/tests/app-action-run-tool.test.ts +178 -0
  186. package/src/tests/app-row-tools.test.ts +385 -0
  187. package/src/tests/apps-json-column.test.ts +611 -0
  188. package/src/tests/apps-script-types.test.ts +2 -0
  189. package/src/tests/apps-sync-engine.test.ts +42 -0
  190. package/src/tests/check-pr-body.test.ts +0 -23
  191. package/src/tests/credential-check.test.ts +38 -0
  192. package/src/tests/db-task-read-contract.test.ts +4 -0
  193. package/src/tests/db-task-write-contract.test.ts +2 -0
  194. package/src/tests/docs-index-footprint.test.js +2 -2
  195. package/src/tests/fleet-benchmark.test.ts +122 -2
  196. package/src/tests/http-users.test.ts +62 -1
  197. package/src/tests/model-catalog-table.test.ts +63 -0
  198. package/src/tests/model-profiles-api.test.ts +19 -7
  199. package/src/tests/models-catalog.test.ts +50 -0
  200. package/src/tests/onboarding.test.ts +21 -0
  201. package/src/tests/org-website.test.ts +62 -0
  202. package/src/tests/pi-mono-adapter.test.ts +23 -0
  203. package/src/tests/pr-body-leaks.test.ts +4 -0
  204. package/src/tests/pr-room-guard.test.ts +242 -0
  205. package/src/tests/ranking-listing.test.ts +8 -23
  206. package/src/tests/ranking-route.test.ts +49 -47
  207. package/src/tests/reasoning-effort.test.ts +39 -3
  208. package/src/tests/runner-harness-telemetry-env.test.ts +62 -1
  209. package/src/tests/status.test.ts +158 -9
  210. package/src/tests/swarm-tool-result-gate.test.ts +2 -4
  211. package/src/tests/task-lineage.test.ts +180 -0
  212. package/src/tests/telemetry-context.test.ts +128 -2
  213. package/src/tests/telemetry-init.test.ts +62 -5
  214. package/src/tests/telemetry-ui-route.test.ts +123 -0
  215. package/src/tests/tool-annotations.test.ts +3 -2
  216. package/src/tests/used-by-route.test.ts +144 -10
  217. package/src/tests/user-token-rest-auth.test.ts +38 -0
  218. package/src/tests/workflow-agent-task-retry.test.ts +130 -4
  219. package/src/tests/workflow-wait-recovery.test.ts +116 -4
  220. package/src/tools/app-action-run.ts +63 -0
  221. package/src/tools/app-rows.ts +239 -0
  222. package/src/tools/model-catalog/index.ts +1 -1
  223. package/src/tools/tool-config.ts +8 -0
  224. package/src/tools/utils.ts +1 -1
  225. package/src/tools/workflows/retry-workflow-run.ts +1 -1
  226. package/src/types.ts +17 -0
  227. package/src/utils/company-profile.ts +24 -0
  228. package/src/utils/org-website.ts +58 -21
  229. package/src/workflows/recovery.ts +10 -22
  230. package/src/workflows/resume.ts +16 -0
  231. package/src/workflows/task-step-routing.ts +47 -7
  232. package/templates/skills/apps/SKILL.md +44 -4
  233. package/templates/skills/apps/content.md +44 -4
  234. package/dist/handlers-zbs90bny.js +0 -39
  235. package/dist/index-8pwc1jc8.js +0 -40
  236. package/dist/index-nxa6me0q.js +0 -41
  237. package/dist/lead-td8h2sfn.js +0 -78
  238. package/dist/worker-wr6xgfr2.js +0 -78
  239. package/src/tests/check-ranking-entry.test.ts +0 -146
@@ -110,8 +110,10 @@ export interface paths {
110
110
  * @description Percentiles over production agent-swarm installs with at least 10 finished
111
111
  * tasks in the last 30 days, overall and by agent count (`1`, `2-5`, `6+`).
112
112
  * Internal, QA, test and E2B installs are excluded. Aggregates only: no install
113
- * ID or org name, and any bucket or metric with fewer than 20 installs is
114
- * omitted. Recomputed hourly from `raw_events`; the request carries no install
113
+ * ID or org name. Whole-fleet buckets require 20 installs. Optional profile
114
+ * filters select orgs by their latest API server or UI context. Both filters
115
+ * must be present. A peer group requires 20 contributing orgs. Smaller groups fall back to the whole fleet with
116
+ * `peer_group: null`. Peer buckets also require 20 distinct orgs. Recomputed hourly from `raw_events`; the request carries no install
115
117
  * ID. Called server to server by agent-swarm API servers, so the response sends
116
118
  * no CORS headers. Rate limited per IP: a burst of 10, then 10 per minute.
117
119
  */
@@ -141,12 +143,15 @@ export interface paths {
141
143
  * `trending` (the index page's fastest growing apps). With `domain`: `chart`
142
144
  * stacked by model, `totalTokens`, `rank`, `modelsUsed` and
143
145
  * `appModelAnalytics` (the app page). Tokens are the only metric served:
144
- * `total_requests` is always 0. An install is listed when its
145
- * `community/ranking/<domain>.json` file is merged into agent-swarm `main`, it
146
- * sent a valid `ranking.opted_in` listing with that file's claim first, it has
147
- * not opted out since, it is not an internal, test, E2B or non-production
148
- * install, and its bound `ranking.usage` has tokens in the period. Recomputed
149
- * hourly. Called server to server by the landing, so the response sends no
146
+ * `total_requests` is always 0. Telemetry alone lists an install: it sent a
147
+ * valid `ranking.opted_in` listing for the domain, has not opted out since,
148
+ * is not an internal, test, E2B or non-production install, sent telemetry in
149
+ * the last 7 days with the domain as its newest `org_website`, and its
150
+ * `ranking.usage` for the domain has tokens in the period. A domain on the
151
+ * proxy's denylist is never listed. When several installs list one domain,
152
+ * the one whose listing was ingested first holds it (ties go to the lower
153
+ * install ID) while it qualifies; the next in that order takes over when it
154
+ * stops. Recomputed hourly. Called server to server by the landing, so the response sends no
150
155
  * CORS headers. Rate limited per IP: a burst of 10, then 10 per minute.
151
156
  */
152
157
  get: operations["getRanking"];
@@ -166,13 +171,14 @@ export interface paths {
166
171
  cookie?: never;
167
172
  };
168
173
  /**
169
- * Check a proposed ranking entry for the agent-swarm PR check
170
- * @description Reads the telemetry store live (no cache) and reports whether an install
171
- * sent a valid `ranking.opted_in` listing with this claim and domain first,
172
- * has not opted out since, is not excluded, sent telemetry in the last 7
173
- * days, and still declares this domain as its website. `listing` shows the
174
- * reviewer what the ranking would display; it never includes the claim.
175
- * Sends no CORS headers. Rate limited per IP: a burst of 10, then 10 per
174
+ * Check whether a domain would be ranked
175
+ * @description Reads the telemetry store live (no cache) and applies the ranking's rules
176
+ * to the domain: it is not denylisted (reason `denylisted`), and an install
177
+ * that listed it has not opted out since, is not excluded, sent telemetry in
178
+ * the last 7 days, and still declares this domain as its website. `listing`
179
+ * and the flags describe the install that would hold the domain or, when
180
+ * none may, the first install that listed it. `listing` never includes a
181
+ * claim. Sends no CORS headers. Rate limited per IP: a burst of 10, then 10 per
176
182
  * minute.
177
183
  */
178
184
  get: operations["verifyRankingEntry"];
@@ -236,6 +242,16 @@ export interface components {
236
242
  [key: string]: unknown;
237
243
  };
238
244
  };
245
+ /** @enum {string|null} */
246
+ TeamSize: "1" | "2-10" | "11-50" | "51+" | null;
247
+ /** @enum {string|null} */
248
+ UseCase: "features" | "bugs" | "review" | "ops" | "docs" | "data" | null;
249
+ /** @enum {string|null} */
250
+ AcquisitionSource: "search" | "github" | "social" | "colleague" | "newsletter" | "event" | "ai_assistant" | "hacker_news" | "other" | null;
251
+ /** @enum {string|null} */
252
+ UserFunction: "engineer" | "eng_lead" | "founder" | "product" | "ops" | "other" | null;
253
+ /** @enum {string|null} */
254
+ NotificationMoment: "task_failed" | "first_workflow" | "default" | null;
239
255
  /**
240
256
  * @description Identity envelope for schema version 2. Pseudonymous by design: no email or
241
257
  * user name is accepted, and `is_internal` is set only by the proxy.
@@ -259,7 +275,10 @@ export interface components {
259
275
  swarm_version: string;
260
276
  install_method?: string | null;
261
277
  install_preset?: string | null;
262
- acquisition_source?: string | null;
278
+ acquisition_source?: components["schemas"]["AcquisitionSource"];
279
+ team_size?: components["schemas"]["TeamSize"];
280
+ use_case?: components["schemas"]["UseCase"];
281
+ user_function?: components["schemas"]["UserFunction"];
263
282
  };
264
283
  EventEnvelope: {
265
284
  /** @description Product or service emitting the telemetry event. */
@@ -359,6 +378,13 @@ export interface components {
359
378
  * @description Required RFC3339 submission timestamp.
360
379
  */
361
380
  submitted_at: string;
381
+ user_function?: components["schemas"]["UserFunction"];
382
+ team_size?: components["schemas"]["TeamSize"];
383
+ use_case?: components["schemas"]["UseCase"];
384
+ acquisition_source?: components["schemas"]["AcquisitionSource"];
385
+ moment?: components["schemas"]["NotificationMoment"];
386
+ /** @description Optional description of the submitter's current work. */
387
+ working_on?: string | null;
362
388
  };
363
389
  UsedByConsent: {
364
390
  /** @description Agent-swarm installation identifier. Omit it when the install has none (telemetry off). */
@@ -375,6 +401,13 @@ export interface components {
375
401
  * @description When the admin changed the setting (RFC3339).
376
402
  */
377
403
  changed_at: string;
404
+ /**
405
+ * Format: email
406
+ * @description Current clients require a valid contact email when consent is granted. Older clients may omit it.
407
+ */
408
+ contact_email?: string | null;
409
+ contact_function?: components["schemas"]["UserFunction"];
410
+ quote?: string | null;
378
411
  };
379
412
  UsedByAcceptedResponse: {
380
413
  /** @constant */
@@ -402,16 +435,22 @@ export interface components {
402
435
  window: "30d";
403
436
  /** Format: date-time */
404
437
  generatedAt: string;
405
- /** @description k-anonymity floor. Buckets and metrics below it are omitted. */
438
+ /** @description k-anonymity floor in installs for the whole fleet, or distinct orgs for a peer group. */
406
439
  minInstallsPerBucket: number;
407
440
  /** @description An install needs this many completed or failed tasks in the window to count. */
408
441
  minFinishedTasks: number;
409
442
  overall: components["schemas"]["FleetBenchmarkBlock"];
410
- /** @description Keyed by `1`, `2-5` or `6+`. A bucket with fewer than `minInstallsPerBucket` installs is absent. */
443
+ /** @description Keyed by `1`, `2-5` or `6+`. A bucket below `minInstallsPerBucket` is absent. The floor counts installs for the whole fleet and distinct orgs for peers. */
411
444
  byAgentCount: {
412
445
  [key: string]: components["schemas"]["FleetBenchmarkBlock"];
413
446
  };
447
+ peer_group?: components["schemas"]["FleetPeerGroup"];
414
448
  };
449
+ FleetPeerGroup: {
450
+ team_size: components["schemas"]["TeamSize"];
451
+ use_case: components["schemas"]["UseCase"];
452
+ orgs: number;
453
+ } | null;
415
454
  FleetBenchmarkBlock: {
416
455
  installs: number;
417
456
  tasksPerWeek: components["schemas"]["FleetMetric"];
@@ -521,7 +560,7 @@ export interface components {
521
560
  };
522
561
  RankingVerification: {
523
562
  verified: boolean;
524
- reasons: ("no_listing" | "opted_out" | "excluded_install" | "telemetry_inactive_7d" | "website_mismatch")[];
563
+ reasons: ("no_listing" | "denylisted" | "opted_out" | "excluded_install" | "telemetry_inactive_7d" | "website_mismatch")[];
525
564
  telemetryActive7d: boolean;
526
565
  /** @description The install's newest event declares this domain as its org_website. */
527
566
  websiteMatchesDomain: boolean;
@@ -669,6 +708,7 @@ export interface components {
669
708
  properties: components["schemas"]["AgentSwarmCompactionTriggeredProperties"];
670
709
  };
671
710
  AgentSwarmFeatureUsedProperties: {
711
+ /** @description Feature identifier, including health_popover and kickoff_call_opened. Existing identifiers remain accepted. */
672
712
  feature: string;
673
713
  /** @description An email channel is configured. */
674
714
  has_email_channel?: boolean;
@@ -698,6 +738,37 @@ export interface components {
698
738
  product: "agent-swarm";
699
739
  properties: components["schemas"]["AgentSwarmFeatureUsedProperties"];
700
740
  };
741
+ AgentSwarmFleetBenchmarkUnlockedProperties: {
742
+ /** @description Profile fields supplied, never their values. */
743
+ fields: ("website" | "team_size" | "use_case")[];
744
+ /** @description An email channel is configured. */
745
+ has_email_channel?: boolean;
746
+ /** @description An embedding API key is configured. */
747
+ has_embedding_key?: boolean;
748
+ /** @description A notification channel is configured. */
749
+ has_notification_channel?: boolean;
750
+ /** @description A Slack channel is configured. */
751
+ has_slack_channel?: boolean;
752
+ /** @description Legacy key kept during the v1 window; v2 carries context.install_method. */
753
+ install_method?: string;
754
+ /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
755
+ is_cloud?: boolean;
756
+ /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
757
+ is_e2b?: boolean;
758
+ /** @description agent-swarm version. Legacy key kept during the v1 window; v2 carries context.swarm_version. */
759
+ swarmVersion?: string;
760
+ };
761
+ /** @description An admin supplied the company profile fields for the full benchmark. (emitter: ui, since 2026-10-18) */
762
+ AgentSwarmFleetBenchmarkUnlockedEvent: {
763
+ /**
764
+ * @description discriminator enum property added by openapi-typescript
765
+ * @enum {string}
766
+ */
767
+ event: "fleet_benchmark.unlocked";
768
+ /** @constant */
769
+ product: "agent-swarm";
770
+ properties: components["schemas"]["AgentSwarmFleetBenchmarkUnlockedProperties"];
771
+ };
701
772
  AgentSwarmFleetBenchmarkViewedProperties: {
702
773
  /** @description An email channel is configured. */
703
774
  has_email_channel?: boolean;
@@ -714,6 +785,8 @@ export interface components {
714
785
  is_cloud?: boolean;
715
786
  /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
716
787
  is_e2b?: boolean;
788
+ /** @enum {string} */
789
+ level?: "basic" | "full";
717
790
  /** @description agent-swarm version. Legacy key kept during the v1 window; v2 carries context.swarm_version. */
718
791
  swarmVersion?: string;
719
792
  };
@@ -728,6 +801,71 @@ export interface components {
728
801
  product: "agent-swarm";
729
802
  properties: components["schemas"]["AgentSwarmFleetBenchmarkViewedProperties"];
730
803
  };
804
+ AgentSwarmIdentityLookupProperties: {
805
+ /** @description An email channel is configured. */
806
+ has_email_channel?: boolean;
807
+ /** @description An embedding API key is configured. */
808
+ has_embedding_key?: boolean;
809
+ /** @description A notification channel is configured. */
810
+ has_notification_channel?: boolean;
811
+ /** @description A Slack channel is configured. */
812
+ has_slack_channel?: boolean;
813
+ /** @description Legacy key kept during the v1 window; v2 carries context.install_method. */
814
+ install_method?: string;
815
+ /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
816
+ is_cloud?: boolean;
817
+ /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
818
+ is_e2b?: boolean;
819
+ matched: boolean;
820
+ /** @description agent-swarm version. Legacy key kept during the v1 window; v2 carries context.swarm_version. */
821
+ swarmVersion?: string;
822
+ };
823
+ /** @description A dashboard identity lookup matched an existing user or found no match. (emitter: ui, since 2026-10-18) */
824
+ AgentSwarmIdentityLookupEvent: {
825
+ /**
826
+ * @description discriminator enum property added by openapi-typescript
827
+ * @enum {string}
828
+ */
829
+ event: "identity.lookup";
830
+ /** @constant */
831
+ product: "agent-swarm";
832
+ properties: components["schemas"]["AgentSwarmIdentityLookupProperties"];
833
+ };
834
+ AgentSwarmIdentityUserCreatedProperties: {
835
+ /** @enum {string} */
836
+ email_kind: "work" | "personal";
837
+ has_company: boolean;
838
+ /** @description An email channel is configured. */
839
+ has_email_channel?: boolean;
840
+ /** @description An embedding API key is configured. */
841
+ has_embedding_key?: boolean;
842
+ has_function: boolean;
843
+ /** @description A notification channel is configured. */
844
+ has_notification_channel?: boolean;
845
+ /** @description A Slack channel is configured. */
846
+ has_slack_channel?: boolean;
847
+ /** @description Legacy key kept during the v1 window; v2 carries context.install_method. */
848
+ install_method?: string;
849
+ /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
850
+ is_cloud?: boolean;
851
+ /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
852
+ is_e2b?: boolean;
853
+ /** @enum {string} */
854
+ surface: "identity_modal" | "setup";
855
+ /** @description agent-swarm version. Legacy key kept during the v1 window; v2 carries context.swarm_version. */
856
+ swarmVersion?: string;
857
+ };
858
+ /** @description A user created a dashboard identity. Email and personal names stay out of telemetry. (emitter: ui, since 2026-10-18) */
859
+ AgentSwarmIdentityUserCreatedEvent: {
860
+ /**
861
+ * @description discriminator enum property added by openapi-typescript
862
+ * @enum {string}
863
+ */
864
+ event: "identity.user_created";
865
+ /** @constant */
866
+ product: "agent-swarm";
867
+ properties: components["schemas"]["AgentSwarmIdentityUserCreatedProperties"];
868
+ };
731
869
  AgentSwarmIntegrationConnectedProperties: {
732
870
  first_of_type: boolean;
733
871
  /** @description An email channel is configured. */
@@ -761,6 +899,7 @@ export interface components {
761
899
  properties: components["schemas"]["AgentSwarmIntegrationConnectedProperties"];
762
900
  };
763
901
  AgentSwarmLeadCapturedProperties: {
902
+ /** @description Lead channel, including setup_help and fleet_report. Existing channels remain accepted. */
764
903
  channel: string;
765
904
  consent: boolean;
766
905
  /** @description An email channel is configured. */
@@ -792,6 +931,11 @@ export interface components {
792
931
  product: "agent-swarm";
793
932
  properties: components["schemas"]["AgentSwarmLeadCapturedProperties"];
794
933
  };
934
+ /**
935
+ * @description Moment that made the Slack Connect invite relevant.
936
+ * @enum {string}
937
+ */
938
+ "schemas-NotificationMoment": "task_failed" | "first_workflow" | "default";
795
939
  AgentSwarmNotificationDismissedProperties: {
796
940
  /** @description An email channel is configured. */
797
941
  has_email_channel?: boolean;
@@ -808,6 +952,7 @@ export interface components {
808
952
  /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
809
953
  is_e2b?: boolean;
810
954
  key: string;
955
+ moment?: components["schemas"]["schemas-NotificationMoment"];
811
956
  /** @description agent-swarm version. Legacy key kept during the v1 window; v2 carries context.swarm_version. */
812
957
  swarmVersion?: string;
813
958
  };
@@ -822,6 +967,11 @@ export interface components {
822
967
  product: "agent-swarm";
823
968
  properties: components["schemas"]["AgentSwarmNotificationDismissedProperties"];
824
969
  };
970
+ /**
971
+ * @description Job function of a user, separate from the RBAC user_role.
972
+ * @enum {string}
973
+ */
974
+ "schemas-UserFunction": "engineer" | "eng_lead" | "founder" | "product" | "ops" | "other";
825
975
  AgentSwarmNotificationSubmittedProperties: {
826
976
  /** @description Domain of the email typed into the item, never the address. */
827
977
  email_domain?: string;
@@ -840,8 +990,10 @@ export interface components {
840
990
  /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
841
991
  is_e2b?: boolean;
842
992
  key: string;
993
+ moment?: components["schemas"]["schemas-NotificationMoment"];
843
994
  /** @description agent-swarm version. Legacy key kept during the v1 window; v2 carries context.swarm_version. */
844
995
  swarmVersion?: string;
996
+ user_function?: components["schemas"]["schemas-UserFunction"];
845
997
  };
846
998
  /** @description A notification-centre item was submitted. (emitter: ui, since 2026-09-30) */
847
999
  AgentSwarmNotificationSubmittedEvent: {
@@ -870,6 +1022,7 @@ export interface components {
870
1022
  /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
871
1023
  is_e2b?: boolean;
872
1024
  key: string;
1025
+ moment?: components["schemas"]["schemas-NotificationMoment"];
873
1026
  /** @description agent-swarm version. Legacy key kept during the v1 window; v2 carries context.swarm_version. */
874
1027
  swarmVersion?: string;
875
1028
  };
@@ -1142,8 +1295,8 @@ export interface components {
1142
1295
  properties: components["schemas"]["AgentSwarmOnboardingStepViewedProperties"];
1143
1296
  };
1144
1297
  AgentSwarmOrgProfileUpdatedProperties: {
1145
- /** @description Changed field names: name, website. */
1146
- fields: unknown[];
1298
+ /** @description Changed profile field names, never their values. */
1299
+ fields: ("name" | "website" | "team_size" | "use_case" | "acquisition_source")[];
1147
1300
  /** @description An email channel is configured. */
1148
1301
  has_email_channel?: boolean;
1149
1302
  /** @description An embedding API key is configured. */
@@ -1162,7 +1315,7 @@ export interface components {
1162
1315
  * @description Where the change was made. Not trigger_surface: that key fills the raw_events.trigger_surface column.
1163
1316
  * @enum {string}
1164
1317
  */
1165
- surface: "prompt" | "setup" | "settings";
1318
+ surface: "prompt" | "setup" | "settings" | "org_name_popup" | "feedback" | "fleet_benchmark" | "telemetry_banner" | "identity_modal";
1166
1319
  /** @description agent-swarm version. Legacy key kept during the v1 window; v2 carries context.swarm_version. */
1167
1320
  swarmVersion?: string;
1168
1321
  };
@@ -1334,6 +1487,8 @@ export interface components {
1334
1487
  properties: components["schemas"]["AgentSwarmPopupShownProperties"];
1335
1488
  };
1336
1489
  AgentSwarmPopupSubmittedProperties: {
1490
+ /** @description Number of profile follow-up questions answered, never their values. */
1491
+ answered?: number;
1337
1492
  /** @description A name or email was left. The values go to /v1/feedback, never here. */
1338
1493
  has_contact: boolean;
1339
1494
  /** @description An email channel is configured. */
@@ -1351,6 +1506,8 @@ export interface components {
1351
1506
  is_cloud?: boolean;
1352
1507
  /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
1353
1508
  is_e2b?: boolean;
1509
+ /** @description Perks the admin explicitly selected. */
1510
+ perks?: ("used_by" | "slack_connect")[];
1354
1511
  popup: components["schemas"]["Popup"];
1355
1512
  /** @description Feedback pop-up only: the 0-10 score. /v1/feedback enforces the upper bound. */
1356
1513
  score?: number;
@@ -1830,6 +1987,39 @@ export interface components {
1830
1987
  product: "agent-swarm";
1831
1988
  properties: components["schemas"]["AgentSwarmSessionSteeredProperties"];
1832
1989
  };
1990
+ AgentSwarmSetupWorkerCommandCopiedProperties: {
1991
+ /** @enum {string} */
1992
+ harness: "claude" | "codex" | "pi" | "devin" | "claude-managed" | "opencode" | "acp" | "dsh" | "amp" | "cursor" | "grok";
1993
+ /** @description An email channel is configured. */
1994
+ has_email_channel?: boolean;
1995
+ /** @description An embedding API key is configured. */
1996
+ has_embedding_key?: boolean;
1997
+ /** @description A notification channel is configured. */
1998
+ has_notification_channel?: boolean;
1999
+ /** @description A Slack channel is configured. */
2000
+ has_slack_channel?: boolean;
2001
+ /** @description Legacy key kept during the v1 window; v2 carries context.install_method. */
2002
+ install_method?: string;
2003
+ /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
2004
+ is_cloud?: boolean;
2005
+ /** @description Legacy key kept during the v1 window; v2 carries context.deployment. */
2006
+ is_e2b?: boolean;
2007
+ /** @description agent-swarm version. Legacy key kept during the v1 window; v2 carries context.swarm_version. */
2008
+ swarmVersion?: string;
2009
+ /** @enum {string} */
2010
+ target: "compose" | "docker" | "kubernetes";
2011
+ };
2012
+ /** @description An admin copied a worker command from the setup health popover. (emitter: ui, since 2026-10-18) */
2013
+ AgentSwarmSetupWorkerCommandCopiedEvent: {
2014
+ /**
2015
+ * @description discriminator enum property added by openapi-typescript
2016
+ * @enum {string}
2017
+ */
2018
+ event: "setup.worker_command_copied";
2019
+ /** @constant */
2020
+ product: "agent-swarm";
2021
+ properties: components["schemas"]["AgentSwarmSetupWorkerCommandCopiedProperties"];
2022
+ };
1833
2023
  AgentSwarmSkillInvokedProperties: {
1834
2024
  /** @description An email channel is configured. */
1835
2025
  has_email_channel?: boolean;
@@ -2187,7 +2377,7 @@ export interface components {
2187
2377
  /** @description agent-swarm version. Legacy key kept during the v1 window; v2 carries context.swarm_version. */
2188
2378
  swarmVersion?: string;
2189
2379
  /** @enum {string} */
2190
- via: "banner" | "settings" | "env";
2380
+ via: "banner" | "settings" | "env" | "benchmark";
2191
2381
  };
2192
2382
  /** @description Telemetry was turned on. Sent once, on the first boot or re-init after opting in. (emitter: api-server, since 2026-10-12) */
2193
2383
  AgentSwarmTelemetryEnabledEvent: {
@@ -2235,8 +2425,10 @@ export interface components {
2235
2425
  has_email_channel?: boolean;
2236
2426
  /** @description An embedding API key is configured. */
2237
2427
  has_embedding_key?: boolean;
2428
+ has_function?: boolean;
2238
2429
  /** @description A notification channel is configured. */
2239
2430
  has_notification_channel?: boolean;
2431
+ has_quote?: boolean;
2240
2432
  /** @description A Slack channel is configured. */
2241
2433
  has_slack_channel?: boolean;
2242
2434
  /** @description Legacy key kept during the v1 window; v2 carries context.install_method. */
@@ -2428,7 +2620,7 @@ export interface components {
2428
2620
  product: "agent-swarm";
2429
2621
  properties: components["schemas"]["AgentSwarmWorkflowStartedProperties"];
2430
2622
  };
2431
- AgentSwarmCatalogEvent: components["schemas"]["AgentSwarmAgentRegisteredEvent"] | components["schemas"]["AgentSwarmCompactionTriggeredEvent"] | components["schemas"]["AgentSwarmFeatureUsedEvent"] | components["schemas"]["AgentSwarmFleetBenchmarkViewedEvent"] | components["schemas"]["AgentSwarmIntegrationConnectedEvent"] | components["schemas"]["AgentSwarmLeadCapturedEvent"] | components["schemas"]["AgentSwarmNotificationDismissedEvent"] | components["schemas"]["AgentSwarmNotificationSubmittedEvent"] | components["schemas"]["AgentSwarmNotificationViewedEvent"] | components["schemas"]["AgentSwarmOnboardingCompletedEvent"] | components["schemas"]["AgentSwarmOnboardingDismissedEvent"] | components["schemas"]["AgentSwarmOnboardingFirstTaskCompletedEvent"] | components["schemas"]["AgentSwarmOnboardingStartedEvent"] | components["schemas"]["AgentSwarmOnboardingStepCompletedEvent"] | components["schemas"]["AgentSwarmOnboardingStepFailedEvent"] | components["schemas"]["AgentSwarmOnboardingStepSkippedEvent"] | components["schemas"]["AgentSwarmOnboardingStepViewedEvent"] | components["schemas"]["AgentSwarmOrgProfileUpdatedEvent"] | components["schemas"]["AgentSwarmOrgSnapshotEvent"] | components["schemas"]["AgentSwarmPageViewedEvent"] | components["schemas"]["AgentSwarmPopupDismissedEvent"] | components["schemas"]["AgentSwarmPopupShownEvent"] | components["schemas"]["AgentSwarmPopupSubmittedEvent"] | components["schemas"]["AgentSwarmRankingOptedInEvent"] | components["schemas"]["AgentSwarmRankingOptedOutEvent"] | components["schemas"]["AgentSwarmRankingUsageEvent"] | components["schemas"]["AgentSwarmScheduleErrorEvent"] | components["schemas"]["AgentSwarmScheduleExecutedEvent"] | components["schemas"]["AgentSwarmServerShutdownEvent"] | components["schemas"]["AgentSwarmServerStartedEvent"] | components["schemas"]["AgentSwarmSessionCancelledEvent"] | components["schemas"]["AgentSwarmSessionCostEvent"] | components["schemas"]["AgentSwarmSessionEndedEvent"] | components["schemas"]["AgentSwarmSessionFailureEvent"] | components["schemas"]["AgentSwarmSessionStartedEvent"] | components["schemas"]["AgentSwarmSessionSteeredEvent"] | components["schemas"]["AgentSwarmSkillInvokedEvent"] | components["schemas"]["AgentSwarmTaskCancelledEvent"] | components["schemas"]["AgentSwarmTaskClaimedEvent"] | components["schemas"]["AgentSwarmTaskCompletedEvent"] | components["schemas"]["AgentSwarmTaskCreatedEvent"] | components["schemas"]["AgentSwarmTaskFailedEvent"] | components["schemas"]["AgentSwarmTaskSessionCompletedEvent"] | components["schemas"]["AgentSwarmTaskStartedEvent"] | components["schemas"]["AgentSwarmTaskSupersededEvent"] | components["schemas"]["AgentSwarmTelemetryEnabledEvent"] | components["schemas"]["AgentSwarmUiSessionStartedEvent"] | components["schemas"]["AgentSwarmUsedByConsentChangedEvent"] | components["schemas"]["AgentSwarmWorkflowCompletedEvent"] | components["schemas"]["AgentSwarmWorkflowCreatedEvent"] | components["schemas"]["AgentSwarmWorkflowDeletedEvent"] | components["schemas"]["AgentSwarmWorkflowFailedEvent"] | components["schemas"]["AgentSwarmWorkflowStartedEvent"];
2623
+ AgentSwarmCatalogEvent: components["schemas"]["AgentSwarmAgentRegisteredEvent"] | components["schemas"]["AgentSwarmCompactionTriggeredEvent"] | components["schemas"]["AgentSwarmFeatureUsedEvent"] | components["schemas"]["AgentSwarmFleetBenchmarkUnlockedEvent"] | components["schemas"]["AgentSwarmFleetBenchmarkViewedEvent"] | components["schemas"]["AgentSwarmIdentityLookupEvent"] | components["schemas"]["AgentSwarmIdentityUserCreatedEvent"] | components["schemas"]["AgentSwarmIntegrationConnectedEvent"] | components["schemas"]["AgentSwarmLeadCapturedEvent"] | components["schemas"]["AgentSwarmNotificationDismissedEvent"] | components["schemas"]["AgentSwarmNotificationSubmittedEvent"] | components["schemas"]["AgentSwarmNotificationViewedEvent"] | components["schemas"]["AgentSwarmOnboardingCompletedEvent"] | components["schemas"]["AgentSwarmOnboardingDismissedEvent"] | components["schemas"]["AgentSwarmOnboardingFirstTaskCompletedEvent"] | components["schemas"]["AgentSwarmOnboardingStartedEvent"] | components["schemas"]["AgentSwarmOnboardingStepCompletedEvent"] | components["schemas"]["AgentSwarmOnboardingStepFailedEvent"] | components["schemas"]["AgentSwarmOnboardingStepSkippedEvent"] | components["schemas"]["AgentSwarmOnboardingStepViewedEvent"] | components["schemas"]["AgentSwarmOrgProfileUpdatedEvent"] | components["schemas"]["AgentSwarmOrgSnapshotEvent"] | components["schemas"]["AgentSwarmPageViewedEvent"] | components["schemas"]["AgentSwarmPopupDismissedEvent"] | components["schemas"]["AgentSwarmPopupShownEvent"] | components["schemas"]["AgentSwarmPopupSubmittedEvent"] | components["schemas"]["AgentSwarmRankingOptedInEvent"] | components["schemas"]["AgentSwarmRankingOptedOutEvent"] | components["schemas"]["AgentSwarmRankingUsageEvent"] | components["schemas"]["AgentSwarmScheduleErrorEvent"] | components["schemas"]["AgentSwarmScheduleExecutedEvent"] | components["schemas"]["AgentSwarmServerShutdownEvent"] | components["schemas"]["AgentSwarmServerStartedEvent"] | components["schemas"]["AgentSwarmSessionCancelledEvent"] | components["schemas"]["AgentSwarmSessionCostEvent"] | components["schemas"]["AgentSwarmSessionEndedEvent"] | components["schemas"]["AgentSwarmSessionFailureEvent"] | components["schemas"]["AgentSwarmSessionStartedEvent"] | components["schemas"]["AgentSwarmSessionSteeredEvent"] | components["schemas"]["AgentSwarmSetupWorkerCommandCopiedEvent"] | components["schemas"]["AgentSwarmSkillInvokedEvent"] | components["schemas"]["AgentSwarmTaskCancelledEvent"] | components["schemas"]["AgentSwarmTaskClaimedEvent"] | components["schemas"]["AgentSwarmTaskCompletedEvent"] | components["schemas"]["AgentSwarmTaskCreatedEvent"] | components["schemas"]["AgentSwarmTaskFailedEvent"] | components["schemas"]["AgentSwarmTaskSessionCompletedEvent"] | components["schemas"]["AgentSwarmTaskStartedEvent"] | components["schemas"]["AgentSwarmTaskSupersededEvent"] | components["schemas"]["AgentSwarmTelemetryEnabledEvent"] | components["schemas"]["AgentSwarmUiSessionStartedEvent"] | components["schemas"]["AgentSwarmUsedByConsentChangedEvent"] | components["schemas"]["AgentSwarmWorkflowCompletedEvent"] | components["schemas"]["AgentSwarmWorkflowCreatedEvent"] | components["schemas"]["AgentSwarmWorkflowDeletedEvent"] | components["schemas"]["AgentSwarmWorkflowFailedEvent"] | components["schemas"]["AgentSwarmWorkflowStartedEvent"];
2432
2624
  /** @description Every catalogued (product, event) pair with its property schema. Generated from contracts/telemetry/catalog/events.json. */
2433
2625
  CatalogEvent: components["schemas"]["AgentFsCatalogEvent"] | components["schemas"]["AgentSwarmCatalogEvent"];
2434
2626
  };
@@ -2754,6 +2946,8 @@ export interface operations {
2754
2946
  query?: {
2755
2947
  /** @description Only `30d` is supported. */
2756
2948
  window?: "30d";
2949
+ team_size?: "1" | "2-10" | "11-50" | "51+";
2950
+ use_case?: "features" | "bugs" | "review" | "ops" | "docs" | "data";
2757
2951
  };
2758
2952
  header?: never;
2759
2953
  path?: never;
@@ -2772,7 +2966,7 @@ export interface operations {
2772
2966
  "application/json": components["schemas"]["FleetBenchmarks"];
2773
2967
  };
2774
2968
  };
2775
- /** @description `window` is not `30d` (code `invalid_window`). */
2969
+ /** @description Invalid window or profile filter (invalid_window, invalid_team_size, invalid_use_case). */
2776
2970
  400: {
2777
2971
  headers: {
2778
2972
  [name: string]: unknown;
@@ -2869,7 +3063,11 @@ export interface operations {
2869
3063
  parameters: {
2870
3064
  query: {
2871
3065
  domain: string;
2872
- claim: string;
3066
+ /**
3067
+ * @deprecated
3068
+ * @description Sent by agent-swarm v2.4.0's PR check. Ignored.
3069
+ */
3070
+ claim?: string;
2873
3071
  };
2874
3072
  header?: never;
2875
3073
  path?: never;
@@ -2888,7 +3086,7 @@ export interface operations {
2888
3086
  "application/json": components["schemas"]["RankingVerification"];
2889
3087
  };
2890
3088
  };
2891
- /** @description `domain` or `claim` is malformed (codes `invalid_domain`, `invalid_claim`). */
3089
+ /** @description `domain` is malformed (code `invalid_domain`). */
2892
3090
  400: {
2893
3091
  headers: {
2894
3092
  [name: string]: unknown;
@@ -4,6 +4,8 @@
4
4
  *
5
5
  * - `context.org_domain`: the email DOMAIN of the org's admin (never the email)
6
6
  * - `context.user_role`: `admin` when the user's grants include everything, else `member`
7
+ * - `context.user_function`: a canonical job function from `users.metadata.jobFunction`
8
+ * (not `users.role`: the dashboard reads an empty or `admin` role as admin-like)
7
9
  *
8
10
  * This file must not import `./be/db` (`be/db.ts` imports the trigger module
9
11
  * that imports this one). It reads through the DB client and lazy-imports RBAC.
@@ -11,26 +13,36 @@
11
13
  import { getDbClient } from "./be/db/runtime";
12
14
  import { setTelemetryOrgDomain } from "./telemetry";
13
15
  import { emailDomain, type TelemetryUserRole } from "./telemetry-context";
16
+ import { USER_FUNCTIONS } from "./utils/company-profile";
14
17
 
15
18
  const ROLE_TTL_MS = 60 * 60_000;
16
19
  const ROLE_CACHE_LIMIT = 1_000;
17
20
  const DOMAIN_RECOMPUTE_DEBOUNCE_MS = 2_000;
18
21
 
19
- const roleCache = new Map<string, { role: TelemetryUserRole; at: number }>();
22
+ interface UserRoleEntry {
23
+ role: TelemetryUserRole;
24
+ userFunction?: (typeof USER_FUNCTIONS)[number];
25
+ at: number;
26
+ }
27
+
28
+ const roleCache = new Map<string, UserRoleEntry>();
20
29
  const roleLoads = new Map<string, Promise<TelemetryUserRole | undefined>>();
21
30
 
22
- async function loadUserRole(userId: string): Promise<TelemetryUserRole | undefined> {
31
+ async function loadUserRole(userId: string): Promise<UserRoleEntry | undefined> {
23
32
  try {
24
33
  // Lazy: be/rbac-roles imports be/db, which (transitively) imports this file.
25
34
  const { getUserGrant } = await import("./be/rbac-roles");
26
35
  const grant = await getUserGrant(userId);
27
36
  const role: TelemetryUserRole = grant.grantsAll ? "admin" : "member";
28
- if (roleCache.size >= ROLE_CACHE_LIMIT) {
29
- const oldest = roleCache.keys().next().value;
30
- if (oldest !== undefined) roleCache.delete(oldest);
31
- }
32
- roleCache.set(userId, { role, at: Date.now() });
33
- return role;
37
+ const user = await getDbClient().get<{ jobFunction: string | null }>(
38
+ "SELECT json_extract(metadata, '$.jobFunction') AS jobFunction FROM users WHERE id = ? AND json_valid(metadata)",
39
+ [userId],
40
+ );
41
+ return {
42
+ role,
43
+ userFunction: USER_FUNCTIONS.find((value) => value === user?.jobFunction),
44
+ at: Date.now(),
45
+ };
34
46
  } catch {
35
47
  return undefined;
36
48
  }
@@ -42,7 +54,20 @@ export function primeUserRole(userId: string): Promise<TelemetryUserRole | undef
42
54
  if (hit && Date.now() - hit.at < ROLE_TTL_MS) return Promise.resolve(hit.role);
43
55
  let load = roleLoads.get(userId);
44
56
  if (!load) {
45
- load = loadUserRole(userId).finally(() => roleLoads.delete(userId));
57
+ load = loadUserRole(userId)
58
+ .then((entry) => {
59
+ if (entry && roleLoads.get(userId) === load) {
60
+ if (roleCache.size >= ROLE_CACHE_LIMIT) {
61
+ const oldest = roleCache.keys().next().value;
62
+ if (oldest !== undefined) roleCache.delete(oldest);
63
+ }
64
+ roleCache.set(userId, entry);
65
+ }
66
+ return entry?.role;
67
+ })
68
+ .finally(() => {
69
+ if (roleLoads.get(userId) === load) roleLoads.delete(userId);
70
+ });
46
71
  roleLoads.set(userId, load);
47
72
  }
48
73
  return load;
@@ -59,6 +84,19 @@ export function cachedUserRole(userId: string): TelemetryUserRole | undefined {
59
84
  return hit?.role;
60
85
  }
61
86
 
87
+ /** Resolve the job function from the same cache and lookup as the RBAC role. */
88
+ export function cachedUserFunction(userId: string): UserRoleEntry["userFunction"] {
89
+ const hit = roleCache.get(userId);
90
+ if (!hit || Date.now() - hit.at >= ROLE_TTL_MS) void primeUserRole(userId);
91
+ return hit?.userFunction;
92
+ }
93
+
94
+ /** Invalidate after a user mutation commits, including any lookup already in progress. */
95
+ export function invalidateTelemetryUserRole(userId: string): void {
96
+ roleCache.delete(userId);
97
+ roleLoads.delete(userId);
98
+ }
99
+
62
100
  /**
63
101
  * The email domain of the org's earliest-created active admin, falling back to
64
102
  * the earliest active user with an email. A candidate whose address has no
@@ -9,9 +9,15 @@
9
9
  */
10
10
 
11
11
  import { getDbClient } from "./be/db/runtime";
12
- import { isTelemetryReady, setTelemetryRoleResolver, telemetry } from "./telemetry";
12
+ import {
13
+ isTelemetryReady,
14
+ setTelemetryFunctionResolver,
15
+ setTelemetryRoleResolver,
16
+ telemetry,
17
+ } from "./telemetry";
13
18
  import type { PropsFor } from "./telemetry-contract";
14
19
  import {
20
+ cachedUserFunction,
15
21
  cachedUserRole,
16
22
  configureOrgDomainPersistence,
17
23
  recomputeOrgDomain,
@@ -169,6 +175,7 @@ export function startTelemetryTicker(deps: SnapshotDeps): void {
169
175
  if (!isTelemetryReady()) return;
170
176
  stopTelemetryTicker();
171
177
  setTelemetryRoleResolver(cachedUserRole);
178
+ setTelemetryFunctionResolver(cachedUserFunction);
172
179
 
173
180
  const tick = async () => {
174
181
  try {
@@ -207,5 +214,6 @@ export function stopTelemetryTicker(): void {
207
214
  tickTimer = null;
208
215
  firstTimer = null;
209
216
  setTelemetryRoleResolver(null);
217
+ setTelemetryFunctionResolver(null);
210
218
  configureOrgDomainPersistence(null);
211
219
  }
@@ -15,6 +15,7 @@ interface PropertySpec {
15
15
  minimum?: number;
16
16
  required?: boolean;
17
17
  nullable?: boolean;
18
+ items?: PropertySpec;
18
19
  }
19
20
 
20
21
  interface CatalogEntry {
@@ -62,8 +63,8 @@ export function uiEventEmitter(event: string): string | undefined {
62
63
  }
63
64
 
64
65
  function resolveSpec(spec: PropertySpec): PropertySpec {
65
- if (!spec.ref) return spec;
66
- return { ...file.definitions[spec.ref], ...spec };
66
+ const resolved = spec.ref ? { ...file.definitions[spec.ref], ...spec } : spec;
67
+ return resolved.items ? { ...resolved, items: resolveSpec(resolved.items) } : resolved;
67
68
  }
68
69
 
69
70
  function typeMatches(type: string | undefined, value: unknown): boolean {
@@ -117,6 +118,12 @@ export function validateUiEvent(event: string, properties: Record<string, unknow
117
118
  if (spec.enum && !spec.enum.includes(value as string)) {
118
119
  problems.push(`"${key}" must be one of ${spec.enum.join(", ")}`);
119
120
  }
121
+ if (Array.isArray(value) && spec.items?.enum) {
122
+ const allowed = spec.items.enum;
123
+ if (value.some((item) => !allowed.includes(item))) {
124
+ problems.push(`"${key}" items must be one of ${allowed.join(", ")}`);
125
+ }
126
+ }
120
127
  if (typeof spec.minimum === "number" && typeof value === "number" && value < spec.minimum) {
121
128
  problems.push(`"${key}" must be at least ${spec.minimum}`);
122
129
  }