@midscene/core 0.8.16 → 0.8.17-beta-20250103010342.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.
package/dist/lib/index.js CHANGED
@@ -1038,10 +1038,10 @@ var require_dist = __commonJS({
1038
1038
  }
1039
1039
  });
1040
1040
 
1041
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/async_caller.js
1041
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/async_caller.js
1042
1042
  var import_p_retry, import_p_queue, STATUS_NO_RETRY, STATUS_IGNORE, AsyncCaller;
1043
1043
  var init_async_caller = __esm({
1044
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/async_caller.js"() {
1044
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/async_caller.js"() {
1045
1045
  "use strict";
1046
1046
  import_p_retry = __toESM(require_p_retry());
1047
1047
  import_p_queue = __toESM(require_dist());
@@ -1163,7 +1163,7 @@ var init_async_caller = __esm({
1163
1163
  }
1164
1164
  });
1165
1165
 
1166
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/messages.js
1166
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/messages.js
1167
1167
  function isLangChainMessage(message) {
1168
1168
  return typeof (message == null ? void 0 : message._getType) === "function";
1169
1169
  }
@@ -1178,25 +1178,25 @@ function convertLangChainMessageToExample(message) {
1178
1178
  return converted;
1179
1179
  }
1180
1180
  var init_messages = __esm({
1181
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/messages.js"() {
1181
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/messages.js"() {
1182
1182
  "use strict";
1183
1183
  }
1184
1184
  });
1185
1185
 
1186
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/_uuid.js
1186
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/_uuid.js
1187
1187
  function assertUuid(str) {
1188
1188
  if (!validate_default(str)) {
1189
1189
  throw new Error(`Invalid UUID: ${str}`);
1190
1190
  }
1191
1191
  }
1192
1192
  var init_uuid = __esm({
1193
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/_uuid.js"() {
1193
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/_uuid.js"() {
1194
1194
  "use strict";
1195
1195
  init_esm_node();
1196
1196
  }
1197
1197
  });
1198
1198
 
