@midscene/test 1.12.10-beta-20260920031616.0 → 1.13.0

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.
@@ -1,96 +1,9 @@
1
- import { aiActInputSchema, aiActOptionsInputSchema, aiAssertInputSchema, aiAssertOptionsInputSchema, aiTapInputSchema, insightInputSchema, insightOptionsInputSchema, locateOptionsInputSchema, promptImageInputSchema, recordToReportInputSchema, recordToReportOptionsInputSchema, reportScreenshotInputSchema, structuredUserPromptInputSchema, userPromptInputSchema } from "@midscene/core/agent/test";
1
+ import { actionInputSchema, aiActInputSchema, aiActOptionsInputSchema, aiAssertInputSchema, aiAssertOptionsInputSchema, aiDragAndDropInputSchema, aiInputInputSchema, aiKeyboardPressInputSchema, aiLongPressInputSchema, aiPinchInputSchema, aiQueryInputSchema, aiScrollInputSchema, aiTapInputSchema, aiWaitForInputSchema, insightInputSchema, insightOptionsInputSchema, javascriptInputSchema, locateOptionsInputSchema, promptImageInputSchema, recordToReportInputSchema, recordToReportOptionsInputSchema, reportScreenshotInputSchema, runGherkinScenarioInputSchema, structuredUserPromptInputSchema, userPromptInputSchema } from "@midscene/core/agent/test";
2
+ import { NodeDefinitionError, assertResourceAvailable, defineNode, trackResourceOperation } from "@midscene/core/internal/test-runner";
3
+ import { enterYamlAction, enterYamlExecution, runInYamlExecutionContext } from "@midscene/core/internal/yaml-runtime";
2
4
  import { getDebug } from "@midscene/shared/logger";
3
5
  import { z } from "zod/v4";
