bitfab 0.64.6 → 0.64.8

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 (34) hide show
  1. package/cloudReplay.py +3 -0
  2. package/dist/{chunk-J342BFLH.js → chunk-25HVPGSF.js} +39 -4
  3. package/dist/chunk-25HVPGSF.js.map +1 -0
  4. package/dist/{chunk-B363XZTL.js → chunk-2U4Y5FHT.js} +150 -3
  5. package/dist/chunk-2U4Y5FHT.js.map +1 -0
  6. package/dist/{chunk-6NUSTEQ6.js → chunk-2UDEQITO.js} +32 -8
  7. package/dist/chunk-2UDEQITO.js.map +1 -0
  8. package/dist/{chunk-MS3GWCJB.js → chunk-P2SYAT44.js} +6 -3
  9. package/dist/{chunk-MS3GWCJB.js.map → chunk-P2SYAT44.js.map} +1 -1
  10. package/dist/{chunk-ROZEHSGO.js → chunk-YGDXDDTX.js} +6 -3
  11. package/dist/chunk-YGDXDDTX.js.map +1 -0
  12. package/dist/{http-BD3WK3FL.js → http-CWPHM5T3.js} +2 -2
  13. package/dist/{http-2UZ6CM3K.js → http-JBQTF36K.js} +2 -2
  14. package/dist/index.cjs +189 -6
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +26 -12
  17. package/dist/index.d.ts +26 -12
  18. package/dist/index.js +3 -3
  19. package/dist/node.cjs +189 -6
  20. package/dist/node.cjs.map +1 -1
  21. package/dist/node.d.cts +1 -1
  22. package/dist/node.d.ts +1 -1
  23. package/dist/node.js +3 -3
  24. package/dist/{replay-KQCLQRJT.js → replay-LBALXLOM.js} +3 -3
  25. package/dist/replayCli.js +2 -2
  26. package/dist/seedCli.js +2 -2
  27. package/package.json +1 -1
  28. package/dist/chunk-6NUSTEQ6.js.map +0 -1
  29. package/dist/chunk-B363XZTL.js.map +0 -1
  30. package/dist/chunk-J342BFLH.js.map +0 -1
  31. package/dist/chunk-ROZEHSGO.js.map +0 -1
  32. /package/dist/{http-2UZ6CM3K.js.map → http-CWPHM5T3.js.map} +0 -0
  33. /package/dist/{http-BD3WK3FL.js.map → http-JBQTF36K.js.map} +0 -0
  34. /package/dist/{replay-KQCLQRJT.js.map → replay-LBALXLOM.js.map} +0 -0
package/dist/index.cjs CHANGED
@@ -51,7 +51,7 @@ var __version__, __packageName__;
51
51
  var init_version_generated = __esm({
52
52
  "src/version.generated.ts"() {
53
53
  "use strict";
54
- __version__ = "0.64.6";
54
+ __version__ = "0.64.8";
55
55
  __packageName__ = "bitfab";
56
56
  }
57
57
  });
