@midscene/core 1.12.3 → 1.12.4-beta-20260902093735.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.
Files changed (61) hide show
  1. package/dist/es/agent/agent.mjs +88 -25
  2. package/dist/es/agent/agent.mjs.map +1 -1
  3. package/dist/es/agent/index.mjs +2 -1
  4. package/dist/es/agent/insight.mjs +40 -10
  5. package/dist/es/agent/insight.mjs.map +1 -1
  6. package/dist/es/agent/prompt-context.mjs +42 -6
  7. package/dist/es/agent/prompt-context.mjs.map +1 -1
  8. package/dist/es/agent/run-gherkin-scenario.mjs.map +1 -1
  9. package/dist/es/agent/utils.mjs +1 -1
  10. package/dist/es/ai-model/prompt/insight/user-prompt.mjs +1 -1
  11. package/dist/es/ai-model/prompt/insight/user-prompt.mjs.map +1 -1
  12. package/dist/es/ai-model/workflows/insight/extraction.mjs +4 -1
  13. package/dist/es/ai-model/workflows/insight/extraction.mjs.map +1 -1
  14. package/dist/es/ai-model/workflows/planning/custom-planning.mjs +3 -3
  15. package/dist/es/ai-model/workflows/planning/custom-planning.mjs.map +1 -1
  16. package/dist/es/ai-model/workflows/planning/standard-planning.mjs +1 -1
  17. package/dist/es/ai-model/workflows/planning/standard-planning.mjs.map +1 -1
  18. package/dist/es/index.mjs +2 -2
  19. package/dist/es/index.mjs.map +1 -1
  20. package/dist/es/report-html-template.mjs +1 -1
  21. package/dist/es/types.mjs.map +1 -1
  22. package/dist/es/utils.mjs +1 -1
  23. package/dist/es/yaml/player.mjs +0 -5
  24. package/dist/es/yaml/player.mjs.map +1 -1
  25. package/dist/es/yaml/utils.mjs +4 -3
  26. package/dist/es/yaml/utils.mjs.map +1 -1
  27. package/dist/lib/agent/agent.js +87 -24
  28. package/dist/lib/agent/agent.js.map +1 -1
  29. package/dist/lib/agent/index.js +5 -1
  30. package/dist/lib/agent/insight.js +40 -10
  31. package/dist/lib/agent/insight.js.map +1 -1
  32. package/dist/lib/agent/prompt-context.js +55 -7
  33. package/dist/lib/agent/prompt-context.js.map +1 -1
  34. package/dist/lib/agent/run-gherkin-scenario.js.map +1 -1
  35. package/dist/lib/agent/utils.js +1 -1
  36. package/dist/lib/ai-model/prompt/insight/user-prompt.js +1 -1
  37. package/dist/lib/ai-model/prompt/insight/user-prompt.js.map +1 -1
  38. package/dist/lib/ai-model/workflows/insight/extraction.js +4 -1
  39. package/dist/lib/ai-model/workflows/insight/extraction.js.map +1 -1
  40. package/dist/lib/ai-model/workflows/planning/custom-planning.js +3 -3
  41. package/dist/lib/ai-model/workflows/planning/custom-planning.js.map +1 -1
  42. package/dist/lib/ai-model/workflows/planning/standard-planning.js +1 -1
  43. package/dist/lib/ai-model/workflows/planning/standard-planning.js.map +1 -1
  44. package/dist/lib/index.js +4 -1
  45. package/dist/lib/index.js.map +1 -1
  46. package/dist/lib/report-html-template.js +1 -1
  47. package/dist/lib/types.js.map +1 -1
  48. package/dist/lib/utils.js +1 -1
  49. package/dist/lib/yaml/player.js +0 -5
  50. package/dist/lib/yaml/player.js.map +1 -1
  51. package/dist/lib/yaml/utils.js +3 -2
  52. package/dist/lib/yaml/utils.js.map +1 -1
  53. package/dist/types/agent/agent.d.ts +22 -3
  54. package/dist/types/agent/index.d.ts +2 -1
  55. package/dist/types/agent/insight.d.ts +6 -1
  56. package/dist/types/agent/prompt-context.d.ts +27 -1
  57. package/dist/types/agent/run-gherkin-scenario.d.ts +1 -0
  58. package/dist/types/index.d.ts +1 -1
  59. package/dist/types/types.d.ts +26 -0
  60. package/dist/types/yaml.d.ts +12 -4
  61. package/package.json +2 -2
