@cursor/july 0.1.107 → 0.1.109

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 (523) hide show
  1. package/AGENTS.md +2 -6
  2. package/README.md +13 -11
  3. package/dist/bin/agent-serve.js +30 -8
  4. package/dist/channels/bitbucket/api.d.ts +41 -0
  5. package/dist/channels/bitbucket/api.d.ts.map +1 -1
  6. package/dist/channels/bitbucket/api.js +260 -0
  7. package/dist/channels/bitbucket/binding.d.ts +4 -0
  8. package/dist/channels/bitbucket/binding.d.ts.map +1 -1
  9. package/dist/channels/bitbucket/binding.js +16 -0
  10. package/dist/channels/bitbucket/index.d.ts +1 -1
  11. package/dist/channels/bitbucket/index.d.ts.map +1 -1
  12. package/dist/channels/bitbucket/index.js +1 -1
  13. package/dist/channels/github/github-channel.js +8 -5
  14. package/dist/channels/github/types.d.ts +5 -1
  15. package/dist/channels/github/types.d.ts.map +1 -1
  16. package/dist/channels/gitlab/api.d.ts +27 -0
  17. package/dist/channels/gitlab/api.d.ts.map +1 -1
  18. package/dist/channels/gitlab/api.js +88 -0
  19. package/dist/channels/gitlab/binding.d.ts +5 -0
  20. package/dist/channels/gitlab/binding.d.ts.map +1 -1
  21. package/dist/channels/gitlab/binding.js +10 -0
  22. package/dist/channels/gitlab/index.d.ts +1 -1
  23. package/dist/channels/gitlab/index.d.ts.map +1 -1
  24. package/dist/channels/gitlab/index.js +1 -1
  25. package/dist/channels/origin/origin-channel.d.ts.map +1 -1
  26. package/dist/channels/origin/origin-channel.js +27 -13
  27. package/dist/channels/origin/types.d.ts +5 -1
  28. package/dist/channels/origin/types.d.ts.map +1 -1
  29. package/dist/channels/slack/dispatch.d.ts +10 -0
  30. package/dist/channels/slack/dispatch.d.ts.map +1 -1
  31. package/dist/channels/slack/dispatch.js +20 -3
  32. package/dist/channels/slack/slack-channel.d.ts +12 -5
  33. package/dist/channels/slack/slack-channel.d.ts.map +1 -1
  34. package/dist/channels/slack/slack-channel.js +59 -8
  35. package/dist/channels.d.ts +45 -0
  36. package/dist/channels.d.ts.map +1 -1
  37. package/dist/channels.js +106 -7
  38. package/dist/connections.d.ts +2 -1
  39. package/dist/connections.d.ts.map +1 -1
  40. package/dist/connections.js +2 -1
  41. package/dist/docs/404.html +2 -2
  42. package/dist/docs/assets/{app.CtuckIiL.js → app.Cr-wVbnB.js} +1 -1
  43. package/dist/docs/assets/{building-with-agents.md.CUSWxlP_.js → building-with-agents.md.D0KbSkJn.js} +2 -2
  44. package/dist/docs/assets/{building-with-agents.md.CUSWxlP_.lean.js → building-with-agents.md.D0KbSkJn.lean.js} +1 -1
  45. package/dist/docs/assets/chunks/@localSearchIndexroot.CFVQ4S17.js +1 -0
  46. package/dist/docs/assets/chunks/{VPLocalSearchBox.Bkkhnu8K.js → VPLocalSearchBox.CVQERt56.js} +1 -1
  47. package/dist/docs/assets/chunks/{theme.DhpIe0Pa.js → theme.Dnsd3XOn.js} +2 -2
  48. package/dist/docs/assets/concepts.md.B4o63Gul.js +1 -0
  49. package/dist/docs/assets/{deployment.md.MFPKqsqI.js → deployment.md.JenwuCCB.js} +4 -4
  50. package/dist/docs/assets/{deployment.md.MFPKqsqI.lean.js → deployment.md.JenwuCCB.lean.js} +1 -1
  51. package/dist/docs/assets/evals.md.C7JLjoEP.js +211 -0
  52. package/dist/docs/assets/evals.md.C7JLjoEP.lean.js +1 -0
  53. package/dist/docs/assets/guides_bitbucket.md.DZPzmUjU.js +10 -0
  54. package/dist/docs/assets/guides_bitbucket.md.DZPzmUjU.lean.js +1 -0
  55. package/dist/docs/assets/guides_cloud-agents.md.BsloyHdY.js +9 -0
  56. package/dist/docs/assets/{guides_cloud-agents.md.DS8RIjwx.lean.js → guides_cloud-agents.md.BsloyHdY.lean.js} +1 -1
  57. package/dist/docs/assets/{guides_github.md.c0gdGJ-D.js → guides_github.md.TZaTZlfz.js} +13 -3
  58. package/dist/docs/assets/{guides_github.md.c0gdGJ-D.lean.js → guides_github.md.TZaTZlfz.lean.js} +1 -1
  59. package/dist/docs/assets/guides_gitlab.md.BmqwQfdG.js +14 -0
  60. package/dist/docs/assets/guides_gitlab.md.BmqwQfdG.lean.js +1 -0
  61. package/dist/docs/assets/{guides_grokbot-agents.md.DVqdhBKb.js → guides_grokbot-agents.md.DyV-WArv.js} +1 -1
  62. package/dist/docs/assets/guides_improve.md.BGVk32bK.js +14 -0
  63. package/dist/docs/assets/guides_improve.md.BGVk32bK.lean.js +1 -0
  64. package/dist/docs/assets/{guides_slack.md.9oHPye9o.js → guides_slack.md.D4RVMM4G.js} +3 -3
  65. package/dist/docs/assets/{guides_slack.md.9oHPye9o.lean.js → guides_slack.md.D4RVMM4G.lean.js} +1 -1
  66. package/dist/docs/assets/{guides_webhooks.md.DKdA43Qm.js → guides_webhooks.md.CJK484ex.js} +2 -2
  67. package/dist/docs/assets/{hillclimbing.md.CpTGTCle.js → hillclimbing.md.BOiVo1tf.js} +1 -1
  68. package/dist/docs/assets/index.md.DD9Q2XuJ.js +5 -0
  69. package/dist/docs/assets/{index.md.BW_6tOgR.lean.js → index.md.DD9Q2XuJ.lean.js} +1 -1
  70. package/dist/docs/assets/{reference_agent-config.md.CHNpiyp4.js → reference_agent-config.md.CvoL6pof.js} +1 -1
  71. package/dist/docs/assets/{reference_channels.md.D-qTqwcq.js → reference_channels.md.CAo-iK4j.js} +2 -2
  72. package/dist/docs/assets/{reference_channels.md.D-qTqwcq.lean.js → reference_channels.md.CAo-iK4j.lean.js} +1 -1
  73. package/dist/docs/assets/{reference_cli.md.Dm67hd2D.js → reference_cli.md.Deg7849l.js} +7 -7
  74. package/dist/docs/assets/{reference_cli.md.Dm67hd2D.lean.js → reference_cli.md.Deg7849l.lean.js} +1 -1
  75. package/dist/docs/assets/{reference_connections.md.Di6jJAXF.js → reference_connections.md.BojkC6c5.js} +1 -1
  76. package/dist/docs/assets/{reference_extensions.md.CGmMLblt.js → reference_extensions.md.ZAVUyuEX.js} +3 -3
  77. package/dist/docs/assets/{reference_hooks.md.Ddt5DdgJ.js → reference_hooks.md.BlM_bOg6.js} +3 -3
  78. package/dist/docs/assets/{reference_hooks.md.Ddt5DdgJ.lean.js → reference_hooks.md.BlM_bOg6.lean.js} +1 -1
  79. package/dist/docs/assets/{reference_http-api.md.oySXBO8o.js → reference_http-api.md.BwaCo-VO.js} +1 -1
  80. package/dist/docs/assets/{reference_playground.md.4myJPxrf.js → reference_playground.md.DLnoaczX.js} +1 -1
  81. package/dist/docs/assets/{reference_playground.md.4myJPxrf.lean.js → reference_playground.md.DLnoaczX.lean.js} +1 -1
  82. package/dist/docs/assets/{reference_project-layout.md.DuBu9a96.js → reference_project-layout.md.BEU8MtQV.js} +3 -3
  83. package/dist/docs/assets/{reference_project-layout.md.DuBu9a96.lean.js → reference_project-layout.md.BEU8MtQV.lean.js} +1 -1
  84. package/dist/docs/assets/reference_sessions.md.CyXV1MUw.js +1 -0
  85. package/dist/docs/assets/{scaffolding-agents.md.em43xlY1.js → scaffolding-agents.md.Kctn3OVb.js} +1 -1
  86. package/dist/docs/assets/{skills_create-agent.md.BVoWPcan.js → skills_create-agent.md.Q3h6Je-e.js} +1 -1
  87. package/dist/docs/assets/{skills_debug.md.CDbPhHfg.js → skills_debug.md.CVjCXMFF.js} +1 -1
  88. package/dist/docs/assets/{skills_debug.md.CDbPhHfg.lean.js → skills_debug.md.CVjCXMFF.lean.js} +1 -1
  89. package/dist/docs/assets/skills_deploy.md.CWqi_ZxW.js +35 -0
  90. package/dist/docs/assets/skills_deploy.md.CWqi_ZxW.lean.js +1 -0
  91. package/dist/docs/assets/skills_evals.md.DFxYPErF.js +25 -0
  92. package/dist/docs/assets/skills_evals.md.DFxYPErF.lean.js +1 -0
  93. package/dist/docs/assets/skills_framework-map.md.BxLSOhSY.js +1 -0
  94. package/dist/docs/assets/{skills_framework-map.md.haibFyoB.lean.js → skills_framework-map.md.BxLSOhSY.lean.js} +1 -1
  95. package/dist/docs/assets/{skills_github.md.D0JahM8c.js → skills_github.md.hgFX_oKY.js} +1 -1
  96. package/dist/docs/assets/skills_index.md.DL7EHaQ-.js +1 -0
  97. package/dist/docs/assets/skills_index.md.DL7EHaQ-.lean.js +1 -0
  98. package/dist/docs/assets/{storage.md.BOHeqk2M.js → storage.md.BUrhJ-Zz.js} +4 -4
  99. package/dist/docs/assets/{storage.md.BOHeqk2M.lean.js → storage.md.BUrhJ-Zz.lean.js} +1 -1
  100. package/dist/docs/assets/troubleshooting.md.CYEAO9bM.js +1 -0
  101. package/dist/docs/building-with-agents.html +5 -5
  102. package/dist/docs/building-with-agents.md +3 -2
  103. package/dist/docs/concepts.html +5 -5
  104. package/dist/docs/concepts.md +2 -4
  105. package/dist/docs/deployment.html +7 -7
  106. package/dist/docs/deployment.md +7 -2
  107. package/dist/docs/evals.html +161 -35
  108. package/dist/docs/evals.md +612 -296
  109. package/dist/docs/guides/agent-to-agent.html +4 -4
  110. package/dist/docs/guides/bitbucket.html +36 -0
  111. package/dist/docs/guides/bitbucket.md +84 -0
  112. package/dist/docs/guides/cloud-agents.html +6 -6
  113. package/dist/docs/guides/cloud-agents.md +4 -3
  114. package/dist/docs/guides/convert-automation.html +4 -4
  115. package/dist/docs/guides/github.html +17 -7
  116. package/dist/docs/guides/github.md +33 -1
  117. package/dist/docs/guides/gitlab.html +40 -0
  118. package/dist/docs/guides/gitlab.md +92 -0
  119. package/dist/docs/guides/grokbot-agents.html +6 -6
  120. package/dist/docs/guides/grokbot-agents.md +2 -2
  121. package/dist/docs/guides/human-in-the-loop.html +4 -4
  122. package/dist/docs/guides/improve.html +40 -0
  123. package/dist/docs/guides/improve.md +91 -0
  124. package/dist/docs/guides/mcp-oauth.html +4 -4
  125. package/dist/docs/guides/opentelemetry.html +5 -5
  126. package/dist/docs/guides/slack.html +7 -7
  127. package/dist/docs/guides/slack.md +2 -1
  128. package/dist/docs/guides/webhooks.html +6 -6
  129. package/dist/docs/guides/webhooks.md +4 -2
  130. package/dist/docs/hashmap.json +1 -1
  131. package/dist/docs/hillclimbing.html +6 -6
  132. package/dist/docs/hillclimbing.md +2 -2
  133. package/dist/docs/index.html +6 -6
  134. package/dist/docs/index.md +14 -6
  135. package/dist/docs/llms-full.txt +1274 -814
  136. package/dist/docs/llms.txt +7 -5
  137. package/dist/docs/quickstart.html +4 -4
  138. package/dist/docs/reference/agent-config.html +6 -6
  139. package/dist/docs/reference/agent-config.md +5 -2
  140. package/dist/docs/reference/artifacts.html +4 -4
  141. package/dist/docs/reference/channels.html +6 -6
  142. package/dist/docs/reference/channels.md +16 -3
  143. package/dist/docs/reference/cli.html +11 -11
  144. package/dist/docs/reference/cli.md +24 -15
  145. package/dist/docs/reference/connections.html +6 -6
  146. package/dist/docs/reference/connections.md +2 -1
  147. package/dist/docs/reference/extensions.html +8 -8
  148. package/dist/docs/reference/extensions.md +2 -3
  149. package/dist/docs/reference/hooks.html +7 -7
  150. package/dist/docs/reference/hooks.md +9 -12
  151. package/dist/docs/reference/http-api.html +6 -6
  152. package/dist/docs/reference/http-api.md +2 -3
  153. package/dist/docs/reference/instructions.html +4 -4
  154. package/dist/docs/reference/playground.html +5 -5
  155. package/dist/docs/reference/playground.md +0 -4
  156. package/dist/docs/reference/project-layout.html +7 -7
  157. package/dist/docs/reference/project-layout.md +1 -8
  158. package/dist/docs/reference/prompt.html +4 -4
  159. package/dist/docs/reference/result.html +4 -4
  160. package/dist/docs/reference/schedules.html +4 -4
  161. package/dist/docs/reference/sessions.html +5 -5
  162. package/dist/docs/reference/sessions.md +1 -2
  163. package/dist/docs/reference/skills.html +4 -4
  164. package/dist/docs/reference/subagents.html +4 -4
  165. package/dist/docs/reference/tools.html +4 -4
  166. package/dist/docs/scaffolding-agents.html +5 -5
  167. package/dist/docs/scaffolding-agents.md +2 -1
  168. package/dist/docs/skills/create-agent.html +6 -6
  169. package/dist/docs/skills/create-agent.md +1 -1
  170. package/dist/docs/skills/debug.html +5 -5
  171. package/dist/docs/skills/debug.md +1 -1
  172. package/dist/docs/skills/deploy.html +61 -0
  173. package/dist/docs/skills/deploy.md +161 -0
  174. package/dist/docs/skills/evals.html +8 -8
  175. package/dist/docs/skills/evals.md +44 -6
  176. package/dist/docs/skills/framework-map.html +5 -5
  177. package/dist/docs/skills/framework-map.md +5 -4
  178. package/dist/docs/skills/github.html +6 -6
  179. package/dist/docs/skills/github.md +1 -1
  180. package/dist/docs/skills/hillclimb.html +4 -4
  181. package/dist/docs/skills/index.html +6 -6
  182. package/dist/docs/skills/index.md +1 -1
  183. package/dist/docs/skills/mcp-auth.html +4 -4
  184. package/dist/docs/skills/otel.html +4 -4
  185. package/dist/docs/skills/setup-slack.html +4 -4
  186. package/dist/docs/storage.html +8 -8
  187. package/dist/docs/storage.md +15 -24
  188. package/dist/docs/templates/agentic-owners.html +4 -4
  189. package/dist/docs/templates/agents-md.html +4 -4
  190. package/dist/docs/templates/code-wiki.html +4 -4
  191. package/dist/docs/templates/demo.html +4 -4
  192. package/dist/docs/templates/grokbot-agents.html +4 -4
  193. package/dist/docs/templates/pr-autofixer.html +4 -4
  194. package/dist/docs/templates/security-help.html +4 -4
  195. package/dist/docs/templates/security-reviewer.html +4 -4
  196. package/dist/docs/templates/triage.html +4 -4
  197. package/dist/docs/troubleshooting.html +5 -5
  198. package/dist/docs/troubleshooting.md +1 -1
  199. package/dist/extensions/improve/extension.d.ts +46 -0
  200. package/dist/extensions/improve/extension.d.ts.map +1 -0
  201. package/dist/extensions/improve/extension.js +41 -0
  202. package/dist/extensions/improve/skills/yourself.d.ts +4 -0
  203. package/dist/extensions/improve/skills/yourself.d.ts.map +1 -0
  204. package/dist/extensions/improve/skills/yourself.js +43 -0
  205. package/dist/extensions.d.ts +2 -3
  206. package/dist/extensions.d.ts.map +1 -1
  207. package/dist/extensions.js +2 -5
  208. package/dist/index.d.ts +2 -3
  209. package/dist/index.d.ts.map +1 -1
  210. package/dist/index.js +1 -2
  211. package/dist/internal/authored-alias-hooks.d.ts +5 -0
  212. package/dist/internal/authored-alias-hooks.d.ts.map +1 -1
  213. package/dist/internal/authored-alias-hooks.js +17 -0
  214. package/dist/internal/authored-loaders.d.ts +4 -0
  215. package/dist/internal/authored-loaders.d.ts.map +1 -1
  216. package/dist/internal/authored-loaders.js +21 -2
  217. package/dist/internal/builtin-tools/artifacts.d.ts.map +1 -1
  218. package/dist/internal/builtin-tools/artifacts.js +2 -3
  219. package/dist/internal/channel-route-dispatch.d.ts +13 -0
  220. package/dist/internal/channel-route-dispatch.d.ts.map +1 -0
  221. package/dist/internal/channel-route-dispatch.js +62 -0
  222. package/dist/internal/channel-state.d.ts +17 -0
  223. package/dist/internal/channel-state.d.ts.map +1 -0
  224. package/dist/internal/channel-state.js +78 -0
  225. package/dist/internal/cli-ax.d.ts +8 -2
  226. package/dist/internal/cli-ax.d.ts.map +1 -1
  227. package/dist/internal/cli-ax.js +100 -3
  228. package/dist/internal/cli-cursor.d.ts.map +1 -1
  229. package/dist/internal/cli-cursor.js +2 -0
  230. package/dist/internal/cli-deploy.d.ts.map +1 -1
  231. package/dist/internal/cli-deploy.js +38 -14
  232. package/dist/internal/cli-mcp-oauth.d.ts.map +1 -1
  233. package/dist/internal/cli-mcp-oauth.js +15 -0
  234. package/dist/internal/cli-mcp.d.ts.map +1 -1
  235. package/dist/internal/cli-mcp.js +12 -0
  236. package/dist/internal/cli-slack.d.ts.map +1 -1
  237. package/dist/internal/cli-slack.js +8 -2
  238. package/dist/internal/continuation-channel.d.ts.map +1 -1
  239. package/dist/internal/continuation-channel.js +2 -2
  240. package/dist/internal/continuation-identity.js +8 -3
  241. package/dist/internal/cursor/credentials.d.ts +8 -2
  242. package/dist/internal/cursor/credentials.d.ts.map +1 -1
  243. package/dist/internal/cursor/credentials.js +27 -5
  244. package/dist/internal/deploy-client.d.ts +27 -0
  245. package/dist/internal/deploy-client.d.ts.map +1 -1
  246. package/dist/internal/deploy-client.js +32 -0
  247. package/dist/internal/deploy-manifest.d.ts +23 -0
  248. package/dist/internal/deploy-manifest.d.ts.map +1 -1
  249. package/dist/internal/deploy-manifest.js +84 -1
  250. package/dist/internal/describe-error.d.ts +1 -0
  251. package/dist/internal/describe-error.d.ts.map +1 -1
  252. package/dist/internal/describe-error.js +25 -0
  253. package/dist/internal/discovery/agent.d.ts +1 -1
  254. package/dist/internal/discovery/agent.d.ts.map +1 -1
  255. package/dist/internal/discovery/agent.js +0 -5
  256. package/dist/internal/discovery/extension-overlay.d.ts +1 -2
  257. package/dist/internal/discovery/extension-overlay.d.ts.map +1 -1
  258. package/dist/internal/discovery/extension-overlay.js +0 -14
  259. package/dist/internal/discovery/extensions.d.ts +1 -2
  260. package/dist/internal/discovery/extensions.d.ts.map +1 -1
  261. package/dist/internal/discovery/extensions.js +4 -22
  262. package/dist/internal/discovery/info.d.ts.map +1 -1
  263. package/dist/internal/discovery/info.js +42 -24
  264. package/dist/internal/discovery/modules.js +0 -1
  265. package/dist/internal/discovery/project.d.ts.map +1 -1
  266. package/dist/internal/discovery/project.js +0 -16
  267. package/dist/internal/eval-runner.js +0 -1
  268. package/dist/internal/framework-file-storage.d.ts +4 -5
  269. package/dist/internal/framework-file-storage.d.ts.map +1 -1
  270. package/dist/internal/framework-file-storage.js +4 -5
  271. package/dist/internal/framework-storage-selection.d.ts +2 -2
  272. package/dist/internal/framework-storage-selection.js +2 -2
  273. package/dist/internal/guest-network.d.ts +4 -10
  274. package/dist/internal/guest-network.d.ts.map +1 -1
  275. package/dist/internal/guest-network.js +42 -26
  276. package/dist/internal/hosted-admission-adapter.d.ts +2 -0
  277. package/dist/internal/hosted-admission-adapter.d.ts.map +1 -1
  278. package/dist/internal/hosted-catch-protocol.d.ts +51 -0
  279. package/dist/internal/hosted-catch-protocol.d.ts.map +1 -0
  280. package/dist/internal/hosted-catch-protocol.js +103 -0
  281. package/dist/internal/hosted-catch.d.ts +40 -0
  282. package/dist/internal/hosted-catch.d.ts.map +1 -0
  283. package/dist/internal/hosted-catch.js +149 -0
  284. package/dist/internal/hosted-delivery-protocol.d.ts +41 -0
  285. package/dist/internal/hosted-delivery-protocol.d.ts.map +1 -1
  286. package/dist/internal/hosted-delivery-protocol.js +249 -0
  287. package/dist/internal/hosted-delivery.d.ts +10 -1
  288. package/dist/internal/hosted-delivery.d.ts.map +1 -1
  289. package/dist/internal/hosted-delivery.js +100 -22
  290. package/dist/internal/hosted-execution-diag.d.ts +4 -1
  291. package/dist/internal/hosted-execution-diag.d.ts.map +1 -1
  292. package/dist/internal/hosted-execution-diag.js +13 -4
  293. package/dist/internal/hosted-execution-flush.d.ts +3 -0
  294. package/dist/internal/hosted-execution-flush.d.ts.map +1 -1
  295. package/dist/internal/hosted-execution-flush.js +2 -4
  296. package/dist/internal/http-control-plane-session.d.ts +30 -0
  297. package/dist/internal/http-control-plane-session.d.ts.map +1 -0
  298. package/dist/internal/http-control-plane-session.js +83 -0
  299. package/dist/internal/init-scaffold.d.ts.map +1 -1
  300. package/dist/internal/init-scaffold.js +1 -2
  301. package/dist/internal/install-cursor-skills.d.ts +5 -2
  302. package/dist/internal/install-cursor-skills.d.ts.map +1 -1
  303. package/dist/internal/install-cursor-skills.js +25 -5
  304. package/dist/internal/legacy-command-guard.d.ts +22 -0
  305. package/dist/internal/legacy-command-guard.d.ts.map +1 -0
  306. package/dist/internal/legacy-command-guard.js +51 -0
  307. package/dist/internal/platform-timers.d.ts +7 -0
  308. package/dist/internal/platform-timers.d.ts.map +1 -1
  309. package/dist/internal/platform-timers.js +139 -0
  310. package/dist/internal/reminder-control-plane-protocol.d.ts +2 -0
  311. package/dist/internal/reminder-control-plane-protocol.d.ts.map +1 -1
  312. package/dist/internal/reminder-control-plane-protocol.js +9 -2
  313. package/dist/internal/reminder-runner.d.ts +8 -0
  314. package/dist/internal/reminder-runner.d.ts.map +1 -1
  315. package/dist/internal/reminder-runner.js +36 -9
  316. package/dist/internal/resolve-prod-target.d.ts +2 -0
  317. package/dist/internal/resolve-prod-target.d.ts.map +1 -1
  318. package/dist/internal/resolve-prod-target.js +13 -0
  319. package/dist/internal/run-client.d.ts +1 -1
  320. package/dist/internal/sdk-runner.d.ts.map +1 -1
  321. package/dist/internal/sdk-runner.js +5 -4
  322. package/dist/internal/server.d.ts.map +1 -1
  323. package/dist/internal/server.js +57 -70
  324. package/dist/internal/session-engine.d.ts +7 -41
  325. package/dist/internal/session-engine.d.ts.map +1 -1
  326. package/dist/internal/session-engine.js +110 -227
  327. package/dist/internal/storage-coordinator.d.ts +5 -19
  328. package/dist/internal/storage-coordinator.d.ts.map +1 -1
  329. package/dist/internal/storage-coordinator.js +3 -62
  330. package/dist/internal/storage-roles.d.ts +4 -9
  331. package/dist/internal/storage-roles.d.ts.map +1 -1
  332. package/dist/internal/storage-roles.js +2 -2
  333. package/dist/playground/assets/index-Bhxzrcf6.css +1 -0
  334. package/dist/playground/assets/index-CqLX5uF3.js +67 -0
  335. package/dist/playground/index.html +2 -2
  336. package/dist/storage-backends/cursor-hosted-v2.d.ts +4 -5
  337. package/dist/storage-backends/cursor-hosted-v2.d.ts.map +1 -1
  338. package/dist/storage-backends/cursor-hosted-v2.js +4 -5
  339. package/dist/storage-backends/cursor-hosted.d.ts +7 -2
  340. package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
  341. package/dist/storage-backends/cursor-hosted.js +29 -31
  342. package/dist/storage-backends/file-kv.d.ts +9 -12
  343. package/dist/storage-backends/file-kv.d.ts.map +1 -1
  344. package/dist/storage-backends/file-kv.js +11 -47
  345. package/dist/storage-protocol.d.ts +3 -11
  346. package/dist/storage-protocol.d.ts.map +1 -1
  347. package/dist/storage-protocol.js +3 -11
  348. package/dist/storage.d.ts +8 -36
  349. package/dist/storage.d.ts.map +1 -1
  350. package/dist/storage.js +8 -44
  351. package/dist/types.d.ts +53 -62
  352. package/dist/types.d.ts.map +1 -1
  353. package/docs/README.md +14 -6
  354. package/docs/building-with-agents.md +3 -2
  355. package/docs/concepts.md +2 -4
  356. package/docs/deployment.md +7 -2
  357. package/docs/evals.md +613 -297
  358. package/docs/guides/bitbucket.md +89 -0
  359. package/docs/guides/cloud-agents.md +4 -3
  360. package/docs/guides/github.md +33 -1
  361. package/docs/guides/gitlab.md +97 -0
  362. package/docs/guides/grokbot-agents.md +2 -2
  363. package/docs/guides/improve.md +96 -0
  364. package/docs/guides/slack.md +2 -1
  365. package/docs/guides/webhooks.md +4 -2
  366. package/docs/hillclimbing.md +2 -2
  367. package/docs/reference/agent-config.md +5 -2
  368. package/docs/reference/channels.md +16 -3
  369. package/docs/reference/cli.md +24 -15
  370. package/docs/reference/connections.md +2 -1
  371. package/docs/reference/extensions.md +2 -3
  372. package/docs/reference/hooks.md +9 -12
  373. package/docs/reference/http-api.md +2 -3
  374. package/docs/reference/playground.md +0 -4
  375. package/docs/reference/project-layout.md +1 -8
  376. package/docs/reference/sessions.md +1 -2
  377. package/docs/scaffolding-agents.md +2 -1
  378. package/docs/skills/index.md +2 -2
  379. package/docs/storage.md +15 -24
  380. package/docs/troubleshooting.md +1 -1
  381. package/package.json +8 -7
  382. package/skills/create-agent/SKILL.md +1 -1
  383. package/skills/debug/SKILL.md +1 -1
  384. package/skills/deploy/SKILL.md +169 -0
  385. package/skills/evals/SKILL.md +45 -8
  386. package/skills/framework-map/SKILL.md +5 -4
  387. package/skills/github/SKILL.md +1 -1
  388. package/src/bin/agent-serve.ts +27 -2
  389. package/src/channels/bitbucket/api.ts +341 -0
  390. package/src/channels/bitbucket/binding.ts +25 -0
  391. package/src/channels/bitbucket/index.ts +2 -0
  392. package/src/channels/github/github-channel.ts +8 -8
  393. package/src/channels/github/types.ts +5 -0
  394. package/src/channels/gitlab/api.ts +123 -0
  395. package/src/channels/gitlab/binding.ts +12 -0
  396. package/src/channels/gitlab/index.ts +1 -0
  397. package/src/channels/origin/origin-channel.ts +29 -13
  398. package/src/channels/origin/types.ts +5 -0
  399. package/src/channels/slack/dispatch.ts +30 -0
  400. package/src/channels/slack/slack-channel.ts +69 -7
  401. package/src/channels.ts +157 -10
  402. package/src/connections.ts +2 -1
  403. package/src/extensions/improve/extension.ts +70 -0
  404. package/src/extensions/improve/skills/yourself.ts +50 -0
  405. package/src/extensions.ts +2 -6
  406. package/src/index.ts +0 -3
  407. package/src/internal/authored-alias-hooks.ts +32 -0
  408. package/src/internal/authored-loaders.ts +26 -2
  409. package/src/internal/builtin-tools/artifacts.ts +2 -3
  410. package/src/internal/channel-route-dispatch.ts +66 -0
  411. package/src/internal/channel-state.ts +96 -0
  412. package/src/internal/cli-ax.ts +111 -3
  413. package/src/internal/cli-cursor.ts +4 -1
  414. package/src/internal/cli-deploy.ts +50 -10
  415. package/src/internal/cli-mcp-oauth.ts +18 -0
  416. package/src/internal/cli-mcp.ts +11 -0
  417. package/src/internal/cli-slack.ts +15 -2
  418. package/src/internal/continuation-channel.ts +2 -1
  419. package/src/internal/continuation-identity.ts +10 -2
  420. package/src/internal/cursor/credentials.ts +35 -7
  421. package/src/internal/deploy-client.ts +54 -0
  422. package/src/internal/deploy-manifest.ts +115 -1
  423. package/src/internal/describe-error.ts +28 -0
  424. package/src/internal/discovery/agent.ts +1 -7
  425. package/src/internal/discovery/extension-overlay.ts +0 -18
  426. package/src/internal/discovery/extensions.ts +2 -26
  427. package/src/internal/discovery/info.ts +3 -13
  428. package/src/internal/discovery/modules.ts +0 -1
  429. package/src/internal/discovery/project.ts +0 -16
  430. package/src/internal/eval-runner.ts +0 -1
  431. package/src/internal/framework-file-storage.ts +4 -5
  432. package/src/internal/framework-storage-selection.ts +2 -2
  433. package/src/internal/guest-network.ts +43 -29
  434. package/src/internal/hosted-admission-adapter.ts +2 -0
  435. package/src/internal/hosted-catch-protocol.ts +130 -0
  436. package/src/internal/hosted-catch.ts +192 -0
  437. package/src/internal/hosted-delivery-protocol.ts +387 -0
  438. package/src/internal/hosted-delivery.ts +155 -22
  439. package/src/internal/hosted-execution-diag.ts +21 -3
  440. package/src/internal/hosted-execution-flush.ts +6 -3
  441. package/src/internal/http-control-plane-session.ts +104 -0
  442. package/src/internal/init-scaffold.ts +1 -2
  443. package/src/internal/install-cursor-skills.ts +38 -5
  444. package/src/internal/legacy-command-guard.ts +59 -0
  445. package/src/internal/platform-timers.ts +191 -0
  446. package/src/internal/reminder-control-plane-protocol.ts +15 -2
  447. package/src/internal/reminder-runner.ts +60 -9
  448. package/src/internal/resolve-prod-target.ts +15 -0
  449. package/src/internal/run-client.ts +1 -1
  450. package/src/internal/sdk-runner.ts +3 -2
  451. package/src/internal/server.ts +89 -95
  452. package/src/internal/session-engine.ts +155 -285
  453. package/src/internal/storage-coordinator.ts +5 -76
  454. package/src/internal/storage-roles.ts +4 -9
  455. package/src/storage-backends/cursor-hosted-v2.ts +4 -7
  456. package/src/storage-backends/cursor-hosted.ts +40 -38
  457. package/src/storage-backends/file-kv.ts +10 -51
  458. package/src/storage-protocol.ts +3 -17
  459. package/src/storage.ts +10 -101
  460. package/src/types.ts +58 -62
  461. package/templates/demo/README.md +10 -6
  462. package/templates/demo/agent/channels/github.ts +2 -0
  463. package/templates/demo/agent/channels/queue.ts +6 -2
  464. package/templates/demo/agent/lib/repos.ts +5 -0
  465. package/templates/demo/init.json +25 -0
  466. package/dist/ab.d.ts +0 -209
  467. package/dist/ab.d.ts.map +0 -1
  468. package/dist/ab.js +0 -246
  469. package/dist/docs/ab.html +0 -80
  470. package/dist/docs/ab.md +0 -332
  471. package/dist/docs/assets/ab.md.mlVgqvSk.js +0 -54
  472. package/dist/docs/assets/ab.md.mlVgqvSk.lean.js +0 -1
  473. package/dist/docs/assets/chunks/@localSearchIndexroot.DXXZxiMv.js +0 -1
  474. package/dist/docs/assets/concepts.md.DgEcZOfT.js +0 -1
  475. package/dist/docs/assets/evals.md.CbMoebP1.js +0 -85
  476. package/dist/docs/assets/evals.md.CbMoebP1.lean.js +0 -1
  477. package/dist/docs/assets/guides_cloud-agents.md.DS8RIjwx.js +0 -9
  478. package/dist/docs/assets/index.md.BW_6tOgR.js +0 -5
  479. package/dist/docs/assets/reference_sessions.md.CueyOHSL.js +0 -1
  480. package/dist/docs/assets/skills_ab.md.CsFNatVx.js +0 -26
  481. package/dist/docs/assets/skills_ab.md.CsFNatVx.lean.js +0 -1
  482. package/dist/docs/assets/skills_evals.md.723kpUmA.js +0 -25
  483. package/dist/docs/assets/skills_evals.md.723kpUmA.lean.js +0 -1
  484. package/dist/docs/assets/skills_framework-map.md.haibFyoB.js +0 -1
  485. package/dist/docs/assets/skills_index.md.DKwIxzGg.js +0 -1
  486. package/dist/docs/assets/skills_index.md.DKwIxzGg.lean.js +0 -1
  487. package/dist/docs/assets/troubleshooting.md.Cus_YZga.js +0 -1
  488. package/dist/docs/skills/ab.html +0 -52
  489. package/dist/docs/skills/ab.md +0 -50
  490. package/dist/internal/ab-collector.d.ts +0 -44
  491. package/dist/internal/ab-collector.d.ts.map +0 -1
  492. package/dist/internal/ab-collector.js +0 -142
  493. package/dist/internal/ab-fold.d.ts +0 -36
  494. package/dist/internal/ab-fold.d.ts.map +0 -1
  495. package/dist/internal/ab-fold.js +0 -175
  496. package/dist/internal/ab-snapshot.d.ts +0 -68
  497. package/dist/internal/ab-snapshot.d.ts.map +0 -1
  498. package/dist/internal/ab-snapshot.js +0 -208
  499. package/dist/internal/discovery/ab.d.ts +0 -9
  500. package/dist/internal/discovery/ab.d.ts.map +0 -1
  501. package/dist/internal/discovery/ab.js +0 -113
  502. package/dist/playground/assets/index-Bq2HpEQB.js +0 -67
  503. package/dist/playground/assets/index-CZKKNlmb.css +0 -1
  504. package/docs/ab.md +0 -337
  505. package/skills/ab/SKILL.md +0 -58
  506. package/src/ab.ts +0 -430
  507. package/src/internal/ab-collector.ts +0 -200
  508. package/src/internal/ab-fold.ts +0 -232
  509. package/src/internal/ab-snapshot.ts +0 -331
  510. package/src/internal/discovery/ab.ts +0 -131
  511. /package/dist/docs/assets/{concepts.md.DgEcZOfT.lean.js → concepts.md.B4o63Gul.lean.js} +0 -0
  512. /package/dist/docs/assets/{guides_grokbot-agents.md.DVqdhBKb.lean.js → guides_grokbot-agents.md.DyV-WArv.lean.js} +0 -0
  513. /package/dist/docs/assets/{guides_webhooks.md.DKdA43Qm.lean.js → guides_webhooks.md.CJK484ex.lean.js} +0 -0
  514. /package/dist/docs/assets/{hillclimbing.md.CpTGTCle.lean.js → hillclimbing.md.BOiVo1tf.lean.js} +0 -0
  515. /package/dist/docs/assets/{reference_agent-config.md.CHNpiyp4.lean.js → reference_agent-config.md.CvoL6pof.lean.js} +0 -0
  516. /package/dist/docs/assets/{reference_connections.md.Di6jJAXF.lean.js → reference_connections.md.BojkC6c5.lean.js} +0 -0
  517. /package/dist/docs/assets/{reference_extensions.md.CGmMLblt.lean.js → reference_extensions.md.ZAVUyuEX.lean.js} +0 -0
  518. /package/dist/docs/assets/{reference_http-api.md.oySXBO8o.lean.js → reference_http-api.md.BwaCo-VO.lean.js} +0 -0
  519. /package/dist/docs/assets/{reference_sessions.md.CueyOHSL.lean.js → reference_sessions.md.CyXV1MUw.lean.js} +0 -0
  520. /package/dist/docs/assets/{scaffolding-agents.md.em43xlY1.lean.js → scaffolding-agents.md.Kctn3OVb.lean.js} +0 -0
  521. /package/dist/docs/assets/{skills_create-agent.md.BVoWPcan.lean.js → skills_create-agent.md.Q3h6Je-e.lean.js} +0 -0
  522. /package/dist/docs/assets/{skills_github.md.D0JahM8c.lean.js → skills_github.md.hgFX_oKY.lean.js} +0 -0
  523. /package/dist/docs/assets/{troubleshooting.md.Cus_YZga.lean.js → troubleshooting.md.CYEAO9bM.lean.js} +0 -0