1199
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/warn.js
1199
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/warn.js
1200
1200
  function warnOnce(message) {
1201
1201
  if (!warnedMessages[message]) {
1202
1202
  console.warn(message);
@@ -1205,13 +1205,13 @@ function warnOnce(message) {
1205
1205
  }
1206
1206
  var warnedMessages;
1207
1207
  var init_warn = __esm({
1208
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/warn.js"() {
1208
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/warn.js"() {
1209
1209
  "use strict";
1210
1210
  warnedMessages = {};
1211
1211
  }
1212
1212
  });
1213
1213
 
1214
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/client.js
1214
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/client.js
1215
1215
  async function mergeRuntimeEnvIntoRunCreates(runs) {
1216
1216
  const runtimeEnv = await getRuntimeEnvironment();
1217
1217
  const envVars = getLangChainEnvVarsMetadata();
@@ -1249,7 +1249,7 @@ function trimQuotes(str) {
1249
1249
  }
1250
1250
  var getTracingSamplingRate, isLocalhost, raiseForStatus, handle429, Queue, DEFAULT_BATCH_SIZE_LIMIT_BYTES, Client;
1251
1251
  var init_client = __esm({
1252
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/client.js"() {
1252
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/client.js"() {
1253
1253
  "use strict";
1254
1254
  init_esm_node();
1255
1255
  init_async_caller();
@@ -3010,10 +3010,10 @@ var init_client = __esm({
3010
3010
  }
3011
3011
  });
3012
3012
 
3013
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/index.js
3013
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/index.js
3014
3014
  var __version__;
3015
3015
  var init_dist = __esm({
3016
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/index.js"() {
3016
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/index.js"() {
3017
3017
  "use strict";
3018
3018
  init_client();
3019
3019
  init_run_trees();
@@ -3021,7 +3021,7 @@ var init_dist = __esm({
3021
3021
  }
3022
3022
  });
3023
3023
 
3024
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/env.js
3024
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/env.js
3025
3025
  async function getRuntimeEnvironment() {
3026
3026
  if (runtimeEnvironment === void 0) {
3027
3027
  const env = getEnv();
@@ -3118,7 +3118,7 @@ function getShas() {
3118
3118
  }
3119
3119
  var globalEnv, isBrowser, isWebWorker, isJsDom, isDeno, isNode, getEnv, runtimeEnvironment, cachedCommitSHAs;
3120
3120
  var init_env = __esm({
3121
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/env.js"() {
3121
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/env.js"() {
3122
3122
  "use strict";
3123
3123
  init_dist();
3124
3124
  isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined";
@@ -3148,10 +3148,10 @@ var init_env = __esm({
3148
3148
  }
3149
3149
  });
3150
3150
 
3151
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/env.js
3151
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/env.js
3152
3152
  var isTracingEnabled;
3153
3153
  var init_env2 = __esm({
3154
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/env.js"() {
3154
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/env.js"() {
3155
3155
  "use strict";
3156
3156
  init_env();
3157
3157
  isTracingEnabled = (tracingEnabled) => {
@@ -3169,7 +3169,7 @@ var init_env2 = __esm({
3169
3169
  }
3170
3170
  });
3171
3171
 
3172
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/run_trees.js
3172
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/run_trees.js
3173
3173
  function stripNonAlphanumeric(input) {
3174
3174
  return input.replace(/[-:.]/g, "");
3175
3175
  }
@@ -3193,7 +3193,7 @@ function isRunnableConfigLike(x) {
3193
3193
  }
3194
3194
  var Baggage, RunTree;
3195
3195
  var init_run_trees = __esm({
3196
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/run_trees.js"() {
3196
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/run_trees.js"() {
3197
3197
  "use strict";
3198
3198
  init_esm_node();
3199
3199
  init_env();
@@ -3617,13 +3617,13 @@ var init_run_trees = __esm({
3617
3617
  }
3618
3618
  });
3619
3619
 
3620
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/singletons/traceable.js
3620
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/singletons/traceable.js
3621
3621
  function isTraceableFunction(x) {
3622
3622
  return typeof x === "function" && "langsmith:traceable" in x;
3623
3623
  }
3624
3624
  var MockAsyncLocalStorage, AsyncLocalStorageProvider, AsyncLocalStorageProviderSingleton, ROOT;
3625
3625
  var init_traceable = __esm({
3626
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/singletons/traceable.js"() {
3626
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/singletons/traceable.js"() {
3627
3627
  "use strict";
3628
3628
  MockAsyncLocalStorage = class {
3629
3629
  getStore() {
@@ -3663,7 +3663,7 @@ var init_traceable = __esm({
3663
3663
  }
3664
3664
  });
3665
3665
 
3666
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/asserts.js
3666
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/asserts.js
3667
3667
  function isPromiseMethod(x) {
3668
3668
  if (x === "then" || x === "catch" || x === "finally") {
3669
3669
  return true;
@@ -3679,7 +3679,7 @@ function isKVMap(x) {
3679
3679
  }
3680
3680
  var isAsyncIterable, isIteratorLike, GeneratorFunction, isGenerator, isThenable, isReadableStream;
3681
3681
  var init_asserts = __esm({
3682
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/asserts.js"() {
3682
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/utils/asserts.js"() {
3683
3683
  "use strict";
3684
3684
  isAsyncIterable = (x) => x != null && typeof x === "object" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
3685
3685
  typeof x[Symbol.asyncIterator] === "function";
@@ -3695,7 +3695,7 @@ var init_asserts = __esm({
3695
3695
  }
3696
3696
  });
3697
3697
 
3698
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/traceable.js
3698
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/traceable.js
3699
3699
  function traceable(wrappedFunc, config) {
3700
3700
  const { aggregator, argsConfigPath, ...runTreeConfig } = config != null ? config : {};
3701
3701
  const traceableFunc = (...args) => {
@@ -3893,7 +3893,7 @@ function traceable(wrappedFunc, config) {
3893
3893
  }
3894
3894
  var import_node_async_hooks, handleRunInputs, handleRunOutputs, getTracingRunTree, getSerializablePromise, convertSerializableArg;
3895
3895
  var init_traceable2 = __esm({
3896
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/traceable.js"() {
3896
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/traceable.js"() {
3897
3897
  "use strict";
3898
3898
  import_node_async_hooks = require("async_hooks");
3899
3899
  init_run_trees();
@@ -4073,7 +4073,7 @@ var init_traceable2 = __esm({
4073
4073
  }
4074
4074
  });
4075
4075
 
4076
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/wrappers/openai.js
4076
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/wrappers/openai.js
4077
4077
  function _combineChatCompletionChoices(choices) {
4078
4078
  var _a, _b;
4079
4079
  const reversedChoices = choices.slice().reverse();
@@ -4147,7 +4147,7 @@ function _combineChatCompletionChoices(choices) {
4147
4147
  }
4148
4148
  var chatAggregator, textAggregator, wrapOpenAI, _wrapClient, wrapSDK;
4149
4149
  var init_openai = __esm({
4150
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/wrappers/openai.js"() {
4150
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/wrappers/openai.js"() {
4151
4151
  "use strict";
4152
4152
  init_traceable2();
4153
4153
  chatAggregator = (chunks) => {
@@ -4259,22 +4259,22 @@ var init_openai = __esm({
4259
4259
  }
4260
4260
  });
4261
4261
 
4262
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/wrappers/index.js
4262
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/wrappers/index.js
4263
4263
  var init_wrappers = __esm({
4264
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/wrappers/index.js"() {
4264
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/dist/wrappers/index.js"() {
4265
4265
  "use strict";
4266
4266
  init_openai();
4267
4267
  }
4268
4268
  });
4269
4269
 
4270
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/wrappers.js
4270
+ // ../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/wrappers.js
4271
4271
  var wrappers_exports = {};
4272
4272
  __export(wrappers_exports, {
4273
4273
  wrapOpenAI: () => wrapOpenAI,
4274
4274
  wrapSDK: () => wrapSDK
4275
4275
  });
4276
4276
  var init_wrappers2 = __esm({
4277
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/wrappers.js"() {
4277
+ "../../node_modules/.pnpm/langsmith@0.1.36_@langchain+core@0.3.26_openai@4.57.1_zod@3.23.8___langchain@0.3.8_@langchain_pnf6d76o2t3a6oyjkhgz2xqm4a/node_modules/langsmith/wrappers.js"() {
4278
4278
  "use strict";
4279
4279
  init_wrappers();
4280
4280
  }
@@ -4319,6 +4319,7 @@ var OPENAI_MAX_TOKENS = "OPENAI_MAX_TOKENS";
4319
4319
  var MIDSCENE_MODEL_TEXT_ONLY = "MIDSCENE_MODEL_TEXT_ONLY";
4320
4320
  var MIDSCENE_CACHE = "MIDSCENE_CACHE";
4321
4321
  var MATCH_BY_POSITION = "MATCH_BY_POSITION";
4322
+ var MIDSCENE_API_TYPE = "MIDSCENE_API_TYPE";
4322
4323
  var MIDSCENE_REPORT_TAG_NAME = "MIDSCENE_REPORT_TAG_NAME";
4323
4324
  var MIDSCENE_USE_AZURE_OPENAI = "MIDSCENE_USE_AZURE_OPENAI";
4324
4325
  var MIDSCENE_AZURE_OPENAI_SCOPE = "MIDSCENE_AZURE_OPENAI_SCOPE";
@@ -4536,7 +4537,7 @@ function stringifyDumpData(data, indents) {
4536
4537
  return JSON.stringify(data, replacerForPageObject, indents);
4537
4538
  }
4538
4539
  function getVersion() {
4539
- return "0.8.16";
4540
+ return "0.8.17-beta-20250103010342.0";
4540
4541
  }
4541
4542
 
4542
4543
  // src/action/executor.ts
@@ -4726,6 +4727,7 @@ var import_openai = __toESM(require("openai"));
4726
4727
  var import_socks_proxy_agent = require("socks-proxy-agent");
4727
4728
 
4728
4729
  // src/ai-model/prompt/element_inspector.ts
4730
+ var import_prompts = require("@langchain/core/prompts");
4729
4731
  function systemPromptToFindElement() {
4730
4732
  if (getAIConfig(MATCH_BY_POSITION)) {
4731
4733
  return systemPromptToFindElementPosition();
@@ -4868,36 +4870,31 @@ Output Example:
4868
4870
  }
4869
4871
  function systemPromptToFindElementPosition() {
4870
4872
  return `
4871
- ## Role:
4872
- You are an expert in software page image (2D) and page element text analysis.
4873
+ You are a GUI agent. You are given a task and your action history, with screenshots. You need to perform the next action to complete the task.
4873
4874
 
4874
- ## Objective:
4875
- Based on screenshots and descriptions, find specific coordinates
4875
+ ## Output Format
4876
+ \`\`\`
4877
+ Action_Summary: ...
4878
+ Action: ...
4879
+ \`\`\`
4876
4880
 
4877
- ## Output Format:
4881
+ ## Action Space
4882
+ click(start_box='[x1, y1, x2, y2]')
4883
+ long_press(start_box='[x1, y1, x2, y2]', time='')
4884
+ type(content='')
4885
+ scroll(direction='down or up or right or left')
4886
+ open_app(app_name='')
4887
+ navigate_back()
4888
+ navigate_home()
4889
+ WAIT()
4890
+ finished() # Submit the task regardless of whether it succeeds or fails.
4878
4891
 
4879
- Please return the result in JSON format as follows:
4892
+ ## Note
4893
+ - Use Chinese in \`Action_Summary\` part.
4880
4894
 
4881
- \`\`\`json
4882
- {
4883
- "elements": [
4884
- {
4885
- // Describe the reason for finding this element, replace with actual value in practice
4886
- "reason": "Reason for finding element 4: It is located in the upper right corner, is an image type, and according to the screenshot, it is a shopping cart icon button",
4887
- // If the target element includes text information, extract the text information; if it does not, do not extract it
4888
- "text": "",
4889
- // position of this element
4890
- "position": { x: number, y: number }
4891
- }
4892
- ],
4893
- "errors": []// Return an error if there is no target element on the picture
4894
- }
4895
- \`\`\`
4895
+ ## User Instruction
4896
4896
  `;
4897
4897
  }
4898
- function multiDescription(multi) {
4899
- return multi ? "multiple elements matching the description (two or more)" : "The element closest to the description (only one)";
4900
- }
4901
4898
  var findElementSchema = {
4902
4899
  type: "json_schema",
4903
4900
  json_schema: {
@@ -4942,6 +4939,23 @@ var findElementSchema = {
4942
4939
  }
4943
4940
  }
4944
4941
  };
4942
+ var findElementPrompt = new import_prompts.PromptTemplate({
4943
+ template: `
4944
+ Here is the item user want to find. Just go ahead:
4945
+ =====================================
4946
+ {{
4947
+ "description": "{targetElementDescription}",
4948
+ "multi": {multi}
4949
+ }}
4950
+ =====================================
4951
+
4952
+ pageDescription: {pageDescription}
4953
+ `,
4954
+ inputVariables: ["pageDescription", "targetElementDescription", "multi"]
4955
+ });
4956
+
4957
+ // src/ai-model/prompt/planning.ts
4958
+ var import_prompts3 = require("@langchain/core/prompts");
4945
4959
 
4946
4960
  // src/ai-model/prompt/util.ts
4947
4961
  var import_node_assert3 = __toESM(require("assert"));
@@ -4950,6 +4964,7 @@ var import_node_assert3 = __toESM(require("assert"));
4950
4964
  var import_img = require("@midscene/shared/img");
4951
4965
 
4952
4966
  // src/ai-model/prompt/util.ts
4967
+ var import_prompts2 = require("@langchain/core/prompts");
4953
4968
  var characteristic = "You are a versatile professional in software UI design and testing. Your outstanding contributions will impact the user experience of billions of users.";
4954
4969
  var contextFormatIntro = `
4955
4970
  The user will give you a screenshot and some of the texts on it. There may be some none-English characters (like Chinese) on it, indicating it's an non-English app. If some text is shown on screenshot but not introduced by the JSON description, use the information you see on screenshot.`;
@@ -4981,6 +4996,22 @@ Return in the following JSON format:
4981
4996
  }
4982
4997
  `;
4983
4998
  }
4999
+ var extractDataPrompt = new import_prompts2.PromptTemplate({
5000
+ template: `
5001
+ pageDescription: {pageDescription}
5002
+
5003
+ Use your extract_data_from_UI skill to find the following data, placing it in the \`data\` field
5004
+ DATA_DEMAND start:
5005
+ =====================================
5006
+ {dataKeys}
5007
+
5008
+ {dataQuery}
5009
+
5010
+ =====================================
5011
+ DATA_DEMAND ends.
5012
+ `,
5013
+ inputVariables: ["pageDescription", "dataKeys", "dataQuery"]
5014
+ });
4984
5015
  function systemPromptToAssert() {
4985
5016
  return `
4986
5017
  ${characteristic}
@@ -5029,7 +5060,7 @@ function truncateText(text, maxLength = 100) {
5029
5060
  }
5030
5061
  return "";
5031
5062
  }
5032
- function elementByPosition(elementsInfo, position) {
5063
+ function elementByPositionWithElementInfo(elementsInfo, position) {
5033
5064
  (0, import_node_assert3.default)(typeof position !== "undefined", "position is required for query");
5034
5065
  const item = elementsInfo.find((item2) => {
5035
5066
  return item2.rect.left <= position.x && position.x <= item2.rect.left + item2.rect.width && item2.rect.top <= position.y && position.y <= item2.rect.top + item2.rect.height;
@@ -5083,23 +5114,26 @@ async function describeUserPage(context, opt) {
5083
5114
  const { id, ...rest } = item;
5084
5115
  return `id=${id}: ${JSON.stringify(rest)}`;
5085
5116
  }).join("\n\n");
5117
+ const pageJSONDescription = getAIConfig(MATCH_BY_POSITION) ? "" : `Some of the elements are marked with a rectangle in the screenshot, some are not.
5118
+ Json description of all the page elements:
5119
+ ${contentList}`;
5120
+ const sizeDescription = describeSize({ width, height });
5086
5121
  return {
5087
5122
  description: `
5088
- The size of the page: ${describeSize({ width, height })}
5089
- Some of the elements are marked with a rectangle in the screenshot, some are not.
5123
+ The size of the page: ${sizeDescription}
5090
5124
 
5091
- ${// if match by id, use the description of the element
5092
- getAIConfig(MATCH_BY_POSITION) ? "" : `Json description of all the page elements:
5093
- ${contentList}`}
5125
+ ${pageJSONDescription}
5094
5126
  `,
5095
5127
  elementById(id) {
5096
5128
  (0, import_node_assert3.default)(typeof id !== "undefined", "id is required for query");
5097
5129
  const item = idElementMap[`${id}`];
5098
5130
  return item;
5099
5131
  },
5100
- elementByPosition(position) {
5101
- return elementByPosition(elementsInfo, position);
5102
- }
5132
+ elementByPosition(position, size) {
5133
+ console.log("elementByPosition", { position, size });
5134
+ return elementByPositionWithElementInfo(elementsInfo, position);
5135
+ },
5136
+ size: { width, height }
5103
5137
  };
5104
5138
  }
5105
5139
  function cropFieldInformation(elementsInfo, truncateTextLength, filterNonTextContent = false) {
@@ -5187,19 +5221,35 @@ function retrieveSection(prompt) {
5187
5221
  // src/ai-model/prompt/planning.ts
5188
5222
  var quickAnswerFormat = () => {
5189
5223
  const matchByPosition = getAIConfig(MATCH_BY_POSITION);
5190
- const description = `
5191
- ${matchByPosition ? `"position": { x: number; y: number } // Represents the position of the element; replace with actual values in practice (ensure it reflects the element's position)` : '"id": string // Represents the ID of the element; replace with actual values in practice'}
5192
- `;
5193
- const format = matchByPosition ? '"position": { x: number; y: number }' : '"id": string';
5194
- const sample = matchByPosition ? '{"position": { x: 100, y: 200 }}' : '{"id": "c81c4e9a33"}';
5224
+ const locationFormat = {
5225
+ position: {
5226
+ description: `"position": { x: number; y: number } // Represents the position of the element; replace with actual values in practice (ensure it reflects the element's position)`,
5227
+ format: '"position": { x: number; y: number }',
5228
+ sample: '{"prompt": "the search bar"}',
5229
+ locateParam: `{
5230
+ "prompt"?: string // the description of the element to find. It can only be omitted when locate is null.
5231
+ } | null // If it's not on the page, the LocateParam should be null`
5232
+ },
5233
+ id: {
5234
+ description: '"id": string // Represents the ID of the element; replace with actual values in practice',
5235
+ format: '"id": string',
5236
+ sample: `{"id": "c81c4e9a33", "prompt": "the search bar"}`,
5237
+ locateParam: `{
5238
+ "id": string, // the id of the element found. It should either be the id marked with a rectangle in the screenshot or the id described in the description.
5239
+ "prompt"?: string // the description of the element to find. It can only be omitted when locate is null.
5240
+ } | null // If it's not on the page, the LocateParam should be null`
5241
+ }
5242
+ };
5243
+ const type = matchByPosition ? "position" : "id";
5244
+ const format = locationFormat[type];
5195
5245
  return {
5196
- description,
5197
- format,
5198
- sample
5246
+ description: format.description,
5247
+ format: format.format,
5248
+ sample: format.sample,
5249
+ locateParam: format.locateParam
5199
5250
  };
5200
5251
  };
5201
- function systemPromptToTaskPlanning() {
5202
- return `
5252
+ var systemTemplate = `
5203
5253
  ## Role
5204
5254
 
5205
5255
  You are a versatile professional in software UI automation. Your outstanding contributions will impact the user experience of billions of users.
@@ -5233,76 +5283,70 @@ You are a versatile professional in software UI automation. Your outstanding con
5233
5283
 
5234
5284
  The \`locate\` param is commonly used in the \`param\` field of the action, means to locate the target element to perform the action, it follows the following scheme:
5235
5285
 
5236
- type LocateParam = {
5237
- "id": string, // the id of the element found. It should either be the id marked with a rectangle in the screenshot or the id described in the description.
5238
- prompt?: string // the description of the element to find. It can only be omitted when locate is null.
5239
- } | null // If it's not on the page, the LocateParam should be null
5286
+ type LocateParam = {locateParam}
5240
5287
 
5241
5288
  ### Supported actions
5242
5289
 
5243
5290
  Each action has a \`type\` and corresponding \`param\`. To be detailed:
5244
5291
  - type: 'Tap', tap the located element
5245
- * { locate: LocateParam, param: null }
5292
+ * {{ locate: {sample}, param: null }}
5246
5293
  - type: 'Hover', move mouse over to the located element
5247
- * { locate: LocateParam, param: null }
5294
+ * {{ locate: LocateParam, param: null }}
5248
5295
  - type: 'Input', replace the value in the input field
5249
- * { locate: LocateParam, param: { value: string } }
5296
+ * {{ locate: LocateParam, param: {{ value: string }} }}
5250
5297
  * \`value\` is the final required input value based on the existing input. No matter what modifications are required, just provide the final value to replace the existing input value.
5251
5298
  - type: 'KeyboardPress', press a key
5252
- * { param: { value: string } }
5299
+ * {{ param: {{ value: string }} }}
5253
5300
  - type: 'Scroll', scroll up or down.
5254
- * {
5301
+ * {{
5255
5302
  locate: LocateParam | null,
5256
- param: {
5303
+ param: {{
5257
5304
  direction: 'down'(default) | 'up' | 'right' | 'left',
5258
5305
  scrollType: 'once' (default) | 'untilBottom' | 'untilTop' | 'untilRight' | 'untilLeft',
5259
5306
  distance: null | number
5260
- }
5261
- }
5307
+ }}
5308
+ }}
5262
5309
  * To scroll some specific element, put the element at the center of the region in the \`locate\` field. If it's a page scroll, put \`null\` in the \`locate\` field.
5263
5310
  * \`param\` is required in this action. If some fields are not specified, use direction \`down\`, \`once\` scroll type, and \`null\` distance.
5264
5311
  - type: 'FalsyConditionStatement'
5265
- * { param: null }
5312
+ * {{ param: null }}
5266
5313
  * use this action when the instruction is an "if" statement and the condition is falsy.
5267
5314
  - type: 'Sleep'
5268
- * { param: { timeMs: number } }
5315
+ * {{ param: {{ timeMs: number }} }}
5269
5316
 
5270
5317
  ## How to compose the \`taskWillBeAccomplished\` and \`furtherPlan\` fields ?
5271
5318
 
5272
5319
  \`taskWillBeAccomplished\` is a boolean field, means whether the task will be accomplished after all the actions.
5273
5320
 
5274
- \`furtherPlan\` is used when the task cannot be accomplished. It follows the scheme { whatHaveDone: string, whatToDoNext: string }:
5321
+ \`furtherPlan\` is used when the task cannot be accomplished. It follows the scheme {{ whatHaveDone: string, whatToDoNext: string }}:
5275
5322
  - \`whatHaveDone\`: a string, describe what have been done after the previous actions.
5276
5323
  - \`whatToDoNext\`: a string, describe what should be done next after the previous actions has finished. It should be a concise and clear description of the actions to be performed. Make sure you don't lose any necessary steps user asked.
5277
-
5324
+ `;
5325
+ var outputTemplate = `
5278
5326
  ## Output JSON Format:
5279
5327
 
5280
5328
  The JSON format is as follows:
5281
5329
 
5282
- {
5330
+ {{
5283
5331
  "actions": [
5284
- {
5332
+ {{
5285
5333
  "thought": "Reasons for generating this task, and why this task is feasible on this page",
5286
5334
  "type": "Tap",
5287
5335
  "param": null,
5288
- "locate": {
5289
- {"id": "c81c4e9a33"},
5290
- prompt: "the search bar"
5291
- } | null,
5292
- },
5336
+ "locate": {sample} | null,
5337
+ }},
5293
5338
  // ... more actions
5294
5339
  ],
5295
5340
  "taskWillBeAccomplished": boolean,
5296
- "furtherPlan": { "whatHaveDone": string, "whatToDoNext": string } | null,
5341
+ "furtherPlan": {{ "whatHaveDone": string, "whatToDoNext": string }} | null,
5297
5342
  "error"?: string
5298
- }
5299
-
5300
- ## Example #1 : How to decompose a task
5343
+ }}
5344
+ Here is an example of how to decompose a task:
5301
5345
 
5302
5346
  When a user says 'Click the language switch button, wait 1s, click "English"', the user will give you the description like this:
5303
5347
 
5304
5348
  ====================
5305
- ${samplePageDescription}
5349
+ {pageDescription}
5306
5350
  ====================
5307
5351
 
5308
5352
  By viewing the page screenshot and description, you should consider this and output the JSON:
@@ -5312,110 +5356,119 @@ By viewing the page screenshot and description, you should consider this and out
5312
5356
  * The "English" option button is not shown in the screenshot now, it means it may only show after the previous actions are finished. So the last action will have a \`null\` value in the \`locate\` field.
5313
5357
  * The task cannot be accomplished (because we cannot see the "English" option now), so a \`furtherPlan\` field is needed.
5314
5358
 
5315
- {
5359
+ {{
5316
5360
  "actions":[
5317
- {
5361
+ {{
5362
+ "type": "Tap",
5318
5363
  "thought": "Click the language switch button to open the language options.",
5319
- "type": "Tap",
5320
5364
  "param": null,
5321
- "locate": {
5322
- ${quickAnswerFormat().sample},
5323
- "prompt": "the language switch button with the text '中文'"
5324
- }
5325
- },
5326
- {
5327
- "thought": "Wait for 1 second to ensure the language options are displayed.",
5365
+ "locate": {sample},
5366
+ }},
5367
+ {{
5328
5368
  "type": "Sleep",
5329
- "param": { "timeMs": 1000 },
5330
- },
5331
- {
5332
- "thought": "Locate the 'English' option in the language menu.",
5369
+ "thought": "Wait for 1 second to ensure the language options are displayed.",
5370
+ "param": {{ "timeMs": 1000 }},
5371
+ }},
5372
+ {{
5333
5373
  "type": "Tap",
5334
- "param": null,
5374
+ "thought": "Locate the 'English' option in the language menu.",
5375
+ "param": null,
5335
5376
  "locate": null
5336
- },
5377
+ }},
5337
5378
  ],
5338
5379
  "error": null,
5339
5380
  "taskWillBeAccomplished": false,
5340
- "furtherPlan": {
5341
- "whatToDoNext": "find the 'English' option and click on it",
5342
- "whatHaveDone": "Click the language switch button and wait 1s"
5343
- }
5344
- }
5381
+ "furtherPlan": {{
5382
+ "whatToDoNext": "find the 'English' option and click on it",
5383
+ "whatHaveDone": "Click the language switch button and wait 1s"
5384
+ }}
5385
+ }}
5345
5386
 
5346
- ## Example #2 : Tolerate the error situation only when the instruction is an "if" statement
5387
+ Here is another example of how to tolerate error situations only when the instruction is an "if" statement:
5347
5388
 
5348
5389
  If the user says "If there is a popup, close it", you should consider this and output the JSON:
5349
5390
 
5350
5391
  * By viewing the page screenshot and description, you cannot find the popup, so the condition is falsy.
5351
5392
  * The instruction itself is an "if" statement, it means the user can tolerate this situation, so you should leave a \`FalsyConditionStatement\` action.
5352
5393
 
5353
- {
5354
- "actions": [{
5355
- "thought": "There is no popup on the page",
5394
+ {{
5395
+ "actions": [{{
5356
5396
  "type": "FalsyConditionStatement",
5397
+ "thought": "There is no popup on the page",
5357
5398
  "param": null
5358
- }
5399
+ }}
5359
5400
  ],
5360
5401
  "taskWillBeAccomplished": true,
5361
5402
  "furtherPlan": null
5362
- }
5403
+ }}
5363
5404
 
5364
5405
  For contrast, if the user says "Close the popup" in this situation, you should consider this and output the JSON:
5365
5406
 
5366
- {
5407
+ {{
5367
5408
  "actions": [],
5368
5409
  "error": "The instruction and page context are irrelevant, there is no popup on the page",
5369
5410
  "taskWillBeAccomplished": true,
5370
5411
  "furtherPlan": null
5371
- }
5412
+ }}
5372
5413
 
5373
- ## Example #3 : When task is accomplished, don't plan more actions
5414
+ Here is an example of when task is accomplished, don't plan more actions:
5374
5415
 
5375
5416
  When the user ask to "Wait 4s", you should consider this:
5376
5417
 
5377
- {
5418
+ {{
5378
5419
  "actions": [
5379
- {
5380
- "thought": "Wait for 4 seconds",
5420
+ {{
5381
5421
  "type": "Sleep",
5382
- "param": { "timeMs": 4000 },
5383
- },
5422
+ "thought": "Wait for 4 seconds",
5423
+ "param": {{ "timeMs": 4000 }},
5424
+ }},
5384
5425
  ],
5385
5426
  "taskWillBeAccomplished": true,
5386
5427
  "furtherPlan": null // All steps have been included in the actions, so no further plan is needed
5387
- }
5428
+ }}
5388
5429
 
5389
- ## Bad case #1 : Missing \`prompt\` in the 'Locate' field; Missing \`furtherPlan\` field when the task won't be accomplished
5430
+ Here is an example of what NOT to do:
5390
5431
 
5391
5432
  Wrong output:
5392
5433
 
5393
- {
5434
+ {{
5394
5435
  "actions":[
5395
- {
5396
- "thought": "Click the language switch button to open the language options.",
5436
+ {{
5397
5437
  "type": "Tap",
5438
+ "thought": "Click the language switch button to open the language options.",
5398
5439
  "param": null,
5399
- "locate": {
5400
- ${quickAnswerFormat().sample}, // WRONG:prompt is missing
5401
- }
5402
- },
5403
- {
5440
+ "locate": {{
5441
+ {sample}, // WRONG:prompt is missing
5442
+ }}
5443
+ }},
5444
+ {{
5445
+ "type": "Tap",
5404
5446
  "thought": "Click the English option",
5405
- "type": "Tap",
5406
5447
  "param": null,
5407
5448
  "locate": null, // This means the 'English' option is not shown in the screenshot, the task cannot be accomplished
5408
- }
5449
+ }}
5409
5450
  ],
5410
5451
  "taskWillBeAccomplished": false,
5411
5452
  // WRONG: should not be null
5412
5453
  "furtherPlan": null,
5413
- }
5454
+ }}
5414
5455
 
5415
- Reason:
5456
+ Reason:
5416
5457
  * The \`prompt\` is missing in the first 'Locate' action
5417
5458
  * Since the option button is not shown in the screenshot, the task cannot be accomplished, so a \`furtherPlan\` field is needed.
5418
5459
  `;
5460
+ async function systemPromptToTaskPlanning() {
5461
+ const promptTemplate = new import_prompts3.PromptTemplate({
5462
+ template: `${systemTemplate}
5463
+
5464
+ ${outputTemplate}`,
5465
+ inputVariables: ["pageDescription", "sample", "locateParam"]
5466
+ });
5467
+ return await promptTemplate.format({
5468
+ pageDescription: samplePageDescription,
5469
+ sample: quickAnswerFormat().sample,
5470
+ locateParam: quickAnswerFormat().locateParam
5471
+ });
5419
5472
  }
5420
5473
  var planSchema = {
5421
5474
  type: "json_schema",
@@ -5499,6 +5552,34 @@ var planSchema = {
5499
5552
  }
5500
5553
  }
5501
5554
  };
5555
+ var taskBackgroundContext = async (originalPrompt, whatHaveDone) => {
5556
+ if (!originalPrompt || !whatHaveDone) {
5557
+ return "";
5558
+ }
5559
+ return `
5560
+ For your information, this is a task that some important person handed to you. Here is the original task description and what have been done after the previous actions:
5561
+ =====================================
5562
+ Original task description:
5563
+ ${originalPrompt}
5564
+ =====================================
5565
+ What have been done:
5566
+ ${whatHaveDone}
5567
+ =====================================
5568
+ `;
5569
+ };
5570
+ var automationUserPrompt = new import_prompts3.PromptTemplate({
5571
+ template: `
5572
+ Here is the instruction:
5573
+ =====================================
5574
+ {userPrompt}
5575
+ =====================================
5576
+
5577
+ {taskBackgroundContext}
5578
+
5579
+ pageDescription: {pageDescription}
5580
+ `,
5581
+ inputVariables: ["pageDescription", "userPrompt", "taskBackgroundContext"]
5582
+ });
5502
5583
 
5503
5584
  // src/ai-model/openai/index.ts
5504
5585
  function checkAIConfig(preferVendor) {
@@ -5521,7 +5602,9 @@ function getModelName() {
5521
5602
  }
5522
5603
  return modelName;
5523
5604
  }
5524
- async function createChatClient() {
5605
+ async function createChatClient({
5606
+ AIActionTypeValue
5607
+ }) {
5525
5608
  let openai;
5526
5609
  const extraConfig = getAIConfigInJson(MIDSCENE_OPENAI_INIT_CONFIG_JSON);
5527
5610
  const socksProxy = getAIConfig(MIDSCENE_OPENAI_SOCKS_PROXY);
@@ -5572,6 +5655,10 @@ async function createChatClient() {
5572
5655
  apiKey: getAIConfig(OPENAI_API_KEY),
5573
5656
  httpAgent: socksAgent,
5574
5657
  ...extraConfig,
5658
+ defaultHeaders: {
5659
+ ...(extraConfig == null ? void 0 : extraConfig.defaultHeaders) || {},
5660
+ [MIDSCENE_API_TYPE]: AIActionTypeValue.toString()
5661
+ },
5575
5662
  dangerouslyAllowBrowser: true
5576
5663
  });
5577
5664
  }
@@ -5604,8 +5691,10 @@ async function createChatClient() {
5604
5691
  }
5605
5692
  throw new Error("Openai SDK or Anthropic SDK is not initialized");
5606
5693
  }
5607
- async function call(messages, responseFormat) {
5608
- const { completion, style } = await createChatClient();
5694
+ async function call(messages, AIActionTypeValue, responseFormat) {
5695
+ const { completion, style } = await createChatClient({
5696
+ AIActionTypeValue
5697
+ });
5609
5698
  const shouldPrintTiming = typeof getAIConfig(MIDSCENE_DEBUG_AI_PROFILE) === "string";
5610
5699
  const maxTokens = getAIConfig(OPENAI_MAX_TOKENS);
5611
5700
  const startTime = Date.now();
@@ -5688,52 +5777,51 @@ async function callToGetJSONObject(messages, AIActionTypeValue) {
5688
5777
  responseFormat = { type: "json_object" /* JSON */ };
5689
5778
  }
5690
5779
  }
5691
- const safeJsonParse = (input) => {
5692
- try {
5693
- return JSON.parse(input);
5694
- } catch (e) {
5695
- return null;
5696
- }
5697
- };
5698
- const response = await call(messages, responseFormat);
5780
+ const response = await call(messages, AIActionTypeValue, responseFormat);
5699
5781
  (0, import_node_assert4.default)(response, "empty response");
5700
- let jsonContent = safeJsonParse(response.content);
5701
- if (jsonContent)
5702
- return { content: jsonContent, usage: response.usage };
5703
- const cleanJsonString = extractJSONFromCodeBlock(response.content);
5704
- try {
5705
- jsonContent = JSON.parse(cleanJsonString);
5706
- } catch (e) {
5707
- }
5708
- if (jsonContent)
5709
- return { content: jsonContent, usage: response.usage };
5782
+ const jsonContent = safeParseJson(response.content);
5783
+ return { content: jsonContent, usage: response.usage };
5784
+ }
5785
+ function extractJSONFromCodeBlock(response) {
5710
5786
  try {
5711
- jsonContent = import_dirty_json.default.parse(cleanJsonString);
5787
+ const jsonMatch = response.match(/^\s*(\{[\s\S]*\})\s*$/);
5788
+ if (jsonMatch) {
5789
+ return jsonMatch[1];
5790
+ }
5791
+ const codeBlockMatch = response.match(
5792
+ /```(?:json)?\s*(\{[\s\S]*?\})\s*```/
5793
+ );
5794
+ if (codeBlockMatch) {
5795
+ return codeBlockMatch[1];
5796
+ }
5797
+ const jsonLikeMatch = response.match(/\{[\s\S]*\}/);
5798
+ if (jsonLikeMatch) {
5799
+ return jsonLikeMatch[0];
5800
+ }
5712
5801
  } catch (e) {
5713
5802
  }
5714
- if (jsonContent)
5715
- return { content: jsonContent, usage: response.usage };
5716
- throw Error(`failed to parse json response: ${response.content}`);
5803
+ return response;
5717
5804
  }
5718
- function extractJSONFromCodeBlock(response) {
5719
- const jsonMatch = response.match(/^\s*(\{[\s\S]*\})\s*$/);
5720
- if (jsonMatch) {
5721
- return jsonMatch[1];
5805
+ function safeParseJson(input) {
5806
+ var _a;
5807
+ const cleanJsonString = extractJSONFromCodeBlock(input);
5808
+ if (cleanJsonString.match(/\((\d+),(\d+)\)/)) {
5809
+ return (_a = cleanJsonString.match(/\((\d+),(\d+)\)/)) == null ? void 0 : _a.slice(1).map(Number);
5722
5810
  }
5723
- const codeBlockMatch = response.match(/```(?:json)?\s*(\{[\s\S]*?\})\s*```/);
5724
- if (codeBlockMatch) {
5725
- return codeBlockMatch[1];
5811
+ try {
5812
+ return JSON.parse(cleanJsonString);
5813
+ } catch (e) {
5726
5814
  }
5727
- const jsonLikeMatch = response.match(/\{[\s\S]*\}/);
5728
- if (jsonLikeMatch) {
5729
- return jsonLikeMatch[0];
5815
+ try {
5816
+ return import_dirty_json.default.parse(cleanJsonString);
5817
+ } catch (e) {
5818
+ console.log("e:", e);
5730
5819
  }
5731
- return response;
5820
+ throw Error(`failed to parse json response: ${input}`);
5732
5821
  }
5733
5822
 
5734
5823
  // src/ai-model/common.ts
5735
- async function callAiFn(options) {
5736
- const { msgs, AIActionType: AIActionTypeValue } = options;
5824
+ async function callAiFn(msgs, AIActionTypeValue) {
5737
5825
  (0, import_node_assert5.default)(
5738
5826
  checkAIConfig(),
5739
5827
  "Cannot find config for AI model service. You should set it before using. https://midscenejs.com/model-provider.html"
@@ -5744,17 +5832,6 @@ async function callAiFn(options) {
5744
5832
  );
5745
5833
  return { content, usage };
5746
5834
  }
5747
- function transformUserMessages(msgs) {
5748
- const textOnly = Boolean(getAIConfig(MIDSCENE_MODEL_TEXT_ONLY));
5749
- if (!textOnly)
5750
- return msgs;
5751
- return msgs.reduce((res, msg) => {
5752
- if (msg.type === "text") {
5753
- res += msg.text;
5754
- }
5755
- return res;
5756
- }, "");
5757
- }
5758
5835
 
5759
5836
  // src/ai-model/inspect.ts
5760
5837
  var import_node_assert6 = __toESM(require("assert"));
@@ -5762,76 +5839,82 @@ var liteContextConfig = {
5762
5839
  filterNonTextContent: true,
5763
5840
  truncateTextLength: 200
5764
5841
  };
5765
- function transformElementPositionToId(aiResult, elementsInfo) {
5842
+ function transformToAbsoluteCoords(relativePosition, size) {
5843
+ return {
5844
+ x: Number((relativePosition.x / 1e3 * size.width).toFixed(3)),
5845
+ y: Number((relativePosition.y / 1e3 * size.height).toFixed(3))
5846
+ };
5847
+ }
5848
+ async function transformElementPositionToId(aiResult, elementsInfo, size, screenshotBase64) {
5849
+ if (Array.isArray(aiResult)) {
5850
+ const relativePosition = aiResult;
5851
+ const absolutePosition = transformToAbsoluteCoords(
5852
+ {
5853
+ x: relativePosition[0],
5854
+ y: relativePosition[1]
5855
+ },
5856
+ size
5857
+ );
5858
+ const element = elementByPositionWithElementInfo(
5859
+ elementsInfo,
5860
+ absolutePosition
5861
+ );
5862
+ (0, import_node_assert6.default)(
5863
+ element,
5864
+ `inspect: no id found with position: ${JSON.stringify({ absolutePosition })}`
5865
+ );
5866
+ return {
5867
+ errors: [],
5868
+ elements: [
5869
+ {
5870
+ id: element.id
5871
+ }
5872
+ ]
5873
+ };
5874
+ }
5766
5875
  return {
5767
5876
  errors: aiResult.errors,
5768
- elements: aiResult.elements.map((item) => {
5769
- var _a;
5770
- if ("id" in item) {
5771
- return item;
5772
- }
5773
- const { position } = item;
5774
- const id = (_a = elementByPosition(elementsInfo, position)) == null ? void 0 : _a.id;
5775
- (0, import_node_assert6.default)(
5776
- id,
5777
- `inspect: no id found with position: ${JSON.stringify({ position })}`
5778
- );
5779
- return {
5780
- ...item,
5781
- id
5782
- };
5783
- })
5877
+ elements: aiResult.elements
5784
5878
  };
5785
5879
  }
5880
+ function getQuickAnswer(quickAnswer, elementById) {
5881
+ if (!quickAnswer) {
5882
+ return void 0;
5883
+ }
5884
+ if ("id" in quickAnswer && quickAnswer.id && elementById(quickAnswer.id)) {
5885
+ return {
5886
+ parseResult: {
5887
+ elements: [quickAnswer],
5888
+ errors: []
5889
+ },
5890
+ rawResponse: quickAnswer,
5891
+ elementById
5892
+ };
5893
+ }
5894
+ }
5786
5895
  async function AiInspectElement(options) {
5787
5896
  const { context, multi, targetElementDescription, callAI } = options;
5788
5897
  const { screenshotBase64, screenshotBase64WithElementMarker } = context;
5789
- const { description, elementById, elementByPosition: elementByPosition2 } = await describeUserPage(context);
5790
- if (options.quickAnswer) {
5791
- if ("id" in options.quickAnswer) {
5792
- if (elementById(options.quickAnswer.id)) {
5793
- return {
5794
- parseResult: {
5795
- elements: [options.quickAnswer],
5796
- errors: []
5797
- },
5798
- elementById
5799
- };
5800
- }
5801
- if (!targetElementDescription) {
5802
- return {
5803
- parseResult: {
5804
- elements: [],
5805
- errors: [
5806
- `inspect: cannot find the target by id: ${options.quickAnswer.id}, and no target element description is provided`
5807
- ]
5808
- },
5809
- elementById
5810
- };
5811
- }
5812
- }
5813
- if ("position" in options.quickAnswer && elementByPosition2(options.quickAnswer.position)) {
5814
- return {
5815
- parseResult: transformElementPositionToId(
5816
- {
5817
- elements: [options.quickAnswer]
5818
- },
5819
- context.content
5820
- ),
5821
- elementById
5822
- };
5823
- }
5898
+ const { description, elementById, elementByPosition, size } = await describeUserPage(context);
5899
+ const quickAnswer = getQuickAnswer(options.quickAnswer, elementById);
5900
+ if (quickAnswer) {
5901
+ return quickAnswer;
5824
5902
  }
5825
5903
  (0, import_node_assert6.default)(
5826
5904
  targetElementDescription,
5827
5905
  "cannot find the target element description"
5828
5906
  );
5907
+ const userInstructionPrompt = await findElementPrompt.format({
5908
+ pageDescription: description,
5909
+ targetElementDescription,
5910
+ multi
5911
+ });
5829
5912
  const systemPrompt = systemPromptToFindElement();
5830
5913
  const msgs = [
5831
5914
  { role: "system", content: systemPrompt },
5832
5915
  {
5833
5916
  role: "user",
5834
- content: transformUserMessages([
5917
+ content: [
5835
5918
  {
5836
5919
  type: "image_url",
5837
5920
  image_url: {
@@ -5840,46 +5923,23 @@ async function AiInspectElement(options) {
5840
5923
  },
5841
5924
  {
5842
5925
  type: "text",
5843
- text: `
5844
- pageDescription:
5845
-
5846
- ${description}
5847
-
5848
- Here is the item user want to find. Just go ahead:
5849
- =====================================
5850
- ${JSON.stringify({
5851
- description: targetElementDescription,
5852
- multi: multiDescription(multi)
5853
- })}
5854
- =====================================`
5926
+ text: userInstructionPrompt
5855
5927
  }
5856
- ])
5928
+ ]
5857
5929
  }
5858
5930
  ];
5859
- if (callAI) {
5860
- const res = await callAI({
5861
- msgs,
5862
- AIActionType: 1 /* INSPECT_ELEMENT */
5863
- });
5864
- return {
5865
- parseResult: transformElementPositionToId(res.content, context.content),
5866
- rawResponse: res,
5867
- elementById,
5868
- usage: res.usage
5869
- };
5870
- }
5871
- const inspectElement = await callAiFn({
5872
- msgs,
5873
- AIActionType: 1 /* INSPECT_ELEMENT */
5874
- });
5931
+ const callAIFn = callAI || callToGetJSONObject;
5932
+ const res = await callAIFn(msgs, 1 /* INSPECT_ELEMENT */);
5875
5933
  return {
5876
- parseResult: transformElementPositionToId(
5877
- inspectElement.content,
5878
- context.content
5934
+ parseResult: await transformElementPositionToId(
5935
+ res.content,
5936
+ context.content,
5937
+ size,
5938
+ screenshotBase64
5879
5939
  ),
5880
- rawResponse: inspectElement,
5940
+ rawResponse: res.content,
5881
5941
  elementById,
5882
- usage: inspectElement.usage
5942
+ usage: res.usage
5883
5943
  };
5884
5944
  }
5885
5945
  async function AiExtractElementInfo(options) {
@@ -5890,11 +5950,25 @@ async function AiExtractElementInfo(options) {
5890
5950
  context,
5891
5951
  liteContextConfig
5892
5952
  );
5953
+ let dataKeys = "";
5954
+ let dataQueryText = "";
5955
+ if (typeof dataQuery === "string") {
5956
+ dataKeys = "";
5957
+ dataQueryText = dataQuery;
5958
+ } else {
5959
+ dataKeys = `return in key-value style object, keys are ${Object.keys(dataQuery).join(",")}`;
5960
+ dataQueryText = JSON.stringify(dataQuery, null, 2);
5961
+ }
5962
+ const extractDataPromptText = await extractDataPrompt.format({
5963
+ pageDescription: description,
5964
+ dataKeys,
5965
+ dataQuery: dataQueryText
5966
+ });
5893
5967
  const msgs = [
5894
5968
  { role: "system", content: systemPrompt },
5895
5969
  {
5896
5970
  role: "user",
5897
- content: transformUserMessages([
5971
+ content: [
5898
5972
  {
5899
5973
  type: "image_url",
5900
5974
  image_url: {
@@ -5903,25 +5977,15 @@ async function AiExtractElementInfo(options) {
5903
5977
  },
5904
5978
  {
5905
5979
  type: "text",
5906
- text: `
5907
- pageDescription: ${description}
5908
-
5909
- Use your extract_data_from_UI skill to find the following data, placing it in the \`data\` field
5910
- DATA_DEMAND start:
5911
- =====================================
5912
- ${typeof dataQuery === "object" ? `return in key-value style object, keys are ${Object.keys(dataQuery).join(",")}` : ""}
5913
- ${typeof dataQuery === "string" ? dataQuery : JSON.stringify(dataQuery, null, 2)}
5914
- =====================================
5915
- DATA_DEMAND ends.
5916
- `
5980
+ text: extractDataPromptText
5917
5981
  }
5918
- ])
5982
+ ]
5919
5983
  }
5920
5984
  ];
5921
- const result = await callAiFn({
5985
+ const result = await callAiFn(
5922
5986
  msgs,
5923
- AIActionType: 2 /* EXTRACT_DATA */
5924
- });
5987
+ 2 /* EXTRACT_DATA */
5988
+ );
5925
5989
  return {
5926
5990
  parseResult: result.content,
5927
5991
  elementById,
@@ -5938,7 +6002,7 @@ async function AiAssert(options) {
5938
6002
  { role: "system", content: systemPrompt },
5939
6003
  {
5940
6004
  role: "user",
5941
- content: transformUserMessages([
6005
+ content: [
5942
6006
  {
5943
6007
  type: "image_url",
5944
6008
  image_url: {
@@ -5957,43 +6021,39 @@ async function AiAssert(options) {
5957
6021
  =====================================
5958
6022
  `
5959
6023
  }
5960
- ])
6024
+ ]
5961
6025
  }
5962
6026
  ];
5963
- const { content: assertResult, usage } = await callAiFn({
6027
+ const { content: assertResult, usage } = await callAiFn(
5964
6028
  msgs,
5965
- AIActionType: 0 /* ASSERT */
5966
- });
6029
+ 0 /* ASSERT */
6030
+ );
5967
6031
  return {
5968
6032
  content: assertResult,
5969
6033
  usage
5970
6034
  };
5971
6035
  }
5972
6036
 
5973
- // src/ai-model/automation/index.ts
6037
+ // src/ai-model/automation.ts
5974
6038
  var import_node_assert7 = __toESM(require("assert"));
5975
6039
  async function plan(userPrompt, opts) {
5976
6040
  const { callAI, context } = opts || {};
5977
6041
  const { screenshotBase64, screenshotBase64WithElementMarker } = context;
5978
- const { description: pageDescription, elementByPosition: elementByPosition2 } = await describeUserPage(context);
5979
- const systemPrompt = systemPromptToTaskPlanning();
5980
- let taskBackgroundContext = "";
5981
- if (opts.originalPrompt && opts.whatHaveDone) {
5982
- taskBackgroundContext = `For your information, this is a task that some important person handed to you. Here is the original task description and what have been done after the previous actions:
5983
- =====================================
5984
- Original task description:
5985
- ${opts.originalPrompt}
5986
- =====================================
5987
- What have been done:
5988
- ${opts.whatHaveDone}
5989
- =====================================
5990
- `;
5991
- }
6042
+ const { description: pageDescription, elementByPosition } = await describeUserPage(context);
6043
+ const systemPrompt = await systemPromptToTaskPlanning();
6044
+ const userInstructionPrompt = await automationUserPrompt.format({
6045
+ pageDescription,
6046
+ userPrompt,
6047
+ taskBackgroundContext: taskBackgroundContext(
6048
+ opts.originalPrompt,
6049
+ opts.whatHaveDone
6050
+ )
6051
+ });
5992
6052
  const msgs = [
5993
6053
  { role: "system", content: systemPrompt },
5994
6054
  {
5995
6055
  role: "user",
5996
- content: transformUserMessages([
6056
+ content: [
5997
6057
  {
5998
6058
  type: "image_url",
5999
6059
  image_url: {
@@ -6003,28 +6063,13 @@ ${opts.whatHaveDone}
6003
6063
  },
6004
6064
  {
6005
6065
  type: "text",
6006
- text: `
6007
- pageDescription:
6008
-
6009
- ${pageDescription}
6010
-
6011
-
6012
- Here is the instruction:
6013
- =====================================
6014
- ${userPrompt}
6015
- =====================================
6016
-
6017
- ${taskBackgroundContext}
6018
- `.trim()
6066
+ text: userInstructionPrompt
6019
6067
  }
6020
- ])
6068
+ ]
6021
6069
  }
6022
6070
  ];
6023
- const call2 = callAI || callAiFn;
6024
- const { content, usage } = await call2({
6025
- msgs,
6026
- AIActionType: 3 /* PLAN */
6027
- });
6071
+ const call3 = callAI || callAiFn;
6072
+ const { content, usage } = await call3(msgs, 3 /* PLAN */);
6028
6073
  const planFromAI = content;
6029
6074
  const actions = (planFromAI == null ? void 0 : planFromAI.actions) || [];
6030
6075
  (0, import_node_assert7.default)(planFromAI, "can't get plans from AI");