@getmagical/cli 0.9.1 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,6 +28,31 @@ mgcl automations run-draft --draft-automation-id ... --agent-id ... --idempotenc
28
28
  mgcl automations publish --draft-automation-id ... # non-production only: mgcl refuses against the production API, and the API rejects it too
29
29
  ```
30
30
 
31
+ ## Regression tests
32
+
33
+ Choose how many historical baseline runs to test per pathway:
34
+
35
+ ```bash
36
+ mgcl regression run \
37
+ --automation-version <automation-version-id> \
38
+ --agent-version <agent-version-id> \
39
+ --runs-per-path 5 \
40
+ --json
41
+ ```
42
+
43
+ `--runs-per-path` accepts integers from 1 to 20 and defaults to 2. This is an
44
+ upper limit: pathways with fewer eligible historical runs use the available
45
+ runs. Each selected baseline gets 30 replay attempts by default, so five
46
+ baselines produce up to 150 attempts per pathway.
47
+
48
+ The count applies only when creating a regression test. Repeating the command
49
+ for the same automation and agent version pair returns the existing test;
50
+ changing the count does not expand or rerun it.
51
+
52
+ `mgcl pathway-regression preview --runs-per-path <count>` remains a historical
53
+ coverage lookup, accepting 1–50 with a default of 2. It does not configure a
54
+ later regression test.
55
+
31
56
  ## Typed classification
32
57
 
33
58
  Use `mgcl classify` for focused typed judgments over context you already have.
package/dist/index.js CHANGED
@@ -7889,6 +7889,53 @@ function safeJsonParseWithoutLogging(json) {
7889
7889
  }
7890
7890
  }
7891
7891
 
7892
+ // ../common/dist/src/constants/agent-node-presets.js
7893
+ var AGENT_NODE_PRESET_TYPES = {
7894
+ minimal: "minimal",
7895
+ browser: "browser",
7896
+ desktop: "desktop",
7897
+ voice: "voice"
7898
+ };
7899
+ var agentNodePresetOrder = [
7900
+ AGENT_NODE_PRESET_TYPES.minimal,
7901
+ AGENT_NODE_PRESET_TYPES.browser,
7902
+ AGENT_NODE_PRESET_TYPES.desktop,
7903
+ AGENT_NODE_PRESET_TYPES.voice
7904
+ ];
7905
+ var presetToEnvironmentMap = {
7906
+ [AGENT_NODE_PRESET_TYPES.minimal]: ["minimal"],
7907
+ [AGENT_NODE_PRESET_TYPES.browser]: ["browser", "browserCoordinates"],
7908
+ [AGENT_NODE_PRESET_TYPES.desktop]: ["desktop", "desktopApp"],
7909
+ [AGENT_NODE_PRESET_TYPES.voice]: ["voice"]
7910
+ };
7911
+ var environmentToPresetMap = {
7912
+ minimal: AGENT_NODE_PRESET_TYPES.minimal,
7913
+ browser: AGENT_NODE_PRESET_TYPES.browser,
7914
+ browserCoordinates: AGENT_NODE_PRESET_TYPES.browser,
7915
+ desktop: AGENT_NODE_PRESET_TYPES.desktop,
7916
+ desktopApp: AGENT_NODE_PRESET_TYPES.desktop,
7917
+ voice: AGENT_NODE_PRESET_TYPES.voice
7918
+ };
7919
+
7920
+ // ../common/dist/src/constants/agents.js
7921
+ var defaultAgentNamesByType = {
7922
+ trigger: "Trigger Agent",
7923
+ worker: "Worker Agent",
7924
+ specialist: "Specialist Agent",
7925
+ asset: "Library Asset",
7926
+ code: "Code Agent",
7927
+ extract: "Extract Agent",
7928
+ branch: "Decision Agent",
7929
+ api: "API Agent",
7930
+ specialized: "Specialized Agent",
7931
+ [AGENT_NODE_PRESET_TYPES.minimal]: "Orchestrate Agent",
7932
+ [AGENT_NODE_PRESET_TYPES.browser]: "Browser Agent",
7933
+ [AGENT_NODE_PRESET_TYPES.desktop]: "Desktop Agent",
7934
+ [AGENT_NODE_PRESET_TYPES.voice]: "Voice Agent"
7935
+ };
7936
+ var PATHWAY_REGRESSION_RUNS_PER_PATH_DEFAULT = 2;
7937
+ var PATHWAY_REGRESSION_MAX_RUNS_PER_PATH = 20;
7938
+
7892
7939
  // ../common/dist/src/constants/automation.js
7893
7940
  var AUTOMATION_BRANCH_NAME_MAX_LENGTH = 100;
7894
7941
  var AUTOMATION_BRANCH_NAME_MAX_LENGTH_MESSAGE = `Branch name must be ${AUTOMATION_BRANCH_NAME_MAX_LENGTH} characters or fewer.`;
@@ -13232,7 +13279,7 @@ var magicalBaseModels = [
13232
13279
  ];
13233
13280
  var DEFAULT_MODEL = "gemini-2.5-flash";
13234
13281
  var modelOptionsSchema = z11.object({
13235
- reasoningEffort: z11.enum(["low", "medium", "high", "xhigh"]).optional().describe("Reasoning effort level for models that support it. Higher effort may produce better results but takes longer. The xhigh level is available on supported OpenAI models."),
13282
+ reasoningEffort: z11.enum(["low", "medium", "high", "xhigh", "max"]).optional().describe("Reasoning effort level for models that support it. Higher effort may produce better results but takes longer. The xhigh and max levels are available on supported OpenAI models."),
13236
13283
  temperature: z11.number().min(0).max(2).optional().describe("Controls randomness in model output. 0 is deterministic, higher values (up to 2) increase creativity and randomness."),
13237
13284
  timeoutMs: z11.number().int().min(1).optional().describe("Maximum time to wait for an LLM provider request before failing through the normal result path.")
13238
13285
  });
@@ -14066,6 +14113,15 @@ var baseToolDeclarations = {
14066
14113
  ...reportStopDataSchema.shape
14067
14114
  })
14068
14115
  },
14116
+ handOff: {
14117
+ id: "handOff",
14118
+ description: "Hand off this work item to another root agent of the same automation and end this run.",
14119
+ parameters: z16.object({
14120
+ [COMMON_PARAMETERS_KEY]: DEFAULT_COMMON_PARAMETERS,
14121
+ agentId: z16.string(),
14122
+ input: z16.record(z16.string(), z16.unknown()).optional()
14123
+ })
14124
+ },
14069
14125
  terminateRun: {
14070
14126
  id: "terminateRun",
14071
14127
  description: "End the whole run early using a configured termination code. This stops every agent in the run, not just the current one, and marks the run as early-terminated.",
@@ -15256,6 +15312,7 @@ var baseAgentConfigFieldsSchema = z25.object({
15256
15312
  taskQueue: z25.string().optional().describe("Temporal task queue name for this agent. If specified, queued child agents run on this queue instead of the parent queue."),
15257
15313
  waitUponQueueing: z25.boolean().optional().default(false).describe("If true, wait for queued child agents to complete before proceeding."),
15258
15314
  queueableAgentIds: z25.array(brandedStringValidator("agentId")).optional().default(() => []).describe("List of agent IDs that this agent can queue using the queueAgents tool. Enables the agent to run a new automation with a different agent as the starting point."),
15315
+ handOffAgentIds: z25.array(brandedStringValidator("agentId")).optional().describe("Other root agents in this automation that can receive this agent\u2019s work item through handOff. Requires root agent handoff to be enabled; targets always use the latest version."),
15259
15316
  callableAgentIds: z25.array(brandedStringValidator("agentId")).optional().describe("List of external root agent IDs that this agent can call using the callSpecializedAgent tool. Same-automation callable agents continue to be configured by graph connections."),
15260
15317
  queuedAgentVariables: z25.record(brandedStringValidator("agentId"), z25.record(z25.string(), z25.unknown())).optional().describe("Static automation variable values to pass when this agent queues another automation by target agent ID."),
15261
15318
  checkpoint: z25.object({
@@ -15266,7 +15323,7 @@ var baseAgentConfigFieldsSchema = z25.object({
15266
15323
  additionalSystemPrompt: z25.string().optional().describe("Additional instructions appended to the system prompt for this agent. Combined with automation-level additionalSystemPrompt."),
15267
15324
  // Backlinking metadata for imported agents
15268
15325
  importedFrom: z25.object({
15269
- automationId: brandedStringValidator("draftAutomationId").describe("ID of the source automation from which this agent was imported."),
15326
+ automationId: brandedStringValidator("automationId").describe("ID of the source automation from which this agent was imported."),
15270
15327
  originalAgentId: brandedStringValidator("agentId").describe("Original agent ID in the source automation.")
15271
15328
  }).optional().describe("Metadata for agents imported from another automation. Used for traceability and updates."),
15272
15329
  ignoreUnstableSessionState: z25.boolean().optional().describe("When true, skips screenshot consistency checks before tool execution. Overrides the automation-level ignoreUnstableSessionState setting."),
@@ -15340,10 +15397,11 @@ var OutcomePayloadSchema = z25.object({
15340
15397
  input: z25.record(z25.string(), z25.unknown()).describe("Input data for the outcome. Maps parameter keys to values."),
15341
15398
  preview: z25.string().describe("Rendered text representation of the outcome.")
15342
15399
  });
15400
+ var decisionIncludeScreenshotDescription = "Requires screenshot context from the calling agent. Every way this Decision can be invoked must provide one.";
15343
15401
  var branchAgentConfigSchema = baseAgentConfigFieldsSchema.safeExtend({
15344
15402
  type: z25.literal("branch").describe("Decision agent type - makes decisions to route to different agents."),
15345
15403
  model: agentModelConfigSchema.describe("LLM model configuration for this decision agent."),
15346
- includeScreenshot: z25.boolean().optional().describe("Whether to include the previous agent's screen state in this decision agent's decision context."),
15404
+ includeScreenshot: z25.boolean().optional().describe(decisionIncludeScreenshotDescription),
15347
15405
  conditionsAndOutcomes: z25.object({
15348
15406
  if: z25.array(z25.object({
15349
15407
  caseName: z25.string().describe("Name of the condition case."),
@@ -15356,7 +15414,7 @@ var branchAgentConfigSchema = baseAgentConfigFieldsSchema.safeExtend({
15356
15414
  var draftBranchAgentConfigSchema = baseAgentConfigFieldsSchema.safeExtend({
15357
15415
  type: z25.literal("branch").describe("Decision agent draft configuration. Allows incomplete conditions and outcomes while the agent is still being authored."),
15358
15416
  model: agentModelConfigSchema.describe("LLM model configuration for this decision agent."),
15359
- includeScreenshot: z25.boolean().optional().describe("Whether to include the previous agent's screen state in this decision agent's decision context."),
15417
+ includeScreenshot: z25.boolean().optional().describe(decisionIncludeScreenshotDescription),
15360
15418
  conditionsAndOutcomes: z25.object({
15361
15419
  if: z25.array(z25.object({
15362
15420
  caseName: z25.string().describe("Name of the condition case."),
@@ -15589,6 +15647,13 @@ var automationRunConfigBaseSchema = z27.object({
15589
15647
  captureActions: z27.boolean().default(false).describe("When true, attach an action recording while a draft run is paused in takeover mode."),
15590
15648
  runDraftQueuedAgents: z27.boolean().optional().describe("Draft-run-only option. When false, queue-agent actions in the draft run report success without starting downstream queued draft child runs. Omit or true preserves queueing."),
15591
15649
  allowPointOfNoReturnOverride: z27.boolean().optional().describe("Internal rerun authorization. When true, the rerun and its queued descendants may proceed past a point-of-no-return crossing owned by an earlier run."),
15650
+ rootAgentHandoffEnabled: z27.literal(true).optional().describe("Infrastructure-owned capability captured when a work-item-backed run is created. Only these runs can hand off to another root agent."),
15651
+ rootAgentHandoff: z27.object({
15652
+ automationBranchId: z27.uuid().optional().describe("Draft branch captured at run creation. Draft handoffs resolve the current head of this branch."),
15653
+ sourceAutomationRunId: z27.uuid().optional().describe("Predecessor run for an admitted handoff. This run executes the latest version resolved at admission."),
15654
+ successorAutomationRunId: z27.uuid().optional().describe("Accepted handoff receipt. The source can no longer mutate the shared Store once this is recorded."),
15655
+ stopRequestedAt: z27.iso.datetime().optional().describe("Time a stop request was recorded, preventing subsequent handoff admission.")
15656
+ }).optional().describe("Infrastructure-owned durable handoff receipt and stop-intent fence. Updated only while holding the source run lock."),
15592
15657
  pointOfNoReturnGateEnabled: z27.literal(true).optional().describe("Infrastructure-owned rollout marker. PONR is enforced only for run trees created after the gate rollout."),
15593
15658
  sla: automationRunSlaSchema.optional(),
15594
15659
  networkTrafficCapture: networkTrafficCaptureSchema.optional(),
@@ -15622,7 +15687,9 @@ var automationRunStartConfigSchema = automationRunConfigBaseSchema.omit({
15622
15687
  queueResourcePools: true,
15623
15688
  resolvedRunSettings: true,
15624
15689
  resolvedRunSettingsSource: true,
15625
- pointOfNoReturnGateEnabled: true
15690
+ pointOfNoReturnGateEnabled: true,
15691
+ rootAgentHandoffEnabled: true,
15692
+ rootAgentHandoff: true
15626
15693
  }).extend({
15627
15694
  networkTrafficCapture: networkTrafficCaptureSchema.nullable().optional().describe("Network traffic capture preference for this run. Omit to apply the implicit recording policy, pass null to explicitly disable capture, or pass a record/replay config to explicitly enable capture.")
15628
15695
  });
@@ -20700,7 +20767,7 @@ ${evalRunExportSelection}
20700
20767
  ];
20701
20768
 
20702
20769
  // src/program.ts
20703
- import { Command as Command6, InvalidArgumentError as InvalidArgumentError2, Option as Option7 } from "commander";
20770
+ import { Command as Command6, InvalidArgumentError as InvalidArgumentError3, Option as Option7 } from "commander";
20704
20771
 
20705
20772
  // src/api.ts
20706
20773
  import { randomUUID } from "node:crypto";
@@ -22145,8 +22212,12 @@ function createMagicalApiClient({
22145
22212
  agentVersionId,
22146
22213
  automationVersionId,
22147
22214
  impersonatedOrganizationId,
22148
- organizationId
22215
+ organizationId,
22216
+ runsPerPath
22149
22217
  }) {
22218
+ const query = new URLSearchParams(
22219
+ runsPerPath === void 0 ? {} : { runsPerPath: String(runsPerPath) }
22220
+ );
22150
22221
  const parsedResponse = regressionTestKickoffResponseSchema.safeParse(
22151
22222
  await fetchJson({
22152
22223
  accessToken,
@@ -22155,7 +22226,7 @@ function createMagicalApiClient({
22155
22226
  ...organizationId ? { organizationId } : {},
22156
22227
  path: `/pathway-regression/tests/automation-versions/${encodeURIComponent(
22157
22228
  automationVersionId
22158
- )}/agent-versions/${encodeURIComponent(agentVersionId)}/run`,
22229
+ )}/agent-versions/${encodeURIComponent(agentVersionId)}/run${query.size > 0 ? `?${query.toString()}` : ""}`,
22159
22230
  init: {
22160
22231
  method: "POST"
22161
22232
  }