4
- function _define_property(obj, key, value) {
5
- if (key in obj) Object.defineProperty(obj, key, {
6
- value: value,
7
- enumerable: true,
8
- configurable: true,
9
- writable: true
10
- });
11
- else obj[key] = value;
12
- return obj;
13
- }
14
- class WorkflowError extends Error {
15
- toJSON() {
16
- return {
17
- name: this.name,
18
- message: this.message,
19
- code: this.code,
20
- ...void 0 === this.details ? {} : {
21
- details: this.details
22
- }
23
- };
24
- }
25
- constructor(message, options = {}){
26
- super(message, {
27
- cause: options.cause
28
- }), _define_property(this, "code", void 0), _define_property(this, "details", void 0);
29
- this.name = new.target.name;
30
- this.code = options.code ?? 'WORKFLOW_ERROR';
31
- this.details = options.details;
32
- }
33
- }
34
- class NodeDefinitionError extends WorkflowError {
35
- constructor(message, details){
36
- super(message, {
37
- code: 'NODE_DEFINITION_ERROR',
38
- details
39
- });
40
- }
41
- }
42
- class NodeExecutionError extends WorkflowError {
43
- constructor(node, cause){
44
- const causeMessage = cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');
45
- super(`Node "${node}" failed: ${causeMessage}`, {
46
- code: 'NODE_EXECUTION_ERROR',
47
- details: {
48
- node
49
- },
50
- cause
51
- }), _define_property(this, "node", void 0);
52
- this.node = node;
53
- }
54
- }
55
- const validateOptionalText = (value, field, node)=>{
56
- if (void 0 !== value && ('string' != typeof value || 0 === value.trim().length)) throw new NodeDefinitionError(`Node "${node}" ${field} must be a non-empty string.`, {
57
- node,
58
- field
59
- });
60
- };
61
- const validateInputSchema = (schema, node)=>{
62
- if (void 0 === schema) return;
63
- if (!(schema instanceof z.ZodObject)) throw new NodeDefinitionError(`Node "${node}" inputSchema must be a Zod object schema.`, {
64
- node,
65
- field: 'inputSchema'
66
- });
67
- if ('$' in schema.shape) throw new NodeDefinitionError(`Node "${node}" inputSchema must not declare "$" as an input property.`, {
68
- node,
69
- field: 'inputSchema.$'
70
- });
71
- };
72
- const validateDefinition = (options)=>{
73
- if (!options || 'object' != typeof options) throw new NodeDefinitionError('Node definition must be an object.');
74
- if ('string' != typeof options.name || 0 === options.name.trim().length) throw new NodeDefinitionError('Node name must be a non-empty string.');
75
- validateOptionalText(options.title, 'title', options.name);
76
- validateOptionalText(options.description, "description", options.name);
77
- if (void 0 !== options.stringInputKey && false !== options.stringInputKey && ('string' != typeof options.stringInputKey || 0 === options.stringInputKey.trim().length)) throw new NodeDefinitionError(`Node "${options.name}" stringInputKey must be a non-empty string or false.`, {
78
- node: options.name,
79
- field: 'stringInputKey'
80
- });
81
- validateInputSchema(options.inputSchema, options.name);
82
- if ('string' == typeof options.stringInputKey && options.inputSchema instanceof z.ZodObject && !(options.stringInputKey in options.inputSchema.shape)) throw new NodeDefinitionError(`Node "${options.name}" stringInputKey must reference a field in inputSchema.`, {
83
- node: options.name,
84
- field: 'stringInputKey'
85
- });
86
- if ('function' != typeof options.execute) throw new NodeDefinitionError(`Node "${options.name}" must provide an execute function.`, {
87
- node: options.name
88
- });
89
- };
90
- function defineNode(options) {
91
- validateDefinition(options);
92
- return options;
93
- }
6
+ const define_node_defineNode = defineNode;
94
7
  const waitInputSchema = z.strictObject({
95
8
  duration: z.number().positive().describe('How long to wait.'),
96
9
  unit: z["enum"]([
@@ -116,64 +29,49 @@ const waitFor = async (durationMs, signal)=>{
116
29
  });
117
30
  };
118
31
  const createAgentTestRunnerNodes = (definitions, getAgent)=>{
119
- const activeAgentCalls = new WeakMap();
120
- const runAgentCall = async (node, execution, agent, call, captureExecutions = true)=>{
121
- execution.signal.throwIfAborted();
122
- const scopeId = 'case' === execution.scope ? execution.case.runId : execution.document.documentRunId;
123
- const activeCall = activeAgentCalls.get(agent);
124
- if (activeCall) throw new NodeExecutionError(node, new Error(`The same Agent instance cannot execute overlapping Midscene Test Steps. Active scope: ${activeCall.scopeId} (${activeCall.node}); requested scope: ${scopeId} (${node}).`));
125
- const currentCall = {
126
- scopeId,
127
- node
128
- };
129
- activeAgentCalls.set(agent, currentCall);
130
- const releaseCall = ()=>{
131
- if (activeAgentCalls.get(agent) === currentCall) activeAgentCalls.delete(agent);
132
- };
133
- let removeListener;
134
- let sawExecutionWithoutId = false;
135
- const stopListening = ()=>{
136
- const remove = removeListener;
137
- removeListener = void 0;
138
- remove?.();
139
- };
140
- const stopListeningOnAbort = ()=>{
32
+ const runAgentCall = async (node, ctx, agent, call, captureExecutions = true)=>runInYamlExecutionContext(async ()=>{
33
+ const scopeId = 'case' === ctx.scope ? ctx.case.runId : ctx.document.documentRunId;
34
+ const isCleanupOwner = assertResourceAvailable(agent, true, ctx.signal);
35
+ const yamlBoundary = enterYamlExecution(agent, {
36
+ allowIndependentOverlap: isCleanupOwner
37
+ });
38
+ const leaveYamlAction = enterYamlAction(agent, ctx.signal);
39
+ let removeListener;
40
+ let sawExecutionWithoutId = false;
41
+ const stopListening = ()=>{
42
+ const remove = removeListener;
43
+ removeListener = void 0;
44
+ remove?.();
45
+ };
46
+ const stopListeningOnAbort = ()=>stopListening();
141
47
  try {
142
- stopListening();
143
- } finally{
144
- releaseCall();
145
- }
146
- };
147
- execution.signal.addEventListener('abort', stopListeningOnAbort, {
148
- once: true
149
- });
150
- try {
151
- if (captureExecutions && agent.addDumpUpdateListener) {
152
- removeListener = agent.addDumpUpdateListener((_dump, executionRef)=>{
153
- if (!executionRef) return;
154
- if (!executionRef.id) {
155
- sawExecutionWithoutId = true;
156
- return;
157
- }
158
- execution.report.addTrace({
159
- type: 'midscene-execution',
160
- executionId: executionRef.id
48
+ if (captureExecutions && agent.addDumpUpdateListener) {
49
+ removeListener = agent.addDumpUpdateListener((_dump, execution)=>{
50
+ if (!execution) return;
51
+ if (!execution.id) {
52
+ sawExecutionWithoutId = true;
53
+ return;
54
+ }
55
+ ctx.report.addTrace({
56
+ type: 'midscene-execution',
57
+ executionId: execution.id
58
+ });
161
59
  });
162
- });
163
- if (execution.signal.aborted) stopListening();
164
- }
165
- return await call();
166
- } finally{
167
- execution.signal.removeEventListener('abort', stopListeningOnAbort);
168
- try {
169
- stopListening();
60
+ if (ctx.signal.aborted) stopListening();
61
+ else ctx.signal.addEventListener('abort', stopListeningOnAbort, {
62
+ once: true
63
+ });
64
+ }
65
+ return await trackResourceOperation(agent, Promise.resolve().then(call), ctx.signal);
170
66
  } finally{
171
- releaseCall();
67
+ leaveYamlAction();
68
+ yamlBoundary.finish();
69
+ ctx.signal.removeEventListener('abort', stopListeningOnAbort);
70
+ stopListening();
71
+ if (sawExecutionWithoutId) warnReportTrace(`Skipped a report trace without a stable execution id for ${node} in scope ${scopeId}.`);
172
72
  }
173
- if (sawExecutionWithoutId) warnReportTrace(`Skipped a report trace without a stable execution id for ${node} in scope ${scopeId}.`);
174
- }
175
- };
176
- return definitions.map((definition)=>defineNode({
73
+ });
74
+ return definitions.map((definition)=>define_node_defineNode({
177
75
  name: definition.name,
178
76
  ...void 0 === definition.title ? {} : {
179
77
  title: definition.title
@@ -185,13 +83,14 @@ const createAgentTestRunnerNodes = (definitions, getAgent)=>{
185
83
  stringInputKey: definition.stringInputKey
186
84
  },
187
85
  inputSchema: definition.inputSchema,
188
- async execute (execution) {
189
- const agent = await getAgent(execution);
190
- const call = async ()=>definition.execute(agent, execution.input, {
191
- signal: execution.signal
86
+ async execute (ctx) {
87
+ const agent = await getAgent(ctx);
88
+ ctx.signal.throwIfAborted();
89
+ const call = async ()=>definition.execute(agent, ctx.input, {
90
+ signal: ctx.signal
192
91
  });
193
92
  if ('object' != typeof agent || null === agent) return call();
194
- return runAgentCall(definition.name, execution, agent, call);
93
+ return runAgentCall(definition.name, ctx, agent, call);
195
94
  }
196
95
  }));
197
96
  };
@@ -202,32 +101,58 @@ function createMidsceneNodes(options) {
202
101
  if (!options || 'object' != typeof options) throw new NodeDefinitionError('createMidsceneNodes() options must be an object.');
203
102
  if ('function' != typeof options.agentProvider?.getAgent && 'function' != typeof options.getAgent) throw new NodeDefinitionError('createMidsceneNodes() requires getAgent or agentProvider.getAgent.');
204
103
  if (!options.agentClass || 'function' != typeof options.agentClass.getTestRunnerNodeDefinitions) throw new NodeDefinitionError('createMidsceneNodes() requires agentClass.getTestRunnerNodeDefinitions().');
205
- const registeredAgentScopes = new Set();
206
- const getExecutionId = (execution)=>'case' === execution.scope ? execution.case.runId : execution.document.documentRunId;
207
- const getAgent = async (execution)=>{
208
- if (!options.agentProvider) return options.getAgent(execution);
209
- const runId = getExecutionId(execution);
210
- if (options.agentProvider.releaseAgent && !registeredAgentScopes.has(runId)) {
211
- registeredAgentScopes.add(runId);
212
- execution.onTeardown(async ()=>{
104
+ const agentsByScope = new Map();
105
+ const getAgent = async (ctx)=>{
106
+ const runId = 'case' === ctx.scope ? ctx.case.runId : ctx.document.documentRunId;
107
+ let agents = agentsByScope.get(runId);
108
+ if (!agents) {
109
+ agents = new Set();
110
+ agentsByScope.set(runId, agents);
111
+ const ownedScope = agents;
112
+ ctx.onTeardown(async ()=>{
113
+ const errors = [];
114
+ const reportPaths = [];
115
+ const reportSources = [];
213
116
  try {
214
- const released = await options.agentProvider.releaseAgent(runId);
215
- return released?.reportPath ? {
216
- reportPaths: [
217
- released.reportPath
218
- ]
219
- } : void 0;
117
+ for (const agent of ownedScope)try {
118
+ const path = await agent.flushReport?.();
119
+ if (path) reportPaths.push(path);
120
+ const source = await agent._createReportSource?.(runId);
121
+ if (source) reportSources.push(source);
122
+ } catch (error) {
123
+ errors.push(error);
124
+ }
125
+ try {
126
+ const released = await options.agentProvider?.releaseAgent?.(runId);
127
+ if (released?.reportPath && !reportPaths.includes(released.reportPath)) reportPaths.push(released.reportPath);
128
+ } catch (error) {
129
+ errors.push(error);
130
+ }
131
+ if (1 === errors.length) throw errors[0];
132
+ if (errors.length) throw new AggregateError(errors, 'Agent report publication and release failed');
133
+ return {
134
+ reportPaths,
135
+ ...reportSources.length ? {
136
+ reportSources
137
+ } : {}
138
+ };
220
139
  } finally{
221
- registeredAgentScopes.delete(runId);
140
+ agentsByScope.delete(runId);
222
141
  }
223
142
  });
224
143
  }
225
- return options.agentProvider.getAgent(runId, execution);
144
+ const scopeAgents = agents;
145
+ return trackResourceOperation({}, Promise.resolve().then(async ()=>{
146
+ const agent = options.agentProvider ? await options.agentProvider.getAgent(runId, ctx) : await options.getAgent(ctx);
147
+ agent._prepareForTestRunner?.();
148
+ scopeAgents.add(agent);
149
+ return agent;
150
+ }), ctx.signal);
226
151
  };
227
152
  const agentDefinitions = options.agentClass.getTestRunnerNodeDefinitions();
228
153
  return [
229
154
  ...createAgentTestRunnerNodes(agentDefinitions, getAgent),
230
- defineNode({
155
+ define_node_defineNode({
231
156
  name: 'wait',
232
157
  description: 'Wait for a fixed duration while honoring cancellation.',
233
158
  stringInputKey: false,
@@ -243,6 +168,6 @@ function createMidsceneNodes(options) {
243
168
  })
244
169
  ];
245
170
  }
246
- export { aiActInputSchema, aiActOptionsInputSchema, aiAssertInputSchema, aiAssertOptionsInputSchema, aiTapInputSchema, createAgentTestRunnerNodes, createMidsceneNodes, insightInputSchema, insightOptionsInputSchema, locateOptionsInputSchema, promptImageInputSchema, recordToReportInputSchema, recordToReportOptionsInputSchema, reportScreenshotInputSchema, structuredUserPromptInputSchema, userPromptInputSchema, waitInputSchema };
171
+ export { actionInputSchema, aiActInputSchema, aiActOptionsInputSchema, aiAssertInputSchema, aiAssertOptionsInputSchema, aiDragAndDropInputSchema, aiInputInputSchema, aiKeyboardPressInputSchema, aiLongPressInputSchema, aiPinchInputSchema, aiQueryInputSchema, aiScrollInputSchema, aiTapInputSchema, aiWaitForInputSchema, createAgentTestRunnerNodes, createMidsceneNodes, insightInputSchema, insightOptionsInputSchema, javascriptInputSchema, locateOptionsInputSchema, promptImageInputSchema, recordToReportInputSchema, recordToReportOptionsInputSchema, reportScreenshotInputSchema, runGherkinScenarioInputSchema, structuredUserPromptInputSchema, userPromptInputSchema, waitInputSchema };
247
172
 
248
173
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"midscene/index.mjs","sources":["../../../src/errors.ts","../../../src/node/define-node.ts","../../../src/midscene/index.ts"],"sourcesContent":["import type { z } from 'zod/v4';\n\nexport interface WorkflowErrorOptions {\n code?: string;\n details?: unknown;\n cause?: unknown;\n}\n\nexport class WorkflowError extends Error {\n readonly code: string;\n readonly details?: unknown;\n\n constructor(message: string, options: WorkflowErrorOptions = {}) {\n super(message, { cause: options.cause });\n this.name = new.target.name;\n this.code = options.code ?? 'WORKFLOW_ERROR';\n this.details = options.details;\n }\n\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n message: this.message,\n code: this.code,\n ...(this.details === undefined ? {} : { details: this.details }),\n };\n }\n}\n\nexport class WorkflowParseError extends WorkflowError {\n constructor(message: string, details?: unknown, cause?: unknown) {\n super(message, { code: 'WORKFLOW_PARSE_ERROR', details, cause });\n }\n}\n\nexport class NodeDefinitionError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'NODE_DEFINITION_ERROR', details });\n }\n}\n\nexport class DuplicateNodeError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string) {\n super(`Node \"${node}\" is already registered.`, {\n code: 'DUPLICATE_NODE',\n details: { node },\n });\n this.node = node;\n }\n}\n\nexport class NodeNotFoundError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string) {\n super(`Node \"${node}\" is not registered.`, {\n code: 'NODE_NOT_FOUND',\n details: { node },\n });\n this.node = node;\n }\n}\n\nexport class NodeInputValidationError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'NODE_INPUT_VALIDATION_ERROR', details });\n }\n\n static fromZod(node: string, error: z.ZodError): NodeInputValidationError {\n const issues = error.issues.map((issue) => ({\n code: issue.code,\n path: issue.path.map(String).join('.'),\n message: issue.message,\n }));\n const firstIssue = issues[0];\n const path = firstIssue?.path || '<root>';\n const message = firstIssue?.message ?? 'invalid input';\n return new NodeInputValidationError(\n `Node \"${node}\" input validation failed at \"${path}\": ${message}`,\n { node, issues },\n );\n }\n}\n\nexport class StepTimeoutError extends WorkflowError {\n readonly timeoutMs: number;\n readonly node?: string;\n\n constructor(timeoutMs: number, node?: string) {\n super(\n node\n ? `Node \"${node}\" timed out after ${timeoutMs}ms.`\n : `Step timed out after ${timeoutMs}ms.`,\n {\n code: 'STEP_TIMEOUT',\n details: { timeoutMs, ...(node === undefined ? {} : { node }) },\n },\n );\n this.timeoutMs = timeoutMs;\n this.node = node;\n }\n}\n\nexport class NodeExecutionError extends WorkflowError {\n readonly node: string;\n\n constructor(node: string, cause: unknown) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Node \"${node}\" failed: ${causeMessage}`, {\n code: 'NODE_EXECUTION_ERROR',\n details: { node },\n cause,\n });\n this.node = node;\n }\n}\n\nexport class WorkflowLifecycleError extends WorkflowError {\n constructor(message: string, details?: unknown) {\n super(message, { code: 'WORKFLOW_LIFECYCLE_ERROR', details });\n }\n}\n\nexport class ProjectSetupError extends WorkflowError {\n constructor(cause: unknown, details: { projectName: string }) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Project \"${details.projectName}\" setup failed: ${causeMessage}`, {\n code: 'PROJECT_SETUP_ERROR',\n details,\n cause,\n });\n }\n}\n\nexport class ProjectTeardownError extends WorkflowError {\n constructor(\n cause: unknown,\n details: { projectName: string; registrationIndex: number },\n ) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(`Project \"${details.projectName}\" teardown failed: ${causeMessage}`, {\n code: 'PROJECT_TEARDOWN_ERROR',\n details,\n cause,\n });\n }\n}\n\nexport class NodeScopeTeardownError extends WorkflowError {\n constructor(\n cause: unknown,\n details: {\n scope: 'case' | 'document';\n scopeId: string;\n node: string;\n registrationIndex: number;\n },\n ) {\n const causeMessage =\n cause instanceof Error ? cause.message : String(cause ?? 'Unknown error');\n super(\n `${details.scope === 'case' ? 'Case attempt' : 'Workflow document'} node teardown failed for \"${details.node}\": ${causeMessage}`,\n { code: 'NODE_SCOPE_TEARDOWN_ERROR', details, cause },\n );\n }\n}\n\nexport class FatalDeviceError extends WorkflowError {\n constructor(message: string, cause?: unknown) {\n super(message, { code: 'FATAL_DEVICE_ERROR', cause });\n }\n}\n\nexport const isFatalDeviceError = (error: unknown): boolean => {\n if (error instanceof FatalDeviceError) return true;\n if (error instanceof WorkflowError && error.code === 'FATAL_DEVICE_ERROR') {\n return true;\n }\n if (\n error instanceof Error &&\n /device offline|device not found|(?:adb|bdc|device) connection (?:was )?closed/i.test(\n error.message,\n )\n ) {\n return true;\n }\n return error instanceof Error && error.cause !== undefined\n ? isFatalDeviceError(error.cause)\n : false;\n};\n\nexport class CaseExecutionError extends WorkflowError {\n readonly result: import('./engine/types').CaseRunResult;\n\n constructor(result: import('./engine/types').CaseRunResult) {\n super(`Case \"${result.name}\" failed.`, {\n code: 'CASE_EXECUTION_FAILED',\n details: { caseId: result.caseId, runId: result.runId },\n });\n this.result = result;\n }\n}\n\nexport class WorkflowDocumentExecutionError extends WorkflowError {\n readonly result: import('./engine/types').WorkflowDocumentRunResult;\n\n constructor(result: import('./engine/types').WorkflowDocumentRunResult) {\n super(`Workflow document \"${result.sourcePath}\" failed.`, {\n code: 'WORKFLOW_DOCUMENT_EXECUTION_FAILED',\n details: {\n documentId: result.documentId,\n documentRunId: result.documentRunId,\n },\n });\n this.result = result;\n }\n}\n\nexport function normalizeNodeExecutionError(\n error: unknown,\n node: string,\n): WorkflowError {\n return error instanceof WorkflowError\n ? error\n : new NodeExecutionError(node, error);\n}\n","import { z } from 'zod/v4';\nimport { NodeDefinitionError } from '../errors';\nimport type {\n DefineNodeOptions,\n DefineNodeWithSchemaOptions,\n NodeDefinition,\n NodeDefinitionWithSchema,\n NodeInputSchema,\n} from './types';\n\nconst validateOptionalText = (\n value: unknown,\n field: 'title' | 'description',\n node: string,\n): void => {\n if (\n value !== undefined &&\n (typeof value !== 'string' || value.trim().length === 0)\n ) {\n throw new NodeDefinitionError(\n `Node \"${node}\" ${field} must be a non-empty string.`,\n { node, field },\n );\n }\n};\n\nconst validateInputSchema = (schema: unknown, node: string): void => {\n if (schema === undefined) return;\n if (!(schema instanceof z.ZodObject)) {\n throw new NodeDefinitionError(\n `Node \"${node}\" inputSchema must be a Zod object schema.`,\n { node, field: 'inputSchema' },\n );\n }\n if ('$' in schema.shape) {\n throw new NodeDefinitionError(\n `Node \"${node}\" inputSchema must not declare \"$\" as an input property.`,\n { node, field: 'inputSchema.$' },\n );\n }\n};\n\nconst validateDefinition = (options: {\n name: string;\n title?: unknown;\n description?: unknown;\n stringInputKey?: unknown;\n inputSchema?: unknown;\n execute: unknown;\n}): void => {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError('Node definition must be an object.');\n }\n\n if (typeof options.name !== 'string' || options.name.trim().length === 0) {\n throw new NodeDefinitionError('Node name must be a non-empty string.');\n }\n\n validateOptionalText(options.title, 'title', options.name);\n validateOptionalText(options.description, 'description', options.name);\n if (\n options.stringInputKey !== undefined &&\n options.stringInputKey !== false &&\n (typeof options.stringInputKey !== 'string' ||\n options.stringInputKey.trim().length === 0)\n ) {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" stringInputKey must be a non-empty string or false.`,\n { node: options.name, field: 'stringInputKey' },\n );\n }\n validateInputSchema(options.inputSchema, options.name);\n\n if (\n typeof options.stringInputKey === 'string' &&\n options.inputSchema instanceof z.ZodObject &&\n !(options.stringInputKey in options.inputSchema.shape)\n ) {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" stringInputKey must reference a field in inputSchema.`,\n { node: options.name, field: 'stringInputKey' },\n );\n }\n\n if (typeof options.execute !== 'function') {\n throw new NodeDefinitionError(\n `Node \"${options.name}\" must provide an execute function.`,\n { node: options.name },\n );\n }\n};\n\nexport function defineNode<\n TSchema extends NodeInputSchema,\n TData = unknown,\n TContext = unknown,\n>(\n options: DefineNodeWithSchemaOptions<TSchema, TData, TContext>,\n): NodeDefinitionWithSchema<TSchema, TData, TContext>;\n\nexport function defineNode<\n TInput = unknown,\n TData = unknown,\n TContext = unknown,\n>(\n options: DefineNodeOptions<TInput, TData, TContext>,\n): NodeDefinition<TInput, TData, TContext>;\n\nexport function defineNode(\n options: DefineNodeOptions<any, any, any>,\n): NodeDefinition<any, any, any> {\n validateDefinition(options);\n return options;\n}\n","import {\n type AgentTestRunnerNodeDefinition,\n type AgentTestRunnerNodeProvider,\n type CommonAgentTestRunnerApi,\n aiActInputSchema,\n aiActOptionsInputSchema,\n aiAssertInputSchema,\n aiAssertOptionsInputSchema,\n aiTapInputSchema,\n insightInputSchema,\n insightOptionsInputSchema,\n locateOptionsInputSchema,\n promptImageInputSchema,\n recordToReportInputSchema,\n recordToReportOptionsInputSchema,\n reportScreenshotInputSchema,\n structuredUserPromptInputSchema,\n userPromptInputSchema,\n} from '@midscene/core/agent/test';\nimport { getDebug } from '@midscene/shared/logger';\nimport { z } from 'zod/v4';\nimport type { Awaitable } from '../engine/types';\nimport { NodeDefinitionError, NodeExecutionError } from '../errors';\nimport { defineNode } from '../node/define-node';\nimport type { NodeDefinition, NodeExecutionContext } from '../node/types';\n\nexport type MidsceneUIAgent = CommonAgentTestRunnerApi & {\n addDumpUpdateListener?(\n listener: (dump: string, execution?: MidsceneExecutionRef) => void,\n ): () => void;\n};\n\nexport {\n aiActInputSchema,\n aiActOptionsInputSchema,\n aiAssertInputSchema,\n aiAssertOptionsInputSchema,\n aiTapInputSchema,\n insightInputSchema,\n insightOptionsInputSchema,\n locateOptionsInputSchema,\n promptImageInputSchema,\n recordToReportInputSchema,\n recordToReportOptionsInputSchema,\n reportScreenshotInputSchema,\n structuredUserPromptInputSchema,\n userPromptInputSchema,\n};\n\nexport interface MidsceneExecutionRef {\n id?: string;\n}\n\nexport interface AgentProvider<TContext> {\n getAgent(\n runId: string,\n execution: NodeExecutionContext<unknown, TContext>,\n ): Awaitable<MidsceneUIAgent>;\n // biome-ignore lint/suspicious/noConfusingVoidType: providers without a report intentionally return void.\n releaseAgent?(runId: string): Awaitable<AgentReleaseResult | void>;\n dispose?(): Awaitable<void>;\n}\n\nexport interface AgentReleaseResult {\n /** Absolute path to the finalized report for this Agent scope. */\n reportPath?: string;\n}\n\nexport const waitInputSchema = z.strictObject({\n duration: z.number().positive().describe('How long to wait.'),\n unit: z\n .enum(['ms', 's', 'min'])\n .default('ms')\n .describe('Duration unit: milliseconds, seconds, or minutes.'),\n});\n\nexport type AiActNodeInput = z.infer<typeof aiActInputSchema>;\nexport type AiAssertNodeInput = z.infer<typeof aiAssertInputSchema>;\nexport type AiTapNodeInput = z.infer<typeof aiTapInputSchema>;\nexport type InsightNodeInput = z.infer<typeof insightInputSchema>;\nexport type RecordToReportNodeInput = z.infer<typeof recordToReportInputSchema>;\nexport type WaitNodeInput = z.infer<typeof waitInputSchema>;\n\nexport interface CreateMidsceneNodesOptions<TContext> {\n getAgent?(\n execution: NodeExecutionContext<unknown, TContext>,\n ): Awaitable<MidsceneUIAgent>;\n agentProvider?: AgentProvider<TContext>;\n /** Agent class that declares the Agent-backed Nodes to register. */\n agentClass: AgentTestRunnerNodeProvider;\n}\n\nconst waitFor = async (durationMs: number, signal: AbortSignal) => {\n if (signal.aborted) {\n throw signal.reason ?? new Error('Wait aborted.');\n }\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n signal.removeEventListener('abort', abort);\n resolve();\n }, durationMs);\n const abort = () => {\n clearTimeout(timeout);\n reject(signal.reason ?? new Error('Wait aborted.'));\n };\n signal.addEventListener('abort', abort, { once: true });\n });\n};\n\n/** Adapt Agent-owned descriptions to executable Midscene Test Nodes. */\nexport const createAgentTestRunnerNodes = <TContext>(\n definitions: readonly AgentTestRunnerNodeDefinition[],\n getAgent: (\n execution: NodeExecutionContext<unknown, TContext>,\n ) => Awaitable<unknown>,\n): readonly NodeDefinition<any, any, TContext>[] => {\n const activeAgentCalls = new WeakMap<\n MidsceneUIAgent,\n { scopeId: string; node: string }\n >();\n const runAgentCall = async <T>(\n node: string,\n execution: NodeExecutionContext<unknown, TContext>,\n agent: MidsceneUIAgent,\n call: () => Promise<T>,\n captureExecutions = true,\n ): Promise<T> => {\n execution.signal.throwIfAborted();\n const scopeId =\n execution.scope === 'case'\n ? execution.case.runId\n : execution.document.documentRunId;\n const activeCall = activeAgentCalls.get(agent);\n if (activeCall) {\n throw new NodeExecutionError(\n node,\n new Error(\n `The same Agent instance cannot execute overlapping Midscene Test Steps. Active scope: ${activeCall.scopeId} (${activeCall.node}); requested scope: ${scopeId} (${node}).`,\n ),\n );\n }\n\n const currentCall = { scopeId, node };\n activeAgentCalls.set(agent, currentCall);\n const releaseCall = () => {\n // An aborted call may finish after another Step has acquired this Agent.\n if (activeAgentCalls.get(agent) === currentCall) {\n activeAgentCalls.delete(agent);\n }\n };\n let removeListener: (() => void) | undefined;\n let sawExecutionWithoutId = false;\n const stopListening = () => {\n const remove = removeListener;\n removeListener = undefined;\n remove?.();\n };\n const stopListeningOnAbort = () => {\n try {\n stopListening();\n } finally {\n releaseCall();\n }\n };\n execution.signal.addEventListener('abort', stopListeningOnAbort, {\n once: true,\n });\n try {\n if (captureExecutions && agent.addDumpUpdateListener) {\n removeListener = agent.addDumpUpdateListener((_dump, executionRef) => {\n if (!executionRef) return;\n if (!executionRef.id) {\n sawExecutionWithoutId = true;\n return;\n }\n execution.report.addTrace({\n type: 'midscene-execution',\n executionId: executionRef.id,\n });\n });\n if (execution.signal.aborted) stopListening();\n }\n return await call();\n } finally {\n execution.signal.removeEventListener('abort', stopListeningOnAbort);\n try {\n stopListening();\n } finally {\n releaseCall();\n }\n if (sawExecutionWithoutId) {\n warnReportTrace(\n `Skipped a report trace without a stable execution id for ${node} in scope ${scopeId}.`,\n );\n }\n }\n };\n\n return definitions.map((definition) =>\n defineNode({\n name: definition.name,\n ...(definition.title === undefined ? {} : { title: definition.title }),\n ...(definition.description === undefined\n ? {}\n : { description: definition.description }),\n ...(definition.stringInputKey === undefined\n ? {}\n : { stringInputKey: definition.stringInputKey }),\n inputSchema: definition.inputSchema,\n async execute(execution) {\n const agent = await getAgent(execution);\n const call = async () =>\n definition.execute(agent, execution.input, {\n signal: execution.signal,\n });\n if (typeof agent !== 'object' || agent === null) return call();\n return runAgentCall(\n definition.name,\n execution,\n agent as MidsceneUIAgent,\n call,\n );\n },\n }),\n );\n};\n\nconst warnReportTrace = getDebug('test-runner:report-trace', {\n console: true,\n});\n\nexport function createMidsceneNodes<TContext>(\n options: CreateMidsceneNodesOptions<TContext>,\n): readonly NodeDefinition<any, any, TContext>[] {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() options must be an object.',\n );\n }\n if (\n typeof options.agentProvider?.getAgent !== 'function' &&\n typeof options.getAgent !== 'function'\n ) {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() requires getAgent or agentProvider.getAgent.',\n );\n }\n if (\n !options.agentClass ||\n typeof options.agentClass.getTestRunnerNodeDefinitions !== 'function'\n ) {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() requires agentClass.getTestRunnerNodeDefinitions().',\n );\n }\n\n const registeredAgentScopes = new Set<string>();\n const getExecutionId = (\n execution: NodeExecutionContext<unknown, TContext>,\n ) =>\n execution.scope === 'case'\n ? execution.case.runId\n : execution.document.documentRunId;\n const getAgent = async (\n execution: NodeExecutionContext<unknown, TContext>,\n ): Promise<MidsceneUIAgent> => {\n if (!options.agentProvider) return options.getAgent!(execution);\n const runId = getExecutionId(execution);\n if (\n options.agentProvider.releaseAgent &&\n !registeredAgentScopes.has(runId)\n ) {\n registeredAgentScopes.add(runId);\n execution.onTeardown(async () => {\n try {\n const released = await options.agentProvider!.releaseAgent!(runId);\n return released?.reportPath\n ? { reportPaths: [released.reportPath] }\n : undefined;\n } finally {\n registeredAgentScopes.delete(runId);\n }\n });\n }\n return options.agentProvider.getAgent(runId, execution);\n };\n\n const agentDefinitions = options.agentClass.getTestRunnerNodeDefinitions();\n\n return [\n ...createAgentTestRunnerNodes(agentDefinitions, getAgent),\n defineNode<typeof waitInputSchema, unknown, TContext>({\n name: 'wait',\n description: 'Wait for a fixed duration while honoring cancellation.',\n stringInputKey: false,\n inputSchema: waitInputSchema,\n async execute(execution) {\n const multiplier =\n execution.input.unit === 'min'\n ? 60_000\n : execution.input.unit === 's'\n ? 1_000\n : 1;\n const durationMs = execution.input.duration * multiplier;\n await waitFor(durationMs, execution.signal);\n return { summary: `Waited ${durationMs}ms` };\n },\n }),\n ];\n}\n"],"names":["WorkflowError","Error","undefined","message","options","NodeDefinitionError","details","NodeExecutionError","node","cause","causeMessage","String","validateOptionalText","value","field","validateInputSchema","schema","z","validateDefinition","defineNode","waitInputSchema","waitFor","durationMs","signal","Promise","resolve","reject","timeout","setTimeout","abort","clearTimeout","createAgentTestRunnerNodes","definitions","getAgent","activeAgentCalls","WeakMap","runAgentCall","execution","agent","call","captureExecutions","scopeId","activeCall","currentCall","releaseCall","removeListener","sawExecutionWithoutId","stopListening","remove","stopListeningOnAbort","_dump","executionRef","warnReportTrace","definition","getDebug","createMidsceneNodes","registeredAgentScopes","Set","getExecutionId","runId","released","agentDefinitions","multiplier"],"mappings":"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"}
1
+ {"version":3,"file":"midscene/index.mjs","sources":["../../../src/node/define-node.ts","../../../src/midscene/index.ts"],"sourcesContent":["import { defineNode as coreDefineNode } from '@midscene/core/internal/test-runner';\nimport type {\n DefineNodeOptions,\n DefineNodeWithSchemaOptions,\n NodeDefinition,\n NodeDefinitionWithSchema,\n NodeInputSchema,\n} from './types';\n\n// A type-only facade: validation and execution still belong to the shared kernel.\ninterface DefineNativeNode {\n <TSchema extends NodeInputSchema, TData = unknown, TContext = unknown>(\n options: DefineNodeWithSchemaOptions<TSchema, TData, TContext>,\n ): NodeDefinitionWithSchema<TSchema, TData, TContext>;\n <TInput = unknown, TData = unknown, TContext = unknown>(\n options: DefineNodeOptions<TInput, TData, TContext>,\n ): NodeDefinition<TInput, TData, TContext>;\n}\nexport const defineNode: DefineNativeNode = coreDefineNode;\n","import {\n type AgentTestRunnerNodeDefinition,\n type AgentTestRunnerNodeProvider,\n type CommonAgentTestRunnerApi,\n aiActInputSchema,\n aiActOptionsInputSchema,\n aiAssertInputSchema,\n aiAssertOptionsInputSchema,\n aiTapInputSchema,\n insightInputSchema,\n insightOptionsInputSchema,\n locateOptionsInputSchema,\n promptImageInputSchema,\n recordToReportInputSchema,\n recordToReportOptionsInputSchema,\n reportScreenshotInputSchema,\n structuredUserPromptInputSchema,\n userPromptInputSchema,\n} from '@midscene/core/agent/test';\nimport {\n type WorkflowReportSource,\n assertResourceAvailable,\n trackResourceOperation,\n} from '@midscene/core/internal/test-runner';\nimport {\n enterYamlAction,\n enterYamlExecution,\n runInYamlExecutionContext,\n} from '@midscene/core/internal/yaml-runtime';\nimport { getDebug } from '@midscene/shared/logger';\nimport { z } from 'zod/v4';\nimport type { Awaitable } from '../engine/types';\nimport { NodeDefinitionError } from '../errors';\nimport { defineNode } from '../node/define-node';\nimport type { NodeDefinition, NodeExecutionContext } from '../node/types';\n\nexport type MidsceneUIAgent = CommonAgentTestRunnerApi & {\n _prepareForTestRunner?(): void;\n _createReportSource?(\n scopeId: string,\n ): Promise<WorkflowReportSource | undefined>;\n flushReport?(): Promise<string | undefined>;\n addDumpUpdateListener?(\n listener: (dump: string, execution?: MidsceneExecutionRef) => void,\n ): () => void;\n};\n\nexport {\n actionInputSchema,\n aiDragAndDropInputSchema,\n aiInputInputSchema,\n aiKeyboardPressInputSchema,\n aiLongPressInputSchema,\n aiPinchInputSchema,\n aiQueryInputSchema,\n aiScrollInputSchema,\n aiWaitForInputSchema,\n javascriptInputSchema,\n runGherkinScenarioInputSchema,\n} from '@midscene/core/agent/test';\nexport type {\n ActionNodeInput,\n AiDragAndDropNodeInput,\n AiInputNodeInput,\n AiKeyboardPressNodeInput,\n AiLongPressNodeInput,\n AiPinchNodeInput,\n AiQueryNodeInput,\n AiScrollNodeInput,\n AiWaitForNodeInput,\n JavascriptNodeInput,\n RunGherkinScenarioNodeInput,\n} from '@midscene/core/agent/test';\n\nexport {\n aiActInputSchema,\n aiActOptionsInputSchema,\n aiAssertInputSchema,\n aiAssertOptionsInputSchema,\n aiTapInputSchema,\n insightInputSchema,\n insightOptionsInputSchema,\n locateOptionsInputSchema,\n promptImageInputSchema,\n recordToReportInputSchema,\n recordToReportOptionsInputSchema,\n reportScreenshotInputSchema,\n structuredUserPromptInputSchema,\n userPromptInputSchema,\n};\n\nexport interface MidsceneExecutionRef {\n id?: string;\n}\n\nexport interface AgentProvider<TContext> {\n getAgent(\n runId: string,\n execution: NodeExecutionContext<unknown, TContext>,\n ): Awaitable<MidsceneUIAgent>;\n // biome-ignore lint/suspicious/noConfusingVoidType: providers without a report intentionally return void.\n releaseAgent?(runId: string): Awaitable<AgentReleaseResult | void>;\n dispose?(): Awaitable<void>;\n}\n\nexport interface AgentReleaseResult {\n /** Absolute path to the finalized report for this Agent scope. */\n reportPath?: string;\n}\n\nexport const waitInputSchema = z.strictObject({\n duration: z.number().positive().describe('How long to wait.'),\n unit: z\n .enum(['ms', 's', 'min'])\n .default('ms')\n .describe('Duration unit: milliseconds, seconds, or minutes.'),\n});\n\nexport type AiActNodeInput = z.infer<typeof aiActInputSchema>;\nexport type AiAssertNodeInput = z.infer<typeof aiAssertInputSchema>;\nexport type AiTapNodeInput = z.infer<typeof aiTapInputSchema>;\nexport type InsightNodeInput = z.infer<typeof insightInputSchema>;\nexport type RecordToReportNodeInput = z.infer<typeof recordToReportInputSchema>;\nexport type WaitNodeInput = z.infer<typeof waitInputSchema>;\n\nexport interface CreateMidsceneNodesOptions<TContext> {\n getAgent?(\n execution: NodeExecutionContext<unknown, TContext>,\n ): Awaitable<MidsceneUIAgent>;\n agentProvider?: AgentProvider<TContext>;\n /** Agent class that declares the Agent-backed Nodes to register. */\n agentClass: AgentTestRunnerNodeProvider;\n}\n\nconst waitFor = async (durationMs: number, signal: AbortSignal) => {\n if (signal.aborted) {\n throw signal.reason ?? new Error('Wait aborted.');\n }\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n signal.removeEventListener('abort', abort);\n resolve();\n }, durationMs);\n const abort = () => {\n clearTimeout(timeout);\n reject(signal.reason ?? new Error('Wait aborted.'));\n };\n signal.addEventListener('abort', abort, { once: true });\n });\n};\n\n/** Adapt Agent-owned descriptions to executable Midscene Test Nodes. */\nexport const createAgentTestRunnerNodes = <TContext>(\n definitions: readonly AgentTestRunnerNodeDefinition[],\n getAgent: (\n ctx: NodeExecutionContext<unknown, TContext>,\n ) => Awaitable<unknown>,\n): readonly NodeDefinition<any, any, TContext>[] => {\n const runAgentCall = async <T>(\n node: string,\n ctx: NodeExecutionContext<unknown, TContext>,\n agent: MidsceneUIAgent,\n call: () => Promise<T>,\n captureExecutions = true,\n ): Promise<T> =>\n runInYamlExecutionContext(async () => {\n const scopeId =\n ctx.scope === 'case' ? ctx.case.runId : ctx.document.documentRunId;\n const isCleanupOwner = assertResourceAvailable(agent, true, ctx.signal);\n // Native Steps own the root report. Any Agent.runYaml invoked underneath\n // contributes to that Step instead of publishing another root snapshot.\n const yamlBoundary = enterYamlExecution(agent, {\n allowIndependentOverlap: isCleanupOwner,\n });\n const leaveYamlAction = enterYamlAction(agent, ctx.signal);\n let removeListener: (() => void) | undefined;\n let sawExecutionWithoutId = false;\n const stopListening = () => {\n const remove = removeListener;\n removeListener = undefined;\n remove?.();\n };\n const stopListeningOnAbort = () => stopListening();\n try {\n if (captureExecutions && agent.addDumpUpdateListener) {\n removeListener = agent.addDumpUpdateListener((_dump, execution) => {\n if (!execution) return;\n if (!execution.id) {\n sawExecutionWithoutId = true;\n return;\n }\n ctx.report.addTrace({\n type: 'midscene-execution',\n executionId: execution.id,\n });\n });\n if (ctx.signal.aborted) stopListening();\n else {\n ctx.signal.addEventListener('abort', stopListeningOnAbort, {\n once: true,\n });\n }\n }\n return await trackResourceOperation(\n agent,\n Promise.resolve().then(call),\n ctx.signal,\n );\n } finally {\n leaveYamlAction();\n yamlBoundary.finish();\n ctx.signal.removeEventListener('abort', stopListeningOnAbort);\n stopListening();\n if (sawExecutionWithoutId) {\n warnReportTrace(\n `Skipped a report trace without a stable execution id for ${node} in scope ${scopeId}.`,\n );\n }\n }\n });\n\n return definitions.map((definition) =>\n defineNode({\n name: definition.name,\n ...(definition.title === undefined ? {} : { title: definition.title }),\n ...(definition.description === undefined\n ? {}\n : { description: definition.description }),\n ...(definition.stringInputKey === undefined\n ? {}\n : { stringInputKey: definition.stringInputKey }),\n inputSchema: definition.inputSchema,\n async execute(ctx) {\n const agent = await getAgent(ctx);\n ctx.signal.throwIfAborted();\n const call = async () =>\n definition.execute(agent, ctx.input, { signal: ctx.signal });\n if (typeof agent !== 'object' || agent === null) return call();\n return runAgentCall(\n definition.name,\n ctx,\n agent as MidsceneUIAgent,\n call,\n );\n },\n }),\n );\n};\n\nconst warnReportTrace = getDebug('test-runner:report-trace', {\n console: true,\n});\n\nexport function createMidsceneNodes<TContext>(\n options: CreateMidsceneNodesOptions<TContext>,\n): readonly NodeDefinition<any, any, TContext>[] {\n if (!options || typeof options !== 'object') {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() options must be an object.',\n );\n }\n if (\n typeof options.agentProvider?.getAgent !== 'function' &&\n typeof options.getAgent !== 'function'\n ) {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() requires getAgent or agentProvider.getAgent.',\n );\n }\n if (\n !options.agentClass ||\n typeof options.agentClass.getTestRunnerNodeDefinitions !== 'function'\n ) {\n throw new NodeDefinitionError(\n 'createMidsceneNodes() requires agentClass.getTestRunnerNodeDefinitions().',\n );\n }\n\n const agentsByScope = new Map<string, Set<MidsceneUIAgent>>();\n const getAgent = async (\n ctx: NodeExecutionContext<unknown, TContext>,\n ): Promise<MidsceneUIAgent> => {\n const runId =\n ctx.scope === 'case' ? ctx.case.runId : ctx.document.documentRunId;\n let agents = agentsByScope.get(runId);\n if (!agents) {\n agents = new Set();\n agentsByScope.set(runId, agents);\n const ownedScope = agents;\n ctx.onTeardown(async () => {\n const errors: unknown[] = [];\n const reportPaths: string[] = [];\n const reportSources: WorkflowReportSource[] = [];\n try {\n for (const agent of ownedScope) {\n try {\n const path = await agent.flushReport?.();\n if (path) reportPaths.push(path);\n const source = await agent._createReportSource?.(runId);\n if (source) reportSources.push(source);\n } catch (error) {\n errors.push(error);\n }\n }\n // Publication failure never prevents the owner from disposing its Agent.\n try {\n const released = await options.agentProvider?.releaseAgent?.(runId);\n if (\n released?.reportPath &&\n !reportPaths.includes(released.reportPath)\n )\n reportPaths.push(released.reportPath);\n } catch (error) {\n errors.push(error);\n }\n if (errors.length === 1) throw errors[0];\n if (errors.length)\n throw new AggregateError(\n errors,\n 'Agent report publication and release failed',\n );\n return {\n reportPaths,\n ...(reportSources.length ? { reportSources } : {}),\n };\n } finally {\n agentsByScope.delete(runId);\n }\n });\n }\n const scopeAgents = agents;\n // Acquisition can outlive cancellation. Teardown waits for actual settlement.\n return trackResourceOperation(\n {},\n Promise.resolve().then(async () => {\n const agent = options.agentProvider\n ? await options.agentProvider.getAgent(runId, ctx)\n : await options.getAgent!(ctx);\n agent._prepareForTestRunner?.();\n scopeAgents.add(agent);\n return agent;\n }),\n ctx.signal,\n );\n };\n\n const agentDefinitions = options.agentClass.getTestRunnerNodeDefinitions();\n\n return [\n ...createAgentTestRunnerNodes(agentDefinitions, getAgent),\n defineNode<typeof waitInputSchema, unknown, TContext>({\n name: 'wait',\n description: 'Wait for a fixed duration while honoring cancellation.',\n stringInputKey: false,\n inputSchema: waitInputSchema,\n async execute(execution) {\n const multiplier =\n execution.input.unit === 'min'\n ? 60_000\n : execution.input.unit === 's'\n ? 1_000\n : 1;\n const durationMs = execution.input.duration * multiplier;\n await waitFor(durationMs, execution.signal);\n return { summary: `Waited ${durationMs}ms` };\n },\n }),\n ];\n}\n"],"names":["defineNode","coreDefineNode","waitInputSchema","z","waitFor","durationMs","signal","Error","Promise","resolve","reject","timeout","setTimeout","abort","clearTimeout","createAgentTestRunnerNodes","definitions","getAgent","runAgentCall","node","ctx","agent","call","captureExecutions","runInYamlExecutionContext","scopeId","isCleanupOwner","assertResourceAvailable","yamlBoundary","enterYamlExecution","leaveYamlAction","enterYamlAction","removeListener","sawExecutionWithoutId","stopListening","remove","undefined","stopListeningOnAbort","_dump","execution","trackResourceOperation","warnReportTrace","definition","getDebug","createMidsceneNodes","options","NodeDefinitionError","agentsByScope","Map","runId","agents","Set","ownedScope","errors","reportPaths","reportSources","path","source","error","released","AggregateError","scopeAgents","agentDefinitions","multiplier"],"mappings":"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"}