@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.
@@ -1033,10 +1033,10 @@ var require_dist = __commonJS({
1033
1033
  }
1034
1034
  });
1035
1035
 
1036
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/async_caller.js
1036
+ // ../../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
1037
1037
  var import_p_retry, import_p_queue, STATUS_NO_RETRY, STATUS_IGNORE, AsyncCaller;
1038
1038
  var init_async_caller = __esm({
1039
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/async_caller.js"() {
1039
+ "../../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"() {
1040
1040
  "use strict";
1041
1041
  import_p_retry = __toESM(require_p_retry());
1042
1042
  import_p_queue = __toESM(require_dist());
@@ -1158,7 +1158,7 @@ var init_async_caller = __esm({
1158
1158
  }
1159
1159
  });
1160
1160
 
1161
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/messages.js
1161
+ // ../../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
1162
1162
  function isLangChainMessage(message) {
1163
1163
  return typeof (message == null ? void 0 : message._getType) === "function";
1164
1164
  }
@@ -1173,25 +1173,25 @@ function convertLangChainMessageToExample(message) {
1173
1173
  return converted;
1174
1174
  }
1175
1175
  var init_messages = __esm({
1176
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/messages.js"() {
1176
+ "../../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"() {
1177
1177
  "use strict";
1178
1178
  }
1179
1179
  });
1180
1180
 
1181
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/_uuid.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/_uuid.js
1182
1182
  function assertUuid(str) {
1183
1183
  if (!validate_default(str)) {
1184
1184
  throw new Error(`Invalid UUID: ${str}`);
1185
1185
  }
1186
1186
  }
1187
1187
  var init_uuid = __esm({
1188
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/_uuid.js"() {
1188
+ "../../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"() {
1189
1189
  "use strict";
1190
1190
  init_esm_node();
1191
1191
  }
1192
1192
  });
1193
1193
 
1194
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/warn.js
1194
+ // ../../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
1195
1195
  function warnOnce(message) {
1196
1196
  if (!warnedMessages[message]) {
1197
1197
  console.warn(message);
@@ -1200,13 +1200,13 @@ function warnOnce(message) {
1200
1200
  }
1201
1201
  var warnedMessages;
1202
1202
  var init_warn = __esm({
1203
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/warn.js"() {
1203
+ "../../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"() {
1204
1204
  "use strict";
1205
1205
  warnedMessages = {};
1206
1206
  }
1207
1207
  });
1208
1208
 
1209
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/client.js
1209
+ // ../../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
1210
1210
  async function mergeRuntimeEnvIntoRunCreates(runs) {
1211
1211
  const runtimeEnv = await getRuntimeEnvironment();
1212
1212
  const envVars = getLangChainEnvVarsMetadata();
@@ -1244,7 +1244,7 @@ function trimQuotes(str) {
1244
1244
  }
1245
1245
  var getTracingSamplingRate, isLocalhost, raiseForStatus, handle429, Queue, DEFAULT_BATCH_SIZE_LIMIT_BYTES, Client;
1246
1246
  var init_client = __esm({
1247
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/client.js"() {
1247
+ "../../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"() {
1248
1248
  "use strict";
1249
1249
  init_esm_node();
1250
1250
  init_async_caller();
@@ -3005,10 +3005,10 @@ var init_client = __esm({
3005
3005
  }
3006
3006
  });
3007
3007
 
3008
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/index.js
3008
+ // ../../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
3009
3009
  var __version__;
3010
3010
  var init_dist = __esm({
3011
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/index.js"() {
3011
+ "../../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"() {
3012
3012
  "use strict";
3013
3013
  init_client();
3014
3014
  init_run_trees();
@@ -3016,7 +3016,7 @@ var init_dist = __esm({
3016
3016
  }
3017
3017
  });
3018
3018
 
3019
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/env.js
3019
+ // ../../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
3020
3020
  async function getRuntimeEnvironment() {
3021
3021
  if (runtimeEnvironment === void 0) {
3022
3022
  const env = getEnv();
@@ -3113,7 +3113,7 @@ function getShas() {
3113
3113
  }
3114
3114
  var globalEnv, isBrowser, isWebWorker, isJsDom, isDeno, isNode, getEnv, runtimeEnvironment, cachedCommitSHAs;
3115
3115
  var init_env = __esm({
3116
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/env.js"() {
3116
+ "../../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"() {
3117
3117
  "use strict";
3118
3118
  init_dist();
3119
3119
  isBrowser = () => typeof window !== "undefined" && typeof window.document !== "undefined";
@@ -3143,10 +3143,10 @@ var init_env = __esm({
3143
3143
  }
3144
3144
  });
3145
3145
 
3146
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/env.js
3146
+ // ../../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
3147
3147
  var isTracingEnabled;
3148
3148
  var init_env2 = __esm({
3149
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/env.js"() {
3149
+ "../../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"() {
3150
3150
  "use strict";
3151
3151
  init_env();
3152
3152
  isTracingEnabled = (tracingEnabled) => {
@@ -3164,7 +3164,7 @@ var init_env2 = __esm({
3164
3164
  }
3165
3165
  });
3166
3166
 
3167
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/run_trees.js
3167
+ // ../../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
3168
3168
  function stripNonAlphanumeric(input) {
3169
3169
  return input.replace(/[-:.]/g, "");
3170
3170
  }
@@ -3188,7 +3188,7 @@ function isRunnableConfigLike(x) {
3188
3188
  }
3189
3189
  var Baggage, RunTree;
3190
3190
  var init_run_trees = __esm({
3191
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/run_trees.js"() {
3191
+ "../../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"() {
3192
3192
  "use strict";
3193
3193
  init_esm_node();
3194
3194
  init_env();
@@ -3612,13 +3612,13 @@ var init_run_trees = __esm({
3612
3612
  }
3613
3613
  });
3614
3614
 
3615
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/singletons/traceable.js
3615
+ // ../../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
3616
3616
  function isTraceableFunction(x) {
3617
3617
  return typeof x === "function" && "langsmith:traceable" in x;
3618
3618
  }
3619
3619
  var MockAsyncLocalStorage, AsyncLocalStorageProvider, AsyncLocalStorageProviderSingleton, ROOT;
3620
3620
  var init_traceable = __esm({
3621
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/singletons/traceable.js"() {
3621
+ "../../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"() {
3622
3622
  "use strict";
3623
3623
  MockAsyncLocalStorage = class {
3624
3624
  getStore() {
@@ -3658,7 +3658,7 @@ var init_traceable = __esm({
3658
3658
  }
3659
3659
  });
3660
3660
 
3661
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/asserts.js
3661
+ // ../../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
3662
3662
  function isPromiseMethod(x) {
3663
3663
  if (x === "then" || x === "catch" || x === "finally") {
3664
3664
  return true;
@@ -3674,7 +3674,7 @@ function isKVMap(x) {
3674
3674
  }
3675
3675
  var isAsyncIterable, isIteratorLike, GeneratorFunction, isGenerator, isThenable, isReadableStream;
3676
3676
  var init_asserts = __esm({
3677
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/utils/asserts.js"() {
3677
+ "../../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"() {
3678
3678
  "use strict";
3679
3679
  isAsyncIterable = (x) => x != null && typeof x === "object" && // eslint-disable-next-line @typescript-eslint/no-explicit-any
3680
3680
  typeof x[Symbol.asyncIterator] === "function";
@@ -3690,7 +3690,7 @@ var init_asserts = __esm({
3690
3690
  }
3691
3691
  });
3692
3692
 
3693
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/traceable.js
3693
+ // ../../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
3694
3694
  function traceable(wrappedFunc, config) {
3695
3695
  const { aggregator, argsConfigPath, ...runTreeConfig } = config != null ? config : {};
3696
3696
  const traceableFunc = (...args) => {
@@ -3888,7 +3888,7 @@ function traceable(wrappedFunc, config) {
3888
3888
  }
3889
3889
  var import_node_async_hooks, handleRunInputs, handleRunOutputs, getTracingRunTree, getSerializablePromise, convertSerializableArg;
3890
3890
  var init_traceable2 = __esm({
3891
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/traceable.js"() {
3891
+ "../../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"() {
3892
3892
  "use strict";
3893
3893
  import_node_async_hooks = require("async_hooks");
3894
3894
  init_run_trees();
@@ -4068,7 +4068,7 @@ var init_traceable2 = __esm({
4068
4068
  }
4069
4069
  });
4070
4070
 
4071
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/wrappers/openai.js
4071
+ // ../../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
4072
4072
  function _combineChatCompletionChoices(choices) {
4073
4073
  var _a, _b;
4074
4074
  const reversedChoices = choices.slice().reverse();
@@ -4142,7 +4142,7 @@ function _combineChatCompletionChoices(choices) {
4142
4142
  }
4143
4143
  var chatAggregator, textAggregator, wrapOpenAI, _wrapClient, wrapSDK;
4144
4144
  var init_openai = __esm({
4145
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/wrappers/openai.js"() {
4145
+ "../../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"() {
4146
4146
  "use strict";
4147
4147
  init_traceable2();
4148
4148
  chatAggregator = (chunks) => {
@@ -4254,22 +4254,22 @@ var init_openai = __esm({
4254
4254
  }
4255
4255
  });
4256
4256
 
4257
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/wrappers/index.js
4257
+ // ../../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
4258
4258
  var init_wrappers = __esm({
4259
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/dist/wrappers/index.js"() {
4259
+ "../../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"() {
4260
4260
  "use strict";
4261
4261
  init_openai();
4262
4262
  }
4263
4263
  });
4264
4264
 
4265
- // ../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/wrappers.js
4265
+ // ../../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
4266
4266
  var wrappers_exports = {};
4267
4267
  __export(wrappers_exports, {
4268
4268
  wrapOpenAI: () => wrapOpenAI,
4269
4269
  wrapSDK: () => wrapSDK
4270
4270
  });
4271
4271
  var init_wrappers2 = __esm({
4272
- "../../node_modules/.pnpm/langsmith@0.1.36_openai@4.57.1_zod@3.23.8_/node_modules/langsmith/wrappers.js"() {
4272
+ "../../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"() {
4273
4273
  "use strict";
4274
4274
  init_wrappers();
4275
4275
  }
@@ -4313,6 +4313,7 @@ var OPENAI_MAX_TOKENS = "OPENAI_MAX_TOKENS";
4313
4313
  var MIDSCENE_MODEL_TEXT_ONLY = "MIDSCENE_MODEL_TEXT_ONLY";
4314
4314
  var MIDSCENE_CACHE = "MIDSCENE_CACHE";
4315
4315
  var MATCH_BY_POSITION = "MATCH_BY_POSITION";
4316
+ var MIDSCENE_API_TYPE = "MIDSCENE_API_TYPE";
4316
4317
  var MIDSCENE_REPORT_TAG_NAME = "MIDSCENE_REPORT_TAG_NAME";
4317
4318
  var MIDSCENE_USE_AZURE_OPENAI = "MIDSCENE_USE_AZURE_OPENAI";
4318
4319
  var MIDSCENE_AZURE_OPENAI_SCOPE = "MIDSCENE_AZURE_OPENAI_SCOPE";
@@ -4375,8 +4376,7 @@ var getAIConfigInJson = (configKey) => {
4375
4376
 
4376
4377
  // src/ai-model/common.ts
4377
4378
  var import_node_assert = __toESM(require("assert"));
4378
- async function callAiFn(options) {
4379
- const { msgs, AIActionType: AIActionTypeValue } = options;
4379
+ async function callAiFn(msgs, AIActionTypeValue) {
4380
4380
  (0, import_node_assert.default)(
4381
4381
  checkAIConfig(),
4382
4382
  "Cannot find config for AI model service. You should set it before using. https://midscenejs.com/model-provider.html"
@@ -4387,19 +4387,9 @@ async function callAiFn(options) {
4387
4387
  );
4388
4388
  return { content, usage };
4389
4389
  }
4390
- function transformUserMessages(msgs) {
4391
- const textOnly = Boolean(getAIConfig(MIDSCENE_MODEL_TEXT_ONLY));
4392
- if (!textOnly)
4393
- return msgs;
4394
- return msgs.reduce((res, msg) => {
4395
- if (msg.type === "text") {
4396
- res += msg.text;
4397
- }
4398
- return res;
4399
- }, "");
4400
- }
4401
4390
 
4402
4391
  // src/ai-model/prompt/element_inspector.ts
4392
+ var import_prompts = require("@langchain/core/prompts");
4403
4393
  function systemPromptToFindElement() {
4404
4394
  if (getAIConfig(MATCH_BY_POSITION)) {
4405
4395
  return systemPromptToFindElementPosition();
@@ -4542,36 +4532,31 @@ Output Example:
4542
4532
  }
4543
4533
  function systemPromptToFindElementPosition() {
4544
4534
  return `
4545
- ## Role:
4546
- You are an expert in software page image (2D) and page element text analysis.
4535
+ 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.
4547
4536
 
4548
- ## Objective:
4549
- Based on screenshots and descriptions, find specific coordinates
4537
+ ## Output Format
4538
+ \`\`\`
4539
+ Action_Summary: ...
4540
+ Action: ...
4541
+ \`\`\`
4550
4542
 
4551
- ## Output Format:
4543
+ ## Action Space
4544
+ click(start_box='[x1, y1, x2, y2]')
4545
+ long_press(start_box='[x1, y1, x2, y2]', time='')
4546
+ type(content='')
4547
+ scroll(direction='down or up or right or left')
4548
+ open_app(app_name='')
4549
+ navigate_back()
4550
+ navigate_home()
4551
+ WAIT()
4552
+ finished() # Submit the task regardless of whether it succeeds or fails.
4552
4553
 
4553
- Please return the result in JSON format as follows:
4554
+ ## Note
4555
+ - Use Chinese in \`Action_Summary\` part.
4554
4556
 
4555
- \`\`\`json
4556
- {
4557
- "elements": [
4558
- {
4559
- // Describe the reason for finding this element, replace with actual value in practice
4560
- "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",
4561
- // If the target element includes text information, extract the text information; if it does not, do not extract it
4562
- "text": "",
4563
- // position of this element
4564
- "position": { x: number, y: number }
4565
- }
4566
- ],
4567
- "errors": []// Return an error if there is no target element on the picture
4568
- }
4569
- \`\`\`
4557
+ ## User Instruction
4570
4558
  `;
4571
4559
  }
4572
- function multiDescription(multi) {
4573
- return multi ? "multiple elements matching the description (two or more)" : "The element closest to the description (only one)";
4574
- }
4575
4560
  var findElementSchema = {
4576
4561
  type: "json_schema",
4577
4562
  json_schema: {
@@ -4616,6 +4601,23 @@ var findElementSchema = {
4616
4601
  }
4617
4602
  }
4618
4603
  };
4604
+ var findElementPrompt = new import_prompts.PromptTemplate({
4605
+ template: `
4606
+ Here is the item user want to find. Just go ahead:
4607
+ =====================================
4608
+ {{
4609
+ "description": "{targetElementDescription}",
4610
+ "multi": {multi}
4611
+ }}
4612
+ =====================================
4613
+
4614
+ pageDescription: {pageDescription}
4615
+ `,
4616
+ inputVariables: ["pageDescription", "targetElementDescription", "multi"]
4617
+ });
4618
+
4619
+ // src/ai-model/prompt/planning.ts
4620
+ var import_prompts3 = require("@langchain/core/prompts");
4619
4621
 
4620
4622
  // src/ai-model/prompt/util.ts
4621
4623
  var import_node_assert2 = __toESM(require("assert"));
@@ -4624,6 +4626,7 @@ var import_node_assert2 = __toESM(require("assert"));
4624
4626
  var import_img = require("@midscene/shared/img");
4625
4627
 
4626
4628
  // src/ai-model/prompt/util.ts
4629
+ var import_prompts2 = require("@langchain/core/prompts");
4627
4630
  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.";
4628
4631
  var contextFormatIntro = `
4629
4632
  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.`;
@@ -4652,6 +4655,22 @@ Return in the following JSON format:
4652
4655
  }
4653
4656
  `;
4654
4657
  }
4658
+ var extractDataPrompt = new import_prompts2.PromptTemplate({
4659
+ template: `
4660
+ pageDescription: {pageDescription}
4661
+
4662
+ Use your extract_data_from_UI skill to find the following data, placing it in the \`data\` field
4663
+ DATA_DEMAND start:
4664
+ =====================================
4665
+ {dataKeys}
4666
+
4667
+ {dataQuery}
4668
+
4669
+ =====================================
4670
+ DATA_DEMAND ends.
4671
+ `,
4672
+ inputVariables: ["pageDescription", "dataKeys", "dataQuery"]
4673
+ });
4655
4674
  function systemPromptToAssert() {
4656
4675
  return `
4657
4676
  ${characteristic}
@@ -4700,7 +4719,7 @@ function truncateText(text, maxLength = 100) {
4700
4719
  }
4701
4720
  return "";
4702
4721
  }
4703
- function elementByPosition(elementsInfo, position) {
4722
+ function elementByPositionWithElementInfo(elementsInfo, position) {
4704
4723
  (0, import_node_assert2.default)(typeof position !== "undefined", "position is required for query");
4705
4724
  const item = elementsInfo.find((item2) => {
4706
4725
  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;
@@ -4754,23 +4773,26 @@ async function describeUserPage(context, opt) {
4754
4773
  const { id, ...rest } = item;
4755
4774
  return `id=${id}: ${JSON.stringify(rest)}`;
4756
4775
  }).join("\n\n");
4776
+ const pageJSONDescription = getAIConfig(MATCH_BY_POSITION) ? "" : `Some of the elements are marked with a rectangle in the screenshot, some are not.
4777
+ Json description of all the page elements:
4778
+ ${contentList}`;
4779
+ const sizeDescription = describeSize({ width, height });
4757
4780
  return {
4758
4781
  description: `
4759
- The size of the page: ${describeSize({ width, height })}
4760
- Some of the elements are marked with a rectangle in the screenshot, some are not.
4782
+ The size of the page: ${sizeDescription}
4761
4783
 
4762
- ${// if match by id, use the description of the element
4763
- getAIConfig(MATCH_BY_POSITION) ? "" : `Json description of all the page elements:
4764
- ${contentList}`}
4784
+ ${pageJSONDescription}
4765
4785
  `,
4766
4786
  elementById(id) {
4767
4787
  (0, import_node_assert2.default)(typeof id !== "undefined", "id is required for query");
4768
4788
  const item = idElementMap[`${id}`];
4769
4789
  return item;
4770
4790
  },
4771
- elementByPosition(position) {
4772
- return elementByPosition(elementsInfo, position);
4773
- }
4791
+ elementByPosition(position, size) {
4792
+ console.log("elementByPosition", { position, size });
4793
+ return elementByPositionWithElementInfo(elementsInfo, position);
4794
+ },
4795
+ size: { width, height }
4774
4796
  };
4775
4797
  }
4776
4798
  function cropFieldInformation(elementsInfo, truncateTextLength, filterNonTextContent = false) {
@@ -4824,19 +4846,35 @@ function cropFieldInformation(elementsInfo, truncateTextLength, filterNonTextCon
4824
4846
  // src/ai-model/prompt/planning.ts
4825
4847
  var quickAnswerFormat = () => {
4826
4848
  const matchByPosition = getAIConfig(MATCH_BY_POSITION);
4827
- const description = `
4828
- ${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'}
4829
- `;
4830
- const format = matchByPosition ? '"position": { x: number; y: number }' : '"id": string';
4831
- const sample = matchByPosition ? '{"position": { x: 100, y: 200 }}' : '{"id": "c81c4e9a33"}';
4849
+ const locationFormat = {
4850
+ position: {
4851
+ 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)`,
4852
+ format: '"position": { x: number; y: number }',
4853
+ sample: '{"prompt": "the search bar"}',
4854
+ locateParam: `{
4855
+ "prompt"?: string // the description of the element to find. It can only be omitted when locate is null.
4856
+ } | null // If it's not on the page, the LocateParam should be null`
4857
+ },
4858
+ id: {
4859
+ description: '"id": string // Represents the ID of the element; replace with actual values in practice',
4860
+ format: '"id": string',
4861
+ sample: `{"id": "c81c4e9a33", "prompt": "the search bar"}`,
4862
+ locateParam: `{
4863
+ "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.
4864
+ "prompt"?: string // the description of the element to find. It can only be omitted when locate is null.
4865
+ } | null // If it's not on the page, the LocateParam should be null`
4866
+ }
4867
+ };
4868
+ const type = matchByPosition ? "position" : "id";
4869
+ const format = locationFormat[type];
4832
4870
  return {
4833
- description,
4834
- format,
4835
- sample
4871
+ description: format.description,
4872
+ format: format.format,
4873
+ sample: format.sample,
4874
+ locateParam: format.locateParam
4836
4875
  };
4837
4876
  };
4838
- function systemPromptToTaskPlanning() {
4839
- return `
4877
+ var systemTemplate = `
4840
4878
  ## Role
4841
4879
 
4842
4880
  You are a versatile professional in software UI automation. Your outstanding contributions will impact the user experience of billions of users.
@@ -4870,76 +4908,70 @@ You are a versatile professional in software UI automation. Your outstanding con
4870
4908
 
4871
4909
  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:
4872
4910
 
4873
- type LocateParam = {
4874
- "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.
4875
- prompt?: string // the description of the element to find. It can only be omitted when locate is null.
4876
- } | null // If it's not on the page, the LocateParam should be null
4911
+ type LocateParam = {locateParam}
4877
4912
 
4878
4913
  ### Supported actions
4879
4914
 
4880
4915
  Each action has a \`type\` and corresponding \`param\`. To be detailed:
4881
4916
  - type: 'Tap', tap the located element
4882
- * { locate: LocateParam, param: null }
4917
+ * {{ locate: {sample}, param: null }}
4883
4918
  - type: 'Hover', move mouse over to the located element
4884
- * { locate: LocateParam, param: null }
4919
+ * {{ locate: LocateParam, param: null }}
4885
4920
  - type: 'Input', replace the value in the input field
4886
- * { locate: LocateParam, param: { value: string } }
4921
+ * {{ locate: LocateParam, param: {{ value: string }} }}
4887
4922
  * \`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.
4888
4923
  - type: 'KeyboardPress', press a key
4889
- * { param: { value: string } }
4924
+ * {{ param: {{ value: string }} }}
4890
4925
  - type: 'Scroll', scroll up or down.
4891
- * {
4926
+ * {{
4892
4927
  locate: LocateParam | null,
4893
- param: {
4928
+ param: {{
4894
4929
  direction: 'down'(default) | 'up' | 'right' | 'left',
4895
4930
  scrollType: 'once' (default) | 'untilBottom' | 'untilTop' | 'untilRight' | 'untilLeft',
4896
4931
  distance: null | number
4897
- }
4898
- }
4932
+ }}
4933
+ }}
4899
4934
  * 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.
4900
4935
  * \`param\` is required in this action. If some fields are not specified, use direction \`down\`, \`once\` scroll type, and \`null\` distance.
4901
4936
  - type: 'FalsyConditionStatement'
4902
- * { param: null }
4937
+ * {{ param: null }}
4903
4938
  * use this action when the instruction is an "if" statement and the condition is falsy.
4904
4939
  - type: 'Sleep'
4905
- * { param: { timeMs: number } }
4940
+ * {{ param: {{ timeMs: number }} }}
4906
4941
 
4907
4942
  ## How to compose the \`taskWillBeAccomplished\` and \`furtherPlan\` fields ?
4908
4943
 
4909
4944
  \`taskWillBeAccomplished\` is a boolean field, means whether the task will be accomplished after all the actions.
4910
4945
 
4911
- \`furtherPlan\` is used when the task cannot be accomplished. It follows the scheme { whatHaveDone: string, whatToDoNext: string }:
4946
+ \`furtherPlan\` is used when the task cannot be accomplished. It follows the scheme {{ whatHaveDone: string, whatToDoNext: string }}:
4912
4947
  - \`whatHaveDone\`: a string, describe what have been done after the previous actions.
4913
4948
  - \`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.
4914
-
4949
+ `;
4950
+ var outputTemplate = `
4915
4951
  ## Output JSON Format:
4916
4952
 
4917
4953
  The JSON format is as follows:
4918
4954
 
4919
- {
4955
+ {{
4920
4956
  "actions": [
4921
- {
4957
+ {{
4922
4958
  "thought": "Reasons for generating this task, and why this task is feasible on this page",
4923
4959
  "type": "Tap",
4924
4960
  "param": null,
4925
- "locate": {
4926
- {"id": "c81c4e9a33"},
4927
- prompt: "the search bar"
4928
- } | null,
4929
- },
4961
+ "locate": {sample} | null,
4962
+ }},
4930
4963
  // ... more actions
4931
4964
  ],
4932
4965
  "taskWillBeAccomplished": boolean,
4933
- "furtherPlan": { "whatHaveDone": string, "whatToDoNext": string } | null,
4966
+ "furtherPlan": {{ "whatHaveDone": string, "whatToDoNext": string }} | null,
4934
4967
  "error"?: string
4935
- }
4936
-
4937
- ## Example #1 : How to decompose a task
4968
+ }}
4969
+ Here is an example of how to decompose a task:
4938
4970
 
4939
4971
  When a user says 'Click the language switch button, wait 1s, click "English"', the user will give you the description like this:
4940
4972
 
4941
4973
  ====================
4942
- ${samplePageDescription}
4974
+ {pageDescription}
4943
4975
  ====================
4944
4976
 
4945
4977
  By viewing the page screenshot and description, you should consider this and output the JSON:
@@ -4949,110 +4981,119 @@ By viewing the page screenshot and description, you should consider this and out
4949
4981
  * 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.
4950
4982
  * The task cannot be accomplished (because we cannot see the "English" option now), so a \`furtherPlan\` field is needed.
4951
4983
 
4952
- {
4984
+ {{
4953
4985
  "actions":[
4954
- {
4986
+ {{
4987
+ "type": "Tap",
4955
4988
  "thought": "Click the language switch button to open the language options.",
4956
- "type": "Tap",
4957
4989
  "param": null,
4958
- "locate": {
4959
- ${quickAnswerFormat().sample},
4960
- "prompt": "the language switch button with the text '中文'"
4961
- }
4962
- },
4963
- {
4964
- "thought": "Wait for 1 second to ensure the language options are displayed.",
4990
+ "locate": {sample},
4991
+ }},
4992
+ {{
4965
4993
  "type": "Sleep",
4966
- "param": { "timeMs": 1000 },
4967
- },
4968
- {
4969
- "thought": "Locate the 'English' option in the language menu.",
4994
+ "thought": "Wait for 1 second to ensure the language options are displayed.",
4995
+ "param": {{ "timeMs": 1000 }},
4996
+ }},
4997
+ {{
4970
4998
  "type": "Tap",
4971
- "param": null,
4999
+ "thought": "Locate the 'English' option in the language menu.",
5000
+ "param": null,
4972
5001
  "locate": null
4973
- },
5002
+ }},
4974
5003
  ],
4975
5004
  "error": null,
4976
5005
  "taskWillBeAccomplished": false,
4977
- "furtherPlan": {
4978
- "whatToDoNext": "find the 'English' option and click on it",
4979
- "whatHaveDone": "Click the language switch button and wait 1s"
4980
- }
4981
- }
5006
+ "furtherPlan": {{
5007
+ "whatToDoNext": "find the 'English' option and click on it",
5008
+ "whatHaveDone": "Click the language switch button and wait 1s"
5009
+ }}
5010
+ }}
4982
5011
 
4983
- ## Example #2 : Tolerate the error situation only when the instruction is an "if" statement
5012
+ Here is another example of how to tolerate error situations only when the instruction is an "if" statement:
4984
5013
 
4985
5014
  If the user says "If there is a popup, close it", you should consider this and output the JSON:
4986
5015
 
4987
5016
  * By viewing the page screenshot and description, you cannot find the popup, so the condition is falsy.
4988
5017
  * The instruction itself is an "if" statement, it means the user can tolerate this situation, so you should leave a \`FalsyConditionStatement\` action.
4989
5018
 
4990
- {
4991
- "actions": [{
4992
- "thought": "There is no popup on the page",
5019
+ {{
5020
+ "actions": [{{
4993
5021
  "type": "FalsyConditionStatement",
5022
+ "thought": "There is no popup on the page",
4994
5023
  "param": null
4995
- }
5024
+ }}
4996
5025
  ],
4997
5026
  "taskWillBeAccomplished": true,
4998
5027
  "furtherPlan": null
4999
- }
5028
+ }}
5000
5029
 
5001
5030
  For contrast, if the user says "Close the popup" in this situation, you should consider this and output the JSON:
5002
5031
 
5003
- {
5032
+ {{
5004
5033
  "actions": [],
5005
5034
  "error": "The instruction and page context are irrelevant, there is no popup on the page",
5006
5035
  "taskWillBeAccomplished": true,
5007
5036
  "furtherPlan": null
5008
- }
5037
+ }}
5009
5038
 
5010
- ## Example #3 : When task is accomplished, don't plan more actions
5039
+ Here is an example of when task is accomplished, don't plan more actions:
5011
5040
 
5012
5041
  When the user ask to "Wait 4s", you should consider this:
5013
5042
 
5014
- {
5043
+ {{
5015
5044
  "actions": [
5016
- {
5017
- "thought": "Wait for 4 seconds",
5045
+ {{
5018
5046
  "type": "Sleep",
5019
- "param": { "timeMs": 4000 },
5020
- },
5047
+ "thought": "Wait for 4 seconds",
5048
+ "param": {{ "timeMs": 4000 }},
5049
+ }},
5021
5050
  ],
5022
5051
  "taskWillBeAccomplished": true,
5023
5052
  "furtherPlan": null // All steps have been included in the actions, so no further plan is needed
5024
- }
5053
+ }}
5025
5054
 
5026
- ## Bad case #1 : Missing \`prompt\` in the 'Locate' field; Missing \`furtherPlan\` field when the task won't be accomplished
5055
+ Here is an example of what NOT to do:
5027
5056
 
5028
5057
  Wrong output:
5029
5058
 
5030
- {
5059
+ {{
5031
5060
  "actions":[
5032
- {
5033
- "thought": "Click the language switch button to open the language options.",
5061
+ {{
5034
5062
  "type": "Tap",
5063
+ "thought": "Click the language switch button to open the language options.",
5035
5064
  "param": null,
5036
- "locate": {
5037
- ${quickAnswerFormat().sample}, // WRONG:prompt is missing
5038
- }
5039
- },
5040
- {
5065
+ "locate": {{
5066
+ {sample}, // WRONG:prompt is missing
5067
+ }}
5068
+ }},
5069
+ {{
5070
+ "type": "Tap",
5041
5071
  "thought": "Click the English option",
5042
- "type": "Tap",
5043
5072
  "param": null,
5044
5073
  "locate": null, // This means the 'English' option is not shown in the screenshot, the task cannot be accomplished
5045
- }
5074
+ }}
5046
5075
  ],
5047
5076
  "taskWillBeAccomplished": false,
5048
5077
  // WRONG: should not be null
5049
5078
  "furtherPlan": null,
5050
- }
5079
+ }}
5051
5080
 
5052
- Reason:
5081
+ Reason:
5053
5082
  * The \`prompt\` is missing in the first 'Locate' action
5054
5083
  * Since the option button is not shown in the screenshot, the task cannot be accomplished, so a \`furtherPlan\` field is needed.
5055
5084
  `;
5085
+ async function systemPromptToTaskPlanning() {
5086
+ const promptTemplate = new import_prompts3.PromptTemplate({
5087
+ template: `${systemTemplate}
5088
+
5089
+ ${outputTemplate}`,
5090
+ inputVariables: ["pageDescription", "sample", "locateParam"]
5091
+ });
5092
+ return await promptTemplate.format({
5093
+ pageDescription: samplePageDescription,
5094
+ sample: quickAnswerFormat().sample,
5095
+ locateParam: quickAnswerFormat().locateParam
5096
+ });
5056
5097
  }
5057
5098
  var planSchema = {
5058
5099
  type: "json_schema",
@@ -5136,6 +5177,34 @@ var planSchema = {
5136
5177
  }
5137
5178
  }
5138
5179
  };
5180
+ var taskBackgroundContext = async (originalPrompt, whatHaveDone) => {
5181
+ if (!originalPrompt || !whatHaveDone) {
5182
+ return "";
5183
+ }
5184
+ return `
5185
+ 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:
5186
+ =====================================
5187
+ Original task description:
5188
+ ${originalPrompt}
5189
+ =====================================
5190
+ What have been done:
5191
+ ${whatHaveDone}
5192
+ =====================================
5193
+ `;
5194
+ };
5195
+ var automationUserPrompt = new import_prompts3.PromptTemplate({
5196
+ template: `
5197
+ Here is the instruction:
5198
+ =====================================
5199
+ {userPrompt}
5200
+ =====================================
5201
+
5202
+ {taskBackgroundContext}
5203
+
5204
+ pageDescription: {pageDescription}
5205
+ `,
5206
+ inputVariables: ["pageDescription", "userPrompt", "taskBackgroundContext"]
5207
+ });
5139
5208
 
5140
5209
  // src/ai-model/openai/index.ts
5141
5210
  function checkAIConfig(preferVendor) {
@@ -5158,7 +5227,9 @@ function getModelName() {
5158
5227
  }
5159
5228
  return modelName;
5160
5229
  }
5161
- async function createChatClient() {
5230
+ async function createChatClient({
5231
+ AIActionTypeValue
5232
+ }) {
5162
5233
  let openai;
5163
5234
  const extraConfig = getAIConfigInJson(MIDSCENE_OPENAI_INIT_CONFIG_JSON);
5164
5235
  const socksProxy = getAIConfig(MIDSCENE_OPENAI_SOCKS_PROXY);
@@ -5209,6 +5280,10 @@ async function createChatClient() {
5209
5280
  apiKey: getAIConfig(OPENAI_API_KEY),
5210
5281
  httpAgent: socksAgent,
5211
5282
  ...extraConfig,
5283
+ defaultHeaders: {
5284
+ ...(extraConfig == null ? void 0 : extraConfig.defaultHeaders) || {},
5285
+ [MIDSCENE_API_TYPE]: AIActionTypeValue.toString()
5286
+ },
5212
5287
  dangerouslyAllowBrowser: true
5213
5288
  });
5214
5289
  }
@@ -5241,8 +5316,10 @@ async function createChatClient() {
5241
5316
  }
5242
5317
  throw new Error("Openai SDK or Anthropic SDK is not initialized");
5243
5318
  }
5244
- async function call(messages, responseFormat) {
5245
- const { completion, style } = await createChatClient();
5319
+ async function call(messages, AIActionTypeValue, responseFormat) {
5320
+ const { completion, style } = await createChatClient({
5321
+ AIActionTypeValue
5322
+ });
5246
5323
  const shouldPrintTiming = typeof getAIConfig(MIDSCENE_DEBUG_AI_PROFILE) === "string";
5247
5324
  const maxTokens = getAIConfig(OPENAI_MAX_TOKENS);
5248
5325
  const startTime = Date.now();
@@ -5325,47 +5402,47 @@ async function callToGetJSONObject(messages, AIActionTypeValue) {
5325
5402
  responseFormat = { type: "json_object" /* JSON */ };
5326
5403
  }
5327
5404
  }
5328
- const safeJsonParse = (input) => {
5329
- try {
5330
- return JSON.parse(input);
5331
- } catch (e) {
5332
- return null;
5333
- }
5334
- };
5335
- const response = await call(messages, responseFormat);
5405
+ const response = await call(messages, AIActionTypeValue, responseFormat);
5336
5406
  (0, import_node_assert3.default)(response, "empty response");
5337
- let jsonContent = safeJsonParse(response.content);
5338
- if (jsonContent)
5339
- return { content: jsonContent, usage: response.usage };
5340
- const cleanJsonString = extractJSONFromCodeBlock(response.content);
5341
- try {
5342
- jsonContent = JSON.parse(cleanJsonString);
5343
- } catch (e) {
5344
- }
5345
- if (jsonContent)
5346
- return { content: jsonContent, usage: response.usage };
5407
+ const jsonContent = safeParseJson(response.content);
5408
+ return { content: jsonContent, usage: response.usage };
5409
+ }
5410
+ function extractJSONFromCodeBlock(response) {
5347
5411
  try {
5348
- jsonContent = import_dirty_json.default.parse(cleanJsonString);
5412
+ const jsonMatch = response.match(/^\s*(\{[\s\S]*\})\s*$/);
5413
+ if (jsonMatch) {
5414
+ return jsonMatch[1];
5415
+ }
5416
+ const codeBlockMatch = response.match(
5417
+ /```(?:json)?\s*(\{[\s\S]*?\})\s*```/
5418
+ );
5419
+ if (codeBlockMatch) {
5420
+ return codeBlockMatch[1];
5421
+ }
5422
+ const jsonLikeMatch = response.match(/\{[\s\S]*\}/);
5423
+ if (jsonLikeMatch) {
5424
+ return jsonLikeMatch[0];
5425
+ }
5349
5426
  } catch (e) {
5350
5427
  }
5351
- if (jsonContent)
5352
- return { content: jsonContent, usage: response.usage };
5353
- throw Error(`failed to parse json response: ${response.content}`);
5428
+ return response;
5354
5429
  }
5355
- function extractJSONFromCodeBlock(response) {
5356
- const jsonMatch = response.match(/^\s*(\{[\s\S]*\})\s*$/);
5357
- if (jsonMatch) {
5358
- return jsonMatch[1];
5430
+ function safeParseJson(input) {
5431
+ var _a;
5432
+ const cleanJsonString = extractJSONFromCodeBlock(input);
5433
+ if (cleanJsonString.match(/\((\d+),(\d+)\)/)) {
5434
+ return (_a = cleanJsonString.match(/\((\d+),(\d+)\)/)) == null ? void 0 : _a.slice(1).map(Number);
5359
5435
  }
5360
- const codeBlockMatch = response.match(/```(?:json)?\s*(\{[\s\S]*?\})\s*```/);
5361
- if (codeBlockMatch) {
5362
- return codeBlockMatch[1];
5436
+ try {
5437
+ return JSON.parse(cleanJsonString);
5438
+ } catch (e) {
5363
5439
  }
5364
- const jsonLikeMatch = response.match(/\{[\s\S]*\}/);
5365
- if (jsonLikeMatch) {
5366
- return jsonLikeMatch[0];
5440
+ try {
5441
+ return import_dirty_json.default.parse(cleanJsonString);
5442
+ } catch (e) {
5443
+ console.log("e:", e);
5367
5444
  }
5368
- return response;
5445
+ throw Error(`failed to parse json response: ${input}`);
5369
5446
  }
5370
5447
 
5371
5448
  // src/ai-model/inspect.ts
@@ -5374,76 +5451,82 @@ var liteContextConfig = {
5374
5451
  filterNonTextContent: true,
5375
5452
  truncateTextLength: 200
5376
5453
  };
5377
- function transformElementPositionToId(aiResult, elementsInfo) {
5454
+ function transformToAbsoluteCoords(relativePosition, size) {
5455
+ return {
5456
+ x: Number((relativePosition.x / 1e3 * size.width).toFixed(3)),
5457
+ y: Number((relativePosition.y / 1e3 * size.height).toFixed(3))
5458
+ };
5459
+ }
5460
+ async function transformElementPositionToId(aiResult, elementsInfo, size, screenshotBase64) {
5461
+ if (Array.isArray(aiResult)) {
5462
+ const relativePosition = aiResult;
5463
+ const absolutePosition = transformToAbsoluteCoords(
5464
+ {
5465
+ x: relativePosition[0],
5466
+ y: relativePosition[1]
5467
+ },
5468
+ size
5469
+ );
5470
+ const element = elementByPositionWithElementInfo(
5471
+ elementsInfo,
5472
+ absolutePosition
5473
+ );
5474
+ (0, import_node_assert4.default)(
5475
+ element,
5476
+ `inspect: no id found with position: ${JSON.stringify({ absolutePosition })}`
5477
+ );
5478
+ return {
5479
+ errors: [],
5480
+ elements: [
5481
+ {
5482
+ id: element.id
5483
+ }
5484
+ ]
5485
+ };
5486
+ }
5378
5487
  return {
5379
5488
  errors: aiResult.errors,
5380
- elements: aiResult.elements.map((item) => {
5381
- var _a;
5382
- if ("id" in item) {
5383
- return item;
5384
- }
5385
- const { position } = item;
5386
- const id = (_a = elementByPosition(elementsInfo, position)) == null ? void 0 : _a.id;
5387
- (0, import_node_assert4.default)(
5388
- id,
5389
- `inspect: no id found with position: ${JSON.stringify({ position })}`
5390
- );
5391
- return {
5392
- ...item,
5393
- id
5394
- };
5395
- })
5489
+ elements: aiResult.elements
5396
5490
  };
5397
5491
  }
5492
+ function getQuickAnswer(quickAnswer, elementById) {
5493
+ if (!quickAnswer) {
5494
+ return void 0;
5495
+ }
5496
+ if ("id" in quickAnswer && quickAnswer.id && elementById(quickAnswer.id)) {
5497
+ return {
5498
+ parseResult: {
5499
+ elements: [quickAnswer],
5500
+ errors: []
5501
+ },
5502
+ rawResponse: quickAnswer,
5503
+ elementById
5504
+ };
5505
+ }
5506
+ }
5398
5507
  async function AiInspectElement(options) {
5399
5508
  const { context, multi, targetElementDescription, callAI } = options;
5400
5509
  const { screenshotBase64, screenshotBase64WithElementMarker } = context;
5401
- const { description, elementById, elementByPosition: elementByPosition2 } = await describeUserPage(context);
5402
- if (options.quickAnswer) {
5403
- if ("id" in options.quickAnswer) {
5404
- if (elementById(options.quickAnswer.id)) {
5405
- return {
5406
- parseResult: {
5407
- elements: [options.quickAnswer],
5408
- errors: []
5409
- },
5410
- elementById
5411
- };
5412
- }
5413
- if (!targetElementDescription) {
5414
- return {
5415
- parseResult: {
5416
- elements: [],
5417
- errors: [
5418
- `inspect: cannot find the target by id: ${options.quickAnswer.id}, and no target element description is provided`
5419
- ]
5420
- },
5421
- elementById
5422
- };
5423
- }
5424
- }
5425
- if ("position" in options.quickAnswer && elementByPosition2(options.quickAnswer.position)) {
5426
- return {
5427
- parseResult: transformElementPositionToId(
5428
- {
5429
- elements: [options.quickAnswer]
5430
- },
5431
- context.content
5432
- ),
5433
- elementById
5434
- };
5435
- }
5510
+ const { description, elementById, elementByPosition, size } = await describeUserPage(context);
5511
+ const quickAnswer = getQuickAnswer(options.quickAnswer, elementById);
5512
+ if (quickAnswer) {
5513
+ return quickAnswer;
5436
5514
  }
5437
5515
  (0, import_node_assert4.default)(
5438
5516
  targetElementDescription,
5439
5517
  "cannot find the target element description"
5440
5518
  );
5519
+ const userInstructionPrompt = await findElementPrompt.format({
5520
+ pageDescription: description,
5521
+ targetElementDescription,
5522
+ multi
5523
+ });
5441
5524
  const systemPrompt = systemPromptToFindElement();
5442
5525
  const msgs = [
5443
5526
  { role: "system", content: systemPrompt },
5444
5527
  {
5445
5528
  role: "user",
5446
- content: transformUserMessages([
5529
+ content: [
5447
5530
  {
5448
5531
  type: "image_url",
5449
5532
  image_url: {
@@ -5452,46 +5535,23 @@ async function AiInspectElement(options) {
5452
5535
  },
5453
5536
  {
5454
5537
  type: "text",
5455
- text: `
5456
- pageDescription:
5457
-
5458
- ${description}
5459
-
5460
- Here is the item user want to find. Just go ahead:
5461
- =====================================
5462
- ${JSON.stringify({
5463
- description: targetElementDescription,
5464
- multi: multiDescription(multi)
5465
- })}
5466
- =====================================`
5538
+ text: userInstructionPrompt
5467
5539
  }
5468
- ])
5540
+ ]
5469
5541
  }
5470
5542
  ];
5471
- if (callAI) {
5472
- const res = await callAI({
5473
- msgs,
5474
- AIActionType: 1 /* INSPECT_ELEMENT */
5475
- });
5476
- return {
5477
- parseResult: transformElementPositionToId(res.content, context.content),
5478
- rawResponse: res,
5479
- elementById,
5480
- usage: res.usage
5481
- };
5482
- }
5483
- const inspectElement = await callAiFn({
5484
- msgs,
5485
- AIActionType: 1 /* INSPECT_ELEMENT */
5486
- });
5543
+ const callAIFn = callAI || callToGetJSONObject;
5544
+ const res = await callAIFn(msgs, 1 /* INSPECT_ELEMENT */);
5487
5545
  return {
5488
- parseResult: transformElementPositionToId(
5489
- inspectElement.content,
5490
- context.content
5546
+ parseResult: await transformElementPositionToId(
5547
+ res.content,
5548
+ context.content,
5549
+ size,
5550
+ screenshotBase64
5491
5551
  ),
5492
- rawResponse: inspectElement,
5552
+ rawResponse: res.content,
5493
5553
  elementById,
5494
- usage: inspectElement.usage
5554
+ usage: res.usage
5495
5555
  };
5496
5556
  }
5497
5557
  async function AiExtractElementInfo(options) {
@@ -5502,11 +5562,25 @@ async function AiExtractElementInfo(options) {
5502
5562
  context,
5503
5563
  liteContextConfig
5504
5564
  );
5565
+ let dataKeys = "";
5566
+ let dataQueryText = "";
5567
+ if (typeof dataQuery === "string") {
5568
+ dataKeys = "";
5569
+ dataQueryText = dataQuery;
5570
+ } else {
5571
+ dataKeys = `return in key-value style object, keys are ${Object.keys(dataQuery).join(",")}`;
5572
+ dataQueryText = JSON.stringify(dataQuery, null, 2);
5573
+ }
5574
+ const extractDataPromptText = await extractDataPrompt.format({
5575
+ pageDescription: description,
5576
+ dataKeys,
5577
+ dataQuery: dataQueryText
5578
+ });
5505
5579
  const msgs = [
5506
5580
  { role: "system", content: systemPrompt },
5507
5581
  {
5508
5582
  role: "user",
5509
- content: transformUserMessages([
5583
+ content: [
5510
5584
  {
5511
5585
  type: "image_url",
5512
5586
  image_url: {
@@ -5515,25 +5589,15 @@ async function AiExtractElementInfo(options) {
5515
5589
  },
5516
5590
  {
5517
5591
  type: "text",
5518
- text: `
5519
- pageDescription: ${description}
5520
-
5521
- Use your extract_data_from_UI skill to find the following data, placing it in the \`data\` field
5522
- DATA_DEMAND start:
5523
- =====================================
5524
- ${typeof dataQuery === "object" ? `return in key-value style object, keys are ${Object.keys(dataQuery).join(",")}` : ""}
5525
- ${typeof dataQuery === "string" ? dataQuery : JSON.stringify(dataQuery, null, 2)}
5526
- =====================================
5527
- DATA_DEMAND ends.
5528
- `
5592
+ text: extractDataPromptText
5529
5593
  }
5530
- ])
5594
+ ]
5531
5595
  }
5532
5596
  ];
5533
- const result = await callAiFn({
5597
+ const result = await callAiFn(
5534
5598
  msgs,
5535
- AIActionType: 2 /* EXTRACT_DATA */
5536
- });
5599
+ 2 /* EXTRACT_DATA */
5600
+ );
5537
5601
  return {
5538
5602
  parseResult: result.content,
5539
5603
  elementById,
@@ -5550,7 +5614,7 @@ async function AiAssert(options) {
5550
5614
  { role: "system", content: systemPrompt },
5551
5615
  {
5552
5616
  role: "user",
5553
- content: transformUserMessages([
5617
+ content: [
5554
5618
  {
5555
5619
  type: "image_url",
5556
5620
  image_url: {
@@ -5569,43 +5633,39 @@ async function AiAssert(options) {
5569
5633
  =====================================
5570
5634
  `
5571
5635
  }
5572
- ])
5636
+ ]
5573
5637
  }
5574
5638
  ];
5575
- const { content: assertResult, usage } = await callAiFn({
5639
+ const { content: assertResult, usage } = await callAiFn(
5576
5640
  msgs,
5577
- AIActionType: 0 /* ASSERT */
5578
- });
5641
+ 0 /* ASSERT */
5642
+ );
5579
5643
  return {
5580
5644
  content: assertResult,
5581
5645
  usage
5582
5646
  };
5583
5647
  }
5584
5648
 
5585
- // src/ai-model/automation/index.ts
5649
+ // src/ai-model/automation.ts
5586
5650
  var import_node_assert5 = __toESM(require("assert"));
5587
5651
  async function plan(userPrompt, opts) {
5588
5652
  const { callAI, context } = opts || {};
5589
5653
  const { screenshotBase64, screenshotBase64WithElementMarker } = context;
5590
- const { description: pageDescription, elementByPosition: elementByPosition2 } = await describeUserPage(context);
5591
- const systemPrompt = systemPromptToTaskPlanning();
5592
- let taskBackgroundContext = "";
5593
- if (opts.originalPrompt && opts.whatHaveDone) {
5594
- 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:
5595
- =====================================
5596
- Original task description:
5597
- ${opts.originalPrompt}
5598
- =====================================
5599
- What have been done:
5600
- ${opts.whatHaveDone}
5601
- =====================================
5602
- `;
5603
- }
5654
+ const { description: pageDescription, elementByPosition } = await describeUserPage(context);
5655
+ const systemPrompt = await systemPromptToTaskPlanning();
5656
+ const userInstructionPrompt = await automationUserPrompt.format({
5657
+ pageDescription,
5658
+ userPrompt,
5659
+ taskBackgroundContext: taskBackgroundContext(
5660
+ opts.originalPrompt,
5661
+ opts.whatHaveDone
5662
+ )
5663
+ });
5604
5664
  const msgs = [
5605
5665
  { role: "system", content: systemPrompt },
5606
5666
  {
5607
5667
  role: "user",
5608
- content: transformUserMessages([
5668
+ content: [
5609
5669
  {
5610
5670
  type: "image_url",
5611
5671
  image_url: {
@@ -5615,28 +5675,13 @@ ${opts.whatHaveDone}
5615
5675
  },
5616
5676
  {
5617
5677
  type: "text",
5618
- text: `
5619
- pageDescription:
5620
-
5621
- ${pageDescription}
5622
-
5623
-
5624
- Here is the instruction:
5625
- =====================================
5626
- ${userPrompt}
5627
- =====================================
5628
-
5629
- ${taskBackgroundContext}
5630
- `.trim()
5678
+ text: userInstructionPrompt
5631
5679
  }
5632
- ])
5680
+ ]
5633
5681
  }
5634
5682
  ];
5635
- const call2 = callAI || callAiFn;
5636
- const { content, usage } = await call2({
5637
- msgs,
5638
- AIActionType: 3 /* PLAN */
5639
- });
5683
+ const call3 = callAI || callAiFn;
5684
+ const { content, usage } = await call3(msgs, 3 /* PLAN */);
5640
5685
  const planFromAI = content;
5641
5686
  const actions = (planFromAI == null ? void 0 : planFromAI.actions) || [];
5642
5687
  (0, import_node_assert5.default)(planFromAI, "can't get plans from AI");