@@ -27943,14 +28014,14 @@ async function prepareFileUpload(inputPath, workingDirectory) {
27943
28014
  );
27944
28015
  }
27945
28016
  const checksum = await (async () => {
27946
- let value = 0;
28017
+ let value = void 0;
27947
28018
  for await (const chunk of createReadStream2(filePath)) {
27948
28019
  if (!(chunk instanceof Uint8Array)) {
27949
28020
  throw new CliError("Upload file stream returned invalid bytes.");
27950
28021
  }
27951
28022
  value = updateS3Crc32Checksum(chunk, value);
27952
28023
  }
27953
- return value;
28024
+ return value ?? updateS3Crc32Checksum(new Uint8Array());
27954
28025
  })().catch((error) => {
27955
28026
  throw new CliError(`Failed to checksum upload file "${filePath}".`, {
27956
28027
  cause: error
@@ -28977,7 +29048,7 @@ var SESSION_ONLY_API_KEY_MANAGEMENT_COMMANDS = /* @__PURE__ */ new Set([
28977
29048
 
28978
29049
  // src/regression-commands.ts
28979
29050
  import { setTimeout as sleep } from "node:timers/promises";
28980
- import { Command as Command4, Option as Option4 } from "commander";
29051
+ import { Command as Command4, InvalidArgumentError as InvalidArgumentError2, Option as Option4 } from "commander";
28981
29052
  var REGRESSION_TEST_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
28982
29053
  "matched",
28983
29054
  "deviated",
@@ -29104,7 +29175,8 @@ async function handleRegressionRunCommand({
29104
29175
  input: {
29105
29176
  ...authParams,
29106
29177
  agentVersionId: options.agentVersion,
29107
- automationVersionId: options.automationVersion
29178
+ automationVersionId: options.automationVersion,
29179
+ ...options.runsPerPath === void 0 ? {} : { runsPerPath: options.runsPerPath }
29108
29180
  },
29109
29181
  startRegressionTest: startAgentVersionRegressionTest
29110
29182
  });
@@ -29191,6 +29263,7 @@ function addRegressionCommands({
29191
29263
  `
29192
29264
  ${formatExamples("Examples", [
29193
29265
  "mgcl regression run --automation-version <id> --agent-version <id>",
29266
+ "mgcl regression run --automation-version <id> --agent-version <id> --runs-per-path 5",
29194
29267
  "mgcl regression show <testId>",
29195
29268
  "mgcl regression show <testId> --pathway <pathwayId>"
29196
29269
  ])}`
@@ -29209,6 +29282,19 @@ ${formatExamples("Examples", [
29209
29282
  ).helpGroup("Regression options:").makeOptionMandatory(true)
29210
29283
  ).addOption(
29211
29284
  new Option4("--agent-version <id>", "Agent version to test.").helpGroup("Regression options:").makeOptionMandatory(true)
29285
+ ).addOption(
29286
+ new Option4(
29287
+ "--runs-per-path <count>",
29288
+ `Maximum historical baseline runs per pathway (1\u2013${PATHWAY_REGRESSION_MAX_RUNS_PER_PATH}; default: ${PATHWAY_REGRESSION_RUNS_PER_PATH_DEFAULT}). Applies only to new tests; existing tests are reused unchanged.`
29289
+ ).helpGroup("Regression options:").argParser((rawValue) => {
29290
+ const count = Number(rawValue);
29291
+ if (!Number.isInteger(count) || count < 1 || count > PATHWAY_REGRESSION_MAX_RUNS_PER_PATH) {
29292
+ throw new InvalidArgumentError2(
29293
+ `Expected an integer from 1 to ${PATHWAY_REGRESSION_MAX_RUNS_PER_PATH}.`
29294
+ );
29295
+ }
29296
+ return count;
29297
+ })
29212
29298
  ).action(async function() {
29213
29299
  await handleRegressionRunCommand({
29214
29300
  dependencies,
@@ -31053,7 +31139,7 @@ function parseCommandOptionValue(rawValue, optionSpec) {
31053
31139
  case "number": {
31054
31140
  const parsedNumber = Number(rawValue);
31055
31141
  if (Number.isNaN(parsedNumber)) {
31056
- throw new InvalidArgumentError2(
31142
+ throw new InvalidArgumentError3(
31057
31143
  `Expected a number for --${optionSpec.flagName}.`
31058
31144
  );
31059
31145
  }
@@ -31065,7 +31151,7 @@ function parseCommandOptionValue(rawValue, optionSpec) {
31065
31151
  case "json": {
31066
31152
  const parsedJson = safeJsonParse(rawValue);
31067
31153
  if (isErr(parsedJson)) {
31068
- throw new InvalidArgumentError2(
31154
+ throw new InvalidArgumentError3(
31069
31155
  `Expected valid JSON for --${optionSpec.flagName}.`
31070
31156
  );
31071
31157
  }
@@ -31098,7 +31184,7 @@ function createCliCommanderOption(optionSpec, helpGroup) {
31098
31184
  function parsePositiveIntegerOption(rawValue) {
31099
31185
  const parsedValue = Number(rawValue);
31100
31186
  if (!Number.isInteger(parsedValue) || parsedValue < 1) {
31101
- throw new InvalidArgumentError2("Expected a positive integer.");
31187
+ throw new InvalidArgumentError3("Expected a positive integer.");
31102
31188
  }
31103
31189
  return parsedValue;
31104
31190
  }