package/dist/docs/ab.md DELETED
@@ -1,332 +0,0 @@
1
- # Live A/B metrics
2
-
3
- Use `defineAB` to compare variants on live agent sessions. New sessions
4
- receive a sticky assignment in each enrolled experiment. The Agent SDK folds
5
- their durable event streams into tool, token, failure, and wall-time
6
- metrics. You can send cumulative samples to your metrics backend and
7
- inspect aggregates in the playground.
8
-
9
- `defineAB` compares live variants through sticky assignment,
10
- instruction overlays, optional tool branches, and cumulative metrics.
11
- Metric callbacks observe the result without approving, rejecting, or
12
- failing a turn. Use [evals](/docs/evals.md) for pass/fail regression checks
13
- on fixed inputs.
14
-
15
- ## Choose live A/B metrics or evals
16
-
17
- Both features read the session event stream, but they answer different
18
- questions.
19
-
20
- | | Live A/B metrics | Evals |
21
- | --- | --- | --- |
22
- | Question | How do variants compare on live sessions? | Does the agent still meet a fixed contract? |
23
- | Location | `agent/ab.ts` or `agent/ab/<name>.ts` | `evals/**/*.eval.ts` |
24
- | Input | Dev or production traffic | Frozen prompts and fixtures |
25
- | Output | Cumulative metrics by session and arm | Pass/fail assertions |
26
- | How it runs | Automatically on new live sessions | `agent-sdk eval` |
27
-
28
- There is no `agent-sdk ab` command or assertion API.
29
-
30
- ## Define an experiment
31
-
32
- Author one experiment in `agent/ab.ts`, add more under
33
- `agent/ab/<name>.ts`, or use both forms. Each file defines one
34
- experiment. The experiment name comes from `name` when set. Otherwise,
35
- the Agent SDK uses `ab` for `agent/ab.ts` and the file stem for files under
36
- `agent/ab/`.
37
-
38
- ```ts
39
- // agent/ab/concise-weather.ts
40
- import {
41
- defineAB,
42
- splitBySessionHash,
43
- } from "@cursor/july/ab";
44
-
45
- export default defineAB({
46
- name: "concise-weather",
47
- variants: {
48
- control: {
49
- label: "Baseline",
50
- },
51
- treatment: {
52
- label: "Short replies",
53
- description: "Adds a one-paragraph response limit.",
54
- instructions: "Keep weather replies to one short paragraph.",
55
- },
56
- },
57
- split: splitBySessionHash({
58
- weights: { control: 1, treatment: 1 },
59
- holdout: 0.1,
60
- }),
61
- derive: {
62
- weatherCalls: (event) =>
63
- event.type === "action.result" &&
64
- event.data.toolName === "get_weather"
65
- ? 1
66
- : null,
67
- },
68
- onSample(sample) {
69
- console.log(
70
- sample.experiment,
71
- sample.variant,
72
- sample.metrics.toolCalls,
73
- sample.metrics.wallTimeMs
74
- );
75
- },
76
- });
77
- ```
78
-
79
- Every definition needs:
80
-
81
- - At least two variants. Variant keys cannot be empty or contain `/` or
82
- `\`.
83
- - A `split` function that returns a variant key or `null`.
84
- - An `onSample` callback for completed or failed turns.
85
-
86
- `label` and `description` appear with the arm in result surfaces.
87
- `instructions` changes the prompt for sessions in that arm. `derive`
88
- adds custom counters.
89
-
90
- Duplicate experiment names are validation errors. Check discovery
91
- before you serve:
92
-
93
- ```bash
94
- agent-sdk validate --dir .
95
- agent-sdk info --dir . --json
96
- ```
97
-
98
- The `abs` field in `info` lists the discovered experiment names.
99
-
100
- ## Assign sticky variants
101
-
102
- Enrollment happens once, when a live session is created and before its
103
- first turn:
104
-
105
- 1. The Agent SDK records `session.started`.
106
- 2. Each experiment runs its `split` function.
107
- 3. The Agent SDK records one durable `ab.assigned` event per experiment.
108
- 4. The selected arms become available on `session.abs`.
109
- 5. Variant instruction overlays reach the first model turn.
110
-
111
- A split can return a variant key or `null`. A null assignment is a
112
- sticky skip for that experiment. It increments the experiment's
113
- `skipped` total, still appears in the snapshot's `sessions` list with
114
- `variant: null`, and does not collect arm metrics or call `onSample`.
115
-
116
- Use the split helper that matches your rollout:
117
-
118
- | Helper | Behavior |
119
- | --- | --- |
120
- | `splitBySessionHash({ weights?, holdout?, salt? })` | Hashes the session id into a reproducible arm; the recommended default |
121
- | `splitByRandom({ weights?, holdout? })` | Draws once when the session starts, then persists the result |
122
- | `splitAlways("control")` | Pins every new session to one arm |
123
- | `splitNone()` | Skips every new session without deleting the experiment |
124
- | `splitIf(predicate, inner)` | Runs `inner` only when the predicate passes |
125
- | Custom `split(ctx)` | Returns a declared variant key or `null` |
126
-
127
- The split context includes the agent name, channel id, session info,
128
- experiment name, and declared variant keys. For example, enroll only
129
- Slack sessions:
130
-
131
- ```ts
132
- split: splitIf(
133
- (ctx) => ctx.channel.id === "slack",
134
- splitBySessionHash()
135
- ),
136
- ```
137
-
138
- Weights default to equal. Non-positive weights leave an arm out of the
139
- draw, and at least one arm must have a positive weight. `holdout` is the
140
- fraction of sessions assigned `null`, from `0` through `1`. Change
141
- `salt` to reshuffle future hash assignments without renaming the
142
- experiment.
143
-
144
- If a custom split throws or returns an unknown variant, the Agent SDK logs
145
- the error and records `variant: null`. The failed decision becomes a
146
- sticky skip instead of breaking the session.
147
-
148
- Enrollment only applies to new sessions. Adding an experiment does not
149
- assign existing conversations. Follow-ups keep the session's original
150
- arms. Keep experiment names and variant keys stable while you collect
151
- and compare results.
152
-
153
- ## Change behavior by variant
154
-
155
- Variant instructions are appended to the agent's base instructions.
156
- Local sessions receive the merged instructions in `AGENTS.md` before
157
- every turn. Cloud sessions receive them in the first-turn preamble
158
- only. For cloud follow-ups, branch through `session.abs` when the arm
159
- must remain visible to deterministic behavior.
160
-
161
- Tools can branch on the assignment through `ctx.session.abs`. Hooks can
162
- read the same field for logging or export:
163
-
164
- ```ts
165
- const treatment =
166
- ctx.session.abs?.["concise-weather"] === "treatment";
167
-
168
- if (treatment) {
169
- return conciseWeatherResult;
170
- }
171
-
172
- return baselineWeatherResult;
173
- ```
174
-
175
- This makes the assignment available to deterministic code as well as
176
- the model prompt. Use both patterns together when one experiment must
177
- steer the prompt and host code at once.
178
-
179
- `defineAB` does not select a different model or runtime for each arm.
180
- Keep those settings in `agent/agent.ts`, or write explicit host logic
181
- when your experiment needs another behavior lever.
182
-
183
- The split and selected arm can affect agent behavior. `derive` and
184
- `onSample` only observe the resulting event stream. Errors in either
185
- callback are logged and never fail the turn.
186
-
187
- ## Collect built-in and custom metrics
188
-
189
- Metrics accumulate for each session and experiment. When one session
190
- joins several experiments, every enrolled experiment folds the same
191
- turn and tool events into its own counters.
192
-
193
- | Metric | How the Agent SDK calculates it |
194
- | --- | --- |
195
- | `turns` | Adds one on `turn.completed` or `turn.failed` |
196
- | `turnFailures` | Adds one on `turn.failed` |
197
- | `toolCalls` | Adds one for each `action.result` |
198
- | `toolErrors` | Adds one when `action.result.data.isError` is true |
199
- | `inputTokens`, `outputTokens` | Adds usage from completed turns |
200
- | `cacheReadTokens`, `cacheWriteTokens` | Adds cache usage from completed turns |
201
- | `costUsd` | Sums the estimated turn cost recorded on `turn.completed` (turns whose model has no known rates contribute 0) |
202
- | `wallTimeMs` | Sums the time from `turn.started` to its completed or failed event |
203
- | `custom` | Sums finite numeric deltas returned by `derive` |
204
-
205
- `onSample` fires after every `turn.completed` and `turn.failed` event
206
- for an enrolled arm. The sample contains:
207
-
208
- | Field | Value |
209
- | --- | --- |
210
- | `experiment` | Experiment name |
211
- | `variant`, `variantLabel?` | Sticky arm and optional display label |
212
- | `sessionId`, `channelId` | Source session |
213
- | `metrics` | Cumulative metrics through this turn |
214
- | `reason` | `turn.completed` or `turn.failed` |
215
- | `at` | Terminal event timestamp |
216
-
217
- The metrics are cumulative, not per-turn deltas. A second sample from
218
- the same session includes the first turn's counts.
219
-
220
- Each `derive` extractor runs on every session event for its enrolled
221
- experiment, including streamed `message.appended` events. Keep it
222
- synchronous and cheap. Return a finite number to add a delta, or
223
- `null` to skip the event. Send samples to your metrics service from
224
- `onSample`; do not perform network or disk work in `derive`.
225
-
226
- Skipped sessions never call `onSample`. Errors from `derive` or
227
- `onSample` are logged, then metric collection continues.
228
-
229
- ## Inspect assignments and results
230
-
231
- Open the playground's **A/Bs** tab to see aggregate arm totals and
232
- per-session assignments. The tab reads `GET /v1/abs`.
233
-
234
- The response has two views of the same durable data:
235
-
236
- | Field | Contents |
237
- | --- | --- |
238
- | `experiments` | Declared variants, skipped-session count, arm session counts, and aggregate metrics |
239
- | `sessions` | Visible sessions with their assignments and cumulative metrics |
240
-
241
- `GET /v1/abs` returns sessions visible to the current principal by
242
- default. In `--dev`, loopback requests include every session. Add
243
- `--allow-anonymous` to include every session from non-loopback callers
244
- too.
245
-
246
- The session event stream is the source of truth for assignment + fold.
247
- `GET /v1/abs` recomputes aggregates from those logs. Any
248
- `agent/storage.ts` exports samples and snapshots durably: an authored
249
- `abs` table when the backend has a native shape for it, or the table
250
- derived over the KV core otherwise. See
251
- [Storage](/docs/storage.md#eval-and-a-b-tables).
252
-
253
- ## Configure the playground fold window
254
-
255
- Assignments and foldable metrics already persist in each session's
256
- event stream. The optional `agent/ab.config.ts` only caps how many
257
- sessions the playground and `GET /v1/abs` fold:
258
-
259
- ```ts
260
- import { defineABConfig } from "@cursor/july/ab";
261
-
262
- export default defineABConfig({
263
- // Optional. Defaults to 200. Only affects GET /v1/abs / A/Bs tab.
264
- maxPlaygroundSessions: 500,
265
- });
266
- ```
267
-
268
- `maxPlaygroundSessions` keeps the newest sessions in the fold. It does
269
- not prune session logs or change assignment. For export to S3, a DB, or
270
- your metrics vendor, send samples from `onSample` or declare a storage
271
- `abs` table.
272
-
273
- ## Keep assignments durable
274
-
275
- The append-only event stream is the source of truth. Each
276
- `ab.assigned` event persists a variant key or null skip. Built-in
277
- metrics come from the turn and tool events that follow it.
278
-
279
- After a server restart or a parked session resumes, the live collector
280
- replays the stream to rebuild cumulative counters. Replay does not call
281
- `onSample` (or write to the storage `abs` table) for historical turns.
282
- Only a new completed or failed turn emits another sample.
283
-
284
- The snapshot API also replays `derive` across the full stream, so
285
- custom totals match the current extractor. Changing a derive function
286
- can change historical snapshot totals. Treat metric definitions as
287
- versioned experiment code.
288
-
289
- ## Keep eval traffic separate
290
-
291
- Sessions created by `agent-sdk eval` and the playground Evals runner use
292
- `purpose: "eval"`. They skip A/B enrollment entirely:
293
-
294
- - No split function runs.
295
- - No `ab.assigned` event is recorded.
296
- - No `onSample` callback fires.
297
- - The session is omitted from `GET /v1/abs`.
298
-
299
- Ordinary chat, `agent-sdk run`, Slack, GitHub, and other channel sessions
300
- use the live purpose. You do not need `splitIf` to exclude eval traffic.
301
-
302
- ## Know the boundaries
303
-
304
- `defineAB` provides sticky assignment, variant instructions,
305
- `session.abs` for tools, cumulative metrics, and local inspection. It
306
- does not provide:
307
-
308
- - A test command, assertion API, or pass/fail result
309
- - Statistical significance calculations
310
- - An experiment rollout or lifecycle service
311
- - Per-variant model or runtime configuration
312
- - A built-in analytics warehouse (bring your own via `onSample` or the
313
- storage `abs` table)
314
-
315
- Use [evals](/docs/evals.md) to protect known behavior. Use `onSample` or a
316
- storage `abs` table when you need sample/snapshot exports beyond the
317
- session event log.
318
-
319
- ## What's next
320
-
321
- Continue with these pages:
322
-
323
- - [Evals](/docs/evals.md): pass/fail regression checks on fixed inputs
324
- - [Hillclimbing](/docs/hillclimbing.md): improve an agent against fixed
325
- fixtures
326
- - [Hooks](/docs/reference/hooks.md): other event-stream consumers
327
- - [Sessions and streaming](/docs/reference/sessions.md): the
328
- `ab.assigned` event and durable log
329
- - [Playground](/docs/reference/playground.md): the A/Bs tab
330
- - [HTTP API](/docs/reference/http-api.md): `GET /v1/abs`
331
- - [Live A/B metrics skill](/docs/skills/ab.md): have a coding agent
332
- wire an experiment
@@ -1,54 +0,0 @@
1
- import{_ as s,c as a,o as t,ag as i}from"./chunks/framework.BCISBCiQ.js";const k=JSON.parse('{"title":"Live A/B metrics","description":"Assign sticky variants with defineAB, collect live performance metrics, and inspect per-arm results.","frontmatter":{"title":"Live A/B metrics","description":"Assign sticky variants with defineAB, collect live performance metrics, and inspect per-arm results."},"headers":[],"relativePath":"ab.md","filePath":"ab.md"}'),n={name:"ab.md"};function o(l,e,r,d,h,p){return t(),a("div",null,[...e[0]||(e[0]=[i(`<h1 id="live-a-b-metrics" tabindex="-1">Live A/B metrics <a class="header-anchor" href="#live-a-b-metrics" aria-label="Permalink to &quot;Live A/B metrics&quot;">​</a></h1><p>Use <code>defineAB</code> to compare variants on live agent sessions. New sessions receive a sticky assignment in each enrolled experiment. The Agent SDK folds their durable event streams into tool, token, failure, and wall-time metrics. You can send cumulative samples to your metrics backend and inspect aggregates in the playground.</p><p><code>defineAB</code> compares live variants through sticky assignment, instruction overlays, optional tool branches, and cumulative metrics. Metric callbacks observe the result without approving, rejecting, or failing a turn. Use <a href="./evals.html">evals</a> for pass/fail regression checks on fixed inputs.</p><h2 id="choose-live-a-b-metrics-or-evals" tabindex="-1">Choose live A/B metrics or evals <a class="header-anchor" href="#choose-live-a-b-metrics-or-evals" aria-label="Permalink to &quot;Choose live A/B metrics or evals&quot;">​</a></h2><p>Both features read the session event stream, but they answer different questions.</p><table tabindex="0"><thead><tr><th></th><th>Live A/B metrics</th><th>Evals</th></tr></thead><tbody><tr><td>Question</td><td>How do variants compare on live sessions?</td><td>Does the agent still meet a fixed contract?</td></tr><tr><td>Location</td><td><code>agent/ab.ts</code> or <code>agent/ab/&lt;name&gt;.ts</code></td><td><code>evals/**/*.eval.ts</code></td></tr><tr><td>Input</td><td>Dev or production traffic</td><td>Frozen prompts and fixtures</td></tr><tr><td>Output</td><td>Cumulative metrics by session and arm</td><td>Pass/fail assertions</td></tr><tr><td>How it runs</td><td>Automatically on new live sessions</td><td><code>agent-sdk eval</code></td></tr></tbody></table><p>There is no <code>agent-sdk ab</code> command or assertion API.</p><h2 id="define-an-experiment" tabindex="-1">Define an experiment <a class="header-anchor" href="#define-an-experiment" aria-label="Permalink to &quot;Define an experiment&quot;">​</a></h2><p>Author one experiment in <code>agent/ab.ts</code>, add more under <code>agent/ab/&lt;name&gt;.ts</code>, or use both forms. Each file defines one experiment. The experiment name comes from <code>name</code> when set. Otherwise, the Agent SDK uses <code>ab</code> for <code>agent/ab.ts</code> and the file stem for files under <code>agent/ab/</code>.</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// agent/ab/concise-weather.ts</span></span>
2
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
3
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> defineAB,</span></span>
4
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> splitBySessionHash,</span></span>
5
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">} </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july/ab&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
6
- <span class="line"></span>
7
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineAB</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
8
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> name: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;concise-weather&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
9
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> variants: {</span></span>
10
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> control: {</span></span>
11
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> label: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;Baseline&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
12
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
13
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> treatment: {</span></span>
14
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> label: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;Short replies&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
15
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> description: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;Adds a one-paragraph response limit.&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
16
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> instructions: </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;Keep weather replies to one short paragraph.&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
17
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
18
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
19
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> split: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">splitBySessionHash</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
20
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> weights: { control: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, treatment: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
21
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> holdout: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">0.1</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
22
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }),</span></span>
23
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> derive: {</span></span>
24
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> weatherCalls</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">event</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span></span>
25
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> event.type </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;action.result&quot;</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> &amp;&amp;</span></span>
26
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> event.data.toolName </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;get_weather&quot;</span></span>
27
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> ?</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> 1</span></span>
28
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> :</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> null</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
29
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
30
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> onSample</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">sample</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
31
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> console.</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">log</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
32
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> sample.experiment,</span></span>
33
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> sample.variant,</span></span>
34
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> sample.metrics.toolCalls,</span></span>
35
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> sample.metrics.wallTimeMs</span></span>
36
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> );</span></span>
37
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> },</span></span>
38
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p>Every definition needs:</p><ul><li>At least two variants. Variant keys cannot be empty or contain <code>/</code> or <code>\\</code>.</li><li>A <code>split</code> function that returns a variant key or <code>null</code>.</li><li>An <code>onSample</code> callback for completed or failed turns.</li></ul><p><code>label</code> and <code>description</code> appear with the arm in result surfaces. <code>instructions</code> changes the prompt for sessions in that arm. <code>derive</code> adds custom counters.</p><p>Duplicate experiment names are validation errors. Check discovery before you serve:</p><div class="language-bash vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">bash</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> validate</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span></span>
39
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">agent-sdk</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> info</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --dir</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> .</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> --json</span></span></code></pre></div><p>The <code>abs</code> field in <code>info</code> lists the discovered experiment names.</p><h2 id="assign-sticky-variants" tabindex="-1">Assign sticky variants <a class="header-anchor" href="#assign-sticky-variants" aria-label="Permalink to &quot;Assign sticky variants&quot;">​</a></h2><p>Enrollment happens once, when a live session is created and before its first turn:</p><ol><li>The Agent SDK records <code>session.started</code>.</li><li>Each experiment runs its <code>split</code> function.</li><li>The Agent SDK records one durable <code>ab.assigned</code> event per experiment.</li><li>The selected arms become available on <code>session.abs</code>.</li><li>Variant instruction overlays reach the first model turn.</li></ol><p>A split can return a variant key or <code>null</code>. A null assignment is a sticky skip for that experiment. It increments the experiment&#39;s <code>skipped</code> total, still appears in the snapshot&#39;s <code>sessions</code> list with <code>variant: null</code>, and does not collect arm metrics or call <code>onSample</code>.</p><p>Use the split helper that matches your rollout:</p><table tabindex="0"><thead><tr><th>Helper</th><th>Behavior</th></tr></thead><tbody><tr><td><code>splitBySessionHash({ weights?, holdout?, salt? })</code></td><td>Hashes the session id into a reproducible arm; the recommended default</td></tr><tr><td><code>splitByRandom({ weights?, holdout? })</code></td><td>Draws once when the session starts, then persists the result</td></tr><tr><td><code>splitAlways(&quot;control&quot;)</code></td><td>Pins every new session to one arm</td></tr><tr><td><code>splitNone()</code></td><td>Skips every new session without deleting the experiment</td></tr><tr><td><code>splitIf(predicate, inner)</code></td><td>Runs <code>inner</code> only when the predicate passes</td></tr><tr><td>Custom <code>split(ctx)</code></td><td>Returns a declared variant key or <code>null</code></td></tr></tbody></table><p>The split context includes the agent name, channel id, session info, experiment name, and declared variant keys. For example, enroll only Slack sessions:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">split</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">: </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">splitIf</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span></span>
40
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">ctx</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ctx.channel.id </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;slack&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
41
- <span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> splitBySessionHash</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">()</span></span>
42
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">),</span></span></code></pre></div><p>Weights default to equal. Non-positive weights leave an arm out of the draw, and at least one arm must have a positive weight. <code>holdout</code> is the fraction of sessions assigned <code>null</code>, from <code>0</code> through <code>1</code>. Change <code>salt</code> to reshuffle future hash assignments without renaming the experiment.</p><p>If a custom split throws or returns an unknown variant, the Agent SDK logs the error and records <code>variant: null</code>. The failed decision becomes a sticky skip instead of breaking the session.</p><p>Enrollment only applies to new sessions. Adding an experiment does not assign existing conversations. Follow-ups keep the session&#39;s original arms. Keep experiment names and variant keys stable while you collect and compare results.</p><h2 id="change-behavior-by-variant" tabindex="-1">Change behavior by variant <a class="header-anchor" href="#change-behavior-by-variant" aria-label="Permalink to &quot;Change behavior by variant&quot;">​</a></h2><p>Variant instructions are appended to the agent&#39;s base instructions. Local sessions receive the merged instructions in <code>AGENTS.md</code> before every turn. Cloud sessions receive them in the first-turn preamble only. For cloud follow-ups, branch through <code>session.abs</code> when the arm must remain visible to deterministic behavior.</p><p>Tools can branch on the assignment through <code>ctx.session.abs</code>. Hooks can read the same field for logging or export:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> treatment</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> =</span></span>
43
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ctx.session.abs?.[</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;concise-weather&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">] </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">===</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;treatment&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
44
- <span class="line"></span>
45
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (treatment) {</span></span>
46
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> conciseWeatherResult;</span></span>
47
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
48
- <span class="line"></span>
49
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> baselineWeatherResult;</span></span></code></pre></div><p>This makes the assignment available to deterministic code as well as the model prompt. Use both patterns together when one experiment must steer the prompt and host code at once.</p><p><code>defineAB</code> does not select a different model or runtime for each arm. Keep those settings in <code>agent/agent.ts</code>, or write explicit host logic when your experiment needs another behavior lever.</p><p>The split and selected arm can affect agent behavior. <code>derive</code> and <code>onSample</code> only observe the resulting event stream. Errors in either callback are logged and never fail the turn.</p><h2 id="collect-built-in-and-custom-metrics" tabindex="-1">Collect built-in and custom metrics <a class="header-anchor" href="#collect-built-in-and-custom-metrics" aria-label="Permalink to &quot;Collect built-in and custom metrics&quot;">​</a></h2><p>Metrics accumulate for each session and experiment. When one session joins several experiments, every enrolled experiment folds the same turn and tool events into its own counters.</p><table tabindex="0"><thead><tr><th>Metric</th><th>How the Agent SDK calculates it</th></tr></thead><tbody><tr><td><code>turns</code></td><td>Adds one on <code>turn.completed</code> or <code>turn.failed</code></td></tr><tr><td><code>turnFailures</code></td><td>Adds one on <code>turn.failed</code></td></tr><tr><td><code>toolCalls</code></td><td>Adds one for each <code>action.result</code></td></tr><tr><td><code>toolErrors</code></td><td>Adds one when <code>action.result.data.isError</code> is true</td></tr><tr><td><code>inputTokens</code>, <code>outputTokens</code></td><td>Adds usage from completed turns</td></tr><tr><td><code>cacheReadTokens</code>, <code>cacheWriteTokens</code></td><td>Adds cache usage from completed turns</td></tr><tr><td><code>costUsd</code></td><td>Sums the estimated turn cost recorded on <code>turn.completed</code> (turns whose model has no known rates contribute 0)</td></tr><tr><td><code>wallTimeMs</code></td><td>Sums the time from <code>turn.started</code> to its completed or failed event</td></tr><tr><td><code>custom</code></td><td>Sums finite numeric deltas returned by <code>derive</code></td></tr></tbody></table><p><code>onSample</code> fires after every <code>turn.completed</code> and <code>turn.failed</code> event for an enrolled arm. The sample contains:</p><table tabindex="0"><thead><tr><th>Field</th><th>Value</th></tr></thead><tbody><tr><td><code>experiment</code></td><td>Experiment name</td></tr><tr><td><code>variant</code>, <code>variantLabel?</code></td><td>Sticky arm and optional display label</td></tr><tr><td><code>sessionId</code>, <code>channelId</code></td><td>Source session</td></tr><tr><td><code>metrics</code></td><td>Cumulative metrics through this turn</td></tr><tr><td><code>reason</code></td><td><code>turn.completed</code> or <code>turn.failed</code></td></tr><tr><td><code>at</code></td><td>Terminal event timestamp</td></tr></tbody></table><p>The metrics are cumulative, not per-turn deltas. A second sample from the same session includes the first turn&#39;s counts.</p><p>Each <code>derive</code> extractor runs on every session event for its enrolled experiment, including streamed <code>message.appended</code> events. Keep it synchronous and cheap. Return a finite number to add a delta, or <code>null</code> to skip the event. Send samples to your metrics service from <code>onSample</code>; do not perform network or disk work in <code>derive</code>.</p><p>Skipped sessions never call <code>onSample</code>. Errors from <code>derive</code> or <code>onSample</code> are logged, then metric collection continues.</p><h2 id="inspect-assignments-and-results" tabindex="-1">Inspect assignments and results <a class="header-anchor" href="#inspect-assignments-and-results" aria-label="Permalink to &quot;Inspect assignments and results&quot;">​</a></h2><p>Open the playground&#39;s <strong>A/Bs</strong> tab to see aggregate arm totals and per-session assignments. The tab reads <code>GET /v1/abs</code>.</p><p>The response has two views of the same durable data:</p><table tabindex="0"><thead><tr><th>Field</th><th>Contents</th></tr></thead><tbody><tr><td><code>experiments</code></td><td>Declared variants, skipped-session count, arm session counts, and aggregate metrics</td></tr><tr><td><code>sessions</code></td><td>Visible sessions with their assignments and cumulative metrics</td></tr></tbody></table><p><code>GET /v1/abs</code> returns sessions visible to the current principal by default. In <code>--dev</code>, loopback requests include every session. Add <code>--allow-anonymous</code> to include every session from non-loopback callers too.</p><p>The session event stream is the source of truth for assignment + fold. <code>GET /v1/abs</code> recomputes aggregates from those logs. Any <code>agent/storage.ts</code> exports samples and snapshots durably: an authored <code>abs</code> table when the backend has a native shape for it, or the table derived over the KV core otherwise. See <a href="./storage.html#eval-and-a-b-tables">Storage</a>.</p><h2 id="configure-the-playground-fold-window" tabindex="-1">Configure the playground fold window <a class="header-anchor" href="#configure-the-playground-fold-window" aria-label="Permalink to &quot;Configure the playground fold window&quot;">​</a></h2><p>Assignments and foldable metrics already persist in each session&#39;s event stream. The optional <code>agent/ab.config.ts</code> only caps how many sessions the playground and <code>GET /v1/abs</code> fold:</p><div class="language-ts vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">ts</span><pre class="shiki shiki-themes github-light github-dark vp-code" tabindex="0"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">import</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> { defineABConfig } </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">from</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;@cursor/july/ab&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
50
- <span class="line"></span>
51
- <span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">export</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> default</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> defineABConfig</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">({</span></span>
52
- <span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // Optional. Defaults to 200. Only affects GET /v1/abs / A/Bs tab.</span></span>
53
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> maxPlaygroundSessions: </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">500</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">,</span></span>
54
- <span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">});</span></span></code></pre></div><p><code>maxPlaygroundSessions</code> keeps the newest sessions in the fold. It does not prune session logs or change assignment. For export to S3, a DB, or your metrics vendor, send samples from <code>onSample</code> or declare a storage <code>abs</code> table.</p><h2 id="keep-assignments-durable" tabindex="-1">Keep assignments durable <a class="header-anchor" href="#keep-assignments-durable" aria-label="Permalink to &quot;Keep assignments durable&quot;">​</a></h2><p>The append-only event stream is the source of truth. Each <code>ab.assigned</code> event persists a variant key or null skip. Built-in metrics come from the turn and tool events that follow it.</p><p>After a server restart or a parked session resumes, the live collector replays the stream to rebuild cumulative counters. Replay does not call <code>onSample</code> (or write to the storage <code>abs</code> table) for historical turns. Only a new completed or failed turn emits another sample.</p><p>The snapshot API also replays <code>derive</code> across the full stream, so custom totals match the current extractor. Changing a derive function can change historical snapshot totals. Treat metric definitions as versioned experiment code.</p><h2 id="keep-eval-traffic-separate" tabindex="-1">Keep eval traffic separate <a class="header-anchor" href="#keep-eval-traffic-separate" aria-label="Permalink to &quot;Keep eval traffic separate&quot;">​</a></h2><p>Sessions created by <code>agent-sdk eval</code> and the playground Evals runner use <code>purpose: &quot;eval&quot;</code>. They skip A/B enrollment entirely:</p><ul><li>No split function runs.</li><li>No <code>ab.assigned</code> event is recorded.</li><li>No <code>onSample</code> callback fires.</li><li>The session is omitted from <code>GET /v1/abs</code>.</li></ul><p>Ordinary chat, <code>agent-sdk run</code>, Slack, GitHub, and other channel sessions use the live purpose. You do not need <code>splitIf</code> to exclude eval traffic.</p><h2 id="know-the-boundaries" tabindex="-1">Know the boundaries <a class="header-anchor" href="#know-the-boundaries" aria-label="Permalink to &quot;Know the boundaries&quot;">​</a></h2><p><code>defineAB</code> provides sticky assignment, variant instructions, <code>session.abs</code> for tools, cumulative metrics, and local inspection. It does not provide:</p><ul><li>A test command, assertion API, or pass/fail result</li><li>Statistical significance calculations</li><li>An experiment rollout or lifecycle service</li><li>Per-variant model or runtime configuration</li><li>A built-in analytics warehouse (bring your own via <code>onSample</code> or the storage <code>abs</code> table)</li></ul><p>Use <a href="./evals.html">evals</a> to protect known behavior. Use <code>onSample</code> or a storage <code>abs</code> table when you need sample/snapshot exports beyond the session event log.</p><h2 id="what-s-next" tabindex="-1">What&#39;s next <a class="header-anchor" href="#what-s-next" aria-label="Permalink to &quot;What&#39;s next&quot;">​</a></h2><p>Continue with these pages:</p><ul><li><a href="./evals.html">Evals</a>: pass/fail regression checks on fixed inputs</li><li><a href="./hillclimbing.html">Hillclimbing</a>: improve an agent against fixed fixtures</li><li><a href="./reference/hooks.html">Hooks</a>: other event-stream consumers</li><li><a href="./reference/sessions.html">Sessions and streaming</a>: the <code>ab.assigned</code> event and durable log</li><li><a href="./reference/playground.html">Playground</a>: the A/Bs tab</li><li><a href="./reference/http-api.html">HTTP API</a>: <code>GET /v1/abs</code></li><li><a href="./skills/ab.html">Live A/B metrics skill</a>: have a coding agent wire an experiment</li></ul>`,67)])])}const u=s(n,[["render",o]]);export{k as __pageData,u as default};
@@ -1 +0,0 @@
1
- import{_ as s,c as a,o as t,ag as i}from"./chunks/framework.BCISBCiQ.js";const k=JSON.parse('{"title":"Live A/B metrics","description":"Assign sticky variants with defineAB, collect live performance metrics, and inspect per-arm results.","frontmatter":{"title":"Live A/B metrics","description":"Assign sticky variants with defineAB, collect live performance metrics, and inspect per-arm results."},"headers":[],"relativePath":"ab.md","filePath":"ab.md"}'),n={name:"ab.md"};function o(l,e,r,d,h,p){return t(),a("div",null,[...e[0]||(e[0]=[i("",67)])])}const u=s(n,[["render",o]]);export{k as __pageData,u as default};