@@ -10,6 +10,7 @@ import { getVersion, processCacheConfig, reportHTMLContent } from "../utils.mjs"
10
10
  import { ScriptPlayer, buildDetailedLocateParam, buildDetailedLocateParamAndRestParams, parseYamlScript } from "../yaml/index.mjs";
11
11
  import { readFile } from "node:fs/promises";
12
12
  import { basename, resolve as external_node_path_resolve } from "node:path";
13
+ import { isAgentContextKey } from "@midscene/shared/agent-tools/agent-context";
13
14
  import { serializeError } from "@midscene/shared/agent-tools/error-formatter";
14
15
  import { observationArtifactAdapterSymbol } from "@midscene/shared/agent-tools/observation-artifact";
15
16
  import { MIDSCENE_REPLANNING_CYCLE_LIMIT, ModelConfigManager, globalConfigManager, globalModelConfigManager } from "@midscene/shared/env";
@@ -21,7 +22,7 @@ import { FileChooserAccepter } from "./file-chooser.mjs";
21
22
  import { Insight } from "./insight.mjs";
22
23
  import { MetricsCollector } from "./metrics.mjs";
23
24
  import { AgentProgressBus } from "./progress/index.mjs";
24
- import { buildPromptWithContext } from "./prompt-context.mjs";
25
+ import { INTERNAL_AI_CONTEXT_METADATA_KEY, buildPromptWithContext, renderAIContext } from "./prompt-context.mjs";
25
26
  import { normalizeRecordToReportScreenshot } from "./record-to-report.mjs";
26
27
  import { runGherkinScenario } from "./run-gherkin-scenario.mjs";
27
28
  import { markdownToAiActPrompt } from "./run-markdown.mjs";
@@ -52,8 +53,44 @@ class Agent {
52
53
  this.dumpUpdateListeners = [];
53
54
  if (callback) this.dumpUpdateListeners.push(callback);
54
55
  }
