@midscene/core 0.3.4 → 0.4.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.
@@ -1536,39 +1536,39 @@ var Client = class _Client {
1536
1536
  }
1537
1537
  return runParams;
1538
1538
  }
1539
- async _getResponse(path2, queryParams) {
1539
+ async _getResponse(path, queryParams) {
1540
1540
  var _a;
1541
1541
  const paramsString = (_a = queryParams == null ? void 0 : queryParams.toString()) != null ? _a : "";
1542
- const url = `${this.apiUrl}${path2}?${paramsString}`;
1542
+ const url = `${this.apiUrl}${path}?${paramsString}`;
1543
1543
  const response = await this.caller.call(fetch, url, __spreadValues({
1544
1544
  method: "GET",
1545
1545
  headers: this.headers,
1546
1546
  signal: AbortSignal.timeout(this.timeout_ms)
1547
1547
  }, this.fetchOptions));
1548
1548
  if (!response.ok) {
1549
- throw new Error(`Failed to fetch ${path2}: ${response.status} ${response.statusText}`);
1549
+ throw new Error(`Failed to fetch ${path}: ${response.status} ${response.statusText}`);
1550
1550
  }
1551
1551
  return response;
1552
1552
  }
1553
- async _get(path2, queryParams) {
1554
- const response = await this._getResponse(path2, queryParams);
1553
+ async _get(path, queryParams) {
1554
+ const response = await this._getResponse(path, queryParams);
1555
1555
  return response.json();
1556
1556
  }
1557
1557
  _getPaginated(_0) {
1558
- return __asyncGenerator(this, arguments, function* (path2, queryParams = new URLSearchParams()) {
1558
+ return __asyncGenerator(this, arguments, function* (path, queryParams = new URLSearchParams()) {
1559
1559
  let offset = Number(queryParams.get("offset")) || 0;
1560
1560
  const limit = Number(queryParams.get("limit")) || 100;
1561
1561
  while (true) {
1562
1562
  queryParams.set("offset", String(offset));
1563
1563
  queryParams.set("limit", String(limit));
1564
- const url = `${this.apiUrl}${path2}?${queryParams}`;
1564
+ const url = `${this.apiUrl}${path}?${queryParams}`;
1565
1565
  const response = yield new __await(this.caller.call(fetch, url, __spreadValues({
1566
1566
  method: "GET",
1567
1567
  headers: this.headers,
1568
1568
  signal: AbortSignal.timeout(this.timeout_ms)
1569
1569
  }, this.fetchOptions)));
1570
1570
  if (!response.ok) {
1571
- throw new Error(`Failed to fetch ${path2}: ${response.status} ${response.statusText}`);
1571
+ throw new Error(`Failed to fetch ${path}: ${response.status} ${response.statusText}`);
1572
1572
  }
1573
1573
  const items = yield new __await(response.json());
1574
1574
  if (items.length === 0) {
@@ -1582,11 +1582,11 @@ var Client = class _Client {
1582
1582
  }
1583
1583
  });
1584
1584
  }
1585
- _getCursorPaginatedList(path2, body = null, requestMethod = "POST", dataKey = "runs") {
1585
+ _getCursorPaginatedList(path, body = null, requestMethod = "POST", dataKey = "runs") {
1586
1586
  return __asyncGenerator(this, null, function* () {
1587
1587
  const bodyParams = body ? __spreadValues({}, body) : {};
1588
1588
  while (true) {
1589
- const response = yield new __await(this.caller.call(fetch, `${this.apiUrl}${path2}`, __spreadProps(__spreadValues({
1589
+ const response = yield new __await(this.caller.call(fetch, `${this.apiUrl}${path}`, __spreadProps(__spreadValues({
1590
1590
  method: requestMethod,
1591
1591
  headers: __spreadProps(__spreadValues({}, this.headers), { "Content-Type": "application/json" }),
1592
1592
  signal: AbortSignal.timeout(this.timeout_ms)
@@ -2246,19 +2246,19 @@ var Client = class _Client {
2246
2246
  return result;
2247
2247
  }
2248
2248
  async hasProject({ projectId, projectName }) {
2249
- let path2 = "/sessions";
2249
+ let path = "/sessions";
2250
2250
  const params = new URLSearchParams();
2251
2251
  if (projectId !== void 0 && projectName !== void 0) {
2252
2252
  throw new Error("Must provide either projectName or projectId, not both");
2253
2253
  } else if (projectId !== void 0) {
2254
2254
  assertUuid(projectId);
2255
- path2 += `/${projectId}`;
2255
+ path += `/${projectId}`;
2256
2256
  } else if (projectName !== void 0) {
2257
2257
  params.append("name", projectName);
2258
2258
  } else {
2259
2259
  throw new Error("Must provide projectName or projectId");
2260
2260
  }
2261
- const response = await this.caller.call(fetch, `${this.apiUrl}${path2}?${params}`, __spreadValues({
2261
+ const response = await this.caller.call(fetch, `${this.apiUrl}${path}?${params}`, __spreadValues({
2262
2262
  method: "GET",
2263
2263
  headers: this.headers,
2264
2264
  signal: AbortSignal.timeout(this.timeout_ms)
@@ -2277,13 +2277,13 @@ var Client = class _Client {
2277
2277
  }
2278
2278
  }
2279
2279
  async readProject({ projectId, projectName, includeStats }) {
2280
- let path2 = "/sessions";
2280
+ let path = "/sessions";
2281
2281
  const params = new URLSearchParams();
2282
2282
  if (projectId !== void 0 && projectName !== void 0) {
2283
2283
  throw new Error("Must provide either projectName or projectId, not both");
2284
2284
  } else if (projectId !== void 0) {
2285
2285
  assertUuid(projectId);
2286
- path2 += `/${projectId}`;
2286
+ path += `/${projectId}`;
2287
2287
  } else if (projectName !== void 0) {
2288
2288
  params.append("name", projectName);
2289
2289
  } else {
@@ -2292,7 +2292,7 @@ var Client = class _Client {
2292
2292
  if (includeStats !== void 0) {
2293
2293
  params.append("include_stats", includeStats.toString());
2294
2294
  }
2295
- const response = await this._get(path2, params);
2295
+ const response = await this._get(path, params);
2296
2296
  let result;
2297
2297
  if (Array.isArray(response)) {
2298
2298
  if (response.length === 0) {
@@ -2464,19 +2464,19 @@ var Client = class _Client {
2464
2464
  return result;
2465
2465
  }
2466
2466
  async readDataset({ datasetId, datasetName }) {
2467
- let path2 = "/datasets";
2467
+ let path = "/datasets";
2468
2468
  const params = new URLSearchParams({ limit: "1" });
2469
2469
  if (datasetId !== void 0 && datasetName !== void 0) {
2470
2470
  throw new Error("Must provide either datasetName or datasetId, not both");
2471
2471
  } else if (datasetId !== void 0) {
2472
2472
  assertUuid(datasetId);
2473
- path2 += `/${datasetId}`;
2473
+ path += `/${datasetId}`;
2474
2474
  } else if (datasetName !== void 0) {
2475
2475
  params.append("name", datasetName);
2476
2476
  } else {
2477
2477
  throw new Error("Must provide datasetName or datasetId");
2478
2478
  }
2479
- const response = await this._get(path2, params);
2479
+ const response = await this._get(path, params);
2480
2480
  let result;
2481
2481
  if (Array.isArray(response)) {
2482
2482
  if (response.length === 0) {
@@ -2520,21 +2520,21 @@ var Client = class _Client {
2520
2520
  return response;
2521
2521
  }
2522
2522
  async readDatasetOpenaiFinetuning({ datasetId, datasetName }) {
2523
- const path2 = "/datasets";
2523
+ const path = "/datasets";
2524
2524
  if (datasetId !== void 0) {
2525
2525
  } else if (datasetName !== void 0) {
2526
2526
  datasetId = (await this.readDataset({ datasetName })).id;
2527
2527
  } else {
2528
2528
  throw new Error("Must provide datasetName or datasetId");
2529
2529
  }
2530
- const response = await this._getResponse(`${path2}/${datasetId}/openai_ft`);
2530
+ const response = await this._getResponse(`${path}/${datasetId}/openai_ft`);
2531
2531
  const datasetText = await response.text();
2532
2532
  const dataset = datasetText.trim().split("\n").map((line) => JSON.parse(line));
2533
2533
  return dataset;
2534
2534
  }
2535
2535
  listDatasets() {
2536
2536
  return __asyncGenerator(this, arguments, function* ({ limit = 100, offset = 0, datasetIds, datasetName, datasetNameContains } = {}) {
2537
- const path2 = "/datasets";
2537
+ const path = "/datasets";
2538
2538
  const params = new URLSearchParams({
2539
2539
  limit: limit.toString(),
2540
2540
  offset: offset.toString()
@@ -2551,7 +2551,7 @@ var Client = class _Client {
2551
2551
  params.append("name_contains", datasetNameContains);
2552
2552
  }
2553
2553
  try {
2554
- for (var iter = __forAwait(this._getPaginated(path2, params)), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
2554
+ for (var iter = __forAwait(this._getPaginated(path, params)), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
2555
2555
  const datasets = temp.value;
2556
2556
  yield* __yieldStar(datasets);
2557
2557
  }
@@ -2591,7 +2591,7 @@ var Client = class _Client {
2591
2591
  return await response.json();
2592
2592
  }
2593
2593
  async deleteDataset({ datasetId, datasetName }) {
2594
- let path2 = "/datasets";
2594
+ let path = "/datasets";
2595
2595
  let datasetId_ = datasetId;
2596
2596
  if (datasetId !== void 0 && datasetName !== void 0) {
2597
2597
  throw new Error("Must provide either datasetName or datasetId, not both");
@@ -2601,17 +2601,17 @@ var Client = class _Client {
2601
2601
  }
2602
2602
  if (datasetId_ !== void 0) {
2603
2603
  assertUuid(datasetId_);
2604
- path2 += `/${datasetId_}`;
2604
+ path += `/${datasetId_}`;
2605
2605
  } else {
2606
2606
  throw new Error("Must provide datasetName or datasetId");
2607
2607
  }
2608
- const response = await this.caller.call(fetch, this.apiUrl + path2, __spreadValues({
2608
+ const response = await this.caller.call(fetch, this.apiUrl + path, __spreadValues({
2609
2609
  method: "DELETE",
2610
2610
  headers: this.headers,
2611
2611
  signal: AbortSignal.timeout(this.timeout_ms)
2612
2612
  }, this.fetchOptions));
2613
2613
  if (!response.ok) {
2614
- throw new Error(`Failed to delete ${path2}: ${response.status} ${response.statusText}`);
2614
+ throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
2615
2615
  }
2616
2616
  await response.json();
2617
2617
  }
@@ -2696,8 +2696,8 @@ var Client = class _Client {
2696
2696
  }
2697
2697
  async readExample(exampleId) {
2698
2698
  assertUuid(exampleId);
2699
- const path2 = `/examples/${exampleId}`;
2700
- return await this._get(path2);
2699
+ const path = `/examples/${exampleId}`;
2700
+ return await this._get(path);
2701
2701
  }
2702
2702
  listExamples() {
2703
2703
  return __asyncGenerator(this, arguments, function* ({ datasetId, datasetName, exampleIds, asOf, splits, inlineS3Urls, metadata, limit, offset, filter } = {}) {
@@ -2768,14 +2768,14 @@ var Client = class _Client {
2768
2768
  }
2769
2769
  async deleteExample(exampleId) {
2770
2770
  assertUuid(exampleId);
2771
- const path2 = `/examples/${exampleId}`;
2772
- const response = await this.caller.call(fetch, this.apiUrl + path2, __spreadValues({
2771
+ const path = `/examples/${exampleId}`;
2772
+ const response = await this.caller.call(fetch, this.apiUrl + path, __spreadValues({
2773
2773
  method: "DELETE",
2774
2774
  headers: this.headers,
2775
2775
  signal: AbortSignal.timeout(this.timeout_ms)
2776
2776
  }, this.fetchOptions));
2777
2777
  if (!response.ok) {
2778
- throw new Error(`Failed to delete ${path2}: ${response.status} ${response.statusText}`);
2778
+ throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
2779
2779
  }
2780
2780
  await response.json();
2781
2781
  }
@@ -2879,20 +2879,20 @@ var Client = class _Client {
2879
2879
  }
2880
2880
  async readFeedback(feedbackId) {
2881
2881
  assertUuid(feedbackId);
2882
- const path2 = `/feedback/${feedbackId}`;
2883
- const response = await this._get(path2);
2882
+ const path = `/feedback/${feedbackId}`;
2883
+ const response = await this._get(path);
2884
2884
  return response;
2885
2885
  }
2886
2886
  async deleteFeedback(feedbackId) {
2887
2887
  assertUuid(feedbackId);
2888
- const path2 = `/feedback/${feedbackId}`;
2889
- const response = await this.caller.call(fetch, this.apiUrl + path2, __spreadValues({
2888
+ const path = `/feedback/${feedbackId}`;
2889
+ const response = await this.caller.call(fetch, this.apiUrl + path, __spreadValues({
2890
2890
  method: "DELETE",
2891
2891
  headers: this.headers,
2892
2892
  signal: AbortSignal.timeout(this.timeout_ms)
2893
2893
  }, this.fetchOptions));
2894
2894
  if (!response.ok) {
2895
- throw new Error(`Failed to delete ${path2}: ${response.status} ${response.statusText}`);
2895
+ throw new Error(`Failed to delete ${path}: ${response.status} ${response.statusText}`);
2896
2896
  }
2897
2897
  await response.json();
2898
2898
  }
@@ -3878,12 +3878,12 @@ function traceable(wrappedFunc, config) {
3878
3878
  try {
3879
3879
  let runtimeConfig;
3880
3880
  if (argsConfigPath) {
3881
- const [index, path2] = argsConfigPath;
3882
- if (index === args.length - 1 && !path2) {
3881
+ const [index, path] = argsConfigPath;
3882
+ if (index === args.length - 1 && !path) {
3883
3883
  runtimeConfig = args.pop();
3884
3884
  } else if (index <= args.length && typeof args[index] === "object" && args[index] !== null) {
3885
- if (path2) {
3886
- const _a2 = args[index], { [path2]: extracted } = _a2, rest = __objRest(_a2, [__restKey(path2)]);
3885
+ if (path) {
3886
+ const _a2 = args[index], { [path]: extracted } = _a2, rest = __objRest(_a2, [__restKey(path)]);
3887
3887
  runtimeConfig = extracted;
3888
3888
  args[index] = rest;
3889
3889
  } else {
@@ -4224,6 +4224,7 @@ import OpenAI from "openai";
4224
4224
  var MIDSCENE_OPENAI_INIT_CONFIG_JSON = "MIDSCENE_OPENAI_INIT_CONFIG_JSON";
4225
4225
  var MIDSCENE_MODEL_NAME = "MIDSCENE_MODEL_NAME";
4226
4226
  var MIDSCENE_LANGSMITH_DEBUG = "MIDSCENE_LANGSMITH_DEBUG";
4227
+ var MIDSCENE_DEBUG_AI_PROFILE = "MIDSCENE_DEBUG_AI_PROFILE";
4227
4228
  var OPENAI_API_KEY = "OPENAI_API_KEY";
4228
4229
  function useOpenAIModel(useModel) {
4229
4230
  if (useModel && useModel !== "openAI")
@@ -4253,12 +4254,16 @@ async function createOpenAI() {
4253
4254
  }
4254
4255
  async function call(messages, responseFormat) {
4255
4256
  const openai = await createOpenAI();
4257
+ const shouldPrintTiming = typeof process.env[MIDSCENE_DEBUG_AI_PROFILE] === "string";
4258
+ shouldPrintTiming && console.time("Midscene - AI call");
4256
4259
  const completion = await openai.chat.completions.create({
4257
4260
  model,
4258
4261
  messages,
4259
4262
  response_format: { type: responseFormat },
4260
4263
  temperature: 0.2
4261
4264
  });
4265
+ shouldPrintTiming && console.timeEnd("Midscene - AI call");
4266
+ shouldPrintTiming && console.log("Midscene - AI usage", completion.usage);
4262
4267
  const { content } = completion.choices[0].message;
4263
4268
  assert(content, "empty content");
4264
4269
  return content;
@@ -4406,45 +4411,18 @@ function multiDescription(multi) {
4406
4411
  }
4407
4412
 
4408
4413
  // src/ai-model/prompt/util.ts
4409
- import assert4 from "assert";
4410
-
4411
- // src/image/info.ts
4412
4414
  import assert2 from "assert";
4413
- import { Buffer as Buffer2 } from "buffer";
4414
- import { readFileSync } from "fs";
4415
- import Sharp from "sharp";
4416
- async function imageInfo(image) {
4417
- const { width, height } = await Sharp(image).metadata();
4418
- assert2(width && height, `invalid image: ${image}`);
4419
- return { width, height };
4420
- }
4421
- async function imageInfoOfBase64(imageBase64) {
4422
- const base64Data = imageBase64.replace(/^data:image\/\w+;base64,/, "");
4423
- return imageInfo(Buffer2.from(base64Data, "base64"));
4424
- }
4425
-
4426
- // src/image/transform.ts
4427
- import { Buffer as Buffer3 } from "buffer";
4428
- import Sharp2 from "sharp";
4429
-
4430
- // src/image/visualization.ts
4431
- import { Buffer as Buffer4 } from "buffer";
4432
4415
 
4433
- // src/utils.ts
4434
- import assert3 from "assert";
4435
- import { randomUUID } from "crypto";
4416
+ // src/image/index.ts
4436
4417
  import {
4437
- existsSync,
4438
- mkdirSync,
4439
- readFileSync as readFileSync2,
4440
- writeFileSync
4441
- } from "fs";
4442
- import { tmpdir } from "os";
4443
- import path, { basename, dirname, join } from "path";
4444
- var logDir = join(process.cwd(), "./midscene_run/");
4445
-
4446
- // src/image/visualization.ts
4447
- import Sharp3 from "sharp";
4418
+ imageInfo,
4419
+ imageInfoOfBase64,
4420
+ base64Encoded,
4421
+ calculateNewDimensions,
4422
+ resizeImg,
4423
+ transformImgPathToBase64,
4424
+ saveBase64Image
4425
+ } from "@midscene/shared/img";
4448
4426
 
4449
4427
  // src/ai-model/prompt/util.ts
4450
4428
  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.";
@@ -4537,7 +4515,7 @@ async function describeUserPage(context) {
4537
4515
  "elementInfos": ${JSON.stringify(elementInfosDescription)}
4538
4516
  }`,
4539
4517
  elementById(id) {
4540
- assert4(typeof id !== "undefined", "id is required for query");
4518
+ assert2(typeof id !== "undefined", "id is required for query");
4541
4519
  const item = idElementMap[`${id}`];
4542
4520
  return item;
4543
4521
  }
@@ -4568,10 +4546,10 @@ function cropFieldInformation(elementsInfo) {
4568
4546
  }
4569
4547
 
4570
4548
  // src/ai-model/inspect.ts
4571
- import assert6 from "assert";
4549
+ import assert4 from "assert";
4572
4550
 
4573
4551
  // src/ai-model/coze/index.ts
4574
- import assert5 from "assert";
4552
+ import assert3 from "assert";
4575
4553
  import fetch2 from "node-fetch";
4576
4554
  var COZE_INSPECT_ELEMENT_BOT_ID = process.env.COZE_INSPECT_ELEMENT_BOT_ID || "";
4577
4555
  var COZE_AI_ACTION_BOT_ID = process.env.COZE_AI_ACTION_BOT_ID || "";
@@ -4624,7 +4602,7 @@ async function callCozeAi(options) {
4624
4602
  throw new Error("aiResponse is undefined", aiResponse);
4625
4603
  }
4626
4604
  const parseContent = (_b = aiResponse == null ? void 0 : aiResponse.messages[0]) == null ? void 0 : _b.content;
4627
- assert5(parseContent, "empty content");
4605
+ assert3(parseContent, "empty content");
4628
4606
  try {
4629
4607
  return JSON.parse(parseContent);
4630
4608
  } catch (err) {
@@ -4799,7 +4777,7 @@ DATA_DEMAND ends.
4799
4777
  }
4800
4778
  async function AiAssert(options) {
4801
4779
  const { assertion, context, useModel } = options;
4802
- assert6(assertion, "assertion should be a string");
4780
+ assert4(assertion, "assertion should be a string");
4803
4781
  const { screenshotBase64 } = context;
4804
4782
  const { description, elementById } = await describeUserPage(context);
4805
4783
  const systemPrompt = systemPromptToAssert();
@@ -4843,7 +4821,7 @@ async function AiAssert(options) {
4843
4821
  }
4844
4822
 
4845
4823
  // src/ai-model/automation/index.ts
4846
- import assert7 from "assert";
4824
+ import assert5 from "assert";
4847
4825
 
4848
4826
  // src/ai-model/automation/planning.ts
4849
4827
  function systemPromptToTaskPlanning() {
@@ -4949,8 +4927,8 @@ async function plan(userPrompt, opts, useModel) {
4949
4927
  });
4950
4928
  }
4951
4929
  const actions = (planFromAI == null ? void 0 : planFromAI.actions) || [];
4952
- assert7(planFromAI, "can't get planFromAI");
4953
- assert7(actions && actions.length > 0, "no actions in ai plan");
4930
+ assert5(planFromAI, "can't get planFromAI");
4931
+ assert5(actions && actions.length > 0, "no actions in ai plan");
4954
4932
  if (planFromAI.error) {
4955
4933
  throw new Error(planFromAI.error);
4956
4934
  }