@@ -2904,7 +2904,7 @@ var init_http = __esm({
2904
2904
  * Start a replay session by fetching historical traces.
2905
2905
  * Blocking call - creates an experiment and returns lightweight item references.
2906
2906
  */
2907
- async startReplay(traceFunctionKey, limit, traceIds, name, codeChangeDescription, codeChangeFiles, includeDbBranchLease, experimentGroupId, datasetIds, graderIds, dbBranchSettings, attempts, includeOriginalMetadata, onlyWithAssertions, skipAssertionJudging, experimentalSelectiveReplay, notes, metadata, dryRun) {
2907
+ async startReplay(traceFunctionKey, limit, traceIds, name, codeChangeDescription, codeChangeFiles, includeDbBranchLease, experimentGroupId, datasetIds, graderIds, dbBranchSettings, attempts, includeOriginalMetadata, onlyWithAssertions, skipAssertionJudging, experimentalSelectiveReplay, notes, metadata, dryRun, invocation) {
2908
2908
  const payload = { traceFunctionKey };
2909
2909
  if (experimentalSelectiveReplay !== void 0) {
2910
2910
  payload.experimentalSelectiveReplay = experimentalSelectiveReplay;
@@ -2965,6 +2965,9 @@ var init_http = __esm({
2965
2965
  if (dryRun) {
2966
2966
  payload.dryRun = true;
2967
2967
  }
2968
+ if (invocation !== void 0) {
2969
+ payload.invocation = invocation;
2970
+ }
2968
2971
  const git = await resolvedGitState();
2969
2972
  if (git && !isEmptyGitState(git)) {
2970
2973
  payload.git = git;
@@ -3760,6 +3763,113 @@ var init_replayInterrupt = __esm({
3760
3763
  }
3761
3764
  });
3762
3765
 
3766
+ // src/replayInvocation.ts
3767
+ function replayEnvironment() {
3768
+ if (readEnv(REPLAY_EXECUTION_TARGET_ENV) === HOSTED_EXECUTION_TARGET) {
3769
+ return "cloud_replay";
3770
+ }
3771
+ if (CI_TRUE_VALUES.has((readEnv(CI_ENV) ?? "").toLowerCase())) {
3772
+ return "ci";
3773
+ }
3774
+ if (CI_PRESENCE_ENV_VARS.some((name) => (readEnv(name) ?? "") !== "")) {
3775
+ return "ci";
3776
+ }
3777
+ return "local";
3778
+ }
3779
+ function flagScalar(value) {
3780
+ if (typeof value === "string") {
3781
+ return value.slice(0, MAX_FLAG_STRING_LENGTH);
3782
+ }
3783
+ if (typeof value === "number") {
3784
+ return Number.isFinite(value) ? value : void 0;
3785
+ }
3786
+ if (typeof value === "boolean" || value === null) {
3787
+ return value;
3788
+ }
3789
+ return void 0;
3790
+ }
3791
+ function flagValue(value) {
3792
+ if (Array.isArray(value)) {
3793
+ const items = value.slice(0, MAX_FLAG_LIST_LENGTH).map(flagScalar);
3794
+ return items.every((item) => item !== void 0) ? items : true;
3795
+ }
3796
+ const scalar = flagScalar(value);
3797
+ return scalar === void 0 ? true : scalar;
3798
+ }
3799
+ function optionFlagName(option) {
3800
+ return OPTION_FLAG_NAMES[option] ?? option.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
3801
+ }
3802
+ function metadataKeys(value) {
3803
+ const keys = Array.isArray(value) ? value.map((pair) => String(pair).split("=")[0]) : typeof value === "object" && value !== null ? Object.keys(value) : void 0;
3804
+ return keys === void 0 ? true : [...new Set(keys)].sort();
3805
+ }
3806
+ function invocationFlags(entries) {
3807
+ const flags = {};
3808
+ const seen = /* @__PURE__ */ new Set();
3809
+ for (const [name, value] of entries) {
3810
+ if (seen.size >= MAX_FLAGS) {
3811
+ break;
3812
+ }
3813
+ if (value === void 0 || seen.has(name) || name.length === 0 || name.length > MAX_FLAG_NAME_LENGTH || SECRET_FLAG_NAME.test(name)) {
3814
+ continue;
3815
+ }
3816
+ flags[name] = flagValue(
3817
+ name === METADATA_FLAG ? metadataKeys(value) : value
3818
+ );
3819
+ seen.add(name);
3820
+ }
3821
+ return flags;
3822
+ }
3823
+ function buildReplayInvocation(entries = []) {
3824
+ return {
3825
+ flags: invocationFlags(entries),
3826
+ sdk: { language: "typescript", version: __version__ },
3827
+ environment: replayEnvironment()
3828
+ };
3829
+ }
3830
+ function safeReplayInvocation(build) {
3831
+ try {
3832
+ return build();
3833
+ } catch {
3834
+ return void 0;
3835
+ }
3836
+ }
3837
+ function cliFlags(options) {
3838
+ return options?.[CLI_FLAGS];
3839
+ }
3840
+ var REPLAY_EXECUTION_TARGET_ENV, HOSTED_EXECUTION_TARGET, CI_ENV, CI_TRUE_VALUES, CI_PRESENCE_ENV_VARS, MAX_FLAGS, MAX_FLAG_NAME_LENGTH, MAX_FLAG_STRING_LENGTH, MAX_FLAG_LIST_LENGTH, SECRET_FLAG_NAME, CLI_FLAGS, METADATA_FLAG, OPTION_FLAG_NAMES;
3841
+ var init_replayInvocation = __esm({
3842
+ "src/replayInvocation.ts"() {
3843
+ "use strict";
3844
+ init_constants();
3845
+ init_readEnv();
3846
+ REPLAY_EXECUTION_TARGET_ENV = "BITFAB_REPLAY_EXECUTION_TARGET";
3847
+ HOSTED_EXECUTION_TARGET = "hosted";
3848
+ CI_ENV = "CI";
3849
+ CI_TRUE_VALUES = /* @__PURE__ */ new Set(["true", "1"]);
3850
+ CI_PRESENCE_ENV_VARS = [
3851
+ "GITHUB_ACTIONS",
3852
+ "GITLAB_CI",
3853
+ "CIRCLECI",
3854
+ "BUILDKITE",
3855
+ "JENKINS_URL",
3856
+ "TF_BUILD"
3857
+ ];
3858
+ MAX_FLAGS = 100;
3859
+ MAX_FLAG_NAME_LENGTH = 100;
3860
+ MAX_FLAG_STRING_LENGTH = 1e3;
3861
+ MAX_FLAG_LIST_LENGTH = 100;
3862
+ SECRET_FLAG_NAME = /key|token|secret|password/i;
3863
+ CLI_FLAGS = /* @__PURE__ */ Symbol("bitfab.replayCliFlags");
3864
+ METADATA_FLAG = "metadata";
3865
+ OPTION_FLAG_NAMES = {
3866
+ maxConcurrency: "concurrency",
3867
+ datasetId: "dataset-ids",
3868
+ datasetIds: "dataset-ids"
3869
+ };
3870
+ }
3871
+ });
3872
+
3763
3873
  // src/selectiveReplay.ts
3764
3874
  function replayNodeKey(node) {
3765
3875
  return JSON.stringify([node.traceFunctionKey, node.spanName]);
@@ -4189,6 +4299,16 @@ function resolveDbBranchSettings(dbBranch) {
4189
4299
  };
4190
4300
  return Object.keys(settings).length === 0 ? void 0 : settings;
4191
4301
  }
4302
+ function explicitReplayOptions(options) {
4303
+ var _a;
4304
+ const explicit = {};
4305
+ for (const name of REPLAY_OPTION_NAMES) {
4306
+ if (options?.[name] !== void 0) {
4307
+ explicit[_a = optionFlagName(name)] ?? (explicit[_a] = options[name]);
4308
+ }
4309
+ }
4310
+ return explicit;
4311
+ }
4192
4312
  function reportReplayProgress(progress) {
4193
4313
  const stderr = typeof process !== "undefined" ? process.stderr : void 0;
4194
4314
  if (!stderr) {
@@ -4700,7 +4820,12 @@ async function replay(httpClient, serviceUrl, traceFunctionKey, fn, options, reg
4700
4820
  options?.experimentalSelectiveReplay,
4701
4821
  options?.notes,
4702
4822
  options?.metadata,
4703
- options?.dryRun === true
4823
+ options?.dryRun === true,
4824
+ safeReplayInvocation(
4825
+ () => buildReplayInvocation(
4826
+ Object.entries(cliFlags(options) ?? explicitReplayOptions(options))
4827
+ )
4828
+ )
4704
4829
  );
4705
4830
  if (started.items.length === 0) {
4706
4831
  try {
@@ -5092,7 +5217,7 @@ async function writeReplayResultFile(result) {
5092
5217
  }
5093
5218
  }
5094
5219
  }
5095
- var REPLAY_PERSISTENCE_TIMEOUT_MS, MAX_REPLAY_ATTEMPTS, RESUME_CONFLICTING_OPTIONS, CARRIED_OVER_ERROR, BITFAB_PROGRESS_PREFIX, ReplayError, DbBranchReplayError, JUDGE_ASSERTIONS_DEPRECATION_WARNING;
5220
+ var REPLAY_PERSISTENCE_TIMEOUT_MS, MAX_REPLAY_ATTEMPTS, RESUME_CONFLICTING_OPTIONS, CARRIED_OVER_ERROR, REPLAY_OPTION_NAMES, BITFAB_PROGRESS_PREFIX, ReplayError, DbBranchReplayError, JUDGE_ASSERTIONS_DEPRECATION_WARNING;
5096
5221
  var init_replay = __esm({
5097
5222
  "src/replay.ts"() {
5098
5223
  "use strict";
@@ -5105,6 +5230,7 @@ var init_replay = __esm({
5105
5230
  init_replayContext();
5106
5231
  init_replayHeartbeat();
5107
5232
  init_replayInterrupt();
5233
+ init_replayInvocation();
5108
5234
  init_selectiveReplayRuntime();
5109
5235
  init_serialize();
5110
5236
  init_warnOnce();
@@ -5122,6 +5248,37 @@ var init_replay = __esm({
5122
5248
  "experimentalSelectiveReplay"
5123
5249
  ];
5124
5250
  CARRIED_OVER_ERROR = "This item errored in an earlier run of this experiment, before it was resumed.";
5251
+ REPLAY_OPTION_NAMES = [
5252
+ "experimentalSelectiveReplay",
5253
+ "limit",
5254
+ "attempts",
5255
+ "traceIds",
5256
+ "name",
5257
+ "notes",
5258
+ "metadata",
5259
+ "maxConcurrency",
5260
+ "codeChangeDescription",
5261
+ "codeChangeFiles",
5262
+ "mock",
5263
+ "mockOverride",
5264
+ "dbBranch",
5265
+ "experimentGroupId",
5266
+ "datasetId",
5267
+ "datasetIds",
5268
+ "graderIds",
5269
+ "onlyWithAssertions",
5270
+ "skipAssertionJudging",
5271
+ "judgeAssertions",
5272
+ "adaptInputs",
5273
+ "dryRun",
5274
+ "onItemFinish",
5275
+ "onProgress",
5276
+ "onItemStart",
5277
+ "onExperimentStart",
5278
+ "onInterrupt",
5279
+ "resume",
5280
+ "force"
5281
+ ];
5125
5282
  BITFAB_PROGRESS_PREFIX = "@@bitfab:progress ";
5126
5283
  ReplayError = class extends BitfabError {
5127
5284
  constructor(message, items, experimentId, experimentUrl, cause) {
@@ -6898,9 +7055,34 @@ var GradersClient = class {
6898
7055
  init_http();
6899
7056
 
6900
7057
  // src/labels.ts
7058
+ init_errors();
6901
7059
  init_http();
6902
7060
  var LABELS_PATH = "/api/sdk/traces/labels";
6903
7061
  var HUMAN_LABELS_PATH = "/api/sdk/traces/labels/human";
7062
+ function assertEveryVerdictNamesAnAssertion(updates) {
7063
+ const unscoped = updates.filter(
7064
+ (update) => !("archive" in update && update.archive === true) && (typeof update.assertionId !== "string" || update.assertionId === "")
7065
+ );
7066
+ if (unscoped.length > 0) {
7067
+ const targets = unscoped.map(
7068
+ (update) => update.traceId ?? update.originalTraceId
7069
+ );
7070
+ throw new BitfabError(
7071
+ `Agent verdicts must name an assertion: ${targets.join(", ")}. Pass the assertionId of the assertion each verdict scores to labels.save, saveAll, and skip. Only archive may omit it, to clear an old whole-trace verdict.`
7072
+ );
7073
+ }
7074
+ }
7075
+ function assertEveryHumanVerdictNamesAnAssertion(updates) {
7076
+ const unscoped = updates.filter(
7077
+ (update) => typeof update.assertionId !== "string" || update.assertionId === ""
7078
+ );
7079
+ if (unscoped.length > 0) {
7080
+ const targets = unscoped.map((update) => update.traceId);
7081
+ throw new BitfabError(
7082
+ `Human verdicts must name an assertion: ${targets.join(", ")}. Pass the assertionId of the assertion each verdict scores to labels.saveHuman and saveHumanAll.`
7083
+ );
7084
+ }
7085
+ }
6904
7086
  function labelEvidencePath(traceId, assertionId) {
6905
7087
  return `/api/sdk/traces/${encodeURIComponent(traceId)}/assertions/${encodeURIComponent(assertionId)}/evidence`;
6906
7088
  }
@@ -6913,6 +7095,7 @@ var LabelsClient = class {
6913
7095
  return outcome;
6914
7096
  }
6915
7097
  async saveAll(updates, experimentId) {
7098
+ assertEveryVerdictNamesAnAssertion(updates);
6916
7099
  const response = await this.httpClient.request(
6917
7100
  LABELS_PATH,
6918
7101
  {
@@ -6922,11 +7105,9 @@ var LabelsClient = class {
6922
7105
  );
6923
7106
  return response.labels;
6924
7107
  }
6925
- /** Withhold a verdict for a trace or replay attempt whose check did not run. */
6926
7108
  async skip(target, experimentId) {
6927
7109
  return this.save({ ...target, skip: true }, experimentId);
6928
7110
  }
6929
- /** Clear a previous verdict for a trace, replay attempt, or assertion. */
6930
7111
  async archive(target, experimentId) {
6931
7112
  return this.save({ ...target, archive: true }, experimentId);
6932
7113
  }
@@ -6935,6 +7116,7 @@ var LabelsClient = class {
6935
7116
  return outcome;
6936
7117
  }
6937
7118
  async saveHumanAll(updates) {
7119
+ assertEveryHumanVerdictNamesAnAssertion(updates);
6938
7120
  const response = await this.httpClient.request(HUMAN_LABELS_PATH, { labels: updates });
6939
7121
  return response.labels;
6940
7122
  }
@@ -11972,6 +12154,7 @@ init_replay();
11972
12154
  init_errors();
11973
12155
  init_replay();
11974
12156
  init_replayInterrupt();
12157
+ init_replayInvocation();
11975
12158
  init_warnOnce();
11976
12159
  function defineReplayRegistry(registry) {
11977
12160
  validateReplayRegistry(registry);