@cursor/july 0.1.108 → 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.
- package/AGENTS.md +2 -6
- package/README.md +3 -6
- package/dist/channels/bitbucket/api.d.ts +41 -0
- package/dist/channels/bitbucket/api.d.ts.map +1 -1
- package/dist/channels/bitbucket/api.js +260 -0
- package/dist/channels/bitbucket/binding.d.ts +4 -0
- package/dist/channels/bitbucket/binding.d.ts.map +1 -1
- package/dist/channels/bitbucket/binding.js +16 -0
- package/dist/channels/bitbucket/index.d.ts +1 -1
- package/dist/channels/bitbucket/index.d.ts.map +1 -1
- package/dist/channels/bitbucket/index.js +1 -1
- package/dist/channels/gitlab/api.d.ts +27 -0
- package/dist/channels/gitlab/api.d.ts.map +1 -1
- package/dist/channels/gitlab/api.js +88 -0
- package/dist/channels/gitlab/binding.d.ts +5 -0
- package/dist/channels/gitlab/binding.d.ts.map +1 -1
- package/dist/channels/gitlab/binding.js +10 -0
- package/dist/channels/gitlab/index.d.ts +1 -1
- package/dist/channels/gitlab/index.d.ts.map +1 -1
- package/dist/channels/gitlab/index.js +1 -1
- package/dist/channels/slack/dispatch.d.ts +10 -0
- package/dist/channels/slack/dispatch.d.ts.map +1 -1
- package/dist/channels/slack/dispatch.js +20 -3
- package/dist/channels/slack/slack-channel.d.ts +12 -5
- package/dist/channels/slack/slack-channel.d.ts.map +1 -1
- package/dist/channels/slack/slack-channel.js +59 -8
- package/dist/docs/404.html +2 -2
- package/dist/docs/assets/{app.BASKM3M4.js → app.Cr-wVbnB.js} +1 -1
- package/dist/docs/assets/{building-with-agents.md.CUSWxlP_.js → building-with-agents.md.D0KbSkJn.js} +2 -2
- package/dist/docs/assets/{building-with-agents.md.CUSWxlP_.lean.js → building-with-agents.md.D0KbSkJn.lean.js} +1 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.CFVQ4S17.js +1 -0
- package/dist/docs/assets/chunks/{VPLocalSearchBox.BOKxlYGP.js → VPLocalSearchBox.CVQERt56.js} +1 -1
- package/dist/docs/assets/chunks/{theme.DbDZW-zb.js → theme.Dnsd3XOn.js} +2 -2
- package/dist/docs/assets/concepts.md.B4o63Gul.js +1 -0
- package/dist/docs/assets/evals.md.C7JLjoEP.js +211 -0
- package/dist/docs/assets/evals.md.C7JLjoEP.lean.js +1 -0
- package/dist/docs/assets/guides_bitbucket.md.DZPzmUjU.js +10 -0
- package/dist/docs/assets/guides_bitbucket.md.DZPzmUjU.lean.js +1 -0
- package/dist/docs/assets/{guides_github.md.BH33UEBJ.js → guides_github.md.TZaTZlfz.js} +13 -3
- package/dist/docs/assets/{guides_github.md.BH33UEBJ.lean.js → guides_github.md.TZaTZlfz.lean.js} +1 -1
- package/dist/docs/assets/guides_gitlab.md.BmqwQfdG.js +14 -0
- package/dist/docs/assets/guides_gitlab.md.BmqwQfdG.lean.js +1 -0
- package/dist/docs/assets/{guides_webhooks.md.DKdA43Qm.js → guides_webhooks.md.CJK484ex.js} +2 -2
- package/dist/docs/assets/{hillclimbing.md.CpTGTCle.js → hillclimbing.md.BOiVo1tf.js} +1 -1
- package/dist/docs/assets/index.md.DD9Q2XuJ.js +5 -0
- package/dist/docs/assets/{index.md.BjH1w2ZW.lean.js → index.md.DD9Q2XuJ.lean.js} +1 -1
- package/dist/docs/assets/{reference_channels.md.D-qTqwcq.js → reference_channels.md.CAo-iK4j.js} +2 -2
- package/dist/docs/assets/{reference_channels.md.D-qTqwcq.lean.js → reference_channels.md.CAo-iK4j.lean.js} +1 -1
- package/dist/docs/assets/{reference_cli.md.Ca26u0Es.js → reference_cli.md.Deg7849l.js} +1 -1
- package/dist/docs/assets/{reference_extensions.md.CPWt00ds.js → reference_extensions.md.ZAVUyuEX.js} +2 -2
- package/dist/docs/assets/{reference_hooks.md.Ddt5DdgJ.js → reference_hooks.md.BlM_bOg6.js} +3 -3
- package/dist/docs/assets/{reference_hooks.md.Ddt5DdgJ.lean.js → reference_hooks.md.BlM_bOg6.lean.js} +1 -1
- package/dist/docs/assets/{reference_http-api.md.oySXBO8o.js → reference_http-api.md.BwaCo-VO.js} +1 -1
- package/dist/docs/assets/{reference_playground.md.4myJPxrf.js → reference_playground.md.DLnoaczX.js} +1 -1
- package/dist/docs/assets/{reference_playground.md.4myJPxrf.lean.js → reference_playground.md.DLnoaczX.lean.js} +1 -1
- package/dist/docs/assets/{reference_project-layout.md.DuBu9a96.js → reference_project-layout.md.BEU8MtQV.js} +3 -3
- package/dist/docs/assets/{reference_project-layout.md.DuBu9a96.lean.js → reference_project-layout.md.BEU8MtQV.lean.js} +1 -1
- package/dist/docs/assets/reference_sessions.md.CyXV1MUw.js +1 -0
- package/dist/docs/assets/skills_deploy.md.CWqi_ZxW.js +35 -0
- package/dist/docs/assets/skills_deploy.md.CWqi_ZxW.lean.js +1 -0
- package/dist/docs/assets/{skills_evals.md.BhovOvrl.js → skills_evals.md.DFxYPErF.js} +3 -3
- package/dist/docs/assets/skills_evals.md.DFxYPErF.lean.js +1 -0
- package/dist/docs/assets/{skills_framework-map.md.D-tFZhFS.js → skills_framework-map.md.BxLSOhSY.js} +1 -1
- package/dist/docs/assets/skills_index.md.DL7EHaQ-.js +1 -0
- package/dist/docs/assets/skills_index.md.DL7EHaQ-.lean.js +1 -0
- package/dist/docs/assets/{storage.md.BOHeqk2M.js → storage.md.BUrhJ-Zz.js} +4 -4
- package/dist/docs/assets/{storage.md.BOHeqk2M.lean.js → storage.md.BUrhJ-Zz.lean.js} +1 -1
- package/dist/docs/building-with-agents.html +5 -5
- package/dist/docs/building-with-agents.md +3 -2
- package/dist/docs/concepts.html +5 -5
- package/dist/docs/concepts.md +2 -4
- package/dist/docs/deployment.html +4 -4
- package/dist/docs/evals.html +161 -35
- package/dist/docs/evals.md +612 -297
- package/dist/docs/guides/agent-to-agent.html +4 -4
- package/dist/docs/guides/bitbucket.html +36 -0
- package/dist/docs/guides/bitbucket.md +84 -0
- package/dist/docs/guides/cloud-agents.html +4 -4
- package/dist/docs/guides/convert-automation.html +4 -4
- package/dist/docs/guides/github.html +17 -7
- package/dist/docs/guides/github.md +31 -0
- package/dist/docs/guides/gitlab.html +40 -0
- package/dist/docs/guides/gitlab.md +92 -0
- package/dist/docs/guides/grokbot-agents.html +4 -4
- package/dist/docs/guides/human-in-the-loop.html +4 -4
- package/dist/docs/guides/improve.html +4 -4
- package/dist/docs/guides/mcp-oauth.html +4 -4
- package/dist/docs/guides/opentelemetry.html +4 -4
- package/dist/docs/guides/slack.html +5 -5
- package/dist/docs/guides/webhooks.html +6 -6
- package/dist/docs/guides/webhooks.md +4 -2
- package/dist/docs/hashmap.json +1 -1
- package/dist/docs/hillclimbing.html +6 -6
- package/dist/docs/hillclimbing.md +2 -2
- package/dist/docs/index.html +6 -6
- package/dist/docs/index.md +10 -6
- package/dist/docs/llms-full.txt +1113 -778
- package/dist/docs/llms.txt +6 -5
- package/dist/docs/quickstart.html +4 -4
- package/dist/docs/reference/agent-config.html +4 -4
- package/dist/docs/reference/artifacts.html +4 -4
- package/dist/docs/reference/channels.html +6 -6
- package/dist/docs/reference/channels.md +16 -3
- package/dist/docs/reference/cli.html +6 -6
- package/dist/docs/reference/cli.md +6 -4
- package/dist/docs/reference/connections.html +4 -4
- package/dist/docs/reference/extensions.html +7 -7
- package/dist/docs/reference/extensions.md +0 -3
- package/dist/docs/reference/hooks.html +7 -7
- package/dist/docs/reference/hooks.md +9 -12
- package/dist/docs/reference/http-api.html +6 -6
- package/dist/docs/reference/http-api.md +2 -3
- package/dist/docs/reference/instructions.html +4 -4
- package/dist/docs/reference/playground.html +5 -5
- package/dist/docs/reference/playground.md +0 -4
- package/dist/docs/reference/project-layout.html +7 -7
- package/dist/docs/reference/project-layout.md +1 -8
- package/dist/docs/reference/prompt.html +4 -4
- package/dist/docs/reference/result.html +4 -4
- package/dist/docs/reference/schedules.html +4 -4
- package/dist/docs/reference/sessions.html +5 -5
- package/dist/docs/reference/sessions.md +1 -2
- package/dist/docs/reference/skills.html +4 -4
- package/dist/docs/reference/subagents.html +4 -4
- package/dist/docs/reference/tools.html +4 -4
- package/dist/docs/scaffolding-agents.html +4 -4
- package/dist/docs/skills/create-agent.html +4 -4
- package/dist/docs/skills/debug.html +4 -4
- package/dist/docs/skills/deploy.html +61 -0
- package/dist/docs/skills/deploy.md +161 -0
- package/dist/docs/skills/evals.html +8 -8
- package/dist/docs/skills/evals.md +44 -6
- package/dist/docs/skills/framework-map.html +5 -5
- package/dist/docs/skills/framework-map.md +1 -2
- package/dist/docs/skills/github.html +4 -4
- package/dist/docs/skills/hillclimb.html +4 -4
- package/dist/docs/skills/index.html +6 -6
- package/dist/docs/skills/index.md +1 -1
- package/dist/docs/skills/mcp-auth.html +4 -4
- package/dist/docs/skills/otel.html +4 -4
- package/dist/docs/skills/setup-slack.html +4 -4
- package/dist/docs/storage.html +8 -8
- package/dist/docs/storage.md +15 -24
- package/dist/docs/templates/agentic-owners.html +4 -4
- package/dist/docs/templates/agents-md.html +4 -4
- package/dist/docs/templates/code-wiki.html +4 -4
- package/dist/docs/templates/demo.html +4 -4
- package/dist/docs/templates/grokbot-agents.html +4 -4
- package/dist/docs/templates/pr-autofixer.html +4 -4
- package/dist/docs/templates/security-help.html +4 -4
- package/dist/docs/templates/security-reviewer.html +4 -4
- package/dist/docs/templates/triage.html +4 -4
- package/dist/docs/troubleshooting.html +4 -4
- package/dist/extensions.d.ts +2 -3
- package/dist/extensions.d.ts.map +1 -1
- package/dist/extensions.js +2 -5
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -2
- package/dist/internal/authored-alias-hooks.d.ts +5 -0
- package/dist/internal/authored-alias-hooks.d.ts.map +1 -1
- package/dist/internal/authored-alias-hooks.js +17 -0
- package/dist/internal/authored-loaders.d.ts +4 -0
- package/dist/internal/authored-loaders.d.ts.map +1 -1
- package/dist/internal/authored-loaders.js +21 -2
- package/dist/internal/cli-ax.d.ts +1 -2
- package/dist/internal/cli-ax.d.ts.map +1 -1
- package/dist/internal/cli-ax.js +1 -2
- package/dist/internal/continuation-channel.d.ts.map +1 -1
- package/dist/internal/continuation-channel.js +2 -2
- package/dist/internal/continuation-identity.js +8 -3
- package/dist/internal/discovery/agent.d.ts +1 -1
- package/dist/internal/discovery/agent.d.ts.map +1 -1
- package/dist/internal/discovery/agent.js +0 -5
- package/dist/internal/discovery/extension-overlay.d.ts +1 -2
- package/dist/internal/discovery/extension-overlay.d.ts.map +1 -1
- package/dist/internal/discovery/extension-overlay.js +0 -14
- package/dist/internal/discovery/extensions.d.ts +1 -2
- package/dist/internal/discovery/extensions.d.ts.map +1 -1
- package/dist/internal/discovery/extensions.js +4 -22
- package/dist/internal/discovery/info.d.ts.map +1 -1
- package/dist/internal/discovery/info.js +42 -24
- package/dist/internal/discovery/modules.js +0 -1
- package/dist/internal/discovery/project.d.ts.map +1 -1
- package/dist/internal/discovery/project.js +0 -16
- package/dist/internal/eval-runner.js +0 -1
- package/dist/internal/framework-file-storage.d.ts +4 -5
- package/dist/internal/framework-file-storage.d.ts.map +1 -1
- package/dist/internal/framework-file-storage.js +4 -5
- package/dist/internal/framework-storage-selection.d.ts +2 -2
- package/dist/internal/framework-storage-selection.js +2 -2
- package/dist/internal/init-scaffold.d.ts.map +1 -1
- package/dist/internal/init-scaffold.js +1 -2
- package/dist/internal/install-cursor-skills.d.ts +5 -2
- package/dist/internal/install-cursor-skills.d.ts.map +1 -1
- package/dist/internal/install-cursor-skills.js +25 -5
- package/dist/internal/run-client.d.ts +1 -1
- package/dist/internal/sdk-runner.js +1 -1
- package/dist/internal/server.js +0 -14
- package/dist/internal/session-engine.d.ts +5 -35
- package/dist/internal/session-engine.d.ts.map +1 -1
- package/dist/internal/session-engine.js +17 -162
- package/dist/internal/storage-coordinator.d.ts +5 -19
- package/dist/internal/storage-coordinator.d.ts.map +1 -1
- package/dist/internal/storage-coordinator.js +3 -62
- package/dist/internal/storage-roles.d.ts +4 -9
- package/dist/internal/storage-roles.d.ts.map +1 -1
- package/dist/internal/storage-roles.js +2 -2
- package/dist/playground/assets/index-Bhxzrcf6.css +1 -0
- package/dist/playground/assets/index-CqLX5uF3.js +67 -0
- package/dist/playground/index.html +2 -2
- package/dist/storage-backends/cursor-hosted-v2.d.ts +4 -5
- package/dist/storage-backends/cursor-hosted-v2.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted-v2.js +4 -5
- package/dist/storage-backends/cursor-hosted.d.ts +1 -2
- package/dist/storage-backends/cursor-hosted.d.ts.map +1 -1
- package/dist/storage-backends/cursor-hosted.js +0 -30
- package/dist/storage-backends/file-kv.d.ts +9 -12
- package/dist/storage-backends/file-kv.d.ts.map +1 -1
- package/dist/storage-backends/file-kv.js +11 -47
- package/dist/storage-protocol.d.ts +3 -11
- package/dist/storage-protocol.d.ts.map +1 -1
- package/dist/storage-protocol.js +3 -11
- package/dist/storage.d.ts +8 -36
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +8 -44
- package/dist/types.d.ts +20 -57
- package/dist/types.d.ts.map +1 -1
- package/docs/README.md +10 -6
- package/docs/building-with-agents.md +3 -2
- package/docs/concepts.md +2 -4
- package/docs/evals.md +613 -298
- package/docs/guides/bitbucket.md +89 -0
- package/docs/guides/github.md +31 -0
- package/docs/guides/gitlab.md +97 -0
- package/docs/guides/webhooks.md +4 -2
- package/docs/hillclimbing.md +2 -2
- package/docs/reference/channels.md +16 -3
- package/docs/reference/cli.md +6 -4
- package/docs/reference/extensions.md +0 -3
- package/docs/reference/hooks.md +9 -12
- package/docs/reference/http-api.md +2 -3
- package/docs/reference/playground.md +0 -4
- package/docs/reference/project-layout.md +1 -8
- package/docs/reference/sessions.md +1 -2
- package/docs/skills/index.md +2 -2
- package/docs/storage.md +15 -24
- package/package.json +1 -7
- package/skills/deploy/SKILL.md +169 -0
- package/skills/evals/SKILL.md +45 -8
- package/skills/framework-map/SKILL.md +1 -2
- package/src/channels/bitbucket/api.ts +341 -0
- package/src/channels/bitbucket/binding.ts +25 -0
- package/src/channels/bitbucket/index.ts +2 -0
- package/src/channels/gitlab/api.ts +123 -0
- package/src/channels/gitlab/binding.ts +12 -0
- package/src/channels/gitlab/index.ts +1 -0
- package/src/channels/slack/dispatch.ts +30 -0
- package/src/channels/slack/slack-channel.ts +69 -7
- package/src/extensions.ts +2 -6
- package/src/index.ts +0 -3
- package/src/internal/authored-alias-hooks.ts +32 -0
- package/src/internal/authored-loaders.ts +26 -2
- package/src/internal/cli-ax.ts +1 -2
- package/src/internal/continuation-channel.ts +2 -1
- package/src/internal/continuation-identity.ts +10 -2
- package/src/internal/discovery/agent.ts +1 -7
- package/src/internal/discovery/extension-overlay.ts +0 -18
- package/src/internal/discovery/extensions.ts +2 -26
- package/src/internal/discovery/info.ts +3 -13
- package/src/internal/discovery/modules.ts +0 -1
- package/src/internal/discovery/project.ts +0 -16
- package/src/internal/eval-runner.ts +0 -1
- package/src/internal/framework-file-storage.ts +4 -5
- package/src/internal/framework-storage-selection.ts +2 -2
- package/src/internal/init-scaffold.ts +1 -2
- package/src/internal/install-cursor-skills.ts +38 -5
- package/src/internal/run-client.ts +1 -1
- package/src/internal/sdk-runner.ts +1 -1
- package/src/internal/server.ts +0 -16
- package/src/internal/session-engine.ts +14 -202
- package/src/internal/storage-coordinator.ts +5 -76
- package/src/internal/storage-roles.ts +4 -9
- package/src/storage-backends/cursor-hosted-v2.ts +4 -7
- package/src/storage-backends/cursor-hosted.ts +0 -37
- package/src/storage-backends/file-kv.ts +10 -51
- package/src/storage-protocol.ts +3 -17
- package/src/storage.ts +10 -101
- package/src/types.ts +19 -56
- package/templates/demo/README.md +10 -6
- package/templates/demo/agent/channels/github.ts +2 -0
- package/templates/demo/agent/channels/queue.ts +6 -2
- package/templates/demo/agent/lib/repos.ts +5 -0
- package/templates/demo/init.json +25 -0
- package/dist/ab.d.ts +0 -209
- package/dist/ab.d.ts.map +0 -1
- package/dist/ab.js +0 -246
- package/dist/docs/ab.html +0 -80
- package/dist/docs/ab.md +0 -332
- package/dist/docs/assets/ab.md.mlVgqvSk.js +0 -54
- package/dist/docs/assets/ab.md.mlVgqvSk.lean.js +0 -1
- package/dist/docs/assets/chunks/@localSearchIndexroot.BHZYsNVi.js +0 -1
- package/dist/docs/assets/concepts.md.DgEcZOfT.js +0 -1
- package/dist/docs/assets/evals.md.C1ekS3k2.js +0 -85
- package/dist/docs/assets/evals.md.C1ekS3k2.lean.js +0 -1
- package/dist/docs/assets/index.md.BjH1w2ZW.js +0 -5
- package/dist/docs/assets/reference_sessions.md.CueyOHSL.js +0 -1
- package/dist/docs/assets/skills_ab.md.CsFNatVx.js +0 -26
- package/dist/docs/assets/skills_ab.md.CsFNatVx.lean.js +0 -1
- package/dist/docs/assets/skills_evals.md.BhovOvrl.lean.js +0 -1
- package/dist/docs/assets/skills_index.md.DKwIxzGg.js +0 -1
- package/dist/docs/assets/skills_index.md.DKwIxzGg.lean.js +0 -1
- package/dist/docs/skills/ab.html +0 -52
- package/dist/docs/skills/ab.md +0 -50
- package/dist/internal/ab-collector.d.ts +0 -44
- package/dist/internal/ab-collector.d.ts.map +0 -1
- package/dist/internal/ab-collector.js +0 -142
- package/dist/internal/ab-fold.d.ts +0 -36
- package/dist/internal/ab-fold.d.ts.map +0 -1
- package/dist/internal/ab-fold.js +0 -175
- package/dist/internal/ab-snapshot.d.ts +0 -68
- package/dist/internal/ab-snapshot.d.ts.map +0 -1
- package/dist/internal/ab-snapshot.js +0 -208
- package/dist/internal/discovery/ab.d.ts +0 -9
- package/dist/internal/discovery/ab.d.ts.map +0 -1
- package/dist/internal/discovery/ab.js +0 -113
- package/dist/playground/assets/index-BMDqAeXu.js +0 -67
- package/dist/playground/assets/index-LUgJoWdL.css +0 -1
- package/docs/ab.md +0 -337
- package/skills/ab/SKILL.md +0 -58
- package/src/ab.ts +0 -430
- package/src/internal/ab-collector.ts +0 -200
- package/src/internal/ab-fold.ts +0 -232
- package/src/internal/ab-snapshot.ts +0 -331
- package/src/internal/discovery/ab.ts +0 -131
- /package/dist/docs/assets/{concepts.md.DgEcZOfT.lean.js → concepts.md.B4o63Gul.lean.js} +0 -0
- /package/dist/docs/assets/{guides_webhooks.md.DKdA43Qm.lean.js → guides_webhooks.md.CJK484ex.lean.js} +0 -0
- /package/dist/docs/assets/{hillclimbing.md.CpTGTCle.lean.js → hillclimbing.md.BOiVo1tf.lean.js} +0 -0
- /package/dist/docs/assets/{reference_cli.md.Ca26u0Es.lean.js → reference_cli.md.Deg7849l.lean.js} +0 -0
- /package/dist/docs/assets/{reference_extensions.md.CPWt00ds.lean.js → reference_extensions.md.ZAVUyuEX.lean.js} +0 -0
- /package/dist/docs/assets/{reference_http-api.md.oySXBO8o.lean.js → reference_http-api.md.BwaCo-VO.lean.js} +0 -0
- /package/dist/docs/assets/{reference_sessions.md.CueyOHSL.lean.js → reference_sessions.md.CyXV1MUw.lean.js} +0 -0
- /package/dist/docs/assets/{skills_framework-map.md.D-tFZhFS.lean.js → skills_framework-map.md.BxLSOhSY.lean.js} +0 -0
package/src/internal/ab-fold.ts
DELETED
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure fold of a session event stream into A/B arms + cumulative metrics.
|
|
3
|
-
* Shared by {@link ABCollector} (live) and {@link buildABSnapshot} (read API).
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
type ABCollectContext,
|
|
8
|
-
type ABDefinition,
|
|
9
|
-
type ABMetrics,
|
|
10
|
-
cloneABMetrics,
|
|
11
|
-
emptyABMetrics,
|
|
12
|
-
} from "../ab.js";
|
|
13
|
-
import type { DiscoveredAB, SessionEvent, SessionInfo } from "../types.js";
|
|
14
|
-
import { describeError } from "./describe-error.js";
|
|
15
|
-
|
|
16
|
-
export interface ABArmAccum {
|
|
17
|
-
variant: string;
|
|
18
|
-
metrics: ABMetrics;
|
|
19
|
-
turnStartedAt: string | null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface FoldedABSession {
|
|
23
|
-
/** experiment → variant key, or `null` for sticky skip */
|
|
24
|
-
arms: Map<string, string | null>;
|
|
25
|
-
/** experiment → metrics (only for enrolled arms) */
|
|
26
|
-
metrics: Map<string, ABArmAccum>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function emptyFoldedABSession(): FoldedABSession {
|
|
30
|
-
return { arms: new Map(), metrics: new Map() };
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** Ensure a metrics bucket exists for an enrolled arm. */
|
|
34
|
-
export function ensureArmAccum(
|
|
35
|
-
state: FoldedABSession,
|
|
36
|
-
experiment: string,
|
|
37
|
-
variant: string
|
|
38
|
-
): ABArmAccum {
|
|
39
|
-
let accum = state.metrics.get(experiment);
|
|
40
|
-
if (accum === undefined) {
|
|
41
|
-
accum = {
|
|
42
|
-
variant,
|
|
43
|
-
metrics: emptyABMetrics(),
|
|
44
|
-
turnStartedAt: null,
|
|
45
|
-
};
|
|
46
|
-
state.metrics.set(experiment, accum);
|
|
47
|
-
}
|
|
48
|
-
return accum;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** Fold one event's built-in metrics + assignment. Does not run `derive`. */
|
|
52
|
-
export function foldABEvent(state: FoldedABSession, event: SessionEvent): void {
|
|
53
|
-
if (event.type === "ab.assigned") {
|
|
54
|
-
const { experiment, variant } = event.data;
|
|
55
|
-
state.arms.set(experiment, variant);
|
|
56
|
-
if (variant === null) {
|
|
57
|
-
state.metrics.delete(experiment);
|
|
58
|
-
} else {
|
|
59
|
-
state.metrics.set(experiment, {
|
|
60
|
-
variant,
|
|
61
|
-
metrics: emptyABMetrics(),
|
|
62
|
-
turnStartedAt: null,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (state.arms.size === 0) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
for (const [experiment, variant] of state.arms) {
|
|
73
|
-
if (variant === null) {
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
applyBuiltinMetrics(ensureArmAccum(state, experiment, variant), event);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function foldABStream(events: readonly SessionEvent[]): FoldedABSession {
|
|
81
|
-
const state = emptyFoldedABSession();
|
|
82
|
-
for (const event of events) {
|
|
83
|
-
foldABEvent(state, event);
|
|
84
|
-
}
|
|
85
|
-
return state;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Apply `derive` extractors for one event into `custom` counters.
|
|
90
|
-
* Errors are reported via `onError` and skipped.
|
|
91
|
-
*/
|
|
92
|
-
export async function applyDeriveForEvent(
|
|
93
|
-
custom: Record<string, number>,
|
|
94
|
-
derive: NonNullable<ABDefinition["derive"]>,
|
|
95
|
-
event: SessionEvent,
|
|
96
|
-
collectCtx: ABCollectContext,
|
|
97
|
-
onError: (key: string, error: unknown) => void
|
|
98
|
-
): Promise<void> {
|
|
99
|
-
for (const [key, extract] of Object.entries(derive)) {
|
|
100
|
-
try {
|
|
101
|
-
const delta = await extract(event, collectCtx);
|
|
102
|
-
if (typeof delta === "number" && Number.isFinite(delta)) {
|
|
103
|
-
custom[key] = (custom[key] ?? 0) + delta;
|
|
104
|
-
}
|
|
105
|
-
} catch (error) {
|
|
106
|
-
onError(key, error);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function collectContext(
|
|
112
|
-
experiment: string,
|
|
113
|
-
variant: string,
|
|
114
|
-
sessionInfo: SessionInfo,
|
|
115
|
-
agentName: string
|
|
116
|
-
): ABCollectContext {
|
|
117
|
-
return {
|
|
118
|
-
agent: { name: agentName },
|
|
119
|
-
channel: { id: sessionInfo.channelId },
|
|
120
|
-
session: sessionInfo,
|
|
121
|
-
experiment,
|
|
122
|
-
variant,
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Re-run `derive` extractors over the stream for enrolled arms.
|
|
128
|
-
* Mutates `state.metrics` in place. Errors are logged and skipped.
|
|
129
|
-
*/
|
|
130
|
-
export async function applyABDerive(
|
|
131
|
-
state: FoldedABSession,
|
|
132
|
-
events: readonly SessionEvent[],
|
|
133
|
-
experiments: readonly DiscoveredAB[],
|
|
134
|
-
sessionInfo: SessionInfo,
|
|
135
|
-
agentName: string,
|
|
136
|
-
logger: (line: string) => void
|
|
137
|
-
): Promise<void> {
|
|
138
|
-
for (const experiment of experiments) {
|
|
139
|
-
const variant = state.arms.get(experiment.name);
|
|
140
|
-
if (variant === undefined || variant === null) {
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
const def = experiment.definition as ABDefinition;
|
|
144
|
-
if (def.derive === undefined) {
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
const accum = ensureArmAccum(state, experiment.name, variant);
|
|
148
|
-
// Reset custom so a re-fold is idempotent.
|
|
149
|
-
accum.metrics.custom = {};
|
|
150
|
-
const ctx = collectContext(
|
|
151
|
-
experiment.name,
|
|
152
|
-
variant,
|
|
153
|
-
sessionInfo,
|
|
154
|
-
agentName
|
|
155
|
-
);
|
|
156
|
-
for (const event of events) {
|
|
157
|
-
await applyDeriveForEvent(
|
|
158
|
-
accum.metrics.custom,
|
|
159
|
-
def.derive,
|
|
160
|
-
event,
|
|
161
|
-
ctx,
|
|
162
|
-
(key, error) => {
|
|
163
|
-
logger(
|
|
164
|
-
`[agent-sdk] ab "${experiment.name}" derive.${key} threw: ${describeError(error)}`
|
|
165
|
-
);
|
|
166
|
-
}
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export function applyBuiltinMetrics(
|
|
173
|
-
accum: ABArmAccum,
|
|
174
|
-
event: SessionEvent
|
|
175
|
-
): void {
|
|
176
|
-
const m = accum.metrics;
|
|
177
|
-
switch (event.type) {
|
|
178
|
-
case "turn.started":
|
|
179
|
-
accum.turnStartedAt = event.at;
|
|
180
|
-
break;
|
|
181
|
-
case "turn.completed": {
|
|
182
|
-
m.turns += 1;
|
|
183
|
-
const usage = event.data.usage;
|
|
184
|
-
if (usage !== undefined) {
|
|
185
|
-
m.inputTokens += usage.inputTokens;
|
|
186
|
-
m.outputTokens += usage.outputTokens;
|
|
187
|
-
m.cacheReadTokens += usage.cacheReadTokens;
|
|
188
|
-
m.cacheWriteTokens += usage.cacheWriteTokens;
|
|
189
|
-
}
|
|
190
|
-
const cost = event.data.cost;
|
|
191
|
-
if (cost !== undefined) {
|
|
192
|
-
m.costUsd += cost.totalUsd;
|
|
193
|
-
}
|
|
194
|
-
addWallTime(accum, event.at);
|
|
195
|
-
break;
|
|
196
|
-
}
|
|
197
|
-
case "turn.failed":
|
|
198
|
-
m.turns += 1;
|
|
199
|
-
m.turnFailures += 1;
|
|
200
|
-
addWallTime(accum, event.at);
|
|
201
|
-
break;
|
|
202
|
-
case "action.result":
|
|
203
|
-
m.toolCalls += 1;
|
|
204
|
-
if (event.data.isError) {
|
|
205
|
-
m.toolErrors += 1;
|
|
206
|
-
}
|
|
207
|
-
break;
|
|
208
|
-
default:
|
|
209
|
-
break;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function addWallTime(accum: ABArmAccum, endedAt: string): void {
|
|
214
|
-
if (accum.turnStartedAt === null) {
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
const start = Date.parse(accum.turnStartedAt);
|
|
218
|
-
const end = Date.parse(endedAt);
|
|
219
|
-
accum.turnStartedAt = null;
|
|
220
|
-
if (Number.isFinite(start) && Number.isFinite(end) && end >= start) {
|
|
221
|
-
accum.metrics.wallTimeMs += end - start;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export function cloneFoldedMetrics(
|
|
226
|
-
accum: ABArmAccum | undefined
|
|
227
|
-
): ABMetrics | undefined {
|
|
228
|
-
if (accum === undefined) {
|
|
229
|
-
return undefined;
|
|
230
|
-
}
|
|
231
|
-
return cloneABMetrics(accum.metrics);
|
|
232
|
-
}
|
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Read-only A/B metrics snapshot: fold durable session event streams into
|
|
3
|
-
* per-session assignments and aggregate arm totals. Used by `GET /v1/abs`.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
type ABDefinition,
|
|
8
|
-
type ABMetrics,
|
|
9
|
-
type ABVariantMeta,
|
|
10
|
-
cloneABMetrics,
|
|
11
|
-
emptyABMetrics,
|
|
12
|
-
} from "../ab.js";
|
|
13
|
-
import type {
|
|
14
|
-
DiscoveredAB,
|
|
15
|
-
SessionEvent,
|
|
16
|
-
SessionInfo,
|
|
17
|
-
SessionRecord,
|
|
18
|
-
SessionSummary,
|
|
19
|
-
} from "../types.js";
|
|
20
|
-
import { applyABDerive, cloneFoldedMetrics, foldABStream } from "./ab-fold.js";
|
|
21
|
-
import { mapPool } from "./map-pool.js";
|
|
22
|
-
|
|
23
|
-
export interface ABSnapshotAssignment {
|
|
24
|
-
experiment: string;
|
|
25
|
-
variant: string | null;
|
|
26
|
-
variantLabel?: string;
|
|
27
|
-
/** Present when enrolled (`variant` non-null). */
|
|
28
|
-
metrics?: ABMetrics;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface ABSnapshotSession {
|
|
32
|
-
sessionId: string;
|
|
33
|
-
channelId: string;
|
|
34
|
-
mode: string;
|
|
35
|
-
title?: string;
|
|
36
|
-
turnCount: number;
|
|
37
|
-
updatedAt?: string;
|
|
38
|
-
assignments: ABSnapshotAssignment[];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface ABSnapshotArm {
|
|
42
|
-
variant: string;
|
|
43
|
-
variantLabel?: string;
|
|
44
|
-
description?: string;
|
|
45
|
-
/** Sessions enrolled in this arm. */
|
|
46
|
-
sessions: number;
|
|
47
|
-
metrics: ABMetrics;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface ABSnapshotExperiment {
|
|
51
|
-
name: string;
|
|
52
|
-
variants: Record<string, ABVariantMeta>;
|
|
53
|
-
/** Sessions with sticky skip (`variant: null`). */
|
|
54
|
-
skipped: number;
|
|
55
|
-
arms: ABSnapshotArm[];
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface ABSnapshotConfig {
|
|
59
|
-
/** Newest-first session fold window for this snapshot (`GET /v1/abs`). */
|
|
60
|
-
maxPlaygroundSessions?: number;
|
|
61
|
-
/** True when the `defineStorage` `abs` table is configured. */
|
|
62
|
-
durableSamples?: boolean;
|
|
63
|
-
/** True when the `abs` table also stores the aggregate snapshot. */
|
|
64
|
-
durableSnapshots?: boolean;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface ABSnapshot {
|
|
68
|
-
experiments: ABSnapshotExperiment[];
|
|
69
|
-
sessions: ABSnapshotSession[];
|
|
70
|
-
config?: ABSnapshotConfig;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface BuildABSnapshotInput {
|
|
74
|
-
experiments: readonly DiscoveredAB[];
|
|
75
|
-
agentName: string;
|
|
76
|
-
/** Newest-first session list (same order as `GET /v1/sessions`). */
|
|
77
|
-
sessions: readonly SessionSummary[];
|
|
78
|
-
loadRecord: (sessionId: string) => Promise<SessionRecord | undefined>;
|
|
79
|
-
loadEvents: (sessionId: string) => Promise<SessionEvent[]>;
|
|
80
|
-
sessionInfo: (record: SessionRecord) => SessionInfo;
|
|
81
|
-
logger: (line: string) => void;
|
|
82
|
-
/** Max concurrent event-log reads (default 8). */
|
|
83
|
-
concurrency?: number;
|
|
84
|
-
/** Attached to the returned snapshot (playground / persistence meta). */
|
|
85
|
-
config?: ABSnapshotConfig;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export async function buildABSnapshot(
|
|
89
|
-
input: BuildABSnapshotInput
|
|
90
|
-
): Promise<ABSnapshot> {
|
|
91
|
-
const experiments = input.experiments;
|
|
92
|
-
|
|
93
|
-
const armTotals = new Map<
|
|
94
|
-
string,
|
|
95
|
-
Map<string, { sessions: number; metrics: ABMetrics }>
|
|
96
|
-
>();
|
|
97
|
-
const skipped = new Map<string, number>();
|
|
98
|
-
for (const experiment of experiments) {
|
|
99
|
-
armTotals.set(experiment.name, new Map());
|
|
100
|
-
skipped.set(experiment.name, 0);
|
|
101
|
-
for (const variant of Object.keys(
|
|
102
|
-
(experiment.definition as ABDefinition).variants
|
|
103
|
-
)) {
|
|
104
|
-
armTotals.get(experiment.name)!.set(variant, {
|
|
105
|
-
sessions: 0,
|
|
106
|
-
metrics: emptyABMetrics(),
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const concurrency = Math.max(1, input.concurrency ?? 8);
|
|
112
|
-
const sessionRows: ABSnapshotSession[] = [];
|
|
113
|
-
|
|
114
|
-
async function processOne(summary: SessionSummary): Promise<void> {
|
|
115
|
-
const record = await input.loadRecord(summary.sessionId);
|
|
116
|
-
if (record === undefined) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
// Eval harness sessions never enroll; keep them out of aggregates too.
|
|
120
|
-
if (record.purpose === "eval") {
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
const events = await input.loadEvents(summary.sessionId);
|
|
124
|
-
const folded = foldABStream(events);
|
|
125
|
-
if (experiments.length > 0) {
|
|
126
|
-
await applyABDerive(
|
|
127
|
-
folded,
|
|
128
|
-
events,
|
|
129
|
-
experiments,
|
|
130
|
-
input.sessionInfo(record),
|
|
131
|
-
input.agentName,
|
|
132
|
-
input.logger
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const assignments: ABSnapshotAssignment[] = [];
|
|
137
|
-
// Prefer declared experiment order; include unknown arms from the log after.
|
|
138
|
-
const seen = new Set<string>();
|
|
139
|
-
for (const experiment of experiments) {
|
|
140
|
-
seen.add(experiment.name);
|
|
141
|
-
const variant = folded.arms.get(experiment.name);
|
|
142
|
-
if (variant === undefined) {
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
const def = experiment.definition as ABDefinition;
|
|
146
|
-
const label = variant === null ? undefined : def.variants[variant]?.label;
|
|
147
|
-
const metrics =
|
|
148
|
-
variant === null
|
|
149
|
-
? undefined
|
|
150
|
-
: cloneFoldedMetrics(folded.metrics.get(experiment.name));
|
|
151
|
-
assignments.push({
|
|
152
|
-
experiment: experiment.name,
|
|
153
|
-
variant,
|
|
154
|
-
...(label !== undefined ? { variantLabel: label } : {}),
|
|
155
|
-
...(metrics !== undefined ? { metrics } : {}),
|
|
156
|
-
});
|
|
157
|
-
if (variant === null) {
|
|
158
|
-
skipped.set(experiment.name, (skipped.get(experiment.name) ?? 0) + 1);
|
|
159
|
-
} else {
|
|
160
|
-
const bucket = armTotals.get(experiment.name)?.get(variant);
|
|
161
|
-
if (bucket !== undefined && metrics !== undefined) {
|
|
162
|
-
bucket.sessions += 1;
|
|
163
|
-
addMetrics(bucket.metrics, metrics);
|
|
164
|
-
} else if (bucket === undefined) {
|
|
165
|
-
// Assigned to an arm no longer in the definition — still surface it.
|
|
166
|
-
const arms = armTotals.get(experiment.name) ?? new Map();
|
|
167
|
-
const created = {
|
|
168
|
-
sessions: 1,
|
|
169
|
-
metrics:
|
|
170
|
-
metrics !== undefined
|
|
171
|
-
? cloneABMetrics(metrics)
|
|
172
|
-
: emptyABMetrics(),
|
|
173
|
-
};
|
|
174
|
-
arms.set(variant, created);
|
|
175
|
-
armTotals.set(experiment.name, arms);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
for (const [experiment, variant] of folded.arms) {
|
|
180
|
-
if (seen.has(experiment)) {
|
|
181
|
-
continue;
|
|
182
|
-
}
|
|
183
|
-
const metrics =
|
|
184
|
-
variant === null
|
|
185
|
-
? undefined
|
|
186
|
-
: cloneFoldedMetrics(folded.metrics.get(experiment));
|
|
187
|
-
assignments.push({
|
|
188
|
-
experiment,
|
|
189
|
-
variant,
|
|
190
|
-
...(metrics !== undefined ? { metrics } : {}),
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (assignments.length === 0) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
sessionRows.push({
|
|
199
|
-
sessionId: summary.sessionId,
|
|
200
|
-
channelId: summary.channelId,
|
|
201
|
-
mode: summary.mode,
|
|
202
|
-
...(summary.title === undefined ? {} : { title: summary.title }),
|
|
203
|
-
turnCount: summary.turnCount,
|
|
204
|
-
...(summary.updatedAt === undefined
|
|
205
|
-
? {}
|
|
206
|
-
: { updatedAt: summary.updatedAt }),
|
|
207
|
-
assignments,
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
await mapPool(input.sessions, concurrency, async (summary) => {
|
|
212
|
-
await processOne(summary);
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
// Preserve newest-first order from the sessions list.
|
|
216
|
-
const order = new Map(
|
|
217
|
-
input.sessions.map((summary, index) => [summary.sessionId, index])
|
|
218
|
-
);
|
|
219
|
-
sessionRows.sort(
|
|
220
|
-
(a, b) => (order.get(a.sessionId) ?? 0) - (order.get(b.sessionId) ?? 0)
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
const experimentRows: ABSnapshotExperiment[] = experiments.map(
|
|
224
|
-
(experiment) => {
|
|
225
|
-
const def = experiment.definition as ABDefinition;
|
|
226
|
-
const arms: ABSnapshotArm[] = [];
|
|
227
|
-
for (const [variant, meta] of Object.entries(def.variants)) {
|
|
228
|
-
const bucket = armTotals.get(experiment.name)?.get(variant) ?? {
|
|
229
|
-
sessions: 0,
|
|
230
|
-
metrics: emptyABMetrics(),
|
|
231
|
-
};
|
|
232
|
-
arms.push({
|
|
233
|
-
variant,
|
|
234
|
-
...(meta.label !== undefined ? { variantLabel: meta.label } : {}),
|
|
235
|
-
...(meta.description !== undefined
|
|
236
|
-
? { description: meta.description }
|
|
237
|
-
: {}),
|
|
238
|
-
sessions: bucket.sessions,
|
|
239
|
-
metrics: cloneABMetrics(bucket.metrics),
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
// Orphan arms from the log (no longer in definition).
|
|
243
|
-
for (const [variant, bucket] of armTotals.get(experiment.name) ?? []) {
|
|
244
|
-
if (variant in def.variants) {
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
arms.push({
|
|
248
|
-
variant,
|
|
249
|
-
sessions: bucket.sessions,
|
|
250
|
-
metrics: cloneABMetrics(bucket.metrics),
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
return {
|
|
254
|
-
name: experiment.name,
|
|
255
|
-
variants: def.variants,
|
|
256
|
-
skipped: skipped.get(experiment.name) ?? 0,
|
|
257
|
-
arms,
|
|
258
|
-
};
|
|
259
|
-
}
|
|
260
|
-
);
|
|
261
|
-
|
|
262
|
-
// Experiments that appear only in logs (definition removed).
|
|
263
|
-
const known = new Set(experiments.map((experiment) => experiment.name));
|
|
264
|
-
const orphanNames = new Set<string>();
|
|
265
|
-
for (const row of sessionRows) {
|
|
266
|
-
for (const assignment of row.assignments) {
|
|
267
|
-
if (!known.has(assignment.experiment)) {
|
|
268
|
-
orphanNames.add(assignment.experiment);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
for (const name of orphanNames) {
|
|
273
|
-
const armsMap = new Map<string, { sessions: number; metrics: ABMetrics }>();
|
|
274
|
-
let skipCount = 0;
|
|
275
|
-
for (const row of sessionRows) {
|
|
276
|
-
for (const assignment of row.assignments) {
|
|
277
|
-
if (assignment.experiment !== name) {
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
if (assignment.variant === null) {
|
|
281
|
-
skipCount += 1;
|
|
282
|
-
continue;
|
|
283
|
-
}
|
|
284
|
-
const bucket = armsMap.get(assignment.variant) ?? {
|
|
285
|
-
sessions: 0,
|
|
286
|
-
metrics: emptyABMetrics(),
|
|
287
|
-
};
|
|
288
|
-
bucket.sessions += 1;
|
|
289
|
-
if (assignment.metrics !== undefined) {
|
|
290
|
-
addMetrics(bucket.metrics, assignment.metrics);
|
|
291
|
-
}
|
|
292
|
-
armsMap.set(assignment.variant, bucket);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
experimentRows.push({
|
|
296
|
-
name,
|
|
297
|
-
variants: {},
|
|
298
|
-
skipped: skipCount,
|
|
299
|
-
arms: [...armsMap.entries()].map(([variant, bucket]) => ({
|
|
300
|
-
variant,
|
|
301
|
-
sessions: bucket.sessions,
|
|
302
|
-
metrics: cloneABMetrics(bucket.metrics),
|
|
303
|
-
})),
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return {
|
|
308
|
-
experiments: experimentRows,
|
|
309
|
-
sessions: sessionRows,
|
|
310
|
-
...(input.config === undefined ? {} : { config: input.config }),
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function addMetrics(target: ABMetrics, delta: ABMetrics): void {
|
|
315
|
-
target.turns += delta.turns;
|
|
316
|
-
target.turnFailures += delta.turnFailures;
|
|
317
|
-
target.toolCalls += delta.toolCalls;
|
|
318
|
-
target.toolErrors += delta.toolErrors;
|
|
319
|
-
target.inputTokens += delta.inputTokens;
|
|
320
|
-
target.outputTokens += delta.outputTokens;
|
|
321
|
-
target.cacheReadTokens += delta.cacheReadTokens;
|
|
322
|
-
target.cacheWriteTokens += delta.cacheWriteTokens;
|
|
323
|
-
target.costUsd += delta.costUsd;
|
|
324
|
-
target.wallTimeMs += delta.wallTimeMs;
|
|
325
|
-
for (const [key, value] of Object.entries(delta.custom)) {
|
|
326
|
-
target.custom[key] = (target.custom[key] ?? 0) + value;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/** Narrow helper so callers don't need the unused DiscoveredAB import above. */
|
|
331
|
-
export type { DiscoveredAB };
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `agent/ab.ts` or `agent/ab/*.ts` plus `agent/ab.config.ts`: live A/B experiments.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { basename, extname, join, relative } from "node:path";
|
|
6
|
-
import type { ABConfigFile } from "../../ab.js";
|
|
7
|
-
import type { DiscoveredAB } from "../../types.js";
|
|
8
|
-
import { getDefinitionKind } from "../brand.js";
|
|
9
|
-
import { type DiscoveryContext, displayPath } from "./context.js";
|
|
10
|
-
import {
|
|
11
|
-
findModuleFile,
|
|
12
|
-
isDirectory,
|
|
13
|
-
isModuleFile,
|
|
14
|
-
toPosix,
|
|
15
|
-
walkFiles,
|
|
16
|
-
} from "./fs.js";
|
|
17
|
-
import { importDefault } from "./modules.js";
|
|
18
|
-
|
|
19
|
-
export async function loadABs(
|
|
20
|
-
ctx: DiscoveryContext,
|
|
21
|
-
agentDir: string,
|
|
22
|
-
onDisable?: (source: string, path: string) => void
|
|
23
|
-
): Promise<DiscoveredAB[]> {
|
|
24
|
-
const abs: DiscoveredAB[] = [];
|
|
25
|
-
const seen = new Set<string>();
|
|
26
|
-
|
|
27
|
-
const single = await findModuleFile(agentDir, "ab");
|
|
28
|
-
if (single !== undefined) {
|
|
29
|
-
const definition = await importDefault(
|
|
30
|
-
ctx,
|
|
31
|
-
single,
|
|
32
|
-
onDisable === undefined ? "ab" : ["ab", "disabled"]
|
|
33
|
-
);
|
|
34
|
-
if (definition !== undefined) {
|
|
35
|
-
if (getDefinitionKind(definition) === "disabled") {
|
|
36
|
-
onDisable?.("ab", single);
|
|
37
|
-
} else {
|
|
38
|
-
const name = resolveABName(definition, "ab");
|
|
39
|
-
seen.add(name);
|
|
40
|
-
abs.push({
|
|
41
|
-
name,
|
|
42
|
-
source: "ab",
|
|
43
|
-
definition: definition as DiscoveredAB["definition"],
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const absDir = join(agentDir, "ab");
|
|
50
|
-
if (await isDirectory(absDir)) {
|
|
51
|
-
for (const filePath of await walkFiles(absDir)) {
|
|
52
|
-
if (!isModuleFile(basename(filePath))) {
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
const rel = toPosix(relative(absDir, filePath));
|
|
56
|
-
const stem = rel.slice(0, -extname(rel).length);
|
|
57
|
-
const definition = await importDefault(
|
|
58
|
-
ctx,
|
|
59
|
-
filePath,
|
|
60
|
-
onDisable === undefined ? "ab" : ["ab", "disabled"]
|
|
61
|
-
);
|
|
62
|
-
if (definition === undefined) {
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
if (getDefinitionKind(definition) === "disabled") {
|
|
66
|
-
onDisable?.(stem, filePath);
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const name = resolveABName(definition, stem);
|
|
70
|
-
if (seen.has(name)) {
|
|
71
|
-
ctx.diagnostics.push({
|
|
72
|
-
severity: "error",
|
|
73
|
-
path: displayPath(ctx, filePath),
|
|
74
|
-
message: `Duplicate A/B experiment name ${JSON.stringify(name)}.`,
|
|
75
|
-
});
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
seen.add(name);
|
|
79
|
-
abs.push({
|
|
80
|
-
name,
|
|
81
|
-
source: stem,
|
|
82
|
-
definition: definition as DiscoveredAB["definition"],
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return abs;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export async function loadABConfig(
|
|
91
|
-
ctx: DiscoveryContext,
|
|
92
|
-
agentDir: string
|
|
93
|
-
): Promise<ABConfigFile | undefined> {
|
|
94
|
-
const path = await findModuleFile(agentDir, "ab.config");
|
|
95
|
-
if (path === undefined) {
|
|
96
|
-
return undefined;
|
|
97
|
-
}
|
|
98
|
-
try {
|
|
99
|
-
const mod = await ctx.importModule(path);
|
|
100
|
-
if (mod.default === null || typeof mod.default !== "object") {
|
|
101
|
-
ctx.diagnostics.push({
|
|
102
|
-
severity: "error",
|
|
103
|
-
path: displayPath(ctx, path),
|
|
104
|
-
message:
|
|
105
|
-
"ab.config.ts must default-export defineABConfig({ ... }) from @cursor/july/ab.",
|
|
106
|
-
});
|
|
107
|
-
return undefined;
|
|
108
|
-
}
|
|
109
|
-
return mod.default as ABConfigFile;
|
|
110
|
-
} catch (error) {
|
|
111
|
-
ctx.diagnostics.push({
|
|
112
|
-
severity: "error",
|
|
113
|
-
path: displayPath(ctx, path),
|
|
114
|
-
message: `Failed to load ab.config: ${error instanceof Error ? error.message : String(error)}`,
|
|
115
|
-
});
|
|
116
|
-
return undefined;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function resolveABName(definition: unknown, fallback: string): string {
|
|
121
|
-
if (
|
|
122
|
-
typeof definition === "object" &&
|
|
123
|
-
definition !== null &&
|
|
124
|
-
"name" in definition &&
|
|
125
|
-
typeof (definition as { name: unknown }).name === "string" &&
|
|
126
|
-
(definition as { name: string }).name.length > 0
|
|
127
|
-
) {
|
|
128
|
-
return (definition as { name: string }).name;
|
|
129
|
-
}
|
|
130
|
-
return fallback;
|
|
131
|
-
}
|
|
File without changes
|
|
File without changes
|
/package/dist/docs/assets/{hillclimbing.md.CpTGTCle.lean.js → hillclimbing.md.BOiVo1tf.lean.js}
RENAMED
|
File without changes
|
/package/dist/docs/assets/{reference_cli.md.Ca26u0Es.lean.js → reference_cli.md.Deg7849l.lean.js}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|