55
- get aiActContext() {
56
- return this.opts.aiActContext ?? this.opts.aiActionContext;
56
+ get contexts() {
57
+ if (!this.opts.contexts) this.opts.contexts = {};
58
+ return this.opts.contexts;
59
+ }
60
+ resolveUserContext(apiName, callContext) {
61
+ if (void 0 !== callContext) return {
62
+ value: callContext,
63
+ metadata: {
64
+ source: 'call'
65
+ }
66
+ };
67
+ const apiContext = this.opts.contexts?.[apiName];
68
+ if (void 0 !== apiContext) return {
69
+ value: apiContext,
70
+ metadata: {
71
+ source: 'api',
72
+ apiName
73
+ }
74
+ };
75
+ const defaultContext = this.opts.contexts?.default;
76
+ if (void 0 !== defaultContext) return {
77
+ value: defaultContext,
78
+ metadata: {
79
+ source: 'default'
80
+ }
81
+ };
82
+ }
83
+ resolveContext(apiName, callContext, additionalContext) {
84
+ return renderAIContext(this.resolveUserContext(apiName, callContext), additionalContext);
85
+ }
86
+ withContext(apiName, options) {
87
+ const resolvedContext = this.resolveUserContext(apiName, options?.context);
88
+ if (void 0 === resolvedContext) return options;
89
+ return {
90
+ ...options ?? {},
91
+ context: resolvedContext.value,
92
+ [INTERNAL_AI_CONTEXT_METADATA_KEY]: resolvedContext.metadata
93
+ };
57
94
  }
58
95
  get page() {
59
96
  return this.interface;
@@ -79,7 +116,7 @@ class Agent {
79
116
  };
80
117
  }
81
118
  createInsight(getUIContext) {
82
- return new Insight(this.taskExecutor, ()=>this.resolveModelRuntime('insight'), getUIContext);
119
+ return new Insight(this.taskExecutor, ()=>this.resolveModelRuntime('insight'), getUIContext, (apiName, callContext)=>this.resolveUserContext(apiName, callContext));
83
120
  }
84
121
  async getActionSpace() {
85
122
  return this.fullActionSpace;
@@ -140,12 +177,24 @@ class Agent {
140
177
  return observer;
141
178
  }
142
179
  async setAIActionContext(prompt) {
143
- await this.setAIActContext(prompt);
180
+ warn('setAIActionContext() is deprecated; use setContext("aiAct", context) instead.');
181
+ this.setContext('aiAct', prompt);
144
182
  }
145
183
  async setAIActContext(prompt) {
146
- if (this.aiActContext) console.warn('aiActContext is already set, and it is called again, will override the previous setting');
147
- this.opts.aiActContext = prompt;
148
- this.opts.aiActionContext = prompt;
184
+ warn('setAIActContext() is deprecated; use setContext("aiAct", context) instead.');
185
+ this.setContext('aiAct', prompt);
186
+ }
187
+ setContext(target, context) {
188
+ if (!isAgentContextKey(target)) throw new TypeError(`Unknown Agent context key: ${String(target)}`);
189
+ if (void 0 !== context && 'string' != typeof context) throw new TypeError('Agent context must be a string or undefined');
190
+ this.contexts[target] = context;
191
+ if ('aiAct' === target) if (void 0 === context) {
192
+ this.opts.aiActContext = void 0;
193
+ this.opts.aiActionContext = void 0;
194
+ } else {
195
+ this.opts.aiActContext = context;
196
+ this.opts.aiActionContext = context;
197
+ }
149
198
  }
150
199
  resetDump() {
151
200
  this.dump = new ReportActionDump({
@@ -249,7 +298,7 @@ class Agent {
249
298
  }
250
299
  async aiTap(locatePrompt, opt) {
251
300
  assert(locatePrompt, 'missing locate prompt for tap');
252
- const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);
301
+ const detailedLocateParam = buildDetailedLocateParam(locatePrompt, this.withContext('aiTap', opt));
253
302
  const fileChooserAccept = opt?.fileChooserAccept ? this.normalizeFileInput(opt.fileChooserAccept) : void 0;
254
303
  await withFileChooser(this.interface, fileChooserAccept, async ()=>{
255
304
  await this.callActionInActionSpace('Tap', {
@@ -259,21 +308,21 @@ class Agent {
259
308
  }
260
309
  async aiRightClick(locatePrompt, opt) {
261
310
  assert(locatePrompt, 'missing locate prompt for right click');
262
- const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);
311
+ const detailedLocateParam = buildDetailedLocateParam(locatePrompt, this.withContext('aiRightClick', opt));
263
312
  await this.callActionInActionSpace('RightClick', {
264
313
  locate: detailedLocateParam
265
314
  });
266
315
  }
267
316
  async aiDoubleClick(locatePrompt, opt) {
268
317
  assert(locatePrompt, 'missing locate prompt for double click');
269
- const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);
318
+ const detailedLocateParam = buildDetailedLocateParam(locatePrompt, this.withContext('aiDoubleClick', opt));
270
319
  await this.callActionInActionSpace('DoubleClick', {
271
320
  locate: detailedLocateParam
272
321
  });
273
322
  }
274
323
  async aiHover(locatePrompt, opt) {
275
324
  assert(locatePrompt, 'missing locate prompt for hover');
276
- const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);
325
+ const detailedLocateParam = buildDetailedLocateParam(locatePrompt, this.withContext('aiHover', opt));
277
326
  await this.callActionInActionSpace('Hover', {
278
327
  locate: detailedLocateParam
279
328
  });
@@ -297,7 +346,7 @@ class Agent {
297
346
  }
298
347
  assert('string' == typeof value || 'number' == typeof value, 'input value must be a string or number, use empty string if you want to clear the input');
299
348
  assert(locatePrompt, 'missing locate prompt for input');
300
- const { locateParam, restParams } = buildDetailedLocateParamAndRestParams(locatePrompt, opt);
349
+ const { locateParam, restParams } = buildDetailedLocateParamAndRestParams(locatePrompt, this.withContext('aiInput', opt));
301
350
  const stringValue = 'number' == typeof value ? String(value) : value;
302
351
  const mode = opt?.mode === 'append' ? 'typeOnly' : opt?.mode;
303
352
  await this.callActionInActionSpace('Input', {
@@ -323,7 +372,7 @@ class Agent {
323
372
  };
324
373
  }
325
374
  assert(opt?.keyName, 'missing keyName for keyboard press');
326
- const { locateParam, restParams } = buildDetailedLocateParamAndRestParams(locatePrompt || '', opt);
375
+ const { locateParam, restParams } = buildDetailedLocateParamAndRestParams(locatePrompt || '', this.withContext('aiKeyboardPress', opt));
327
376
  await this.callActionInActionSpace('KeyboardPress', {
328
377
  ...restParams,
329
378
  locate: locateParam
@@ -355,14 +404,14 @@ class Agent {
355
404
  scrollType: normalizedScrollType
356
405
  };
357
406
  }
358
- const { locateParam, restParams } = buildDetailedLocateParamAndRestParams(locatePrompt || '', opt);
407
+ const { locateParam, restParams } = buildDetailedLocateParamAndRestParams(locatePrompt || '', this.withContext('aiScroll', opt));
359
408
  await this.callActionInActionSpace('Scroll', {
360
409
  ...restParams,
361
410
  locate: locateParam
362
411
  });
363
412
  }
364
413
  async aiPinch(locatePrompt, opt) {
365
- const { locateParam, restParams } = buildDetailedLocateParamAndRestParams(locatePrompt || '', opt);
414
+ const { locateParam, restParams } = buildDetailedLocateParamAndRestParams(locatePrompt || '', this.withContext('aiPinch', opt));
366
415
  await this.callActionInActionSpace('Pinch', {
367
416
  ...restParams,
368
417
  locate: locateParam
@@ -370,7 +419,7 @@ class Agent {
370
419
  }
371
420
  async aiLongPress(locatePrompt, opt) {
372
421
  assert(locatePrompt, 'missing locate prompt for long press');
373
- const { locateParam, restParams } = buildDetailedLocateParamAndRestParams(locatePrompt, opt);
422
+ const { locateParam, restParams } = buildDetailedLocateParamAndRestParams(locatePrompt, this.withContext('aiLongPress', opt));
374
423
  await this.callActionInActionSpace('LongPress', {
375
424
  ...restParams,
376
425
  locate: locateParam
@@ -378,13 +427,14 @@ class Agent {
378
427
  }
379
428
  async aiClearInput(locatePrompt, opt) {
380
429
  assert(locatePrompt, 'missing locate prompt for clear input');
381
- const detailedLocateParam = buildDetailedLocateParam(locatePrompt, opt);
430
+ const detailedLocateParam = buildDetailedLocateParam(locatePrompt, this.withContext('aiClearInput', opt));
382
431
  await this.callActionInActionSpace('ClearInput', {
383
432
  locate: detailedLocateParam
384
433
  });
385
434
  }
386
435
  async aiAct(taskPrompt, opt) {
387
- const internalReportDisplay = opt?._internalReportDisplay;
436
+ const internalOptions = opt;
437
+ const internalReportDisplay = internalOptions?._internalReportDisplay;
388
438
  const taskPromptText = 'string' == typeof taskPrompt ? taskPrompt : taskPrompt.prompt;
389
439
  const reportPrompt = internalReportDisplay?.prompt || taskPromptText;
390
440
  const fileChooserAccept = opt?.fileChooserAccept ? this.normalizeFileInput(opt.fileChooserAccept) : void 0;
@@ -393,7 +443,7 @@ class Agent {
393
443
  const runAiAct = async ()=>{
394
444
  const planningModel = this.resolveModelRuntime('planning');
395
445
  const defaultModel = this.resolveModelRuntime('default');
396
- const aiActContext = opt?.context !== void 0 ? opt.context : this.aiActContext;
446
+ const aiActContext = this.resolveContext('aiAct', opt?.context, internalOptions?._internalAdditionalContext);
397
447
  const cachePrompt = buildPromptWithContext(taskPrompt, aiActContext);
398
448
  const effort = (()=>{
399
449
  const resolvedEffort = opt?.effort ?? (opt?.deepThink === true ? 'deepThink' : 'balance');
@@ -511,7 +561,7 @@ class Agent {
511
561
  return this.createInsight().aiAsk(prompt, opt);
512
562
  }
513
563
  async aiLocate(prompt, opt) {
514
- const locateParam = buildDetailedLocateParam(prompt, opt);
564
+ const locateParam = buildDetailedLocateParam(prompt, this.withContext('aiLocate', opt));
515
565
  assert(locateParam, 'cannot get locate param for aiLocate');
516
566
  const locatePlan = locatePlanForLocate(locateParam);
517
567
  const plans = [
@@ -534,10 +584,11 @@ class Agent {
534
584
  }
535
585
  async aiWaitFor(assertion, opt) {
536
586
  const modelRuntime = this.resolveModelRuntime('insight');
587
+ const options = this.withContext('aiWaitFor', opt);
537
588
  await this.taskExecutor.waitFor(assertion, {
538
- ...opt,
539
- timeoutMs: opt?.timeoutMs || 15000,
540
- checkIntervalMs: opt?.checkIntervalMs || 3000
589
+ ...options,
590
+ timeoutMs: options?.timeoutMs || 15000,
591
+ checkIntervalMs: options?.checkIntervalMs || 3000
541
592
  }, modelRuntime);
542
593
  }
543
594
  async ai(...args) {
@@ -806,11 +857,23 @@ class Agent {
806
857
  groupDescription: ''
807
858
  }, opts || {});
808
859
  assertReportGenerationOptions(this.opts);
809
- const resolvedAiActContext = this.opts.aiActContext ?? this.opts.aiActionContext;
860
+ if (void 0 !== this.opts.contexts && ('object' != typeof this.opts.contexts || null === this.opts.contexts || Array.isArray(this.opts.contexts))) throw new TypeError('opts.contexts must be a plain object');
861
+ for (const [key, value] of Object.entries(this.opts.contexts ?? {})){
862
+ if (!isAgentContextKey(key)) throw new TypeError(`Unknown Agent context key: ${key}`);
863
+ if (void 0 !== value && 'string' != typeof value) throw new TypeError(`Agent context "${key}" must be a string`);
864
+ }
865
+ const deprecatedAiActContextOption = void 0 !== this.opts.aiActContext ? 'aiActContext' : void 0 !== this.opts.aiActionContext ? 'aiActionContext' : void 0;
866
+ if (deprecatedAiActContextOption) warn(`Agent option "${deprecatedAiActContextOption}" is deprecated; use "contexts.aiAct" instead. When both are provided, "contexts.aiAct" takes precedence.`);
867
+ const normalizedContexts = {
868
+ ...this.opts.contexts
869
+ };
870
+ const resolvedAiActContext = normalizedContexts.aiAct ?? this.opts.aiActContext ?? this.opts.aiActionContext;
810
871
  if (void 0 !== resolvedAiActContext) {
872
+ normalizedContexts.aiAct = resolvedAiActContext;
811
873
  this.opts.aiActContext = resolvedAiActContext;
812
874
  this.opts.aiActionContext ??= resolvedAiActContext;
813
875
  }
876
+ this.opts.contexts = normalizedContexts;
814
877
  if (opts?.modelConfig && ('object' != typeof opts?.modelConfig || Array.isArray(opts.modelConfig))) throw new Error(`opts.modelConfig must be a plain object map of env keys to values, but got ${typeof opts?.modelConfig}`);
815
878
  const hasCustomConfig = opts?.modelConfig || opts?.createOpenAIClient;
816
879
  this.modelConfigManager = hasCustomConfig ? new ModelConfigManager(opts?.modelConfig, opts?.createOpenAIClient) : globalModelConfigManager;