@ishlabs/cli 0.14.0 → 0.14.1

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.
@@ -21,6 +21,23 @@ function parseMaxInteractions(value) {
21
21
  throw new Error(`Invalid --max-interactions value: ${value}`);
22
22
  return n;
23
23
  }
24
+ /**
25
+ * Default cap the CLI sends when neither `--max-interactions` nor the
26
+ * iteration carries its own value. Picked to match the frontend's
27
+ * conservative interactive launchers and to prevent runaway spend when an
28
+ * iteration runs against a broken or non-responsive surface — without a
29
+ * cap, a stuck tester can rack up hundreds of steps before the SDK gives
30
+ * up.
31
+ */
32
+ const DEFAULT_MAX_INTERACTIONS = 20;
33
+ function resolveMaxInteractions(optsValue, iterationDetails) {
34
+ if (optsValue)
35
+ return parseMaxInteractions(optsValue);
36
+ if (typeof iterationDetails?.max_interactions === "number") {
37
+ return iterationDetails.max_interactions;
38
+ }
39
+ return DEFAULT_MAX_INTERACTIONS;
40
+ }
24
41
  function parseSlowMo(value) {
25
42
  const n = parseInt(value, 10);
26
43
  if (isNaN(n) || n < 0)
@@ -162,7 +179,7 @@ export function attachStudyRunCommands(study) {
162
179
  allFlagDescription: "Use every AI profile matching the filters (workspace-wide if no filters set)",
163
180
  })
164
181
  .option("--config <id>", "Simulation config ID (required for media unless every profile has one)")
165
- .option("--max-interactions <n>", "Max interactions per tester")
182
+ .option("--max-interactions <n>", `Max interactions per tester (interactive / media only). Precedence: flag > iteration's stored value > CLI default (${DEFAULT_MAX_INTERACTIONS}).`)
166
183
  .option("--max-turns <n>", "Max conversation turns per tester (chat studies only)")
167
184
  .option("--early-termination", "Allow chat agent to end the conversation early when goals are met (chat studies only)")
168
185
  .option("--language <lang>", "Language code (e.g. en, sv)")
@@ -208,6 +225,10 @@ Examples:
208
225
  # Override the simulation config (e.g. for a media study):
209
226
  $ ish study run --config c-c3c
210
227
 
228
+ # Cap interactions per tester (default 20 — pass higher to allow deeper
229
+ # exploration, lower to cap spend on a known-broken surface):
230
+ $ ish study run --max-interactions 30
231
+
211
232
  # Block until all simulations finish (or timeout):
212
233
  $ ish study run --wait
213
234
  $ ish study run --wait --timeout 600
@@ -499,11 +520,13 @@ Examples:
499
520
  }
500
521
  }
501
522
  else {
502
- const stepsForMedia = opts.maxInteractions
503
- ? parseMaxInteractions(opts.maxInteractions)
504
- : (typeof iteration.details?.max_interactions === "number"
505
- ? iteration.details.max_interactions
506
- : 30);
523
+ const stepsForMedia = resolveMaxInteractions(opts.maxInteractions, iteration.details);
524
+ const source = opts.maxInteractions
525
+ ? "from --max-interactions"
526
+ : typeof iteration.details?.max_interactions === "number"
527
+ ? "from iteration"
528
+ : `CLI default — pass --max-interactions to override`;
529
+ log(` Max steps: ${stepsForMedia} (${source})`);
507
530
  if (Number.isFinite(stepsForMedia)) {
508
531
  const est = estimateMediaRun({ testerCount, maxInteractions: stepsForMedia });
509
532
  log(` Credits (est): ≈ ${est.upper_bound} credit(s) upper bound — ${est.breakdown}`);
@@ -638,7 +661,7 @@ Examples:
638
661
  url: detailsView.url,
639
662
  screenFormat: detailsView.screenFormat,
640
663
  locale: detailsView.locale,
641
- maxInteractions: opts.maxInteractions ? parseMaxInteractions(opts.maxInteractions) : undefined,
664
+ maxInteractions: resolveMaxInteractions(opts.maxInteractions, iteration.details),
642
665
  headed: !!opts.headed,
643
666
  slowMo: opts.slowMo ? parseSlowMo(opts.slowMo) : undefined,
644
667
  devtools: opts.devtools,
@@ -758,7 +781,7 @@ Examples:
758
781
  const simResult = await dispatchAttempt(() => client.post("/simulation/media/start/batch", {
759
782
  product_id: resolvedWorkspace,
760
783
  simulations: mediaBatchItems,
761
- ...(opts.maxInteractions && { max_interactions: parseMaxInteractions(opts.maxInteractions) }),
784
+ max_interactions: resolveMaxInteractions(opts.maxInteractions, iteration.details),
762
785
  }, { timeout: dispatchTimeoutMs }));
763
786
  simResults = simResult.results;
764
787
  }
@@ -776,7 +799,7 @@ Examples:
776
799
  platform: detailsView.platform || "browser",
777
800
  ...(detailsView.url && { url: detailsView.url }),
778
801
  screen_format: detailsView.screenFormat || "desktop",
779
- ...(opts.maxInteractions && { max_interactions: parseMaxInteractions(opts.maxInteractions) }),
802
+ max_interactions: resolveMaxInteractions(opts.maxInteractions, iteration.details),
780
803
  }, { timeout: dispatchTimeoutMs }));
781
804
  simResults = simResult.results;
782
805
  }
@@ -843,11 +866,7 @@ Examples:
843
866
  return null;
844
867
  return estimateChatSolo({ testerCount, maxTurns: turns });
845
868
  }
846
- const steps = opts.maxInteractions
847
- ? parseMaxInteractions(opts.maxInteractions)
848
- : (typeof iteration.details?.max_interactions === "number"
849
- ? iteration.details.max_interactions
850
- : 30);
869
+ const steps = resolveMaxInteractions(opts.maxInteractions, iteration.details);
851
870
  if (!Number.isFinite(steps))
852
871
  return null;
853
872
  return estimateMediaRun({ testerCount, maxInteractions: steps });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ishlabs/cli",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "description": "The command-line interface for ish",
5
5
  "type": "module",
6
6
  "bin": {