@midscene/core 1.10.2-beta-20260706032158.0 → 1.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/dist/es/agent/agent.mjs +40 -1
  2. package/dist/es/agent/agent.mjs.map +1 -1
  3. package/dist/es/agent/metrics.mjs +81 -0
  4. package/dist/es/agent/metrics.mjs.map +1 -0
  5. package/dist/es/agent/task-builder.mjs +1 -1
  6. package/dist/es/agent/task-builder.mjs.map +1 -1
  7. package/dist/es/agent/utils.mjs +1 -1
  8. package/dist/es/ai-model/connectivity/run-connectivity-test.mjs +9 -3
  9. package/dist/es/ai-model/connectivity/run-connectivity-test.mjs.map +1 -1
  10. package/dist/es/ai-model/inspect.mjs +3 -3
  11. package/dist/es/ai-model/inspect.mjs.map +1 -1
  12. package/dist/es/ai-model/llm-planning.mjs +1 -1
  13. package/dist/es/ai-model/llm-planning.mjs.map +1 -1
  14. package/dist/es/ai-model/model-adapter/resolve.mjs +2 -2
  15. package/dist/es/ai-model/model-adapter/resolve.mjs.map +1 -1
  16. package/dist/es/ai-model/models/default.mjs +2 -1
  17. package/dist/es/ai-model/models/default.mjs.map +1 -1
  18. package/dist/es/ai-model/models/doubao.mjs +38 -60
  19. package/dist/es/ai-model/models/doubao.mjs.map +1 -1
  20. package/dist/es/ai-model/models/gemini.mjs +4 -15
  21. package/dist/es/ai-model/models/gemini.mjs.map +1 -1
  22. package/dist/es/ai-model/models/glm.mjs +4 -0
  23. package/dist/es/ai-model/models/glm.mjs.map +1 -1
  24. package/dist/es/ai-model/models/gpt.mjs +5 -1
  25. package/dist/es/ai-model/models/gpt.mjs.map +1 -1
  26. package/dist/es/ai-model/models/kimi.mjs +4 -0
  27. package/dist/es/ai-model/models/kimi.mjs.map +1 -1
  28. package/dist/es/ai-model/models/mimo.mjs +3 -2
  29. package/dist/es/ai-model/models/mimo.mjs.map +1 -1
  30. package/dist/es/ai-model/models/qwen.mjs.map +1 -1
  31. package/dist/es/ai-model/models/ui-tars/adapter.mjs +2 -41
  32. package/dist/es/ai-model/models/ui-tars/adapter.mjs.map +1 -1
  33. package/dist/es/ai-model/models/utils/intent.mjs +6 -0
  34. package/dist/es/ai-model/models/utils/intent.mjs.map +1 -0
  35. package/dist/es/ai-model/prompt/describe.mjs +31 -34
  36. package/dist/es/ai-model/prompt/describe.mjs.map +1 -1
  37. package/dist/es/ai-model/prompt/extraction.mjs +15 -9
  38. package/dist/es/ai-model/prompt/extraction.mjs.map +1 -1
  39. package/dist/es/ai-model/prompt/llm-planning.mjs +19 -19
  40. package/dist/es/ai-model/prompt/llm-planning.mjs.map +1 -1
  41. package/dist/es/ai-model/prompt/locate-grounding-rules.mjs +7 -3
  42. package/dist/es/ai-model/prompt/locate-grounding-rules.mjs.map +1 -1
  43. package/dist/es/ai-model/prompt/recorder-metadata-generator.mjs +2 -1
  44. package/dist/es/ai-model/prompt/recorder-metadata-generator.mjs.map +1 -1
  45. package/dist/es/ai-model/service-caller/index.mjs +40 -19
  46. package/dist/es/ai-model/service-caller/index.mjs.map +1 -1
  47. package/dist/es/ai-model/service-caller/json.mjs +31 -28
  48. package/dist/es/ai-model/service-caller/json.mjs.map +1 -1
  49. package/dist/es/device/index.mjs +2 -4
  50. package/dist/es/device/index.mjs.map +1 -1
  51. package/dist/es/dump/html-utils.mjs +63 -1
  52. package/dist/es/dump/html-utils.mjs.map +1 -1
  53. package/dist/es/dump/screenshot-restoration.mjs +6 -0
  54. package/dist/es/dump/screenshot-restoration.mjs.map +1 -1
  55. package/dist/es/element-describer.mjs +36 -18
  56. package/dist/es/element-describer.mjs.map +1 -1
  57. package/dist/es/index.mjs +2 -2
  58. package/dist/es/index.mjs.map +1 -1
  59. package/dist/es/report-generator.mjs +28 -1
  60. package/dist/es/report-generator.mjs.map +1 -1
  61. package/dist/es/report-markdown.mjs +300 -35
  62. package/dist/es/report-markdown.mjs.map +1 -1
  63. package/dist/es/report.mjs +29 -1
  64. package/dist/es/report.mjs.map +1 -1
  65. package/dist/es/service/index.mjs +101 -25
  66. package/dist/es/service/index.mjs.map +1 -1
  67. package/dist/es/service/utils.mjs +65 -1
  68. package/dist/es/service/utils.mjs.map +1 -1
  69. package/dist/es/types.mjs.map +1 -1
  70. package/dist/es/utils.mjs +2 -2
  71. package/dist/lib/agent/agent.js +40 -1
  72. package/dist/lib/agent/agent.js.map +1 -1
  73. package/dist/lib/agent/metrics.js +115 -0
  74. package/dist/lib/agent/metrics.js.map +1 -0
  75. package/dist/lib/agent/task-builder.js +1 -1
  76. package/dist/lib/agent/task-builder.js.map +1 -1
  77. package/dist/lib/agent/utils.js +1 -1
  78. package/dist/lib/ai-model/connectivity/run-connectivity-test.js +9 -3
  79. package/dist/lib/ai-model/connectivity/run-connectivity-test.js.map +1 -1
  80. package/dist/lib/ai-model/inspect.js +3 -3
  81. package/dist/lib/ai-model/inspect.js.map +1 -1
  82. package/dist/lib/ai-model/llm-planning.js +1 -1
  83. package/dist/lib/ai-model/llm-planning.js.map +1 -1
  84. package/dist/lib/ai-model/model-adapter/resolve.js +1 -1
  85. package/dist/lib/ai-model/model-adapter/resolve.js.map +1 -1
  86. package/dist/lib/ai-model/models/default.js +2 -1
  87. package/dist/lib/ai-model/models/default.js.map +1 -1
  88. package/dist/lib/ai-model/models/doubao.js +38 -69
  89. package/dist/lib/ai-model/models/doubao.js.map +1 -1
  90. package/dist/lib/ai-model/models/gemini.js +4 -15
  91. package/dist/lib/ai-model/models/gemini.js.map +1 -1
  92. package/dist/lib/ai-model/models/glm.js +4 -0
  93. package/dist/lib/ai-model/models/glm.js.map +1 -1
  94. package/dist/lib/ai-model/models/gpt.js +5 -1
  95. package/dist/lib/ai-model/models/gpt.js.map +1 -1
  96. package/dist/lib/ai-model/models/kimi.js +4 -0
  97. package/dist/lib/ai-model/models/kimi.js.map +1 -1
  98. package/dist/lib/ai-model/models/mimo.js +3 -2
  99. package/dist/lib/ai-model/models/mimo.js.map +1 -1
  100. package/dist/lib/ai-model/models/qwen.js.map +1 -1
  101. package/dist/lib/ai-model/models/ui-tars/adapter.js +1 -40
  102. package/dist/lib/ai-model/models/ui-tars/adapter.js.map +1 -1
  103. package/dist/lib/ai-model/models/utils/intent.js +40 -0
  104. package/dist/lib/ai-model/models/utils/intent.js.map +1 -0
  105. package/dist/lib/ai-model/prompt/describe.js +31 -34
  106. package/dist/lib/ai-model/prompt/describe.js.map +1 -1
  107. package/dist/lib/ai-model/prompt/extraction.js +14 -8
  108. package/dist/lib/ai-model/prompt/extraction.js.map +1 -1
  109. package/dist/lib/ai-model/prompt/llm-planning.js +19 -19
  110. package/dist/lib/ai-model/prompt/llm-planning.js.map +1 -1
  111. package/dist/lib/ai-model/prompt/locate-grounding-rules.js +7 -3
  112. package/dist/lib/ai-model/prompt/locate-grounding-rules.js.map +1 -1
  113. package/dist/lib/ai-model/prompt/recorder-metadata-generator.js +4 -3
  114. package/dist/lib/ai-model/prompt/recorder-metadata-generator.js.map +1 -1
  115. package/dist/lib/ai-model/service-caller/index.js +44 -23
  116. package/dist/lib/ai-model/service-caller/index.js.map +1 -1
  117. package/dist/lib/ai-model/service-caller/json.js +33 -33
  118. package/dist/lib/ai-model/service-caller/json.js.map +1 -1
  119. package/dist/lib/device/index.js +2 -4
  120. package/dist/lib/device/index.js.map +1 -1
  121. package/dist/lib/dump/html-utils.js +65 -0
  122. package/dist/lib/dump/html-utils.js.map +1 -1
  123. package/dist/lib/dump/screenshot-restoration.js +6 -0
  124. package/dist/lib/dump/screenshot-restoration.js.map +1 -1
  125. package/dist/lib/element-describer.js +37 -22
  126. package/dist/lib/element-describer.js.map +1 -1
  127. package/dist/lib/index.js +1 -4
  128. package/dist/lib/index.js.map +1 -1
  129. package/dist/lib/report-generator.js +27 -0
  130. package/dist/lib/report-generator.js.map +1 -1
  131. package/dist/lib/report-markdown.js +300 -35
  132. package/dist/lib/report-markdown.js.map +1 -1
  133. package/dist/lib/report.js +28 -0
  134. package/dist/lib/report.js.map +1 -1
  135. package/dist/lib/service/index.js +99 -23
  136. package/dist/lib/service/index.js.map +1 -1
  137. package/dist/lib/service/utils.js +98 -1
  138. package/dist/lib/service/utils.js.map +1 -1
  139. package/dist/lib/types.js.map +1 -1
  140. package/dist/lib/utils.js +2 -2
  141. package/dist/types/agent/agent.d.ts +15 -2
  142. package/dist/types/agent/index.d.ts +1 -0
  143. package/dist/types/agent/metrics.d.ts +48 -0
  144. package/dist/types/ai-model/model-adapter/types.d.ts +8 -0
  145. package/dist/types/ai-model/models/doubao.d.ts +1 -4
  146. package/dist/types/ai-model/models/gemini.d.ts +1 -1
  147. package/dist/types/ai-model/models/registry.d.ts +1 -1
  148. package/dist/types/ai-model/models/utils/intent.d.ts +2 -0
  149. package/dist/types/ai-model/service-caller/index.d.ts +8 -3
  150. package/dist/types/ai-model/service-caller/json.d.ts +19 -2
  151. package/dist/types/device/device-options.d.ts +0 -28
  152. package/dist/types/device/index.d.ts +0 -5
  153. package/dist/types/dump/html-utils.d.ts +2 -0
  154. package/dist/types/dump/screenshot-restoration.d.ts +1 -1
  155. package/dist/types/element-describer.d.ts +3 -6
  156. package/dist/types/index.d.ts +2 -2
  157. package/dist/types/report-generator.d.ts +6 -0
  158. package/dist/types/service/index.d.ts +1 -1
  159. package/dist/types/service/utils.d.ts +21 -2
  160. package/dist/types/types.d.ts +12 -2
  161. package/package.json +3 -3
@@ -1,6 +1,4 @@
1
- import { assert } from "@midscene/shared/utils";
2
- import { jsonrepair } from "jsonrepair";
3
- import { extractJSONFromCodeBlock, safeParseJson } from "../service-caller/json.mjs";
1
+ import { parseModelResponseJson } from "../service-caller/json.mjs";
4
2
  import { createLocateResultValue, unwrapCoordinateListLikeInput } from "../shared/model-locate-result/index.mjs";
5
3
  const doubaoBboxCoordinatesMeta = {
6
4
  shape: 'bbox',
@@ -12,68 +10,48 @@ const doubaoPointCoordinatesMeta = {
12
10
  order: 'xy',
13
11
  normalizedBy: 1000
14
12
  };
15
- function normalizeDoubaoJsonObject(obj, context = {}) {
16
- if (null == obj) return obj;
17
- if (Array.isArray(obj)) return obj.map((item)=>normalizeDoubaoJsonObject(item, context));
18
- if ('object' == typeof obj) {
19
- const normalized = {};
20
- for (const [key, value] of Object.entries(obj)){
21
- const trimmedKey = key.trim();
22
- const preserveStringValue = context.preserveStringValueKeys?.includes(trimmedKey) ?? false;
23
- const normalizedValue = 'string' == typeof value ? preserveStringValue ? value : value.trim() : normalizeDoubaoJsonObject(value, context);
24
- normalized[trimmedKey] = normalizedValue;
25
- }
26
- return normalized;
27
- }
28
- return 'string' == typeof obj ? obj.trim() : obj;
13
+ function parseNumbersFromBboxString(input) {
14
+ return (input.match(/\d+/g) ?? []).map(Number).filter(Number.isFinite);
29
15
  }
30
- function shouldRepairDoubaoLocateJson(source) {
31
- return 'locate' === source || 'section-locator' === source || 'planning-action-param' === source;
16
+ function parseLeadingNumberFromString(input) {
17
+ const match = input.match(/^\s*(\d+)/);
18
+ return match ? Number(match[1]) : void 0;
32
19
  }
33
- function preprocessDoubaoLocateJson(input) {
34
- if (input.includes('bbox')) while(/\d+\s+\d+/.test(input))input = input.replace(/(\d+)\s+(\d+)/g, '$1,$2');
35
- return input;
20
+ function isCleanCoordinateString(input) {
21
+ return /^\s*\d+(?:[\s,;]+\d+)*\s*[,;]?\s*$/.test(input);
36
22
  }
37
- const doubaoJsonParser = (raw, context = {
38
- source: 'generic-object'
39
- })=>{
40
- const { source } = context;
41
- try {
42
- return safeParseJson(raw, context);
43
- } catch (firstError) {
44
- if (!shouldRepairDoubaoLocateJson(source)) throw firstError;
45
- const jsonString = preprocessDoubaoLocateJson(extractJSONFromCodeBlock(raw));
46
- try {
47
- return normalizeDoubaoJsonObject(JSON.parse(jsonrepair(jsonString)), context);
48
- } catch (error) {
49
- throw Error(`failed to parse LLM response into JSON. Error - ${String(error ?? firstError ?? 'unknown error')}. Response - \n ${raw}`);
23
+ function parseNumbersFromBboxArray(input) {
24
+ const numbers = [];
25
+ for (const item of input){
26
+ if ('number' == typeof item) {
27
+ numbers.push(item);
28
+ continue;
29
+ }
30
+ if ('string' == typeof item) if (isCleanCoordinateString(item)) {
31
+ numbers.push(...parseNumbersFromBboxString(item));
32
+ continue;
33
+ } else {
34
+ const leadingNumber = parseLeadingNumberFromString(item);
35
+ if (void 0 !== leadingNumber) numbers.push(leadingNumber);
50
36
  }
37
+ break;
51
38
  }
52
- };
39
+ return numbers.filter(Number.isFinite);
40
+ }
41
+ function parseNumbersFromTaggedBboxArray(input) {
42
+ if (input.length < 2) return null;
43
+ const taggedBbox = input[1];
44
+ if ('string' == typeof taggedBbox) return parseNumbersFromBboxString(taggedBbox);
45
+ if (Array.isArray(taggedBbox)) return parseNumbersFromBboxArray(taggedBbox);
46
+ return null;
47
+ }
53
48
  function parseDoubaoRawLocateValue(input) {
54
49
  const bbox = unwrapCoordinateListLikeInput(input);
55
- if ('string' == typeof bbox) {
56
- assert(/^(\d+)\s(\d+)\s(\d+)\s(\d+)$/.test(bbox.trim()), `invalid bbox data string for doubao-vision mode: ${bbox}`);
57
- const splitted = bbox.split(' ');
58
- if (4 === splitted.length) return createLocateResultValue(doubaoBboxCoordinatesMeta, [
59
- Number(splitted[0]),
60
- Number(splitted[1]),
61
- Number(splitted[2]),
62
- Number(splitted[3])
63
- ]);
64
- throw new Error(`invalid bbox data string for doubao-vision mode: ${bbox}`);
65
- }
66
50
  let bboxList = [];
67
- if (Array.isArray(bbox) && 'string' == typeof bbox[0]) bbox.forEach((item)=>{
68
- if ('string' == typeof item && item.includes(',')) {
69
- const [x, y] = item.split(',');
70
- bboxList.push(Number(x.trim()), Number(y.trim()));
71
- } else if ('string' == typeof item && item.includes(' ')) {
72
- const [x, y] = item.split(' ');
73
- bboxList.push(Number(x.trim()), Number(y.trim()));
74
- } else bboxList.push(Number(item));
75
- });
76
- else bboxList = bbox;
51
+ if ('string' == typeof bbox) {
52
+ bboxList = parseNumbersFromBboxString(bbox);
53
+ if (4 !== bboxList.length) throw new Error(`invalid bbox data string for doubao-vision mode: ${bbox}`);
54
+ } else bboxList = Array.isArray(bbox) ? 'string' == typeof bbox[0] && 'bbox' === bbox[0].trim() ? parseNumbersFromTaggedBboxArray(bbox) ?? [] : parseNumbersFromBboxArray(bbox) : bbox;
77
55
  if (4 === bboxList.length || 5 === bboxList.length) return createLocateResultValue(doubaoBboxCoordinatesMeta, [
78
56
  bboxList[0],
79
57
  bboxList[1],
@@ -84,7 +62,7 @@ function parseDoubaoRawLocateValue(input) {
84
62
  bboxList[0],
85
63
  bboxList[1]
86
64
  ]);
87
- if (8 === bbox.length) return createLocateResultValue(doubaoBboxCoordinatesMeta, [
65
+ if (8 === bboxList.length) return createLocateResultValue(doubaoBboxCoordinatesMeta, [
88
66
  bboxList[0],
89
67
  bboxList[1],
90
68
  bboxList[4],
@@ -114,7 +92,7 @@ const buildDoubaoChatCompletionParams = (input)=>{
114
92
  };
115
93
  };
116
94
  const doubaoVisionAdapter = {
117
- jsonParser: doubaoJsonParser,
95
+ jsonParser: parseModelResponseJson,
118
96
  chatCompletion: {
119
97
  unsupportedUserConfig: [
120
98
  'reasoningBudget'
@@ -133,6 +111,6 @@ const doubaoAdapters = {
133
111
  'doubao-vision': doubaoVisionAdapter,
134
112
  'doubao-seed': doubaoVisionAdapter
135
113
  };
136
- export { doubaoAdapters, normalizeDoubaoJsonObject, parseDoubaoRawLocateValue, preprocessDoubaoLocateJson, shouldRepairDoubaoLocateJson };
114
+ export { doubaoAdapters, parseDoubaoRawLocateValue };
137
115
 
138
116
  //# sourceMappingURL=doubao.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/models/doubao.mjs","sources":["../../../../src/ai-model/models/doubao.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport { assert } from '@midscene/shared/utils';\nimport { jsonrepair } from 'jsonrepair';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n JsonParserContext,\n JsonParserSource,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\nimport {\n extractJSONFromCodeBlock,\n safeParseJson,\n} from '../service-caller/json';\nimport {\n type LocateResultValue,\n createLocateResultValue,\n unwrapCoordinateListLikeInput,\n} from '../shared/model-locate-result';\n\nconst doubaoBboxCoordinatesMeta = {\n shape: 'bbox',\n order: 'xy',\n normalizedBy: 1000,\n} as const;\nconst doubaoPointCoordinatesMeta = {\n shape: 'point',\n order: 'xy',\n normalizedBy: 1000,\n} as const;\n\nexport function normalizeDoubaoJsonObject(\n obj: any,\n context: Pick<JsonParserContext, 'preserveStringValueKeys'> = {},\n): any {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => normalizeDoubaoJsonObject(item, context));\n }\n\n if (typeof obj === 'object') {\n const normalized: any = {};\n for (const [key, value] of Object.entries(obj)) {\n const trimmedKey = key.trim();\n const preserveStringValue =\n context.preserveStringValueKeys?.includes(trimmedKey) ?? false;\n const normalizedValue =\n typeof value === 'string'\n ? preserveStringValue\n ? value\n : value.trim()\n : normalizeDoubaoJsonObject(value, context);\n normalized[trimmedKey] = normalizedValue;\n }\n return normalized;\n }\n\n return typeof obj === 'string' ? obj.trim() : obj;\n}\n\nexport function shouldRepairDoubaoLocateJson(source: JsonParserSource) {\n return (\n source === 'locate' ||\n source === 'section-locator' ||\n source === 'planning-action-param'\n );\n}\n\nexport function preprocessDoubaoLocateJson(input: string) {\n if (input.includes('bbox')) {\n while (/\\d+\\s+\\d+/.test(input)) {\n input = input.replace(/(\\d+)\\s+(\\d+)/g, '$1,$2');\n }\n }\n return input;\n}\n\nconst doubaoJsonParser: ModelAdapterDefinition['jsonParser'] = (\n raw,\n context = { source: 'generic-object' },\n) => {\n const { source } = context;\n try {\n return safeParseJson(raw, context);\n } catch (firstError) {\n if (!shouldRepairDoubaoLocateJson(source)) {\n throw firstError;\n }\n\n const jsonString = preprocessDoubaoLocateJson(\n extractJSONFromCodeBlock(raw),\n );\n try {\n return normalizeDoubaoJsonObject(\n JSON.parse(jsonrepair(jsonString)),\n context,\n );\n } catch (error) {\n throw Error(\n `failed to parse LLM response into JSON. Error - ${String(\n error ?? firstError ?? 'unknown error',\n )}. Response - \\n ${raw}`,\n );\n }\n }\n};\n\nexport function parseDoubaoRawLocateValue(input: unknown): LocateResultValue {\n const bbox = unwrapCoordinateListLikeInput(input as any);\n if (typeof bbox === 'string') {\n assert(\n /^(\\d+)\\s(\\d+)\\s(\\d+)\\s(\\d+)$/.test(bbox.trim()),\n `invalid bbox data string for doubao-vision mode: ${bbox}`,\n );\n const splitted = bbox.split(' ');\n if (splitted.length === 4) {\n return createLocateResultValue(doubaoBboxCoordinatesMeta, [\n Number(splitted[0]),\n Number(splitted[1]),\n Number(splitted[2]),\n Number(splitted[3]),\n ]);\n }\n throw new Error(`invalid bbox data string for doubao-vision mode: ${bbox}`);\n }\n\n let bboxList: number[] = [];\n if (Array.isArray(bbox) && typeof bbox[0] === 'string') {\n bbox.forEach((item) => {\n if (typeof item === 'string' && item.includes(',')) {\n const [x, y] = item.split(',');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else if (typeof item === 'string' && item.includes(' ')) {\n const [x, y] = item.split(' ');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else {\n bboxList.push(Number(item));\n }\n });\n } else {\n bboxList = bbox as number[];\n }\n\n if (bboxList.length === 4 || bboxList.length === 5) {\n return createLocateResultValue(doubaoBboxCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n bboxList[2],\n bboxList[3],\n ]);\n }\n\n if (\n bboxList.length === 6 ||\n bboxList.length === 2 ||\n bboxList.length === 3 ||\n bboxList.length === 7\n ) {\n return createLocateResultValue(doubaoPointCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n ]);\n }\n\n if (bbox.length === 8) {\n return createLocateResultValue(doubaoBboxCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n bboxList[4],\n bboxList[5],\n ]);\n }\n\n const msg = `invalid bbox data for doubao-vision mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n}\n\nconst buildDoubaoChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const { reasoningEnabled, reasoningEffort } = userConfig;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n const modelSpecificConfig: Record<string, unknown> = {};\n\n if (reasoningEnabled !== 'default') {\n modelSpecificConfig.thinking = {\n type: (reasoningEnabled ?? false) ? 'enabled' : 'disabled',\n };\n if (reasoningEffort) {\n modelSpecificConfig.reasoning_effort = reasoningEffort;\n }\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nconst doubaoVisionAdapter: ModelAdapterDefinition = {\n jsonParser: doubaoJsonParser,\n chatCompletion: {\n unsupportedUserConfig: ['reasoningBudget'],\n buildChatCompletionParams: buildDoubaoChatCompletionParams,\n useReasoningAsContentFallback: true,\n },\n locate: {\n resultAdapter: {\n coordinates: doubaoBboxCoordinatesMeta,\n parseRawLocateValue: parseDoubaoRawLocateValue,\n },\n },\n};\n\nexport const doubaoAdapters = {\n 'doubao-vision': doubaoVisionAdapter,\n 'doubao-seed': doubaoVisionAdapter,\n} satisfies Pick<\n Record<TModelFamily, ModelAdapterDefinition>,\n 'doubao-vision' | 'doubao-seed'\n>;\n"],"names":["doubaoBboxCoordinatesMeta","doubaoPointCoordinatesMeta","normalizeDoubaoJsonObject","obj","context","Array","item","normalized","key","value","Object","trimmedKey","preserveStringValue","normalizedValue","shouldRepairDoubaoLocateJson","source","preprocessDoubaoLocateJson","input","doubaoJsonParser","raw","safeParseJson","firstError","jsonString","extractJSONFromCodeBlock","JSON","jsonrepair","error","Error","String","parseDoubaoRawLocateValue","bbox","unwrapCoordinateListLikeInput","assert","splitted","createLocateResultValue","Number","bboxList","x","y","msg","buildDoubaoChatCompletionParams","midsceneDefaults","userConfig","reasoningEnabled","reasoningEffort","commonOverrideConfig","undefined","modelSpecificConfig","doubaoVisionAdapter","doubaoAdapters"],"mappings":"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"}
1
+ {"version":3,"file":"ai-model/models/doubao.mjs","sources":["../../../../src/ai-model/models/doubao.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\nimport { parseModelResponseJson } from '../service-caller/json';\nimport {\n type LocateResultValue,\n createLocateResultValue,\n unwrapCoordinateListLikeInput,\n} from '../shared/model-locate-result';\n\nconst doubaoBboxCoordinatesMeta = {\n shape: 'bbox',\n order: 'xy',\n normalizedBy: 1000,\n} as const;\nconst doubaoPointCoordinatesMeta = {\n shape: 'point',\n order: 'xy',\n normalizedBy: 1000,\n} as const;\n\nfunction parseNumbersFromBboxString(input: string): number[] {\n return (input.match(/\\d+/g) ?? []).map(Number).filter(Number.isFinite);\n}\n\nfunction parseLeadingNumberFromString(input: string): number | undefined {\n const match = input.match(/^\\s*(\\d+)/);\n return match ? Number(match[1]) : undefined;\n}\n\n/**\n * Clean coordinate strings can contain multiple positive integers, e.g.\n * - \"123 100\"\n * - \"123,100\"\n * - \"277; 664 291;\"\n * Dirty strings like \"345<\" are handled by taking the leading number and\n * dropping the remaining array items.\n */\nfunction isCleanCoordinateString(input: string): boolean {\n return /^\\s*\\d+(?:[\\s,;]+\\d+)*\\s*[,;]?\\s*$/.test(input);\n}\n\nfunction parseNumbersFromBboxArray(input: unknown[]): number[] {\n const numbers: number[] = [];\n\n for (const item of input) {\n if (typeof item === 'number') {\n numbers.push(item);\n continue;\n }\n\n if (typeof item === 'string') {\n if (isCleanCoordinateString(item)) {\n numbers.push(...parseNumbersFromBboxString(item));\n continue;\n } else {\n const leadingNumber = parseLeadingNumberFromString(item);\n if (leadingNumber !== undefined) {\n numbers.push(leadingNumber);\n }\n // Once a dirty string appears, the remaining array items usually belong\n // to broken JSON repair output, e.g. [410, 295, 885, \"345<\", \"/bbox>...\"].\n break;\n }\n }\n\n break;\n }\n\n return numbers.filter(Number.isFinite);\n}\n\n/**\n * Some models return a tagged bbox tuple, e.g.\n * - [\"bbox\", [782, 541, 815, 559]]\n * - [\"bbox\", \"782, 541, 815, 559\"]\n */\nfunction parseNumbersFromTaggedBboxArray(input: unknown[]): number[] | null {\n if (input.length < 2) {\n return null;\n }\n\n const taggedBbox = input[1];\n if (typeof taggedBbox === 'string') {\n return parseNumbersFromBboxString(taggedBbox);\n }\n\n if (Array.isArray(taggedBbox)) {\n return parseNumbersFromBboxArray(taggedBbox);\n }\n\n return null;\n}\n\nexport function parseDoubaoRawLocateValue(input: unknown): LocateResultValue {\n const bbox = unwrapCoordinateListLikeInput(input as any);\n let bboxList: number[] = [];\n\n if (typeof bbox === 'string') {\n /**\n * Some models return bbox as a string, e.g.\n * - { \"bbox\": \"[336, 163, 717, 200]\" }.\n * - { \"bbox\": \"336, 163, 717, 200\" }.\n * - { \"bbox\": \"336 163 717 200\" }.\n */\n bboxList = parseNumbersFromBboxString(bbox);\n if (bboxList.length !== 4) {\n throw new Error(\n `invalid bbox data string for doubao-vision mode: ${bbox}`,\n );\n }\n } else if (Array.isArray(bbox)) {\n if (typeof bbox[0] === 'string' && bbox[0].trim() === 'bbox') {\n bboxList = parseNumbersFromTaggedBboxArray(bbox) ?? [];\n } else {\n bboxList = parseNumbersFromBboxArray(bbox);\n }\n } else {\n bboxList = bbox as number[];\n }\n\n if (bboxList.length === 4 || bboxList.length === 5) {\n return createLocateResultValue(doubaoBboxCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n bboxList[2],\n bboxList[3],\n ]);\n }\n\n if (\n bboxList.length === 6 ||\n bboxList.length === 2 ||\n bboxList.length === 3 ||\n bboxList.length === 7\n ) {\n return createLocateResultValue(doubaoPointCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n ]);\n }\n\n if (bboxList.length === 8) {\n return createLocateResultValue(doubaoBboxCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n bboxList[4],\n bboxList[5],\n ]);\n }\n\n const msg = `invalid bbox data for doubao-vision mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n}\n\nconst buildDoubaoChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const { reasoningEnabled, reasoningEffort } = userConfig;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n const modelSpecificConfig: Record<string, unknown> = {};\n\n if (reasoningEnabled !== 'default') {\n modelSpecificConfig.thinking = {\n type: (reasoningEnabled ?? false) ? 'enabled' : 'disabled',\n };\n if (reasoningEffort) {\n modelSpecificConfig.reasoning_effort = reasoningEffort;\n }\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nconst doubaoVisionAdapter: ModelAdapterDefinition = {\n jsonParser: parseModelResponseJson,\n chatCompletion: {\n unsupportedUserConfig: ['reasoningBudget'],\n buildChatCompletionParams: buildDoubaoChatCompletionParams,\n useReasoningAsContentFallback: true,\n },\n locate: {\n resultAdapter: {\n coordinates: doubaoBboxCoordinatesMeta,\n parseRawLocateValue: parseDoubaoRawLocateValue,\n },\n },\n};\n\nexport const doubaoAdapters = {\n 'doubao-vision': doubaoVisionAdapter,\n 'doubao-seed': doubaoVisionAdapter,\n} satisfies Pick<\n Record<TModelFamily, ModelAdapterDefinition>,\n 'doubao-vision' | 'doubao-seed'\n>;\n"],"names":["doubaoBboxCoordinatesMeta","doubaoPointCoordinatesMeta","parseNumbersFromBboxString","input","Number","parseLeadingNumberFromString","match","undefined","isCleanCoordinateString","parseNumbersFromBboxArray","numbers","item","leadingNumber","parseNumbersFromTaggedBboxArray","taggedBbox","Array","parseDoubaoRawLocateValue","bbox","unwrapCoordinateListLikeInput","bboxList","Error","createLocateResultValue","msg","JSON","buildDoubaoChatCompletionParams","midsceneDefaults","userConfig","reasoningEnabled","reasoningEffort","commonOverrideConfig","modelSpecificConfig","doubaoVisionAdapter","parseModelResponseJson","doubaoAdapters"],"mappings":"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"}
@@ -1,27 +1,17 @@
1
1
  const buildGeminiChatCompletionParams = (input)=>{
2
- const { midsceneDefaults, userConfig, intent } = input;
2
+ const { midsceneDefaults, userConfig } = input;
3
3
  const { reasoningEnabled, reasoningEffort } = userConfig;
4
4
  const commonOverrideConfig = {};
5
5
  if (void 0 !== userConfig.temperature) commonOverrideConfig.temperature = userConfig.temperature;
6
6
  const modelSpecificConfig = {};
7
- if ('default' !== reasoningEnabled) if (reasoningEffort) modelSpecificConfig.extra_body = {
7
+ if ('default' !== reasoningEnabled) modelSpecificConfig.extra_body = {
8
8
  google: {
9
9
  thinking_config: {
10
- thinking_level: reasoningEffort,
11
- include_thoughts: true
10
+ include_thoughts: true,
11
+ thinking_level: reasoningEnabled ? reasoningEffort ?? 'medium' : 'minimal'
12
12
  }
13
13
  }
14
14
  };
15
- else {
16
- if ('insight' === intent) modelSpecificConfig.extra_body = {
17
- google: {
18
- thinking_config: {
19
- include_thoughts: true
20
- }
21
- }
22
- };
23
- modelSpecificConfig.reasoning_effort = 'minimal';
24
- }
25
15
  return {
26
16
  config: {
27
17
  ...midsceneDefaults,
@@ -84,7 +74,6 @@ const geminiAdapters = {
84
74
  gemini: {
85
75
  chatCompletion: {
86
76
  unsupportedUserConfig: [
87
- 'reasoningEnabled',
88
77
  'reasoningBudget'
89
78
  ],
90
79
  buildChatCompletionParams: buildGeminiChatCompletionParams,
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/models/gemini.mjs","sources":["../../../../src/ai-model/models/gemini.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type OpenAI from 'openai';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionContentSource,\n ChatCompletionParamsResult,\n ContentAndReasoning,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\n\ntype GeminiContentPart = Record<string, unknown> & {\n text?: string;\n thought?: boolean;\n};\n\ntype GeminiContentExtension = {\n content: string | null | GeminiContentPart[];\n reasoning_content?: string;\n extra_content?: unknown;\n};\n\ntype GeminiContentSource =\n | ChatCompletionContentSource\n | (Omit<OpenAI.Chat.Completions.ChatCompletionMessage, 'content'> &\n GeminiContentExtension)\n | (Omit<OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta, 'content'> &\n GeminiContentExtension);\n\nconst buildGeminiChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig, intent } = input;\n const { reasoningEnabled, reasoningEffort } = userConfig;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n const modelSpecificConfig: {\n extra_body?: {\n google?: {\n thinking_config: Record<string, unknown>;\n };\n };\n reasoning_effort?: unknown;\n } = {};\n\n if (reasoningEnabled !== 'default') {\n if (reasoningEffort) {\n modelSpecificConfig.extra_body = {\n google: {\n thinking_config: {\n thinking_level: reasoningEffort,\n include_thoughts: true,\n },\n },\n };\n } else {\n if (intent === 'insight') {\n modelSpecificConfig.extra_body = {\n google: {\n thinking_config: {\n // In real Gemini tests, insight calls need `include_thoughts` to get\n // the model's thinking, and Gemini puts that thinking into `content`.\n include_thoughts: true,\n },\n },\n };\n }\n\n // Gemini 3.x cannot fully disable native thinking, so use the lowest\n // supported effort unless the user explicitly requests another level.\n modelSpecificConfig.reasoning_effort = 'minimal';\n }\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nconst extractInlineThought = (content: string): string | undefined => {\n const match = content.match(/<thought>([\\s\\S]*?)<\\/thought>/i);\n return match?.[1]?.trim() || undefined;\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\ntype GeminiExtractedContent = {\n content: string;\n geminiReasoningContent: string;\n};\n\nconst formatReasoningContent = ({\n geminiReasoningContent,\n providerReasoningContent,\n}: {\n geminiReasoningContent: string;\n providerReasoningContent: string;\n}): string => {\n if (geminiReasoningContent && providerReasoningContent) {\n return `thoughtParts:${geminiReasoningContent}; reasoning_content:${providerReasoningContent}`;\n }\n\n return geminiReasoningContent || providerReasoningContent || '';\n};\n\nconst extractGeminiThoughtParts = (\n content: GeminiContentPart[],\n): GeminiExtractedContent => {\n const contentParts: string[] = [];\n const reasoningParts: string[] = [];\n\n for (const part of content) {\n if (!isRecord(part)) {\n continue;\n }\n\n const text = typeof part.text === 'string' ? part.text : undefined;\n if (!text) {\n continue;\n }\n\n if (part.thought === true) {\n reasoningParts.push(text);\n } else {\n contentParts.push(text);\n }\n }\n\n return {\n content: contentParts.join(''),\n geminiReasoningContent: reasoningParts.join(''),\n };\n};\n\nexport const extractGeminiContentAndReasoning = (\n message: GeminiContentSource | undefined,\n): ContentAndReasoning => {\n // Gemini native API exposes thought summaries in\n // `response.candidates[0].content.parts`, where each text part can carry\n // `thought: true`. Some OpenAI-compatible adapters may pass through a\n // native-like content-parts shape, even though the Gemini OpenAI\n // compatibility docs do not guarantee it.\n // Docs: https://ai.google.dev/gemini-api/docs/thinking#thought-summaries\n\n if (!message) {\n return {\n content: '',\n reasoning_content: '',\n };\n }\n\n if (Array.isArray(message.content)) {\n const extracted = extractGeminiThoughtParts(message.content);\n\n return {\n content: extracted.content,\n reasoning_content: formatReasoningContent({\n geminiReasoningContent: extracted.geminiReasoningContent,\n providerReasoningContent:\n typeof message.reasoning_content === 'string'\n ? message.reasoning_content\n : '',\n }),\n };\n }\n\n const content = typeof message.content === 'string' ? message.content : '';\n // In real Gemini OpenAI-compatible responses we observed that\n // `include_thoughts` can still return a plain string `message.content`,\n // with the thought summary prepended as `<thought>...</thought>` before the\n // visible answer. Keep content unchanged, but extract that leading thought\n // text for report display.\n const geminiReasoningContent = extractInlineThought(content) || '';\n\n return {\n content,\n reasoning_content: formatReasoningContent({\n geminiReasoningContent,\n providerReasoningContent:\n typeof message.reasoning_content === 'string'\n ? message.reasoning_content\n : '',\n }),\n };\n};\n\nexport const geminiAdapters = {\n gemini: {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningEnabled', 'reasoningBudget'],\n buildChatCompletionParams: buildGeminiChatCompletionParams,\n messageExtraction: {\n kind: 'custom',\n extractContentAndReasoning: extractGeminiContentAndReasoning,\n },\n },\n locate: {\n resultAdapter: {\n coordinates: { shape: 'bbox', order: 'yx', normalizedBy: 1000 },\n },\n },\n },\n} satisfies Pick<Record<TModelFamily, ModelAdapterDefinition>, 'gemini'>;\n"],"names":["buildGeminiChatCompletionParams","input","midsceneDefaults","userConfig","intent","reasoningEnabled","reasoningEffort","commonOverrideConfig","undefined","modelSpecificConfig","extractInlineThought","content","match","isRecord","value","Array","formatReasoningContent","geminiReasoningContent","providerReasoningContent","extractGeminiThoughtParts","contentParts","reasoningParts","part","text","extractGeminiContentAndReasoning","message","extracted","geminiAdapters"],"mappings":"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"}
1
+ {"version":3,"file":"ai-model/models/gemini.mjs","sources":["../../../../src/ai-model/models/gemini.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type OpenAI from 'openai';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionContentSource,\n ChatCompletionParamsResult,\n ContentAndReasoning,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\n\ntype GeminiContentPart = Record<string, unknown> & {\n text?: string;\n thought?: boolean;\n};\n\ntype GeminiContentExtension = {\n content: string | null | GeminiContentPart[];\n reasoning_content?: string;\n extra_content?: unknown;\n};\n\ntype GeminiContentSource =\n | ChatCompletionContentSource\n | (Omit<OpenAI.Chat.Completions.ChatCompletionMessage, 'content'> &\n GeminiContentExtension)\n | (Omit<OpenAI.Chat.Completions.ChatCompletionChunk.Choice.Delta, 'content'> &\n GeminiContentExtension);\n\nconst buildGeminiChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const { reasoningEnabled, reasoningEffort } = userConfig;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n const modelSpecificConfig: {\n extra_body?: {\n google?: {\n thinking_config: {\n include_thoughts: true;\n thinking_level: string;\n };\n };\n };\n } = {};\n\n if (reasoningEnabled !== 'default') {\n // Gemini cannot fully disable native thinking, so \"disabled\" maps to the\n // lowest thinking level. `include_thoughts` only controls whether Gemini\n // returns thought summaries; it does not enable thinking, and thought token\n // usage is based on the full thoughts Gemini generates regardless of\n // whether summaries are included.\n modelSpecificConfig.extra_body = {\n google: {\n thinking_config: {\n include_thoughts: true,\n thinking_level: reasoningEnabled\n ? (reasoningEffort ?? 'medium')\n : 'minimal',\n },\n },\n };\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nconst extractInlineThought = (content: string): string | undefined => {\n const match = content.match(/<thought>([\\s\\S]*?)<\\/thought>/i);\n return match?.[1]?.trim() || undefined;\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === 'object' && !Array.isArray(value);\n}\n\ntype GeminiExtractedContent = {\n content: string;\n geminiReasoningContent: string;\n};\n\nconst formatReasoningContent = ({\n geminiReasoningContent,\n providerReasoningContent,\n}: {\n geminiReasoningContent: string;\n providerReasoningContent: string;\n}): string => {\n if (geminiReasoningContent && providerReasoningContent) {\n return `thoughtParts:${geminiReasoningContent}; reasoning_content:${providerReasoningContent}`;\n }\n\n return geminiReasoningContent || providerReasoningContent || '';\n};\n\nconst extractGeminiThoughtParts = (\n content: GeminiContentPart[],\n): GeminiExtractedContent => {\n const contentParts: string[] = [];\n const reasoningParts: string[] = [];\n\n for (const part of content) {\n if (!isRecord(part)) {\n continue;\n }\n\n const text = typeof part.text === 'string' ? part.text : undefined;\n if (!text) {\n continue;\n }\n\n if (part.thought === true) {\n reasoningParts.push(text);\n } else {\n contentParts.push(text);\n }\n }\n\n return {\n content: contentParts.join(''),\n geminiReasoningContent: reasoningParts.join(''),\n };\n};\n\nexport const extractGeminiContentAndReasoning = (\n message: GeminiContentSource | undefined,\n): ContentAndReasoning => {\n // Gemini native API exposes thought summaries in\n // `response.candidates[0].content.parts`, where each text part can carry\n // `thought: true`. Some OpenAI-compatible adapters may pass through a\n // native-like content-parts shape, even though the Gemini OpenAI\n // compatibility docs do not guarantee it.\n // Docs: https://ai.google.dev/gemini-api/docs/thinking#thought-summaries\n\n if (!message) {\n return {\n content: '',\n reasoning_content: '',\n };\n }\n\n if (Array.isArray(message.content)) {\n const extracted = extractGeminiThoughtParts(message.content);\n\n return {\n content: extracted.content,\n reasoning_content: formatReasoningContent({\n geminiReasoningContent: extracted.geminiReasoningContent,\n providerReasoningContent:\n typeof message.reasoning_content === 'string'\n ? message.reasoning_content\n : '',\n }),\n };\n }\n\n const content = typeof message.content === 'string' ? message.content : '';\n // In real Gemini OpenAI-compatible responses we observed that\n // `include_thoughts` can still return a plain string `message.content`,\n // with the thought summary prepended as `<thought>...</thought>` before the\n // visible answer. Keep content unchanged, but extract that leading thought\n // text for report display.\n const geminiReasoningContent = extractInlineThought(content) || '';\n\n return {\n content,\n reasoning_content: formatReasoningContent({\n geminiReasoningContent,\n providerReasoningContent:\n typeof message.reasoning_content === 'string'\n ? message.reasoning_content\n : '',\n }),\n };\n};\n\nexport const geminiAdapters = {\n gemini: {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningBudget'],\n buildChatCompletionParams: buildGeminiChatCompletionParams,\n messageExtraction: {\n kind: 'custom',\n extractContentAndReasoning: extractGeminiContentAndReasoning,\n },\n },\n locate: {\n resultAdapter: {\n coordinates: { shape: 'bbox', order: 'yx', normalizedBy: 1000 },\n },\n },\n },\n} satisfies Pick<Record<TModelFamily, ModelAdapterDefinition>, 'gemini'>;\n"],"names":["buildGeminiChatCompletionParams","input","midsceneDefaults","userConfig","reasoningEnabled","reasoningEffort","commonOverrideConfig","undefined","modelSpecificConfig","extractInlineThought","content","match","isRecord","value","Array","formatReasoningContent","geminiReasoningContent","providerReasoningContent","extractGeminiThoughtParts","contentParts","reasoningParts","part","text","extractGeminiContentAndReasoning","message","extracted","geminiAdapters"],"mappings":"AA4BA,MAAMA,kCAAkC,CACtCC;IAEA,MAAM,EAAEC,gBAAgB,EAAEC,UAAU,EAAE,GAAGF;IACzC,MAAM,EAAEG,gBAAgB,EAAEC,eAAe,EAAE,GAAGF;IAC9C,MAAMG,uBAAgD,CAAC;IAEvD,IAAIH,AAA2BI,WAA3BJ,WAAW,WAAW,EACxBG,qBAAqB,WAAW,GAAGH,WAAW,WAAW;IAG3D,MAAMK,sBASF,CAAC;IAEL,IAAIJ,AAAqB,cAArBA,kBAMFI,oBAAoB,UAAU,GAAG;QAC/B,QAAQ;YACN,iBAAiB;gBACf,kBAAkB;gBAClB,gBAAgBJ,mBACXC,mBAAmB,WACpB;YACN;QACF;IACF;IAGF,OAAO;QACL,QAAQ;YACN,GAAGH,gBAAgB;YACnB,GAAGI,oBAAoB;YACvB,GAAGE,mBAAmB;QACxB;IACF;AACF;AAEA,MAAMC,uBAAuB,CAACC;IAC5B,MAAMC,QAAQD,QAAQ,KAAK,CAAC;IAC5B,OAAOC,OAAO,CAAC,EAAE,EAAE,UAAUJ;AAC/B;AAEA,SAASK,SAASC,KAAc;IAC9B,OAAO,CAAC,CAACA,SAAS,AAAiB,YAAjB,OAAOA,SAAsB,CAACC,MAAM,OAAO,CAACD;AAChE;AAOA,MAAME,yBAAyB,CAAC,EAC9BC,sBAAsB,EACtBC,wBAAwB,EAIzB;IACC,IAAID,0BAA0BC,0BAC5B,OAAO,CAAC,aAAa,EAAED,uBAAuB,oBAAoB,EAAEC,0BAA0B;IAGhG,OAAOD,0BAA0BC,4BAA4B;AAC/D;AAEA,MAAMC,4BAA4B,CAChCR;IAEA,MAAMS,eAAyB,EAAE;IACjC,MAAMC,iBAA2B,EAAE;IAEnC,KAAK,MAAMC,QAAQX,QAAS;QAC1B,IAAI,CAACE,SAASS,OACZ;QAGF,MAAMC,OAAO,AAAqB,YAArB,OAAOD,KAAK,IAAI,GAAgBA,KAAK,IAAI,GAAGd;QACzD,IAAKe,MAIL,IAAID,AAAiB,SAAjBA,KAAK,OAAO,EACdD,eAAe,IAAI,CAACE;aAEpBH,aAAa,IAAI,CAACG;IAEtB;IAEA,OAAO;QACL,SAASH,aAAa,IAAI,CAAC;QAC3B,wBAAwBC,eAAe,IAAI,CAAC;IAC9C;AACF;AAEO,MAAMG,mCAAmC,CAC9CC;IASA,IAAI,CAACA,SACH,OAAO;QACL,SAAS;QACT,mBAAmB;IACrB;IAGF,IAAIV,MAAM,OAAO,CAACU,QAAQ,OAAO,GAAG;QAClC,MAAMC,YAAYP,0BAA0BM,QAAQ,OAAO;QAE3D,OAAO;YACL,SAASC,UAAU,OAAO;YAC1B,mBAAmBV,uBAAuB;gBACxC,wBAAwBU,UAAU,sBAAsB;gBACxD,0BACE,AAAqC,YAArC,OAAOD,QAAQ,iBAAiB,GAC5BA,QAAQ,iBAAiB,GACzB;YACR;QACF;IACF;IAEA,MAAMd,UAAU,AAA2B,YAA3B,OAAOc,QAAQ,OAAO,GAAgBA,QAAQ,OAAO,GAAG;IAMxE,MAAMR,yBAAyBP,qBAAqBC,YAAY;IAEhE,OAAO;QACLA;QACA,mBAAmBK,uBAAuB;YACxCC;YACA,0BACE,AAAqC,YAArC,OAAOQ,QAAQ,iBAAiB,GAC5BA,QAAQ,iBAAiB,GACzB;QACR;IACF;AACF;AAEO,MAAME,iBAAiB;IAC5B,QAAQ;QACN,gBAAgB;YACd,uBAAuB;gBAAC;aAAkB;YAC1C,2BAA2B1B;YAC3B,mBAAmB;gBACjB,MAAM;gBACN,4BAA4BuB;YAC9B;QACF;QACA,QAAQ;YACN,eAAe;gBACb,aAAa;oBAAE,OAAO;oBAAQ,OAAO;oBAAM,cAAc;gBAAK;YAChE;QACF;IACF;AACF"}
@@ -1,8 +1,12 @@
1
+ import { isLocateIntent } from "./utils/intent.mjs";
1
2
  const buildGlmChatCompletionParams = (input)=>{
2
3
  const { midsceneDefaults, userConfig } = input;
3
4
  const { reasoningEnabled } = userConfig;
4
5
  const commonOverrideConfig = {};
5
6
  if (void 0 !== userConfig.temperature) commonOverrideConfig.temperature = userConfig.temperature;
7
+ if (isLocateIntent(input.intent)) commonOverrideConfig.response_format = {
8
+ type: 'json_object'
9
+ };
6
10
  const modelSpecificConfig = {};
7
11
  if ('default' !== reasoningEnabled) modelSpecificConfig.thinking = {
8
12
  type: reasoningEnabled ?? false ? 'enabled' : 'disabled'
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/models/glm.mjs","sources":["../../../../src/ai-model/models/glm.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\n\nconst buildGlmChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const { reasoningEnabled } = userConfig;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n const modelSpecificConfig: Record<string, unknown> = {};\n\n if (reasoningEnabled !== 'default') {\n modelSpecificConfig.thinking = {\n type: (reasoningEnabled ?? false) ? 'enabled' : 'disabled',\n };\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nexport const glmAdapters = {\n 'glm-v': {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningEffort', 'reasoningBudget'],\n buildChatCompletionParams: buildGlmChatCompletionParams,\n useReasoningAsContentFallback: true,\n },\n locate: {\n resultAdapter: {\n coordinates: { shape: 'bbox', order: 'xy', normalizedBy: 1000 },\n },\n },\n },\n} satisfies Pick<Record<TModelFamily, ModelAdapterDefinition>, 'glm-v'>;\n"],"names":["buildGlmChatCompletionParams","input","midsceneDefaults","userConfig","reasoningEnabled","commonOverrideConfig","undefined","modelSpecificConfig","glmAdapters"],"mappings":"AAOA,MAAMA,+BAA+B,CACnCC;IAEA,MAAM,EAAEC,gBAAgB,EAAEC,UAAU,EAAE,GAAGF;IACzC,MAAM,EAAEG,gBAAgB,EAAE,GAAGD;IAC7B,MAAME,uBAAgD,CAAC;IAEvD,IAAIF,AAA2BG,WAA3BH,WAAW,WAAW,EACxBE,qBAAqB,WAAW,GAAGF,WAAW,WAAW;IAG3D,MAAMI,sBAA+C,CAAC;IAEtD,IAAIH,AAAqB,cAArBA,kBACFG,oBAAoB,QAAQ,GAAG;QAC7B,MAAOH,oBAAoB,QAAS,YAAY;IAClD;IAGF,OAAO;QACL,QAAQ;YACN,GAAGF,gBAAgB;YACnB,GAAGG,oBAAoB;YACvB,GAAGE,mBAAmB;QACxB;IACF;AACF;AAEO,MAAMC,cAAc;IACzB,SAAS;QACP,gBAAgB;YACd,uBAAuB;gBAAC;gBAAmB;aAAkB;YAC7D,2BAA2BR;YAC3B,+BAA+B;QACjC;QACA,QAAQ;YACN,eAAe;gBACb,aAAa;oBAAE,OAAO;oBAAQ,OAAO;oBAAM,cAAc;gBAAK;YAChE;QACF;IACF;AACF"}
1
+ {"version":3,"file":"ai-model/models/glm.mjs","sources":["../../../../src/ai-model/models/glm.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\nimport { isLocateIntent } from './utils/intent';\n\nconst buildGlmChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const { reasoningEnabled } = userConfig;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n // Zhipu structured output JSON mode:\n // https://docs.bigmodel.cn/cn/guide/capabilities/struct-output\n if (isLocateIntent(input.intent)) {\n commonOverrideConfig.response_format = { type: 'json_object' };\n }\n\n const modelSpecificConfig: Record<string, unknown> = {};\n\n if (reasoningEnabled !== 'default') {\n modelSpecificConfig.thinking = {\n type: (reasoningEnabled ?? false) ? 'enabled' : 'disabled',\n };\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nexport const glmAdapters = {\n 'glm-v': {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningEffort', 'reasoningBudget'],\n buildChatCompletionParams: buildGlmChatCompletionParams,\n useReasoningAsContentFallback: true,\n },\n locate: {\n resultAdapter: {\n coordinates: { shape: 'bbox', order: 'xy', normalizedBy: 1000 },\n },\n },\n },\n} satisfies Pick<Record<TModelFamily, ModelAdapterDefinition>, 'glm-v'>;\n"],"names":["buildGlmChatCompletionParams","input","midsceneDefaults","userConfig","reasoningEnabled","commonOverrideConfig","undefined","isLocateIntent","modelSpecificConfig","glmAdapters"],"mappings":";AAQA,MAAMA,+BAA+B,CACnCC;IAEA,MAAM,EAAEC,gBAAgB,EAAEC,UAAU,EAAE,GAAGF;IACzC,MAAM,EAAEG,gBAAgB,EAAE,GAAGD;IAC7B,MAAME,uBAAgD,CAAC;IAEvD,IAAIF,AAA2BG,WAA3BH,WAAW,WAAW,EACxBE,qBAAqB,WAAW,GAAGF,WAAW,WAAW;IAK3D,IAAII,eAAeN,MAAM,MAAM,GAC7BI,qBAAqB,eAAe,GAAG;QAAE,MAAM;IAAc;IAG/D,MAAMG,sBAA+C,CAAC;IAEtD,IAAIJ,AAAqB,cAArBA,kBACFI,oBAAoB,QAAQ,GAAG;QAC7B,MAAOJ,oBAAoB,QAAS,YAAY;IAClD;IAGF,OAAO;QACL,QAAQ;YACN,GAAGF,gBAAgB;YACnB,GAAGG,oBAAoB;YACvB,GAAGG,mBAAmB;QACxB;IACF;AACF;AAEO,MAAMC,cAAc;IACzB,SAAS;QACP,gBAAgB;YACd,uBAAuB;gBAAC;gBAAmB;aAAkB;YAC7D,2BAA2BT;YAC3B,+BAA+B;QACjC;QACA,QAAQ;YACN,eAAe;gBACb,aAAa;oBAAE,OAAO;oBAAQ,OAAO;oBAAM,cAAc;gBAAK;YAChE;QACF;IACF;AACF"}
@@ -1,9 +1,13 @@
1
- const originalImageDetailForDefaultIntent = (input)=>'default' === input.intent || input.requiresOriginalImageDetail ? 'original' : void 0;
1
+ import { isLocateIntent } from "./utils/intent.mjs";
2
+ const originalImageDetailForDefaultIntent = (input)=>isLocateIntent(input.intent) || input.requiresOriginalImageDetail ? 'original' : void 0;
2
3
  const buildGpt5ChatCompletionParams = (input)=>{
3
4
  const { midsceneDefaults, userConfig } = input;
4
5
  const { reasoningEnabled, reasoningEffort } = userConfig;
5
6
  const commonOverrideConfig = {};
6
7
  if (void 0 !== userConfig.temperature) commonOverrideConfig.temperature = userConfig.temperature;
8
+ if (isLocateIntent(input.intent)) commonOverrideConfig.response_format = {
9
+ type: 'json_object'
10
+ };
7
11
  const effectiveReasoningEffort = true === reasoningEnabled ? reasoningEffort ?? 'medium' : 'none';
8
12
  return {
9
13
  config: {
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/models/gpt.mjs","sources":["../../../../src/ai-model/models/gpt.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n ImageDetail,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\n\nconst originalImageDetailForDefaultIntent = (\n input: ChatCompletionCallContext,\n): ImageDetail | undefined =>\n input.intent === 'default' || input.requiresOriginalImageDetail\n ? 'original'\n : undefined;\n\nconst buildGpt5ChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const { reasoningEnabled, reasoningEffort } = userConfig;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n const effectiveReasoningEffort =\n reasoningEnabled === true ? (reasoningEffort ?? 'medium') : 'none';\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n reasoning_effort: effectiveReasoningEffort,\n },\n };\n};\n\nexport const gptAdapters = {\n 'gpt-5': {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningBudget'],\n buildChatCompletionParams: buildGpt5ChatCompletionParams,\n resolveImageDetail: originalImageDetailForDefaultIntent,\n },\n locate: {\n resultAdapter: {\n coordinates: { shape: 'bbox', order: 'xy' },\n },\n },\n },\n} satisfies Pick<Record<TModelFamily, ModelAdapterDefinition>, 'gpt-5'>;\n"],"names":["originalImageDetailForDefaultIntent","input","undefined","buildGpt5ChatCompletionParams","midsceneDefaults","userConfig","reasoningEnabled","reasoningEffort","commonOverrideConfig","effectiveReasoningEffort","gptAdapters"],"mappings":"AAQA,MAAMA,sCAAsC,CAC1CC,QAEAA,AAAiB,cAAjBA,MAAM,MAAM,IAAkBA,MAAM,2BAA2B,GAC3D,aACAC;AAEN,MAAMC,gCAAgC,CACpCF;IAEA,MAAM,EAAEG,gBAAgB,EAAEC,UAAU,EAAE,GAAGJ;IACzC,MAAM,EAAEK,gBAAgB,EAAEC,eAAe,EAAE,GAAGF;IAC9C,MAAMG,uBAAgD,CAAC;IAEvD,IAAIH,AAA2BH,WAA3BG,WAAW,WAAW,EACxBG,qBAAqB,WAAW,GAAGH,WAAW,WAAW;IAG3D,MAAMI,2BACJH,AAAqB,SAArBA,mBAA6BC,mBAAmB,WAAY;IAE9D,OAAO;QACL,QAAQ;YACN,GAAGH,gBAAgB;YACnB,GAAGI,oBAAoB;YACvB,kBAAkBC;QACpB;IACF;AACF;AAEO,MAAMC,cAAc;IACzB,SAAS;QACP,gBAAgB;YACd,uBAAuB;gBAAC;aAAkB;YAC1C,2BAA2BP;YAC3B,oBAAoBH;QACtB;QACA,QAAQ;YACN,eAAe;gBACb,aAAa;oBAAE,OAAO;oBAAQ,OAAO;gBAAK;YAC5C;QACF;IACF;AACF"}
1
+ {"version":3,"file":"ai-model/models/gpt.mjs","sources":["../../../../src/ai-model/models/gpt.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n ImageDetail,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\nimport { isLocateIntent } from './utils/intent';\n\nconst originalImageDetailForDefaultIntent = (\n input: ChatCompletionCallContext,\n): ImageDetail | undefined =>\n isLocateIntent(input.intent) || input.requiresOriginalImageDetail\n ? 'original'\n : undefined;\n\nconst buildGpt5ChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const { reasoningEnabled, reasoningEffort } = userConfig;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n // OpenAI Chat Completions JSON mode:\n // https://platform.openai.com/docs/guides/structured-outputs?api-mode=chat#json-mode\n if (isLocateIntent(input.intent)) {\n commonOverrideConfig.response_format = { type: 'json_object' };\n }\n\n const effectiveReasoningEffort =\n reasoningEnabled === true ? (reasoningEffort ?? 'medium') : 'none';\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n reasoning_effort: effectiveReasoningEffort,\n },\n };\n};\n\nexport const gptAdapters = {\n 'gpt-5': {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningBudget'],\n buildChatCompletionParams: buildGpt5ChatCompletionParams,\n resolveImageDetail: originalImageDetailForDefaultIntent,\n },\n locate: {\n resultAdapter: {\n coordinates: { shape: 'bbox', order: 'xy' },\n },\n },\n },\n} satisfies Pick<Record<TModelFamily, ModelAdapterDefinition>, 'gpt-5'>;\n"],"names":["originalImageDetailForDefaultIntent","input","isLocateIntent","undefined","buildGpt5ChatCompletionParams","midsceneDefaults","userConfig","reasoningEnabled","reasoningEffort","commonOverrideConfig","effectiveReasoningEffort","gptAdapters"],"mappings":";AASA,MAAMA,sCAAsC,CAC1CC,QAEAC,eAAeD,MAAM,MAAM,KAAKA,MAAM,2BAA2B,GAC7D,aACAE;AAEN,MAAMC,gCAAgC,CACpCH;IAEA,MAAM,EAAEI,gBAAgB,EAAEC,UAAU,EAAE,GAAGL;IACzC,MAAM,EAAEM,gBAAgB,EAAEC,eAAe,EAAE,GAAGF;IAC9C,MAAMG,uBAAgD,CAAC;IAEvD,IAAIH,AAA2BH,WAA3BG,WAAW,WAAW,EACxBG,qBAAqB,WAAW,GAAGH,WAAW,WAAW;IAK3D,IAAIJ,eAAeD,MAAM,MAAM,GAC7BQ,qBAAqB,eAAe,GAAG;QAAE,MAAM;IAAc;IAG/D,MAAMC,2BACJH,AAAqB,SAArBA,mBAA6BC,mBAAmB,WAAY;IAE9D,OAAO;QACL,QAAQ;YACN,GAAGH,gBAAgB;YACnB,GAAGI,oBAAoB;YACvB,kBAAkBC;QACpB;IACF;AACF;AAEO,MAAMC,cAAc;IACzB,SAAS;QACP,gBAAgB;YACd,uBAAuB;gBAAC;aAAkB;YAC1C,2BAA2BP;YAC3B,oBAAoBJ;QACtB;QACA,QAAQ;YACN,eAAe;gBACb,aAAa;oBAAE,OAAO;oBAAQ,OAAO;gBAAK;YAC5C;QACF;IACF;AACF"}
@@ -1,4 +1,5 @@
1
1
  import { createLocateResultValue, parseCoordinateList } from "../shared/model-locate-result/index.mjs";
2
+ import { isLocateIntent } from "./utils/intent.mjs";
2
3
  const kimiNormalizedPointCoordinatesMeta = {
3
4
  shape: 'point',
4
5
  order: 'xy',
@@ -24,6 +25,9 @@ const buildKimiChatCompletionParams = (input)=>{
24
25
  const effectiveReasoningEnabled = reasoningEnabled ?? false;
25
26
  const commonOverrideConfig = {};
26
27
  commonOverrideConfig.temperature = void 0;
28
+ if (isLocateIntent(input.intent)) commonOverrideConfig.response_format = {
29
+ type: 'json_object'
30
+ };
27
31
  const modelSpecificConfig = {
28
32
  thinking: {
29
33
  type: effectiveReasoningEnabled ? 'enabled' : 'disabled'
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/models/kimi.mjs","sources":["../../../../src/ai-model/models/kimi.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\nimport {\n type LocateResultValue,\n createLocateResultValue,\n parseCoordinateList,\n} from '../shared/model-locate-result';\n\nconst kimiNormalizedPointCoordinatesMeta = {\n shape: 'point',\n order: 'xy',\n normalizedBy: 1,\n} as const;\nconst kimiPixelPointCoordinatesMeta = {\n shape: 'point',\n order: 'xy',\n} as const;\n\nfunction parseKimiRawLocateValue(input: unknown): LocateResultValue {\n const point = parseCoordinateList(input, 'point');\n if (point.length < 2) {\n throw new Error(`invalid point data: ${JSON.stringify(input)} `);\n }\n const [x, y] = point;\n // Keep this compatible with OSWorld's Kimi adapter: values <= 1 are\n // normalized coordinates, otherwise they are treated as screenshot pixels.\n const coordinatesMeta =\n x <= 1 && y <= 1\n ? kimiNormalizedPointCoordinatesMeta\n : kimiPixelPointCoordinatesMeta;\n return createLocateResultValue(coordinatesMeta, [x, y]);\n}\n\nconst buildKimiChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const { reasoningEnabled } = userConfig;\n const effectiveReasoningEnabled = reasoningEnabled ?? false;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n // kimi disallow custom temperature\n commonOverrideConfig.temperature = undefined;\n\n const modelSpecificConfig: Record<string, unknown> = {\n thinking: {\n type: effectiveReasoningEnabled ? 'enabled' : 'disabled',\n },\n };\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nexport const kimiAdapters = {\n kimi: {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningEffort', 'reasoningBudget'],\n buildChatCompletionParams: buildKimiChatCompletionParams,\n useReasoningAsContentFallback: true,\n },\n locate: {\n resultAdapter: {\n coordinates: kimiNormalizedPointCoordinatesMeta,\n parseRawLocateValue: parseKimiRawLocateValue,\n },\n },\n },\n} satisfies Pick<Record<TModelFamily, ModelAdapterDefinition>, 'kimi'>;\n"],"names":["kimiNormalizedPointCoordinatesMeta","kimiPixelPointCoordinatesMeta","parseKimiRawLocateValue","input","point","parseCoordinateList","Error","JSON","x","y","coordinatesMeta","createLocateResultValue","buildKimiChatCompletionParams","midsceneDefaults","userConfig","reasoningEnabled","effectiveReasoningEnabled","commonOverrideConfig","undefined","modelSpecificConfig","kimiAdapters"],"mappings":";AAYA,MAAMA,qCAAqC;IACzC,OAAO;IACP,OAAO;IACP,cAAc;AAChB;AACA,MAAMC,gCAAgC;IACpC,OAAO;IACP,OAAO;AACT;AAEA,SAASC,wBAAwBC,KAAc;IAC7C,MAAMC,QAAQC,oBAAoBF,OAAO;IACzC,IAAIC,MAAM,MAAM,GAAG,GACjB,MAAM,IAAIE,MAAM,CAAC,oBAAoB,EAAEC,KAAK,SAAS,CAACJ,OAAO,CAAC,CAAC;IAEjE,MAAM,CAACK,GAAGC,EAAE,GAAGL;IAGf,MAAMM,kBACJF,KAAK,KAAKC,KAAK,IACXT,qCACAC;IACN,OAAOU,wBAAwBD,iBAAiB;QAACF;QAAGC;KAAE;AACxD;AAEA,MAAMG,gCAAgC,CACpCT;IAEA,MAAM,EAAEU,gBAAgB,EAAEC,UAAU,EAAE,GAAGX;IACzC,MAAM,EAAEY,gBAAgB,EAAE,GAAGD;IAC7B,MAAME,4BAA4BD,oBAAoB;IACtD,MAAME,uBAAgD,CAAC;IAGvDA,qBAAqB,WAAW,GAAGC;IAEnC,MAAMC,sBAA+C;QACnD,UAAU;YACR,MAAMH,4BAA4B,YAAY;QAChD;IACF;IAEA,OAAO;QACL,QAAQ;YACN,GAAGH,gBAAgB;YACnB,GAAGI,oBAAoB;YACvB,GAAGE,mBAAmB;QACxB;IACF;AACF;AAEO,MAAMC,eAAe;IAC1B,MAAM;QACJ,gBAAgB;YACd,uBAAuB;gBAAC;gBAAmB;aAAkB;YAC7D,2BAA2BR;YAC3B,+BAA+B;QACjC;QACA,QAAQ;YACN,eAAe;gBACb,aAAaZ;gBACb,qBAAqBE;YACvB;QACF;IACF;AACF"}
1
+ {"version":3,"file":"ai-model/models/kimi.mjs","sources":["../../../../src/ai-model/models/kimi.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\nimport {\n type LocateResultValue,\n createLocateResultValue,\n parseCoordinateList,\n} from '../shared/model-locate-result';\nimport { isLocateIntent } from './utils/intent';\n\nconst kimiNormalizedPointCoordinatesMeta = {\n shape: 'point',\n order: 'xy',\n normalizedBy: 1,\n} as const;\nconst kimiPixelPointCoordinatesMeta = {\n shape: 'point',\n order: 'xy',\n} as const;\n\nfunction parseKimiRawLocateValue(input: unknown): LocateResultValue {\n const point = parseCoordinateList(input, 'point');\n if (point.length < 2) {\n throw new Error(`invalid point data: ${JSON.stringify(input)} `);\n }\n const [x, y] = point;\n // Keep this compatible with OSWorld's Kimi adapter: values <= 1 are\n // normalized coordinates, otherwise they are treated as screenshot pixels.\n const coordinatesMeta =\n x <= 1 && y <= 1\n ? kimiNormalizedPointCoordinatesMeta\n : kimiPixelPointCoordinatesMeta;\n return createLocateResultValue(coordinatesMeta, [x, y]);\n}\n\nconst buildKimiChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const { reasoningEnabled } = userConfig;\n const effectiveReasoningEnabled = reasoningEnabled ?? false;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n // kimi disallow custom temperature\n commonOverrideConfig.temperature = undefined;\n\n // Kimi Chat Completions response_format:\n // https://platform.kimi.com/docs/api/chat\n if (isLocateIntent(input.intent)) {\n commonOverrideConfig.response_format = { type: 'json_object' };\n }\n\n const modelSpecificConfig: Record<string, unknown> = {\n thinking: {\n type: effectiveReasoningEnabled ? 'enabled' : 'disabled',\n },\n };\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nexport const kimiAdapters = {\n kimi: {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningEffort', 'reasoningBudget'],\n buildChatCompletionParams: buildKimiChatCompletionParams,\n useReasoningAsContentFallback: true,\n },\n locate: {\n resultAdapter: {\n coordinates: kimiNormalizedPointCoordinatesMeta,\n parseRawLocateValue: parseKimiRawLocateValue,\n },\n },\n },\n} satisfies Pick<Record<TModelFamily, ModelAdapterDefinition>, 'kimi'>;\n"],"names":["kimiNormalizedPointCoordinatesMeta","kimiPixelPointCoordinatesMeta","parseKimiRawLocateValue","input","point","parseCoordinateList","Error","JSON","x","y","coordinatesMeta","createLocateResultValue","buildKimiChatCompletionParams","midsceneDefaults","userConfig","reasoningEnabled","effectiveReasoningEnabled","commonOverrideConfig","undefined","isLocateIntent","modelSpecificConfig","kimiAdapters"],"mappings":";;AAaA,MAAMA,qCAAqC;IACzC,OAAO;IACP,OAAO;IACP,cAAc;AAChB;AACA,MAAMC,gCAAgC;IACpC,OAAO;IACP,OAAO;AACT;AAEA,SAASC,wBAAwBC,KAAc;IAC7C,MAAMC,QAAQC,oBAAoBF,OAAO;IACzC,IAAIC,MAAM,MAAM,GAAG,GACjB,MAAM,IAAIE,MAAM,CAAC,oBAAoB,EAAEC,KAAK,SAAS,CAACJ,OAAO,CAAC,CAAC;IAEjE,MAAM,CAACK,GAAGC,EAAE,GAAGL;IAGf,MAAMM,kBACJF,KAAK,KAAKC,KAAK,IACXT,qCACAC;IACN,OAAOU,wBAAwBD,iBAAiB;QAACF;QAAGC;KAAE;AACxD;AAEA,MAAMG,gCAAgC,CACpCT;IAEA,MAAM,EAAEU,gBAAgB,EAAEC,UAAU,EAAE,GAAGX;IACzC,MAAM,EAAEY,gBAAgB,EAAE,GAAGD;IAC7B,MAAME,4BAA4BD,oBAAoB;IACtD,MAAME,uBAAgD,CAAC;IAGvDA,qBAAqB,WAAW,GAAGC;IAInC,IAAIC,eAAehB,MAAM,MAAM,GAC7Bc,qBAAqB,eAAe,GAAG;QAAE,MAAM;IAAc;IAG/D,MAAMG,sBAA+C;QACnD,UAAU;YACR,MAAMJ,4BAA4B,YAAY;QAChD;IACF;IAEA,OAAO;QACL,QAAQ;YACN,GAAGH,gBAAgB;YACnB,GAAGI,oBAAoB;YACvB,GAAGG,mBAAmB;QACxB;IACF;AACF;AAEO,MAAMC,eAAe;IAC1B,MAAM;QACJ,gBAAgB;YACd,uBAAuB;gBAAC;gBAAmB;aAAkB;YAC7D,2BAA2BT;YAC3B,+BAA+B;QACjC;QACA,QAAQ;YACN,eAAe;gBACb,aAAaZ;gBACb,qBAAqBE;YACvB;QACF;IACF;AACF"}
@@ -1,9 +1,10 @@
1
+ import { isLocateIntent } from "./utils/intent.mjs";
1
2
  const buildMimoChatCompletionParams = (input)=>{
2
3
  const { intent, midsceneDefaults, userConfig } = input;
3
4
  const { reasoningEnabled } = userConfig;
4
5
  const commonOverrideConfig = {};
5
- commonOverrideConfig.response_format = {
6
- type: 'default' === intent ? 'json_object' : 'text'
6
+ if (isLocateIntent(intent)) commonOverrideConfig.response_format = {
7
+ type: 'json_object'
7
8
  };
8
9
  if (void 0 !== userConfig.temperature) commonOverrideConfig.temperature = userConfig.temperature;
9
10
  const modelSpecificConfig = {
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/models/mimo.mjs","sources":["../../../../src/ai-model/models/mimo.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\n\nconst buildMimoChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { intent, midsceneDefaults, userConfig } = input;\n const { reasoningEnabled } = userConfig;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n // https://platform.xiaomimimo.com/docs/zh-CN/api/chat/openai-api\n // Observed with thinking disabled: Mimo needs json_object to return JSON.\n commonOverrideConfig.response_format = {\n type: intent === 'default' ? 'json_object' : 'text',\n };\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n const modelSpecificConfig: Record<string, unknown> = {\n thinking: {\n type: (reasoningEnabled ?? false) ? 'enabled' : 'disabled',\n },\n };\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nexport const mimoAdapters = {\n 'xiaomi-mimo': {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningEffort', 'reasoningBudget'],\n buildChatCompletionParams: buildMimoChatCompletionParams,\n useReasoningAsContentFallback: true,\n },\n },\n} satisfies Pick<Record<TModelFamily, ModelAdapterDefinition>, 'xiaomi-mimo'>;\n"],"names":["buildMimoChatCompletionParams","input","intent","midsceneDefaults","userConfig","reasoningEnabled","commonOverrideConfig","undefined","modelSpecificConfig","mimoAdapters"],"mappings":"AAOA,MAAMA,gCAAgC,CACpCC;IAEA,MAAM,EAAEC,MAAM,EAAEC,gBAAgB,EAAEC,UAAU,EAAE,GAAGH;IACjD,MAAM,EAAEI,gBAAgB,EAAE,GAAGD;IAC7B,MAAME,uBAAgD,CAAC;IAIvDA,qBAAqB,eAAe,GAAG;QACrC,MAAMJ,AAAW,cAAXA,SAAuB,gBAAgB;IAC/C;IAEA,IAAIE,AAA2BG,WAA3BH,WAAW,WAAW,EACxBE,qBAAqB,WAAW,GAAGF,WAAW,WAAW;IAG3D,MAAMI,sBAA+C;QACnD,UAAU;YACR,MAAOH,oBAAoB,QAAS,YAAY;QAClD;IACF;IAEA,OAAO;QACL,QAAQ;YACN,GAAGF,gBAAgB;YACnB,GAAGG,oBAAoB;YACvB,GAAGE,mBAAmB;QACxB;IACF;AACF;AAEO,MAAMC,eAAe;IAC1B,eAAe;QACb,gBAAgB;YACd,uBAAuB;gBAAC;gBAAmB;aAAkB;YAC7D,2BAA2BT;YAC3B,+BAA+B;QACjC;IACF;AACF"}
1
+ {"version":3,"file":"ai-model/models/mimo.mjs","sources":["../../../../src/ai-model/models/mimo.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\nimport { isLocateIntent } from './utils/intent';\n\nconst buildMimoChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { intent, midsceneDefaults, userConfig } = input;\n const { reasoningEnabled } = userConfig;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n // https://platform.xiaomimimo.com/docs/zh-CN/api/chat/openai-api\n // Observed with thinking disabled: Mimo needs json_object to return JSON.\n if (isLocateIntent(intent)) {\n commonOverrideConfig.response_format = { type: 'json_object' };\n }\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n const modelSpecificConfig: Record<string, unknown> = {\n thinking: {\n type: (reasoningEnabled ?? false) ? 'enabled' : 'disabled',\n },\n };\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nexport const mimoAdapters = {\n 'xiaomi-mimo': {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningEffort', 'reasoningBudget'],\n buildChatCompletionParams: buildMimoChatCompletionParams,\n useReasoningAsContentFallback: true,\n },\n },\n} satisfies Pick<Record<TModelFamily, ModelAdapterDefinition>, 'xiaomi-mimo'>;\n"],"names":["buildMimoChatCompletionParams","input","intent","midsceneDefaults","userConfig","reasoningEnabled","commonOverrideConfig","isLocateIntent","undefined","modelSpecificConfig","mimoAdapters"],"mappings":";AAQA,MAAMA,gCAAgC,CACpCC;IAEA,MAAM,EAAEC,MAAM,EAAEC,gBAAgB,EAAEC,UAAU,EAAE,GAAGH;IACjD,MAAM,EAAEI,gBAAgB,EAAE,GAAGD;IAC7B,MAAME,uBAAgD,CAAC;IAIvD,IAAIC,eAAeL,SACjBI,qBAAqB,eAAe,GAAG;QAAE,MAAM;IAAc;IAG/D,IAAIF,AAA2BI,WAA3BJ,WAAW,WAAW,EACxBE,qBAAqB,WAAW,GAAGF,WAAW,WAAW;IAG3D,MAAMK,sBAA+C;QACnD,UAAU;YACR,MAAOJ,oBAAoB,QAAS,YAAY;QAClD;IACF;IAEA,OAAO;QACL,QAAQ;YACN,GAAGF,gBAAgB;YACnB,GAAGG,oBAAoB;YACvB,GAAGG,mBAAmB;QACxB;IACF;AACF;AAEO,MAAMC,eAAe;IAC1B,eAAe;QACb,gBAAgB;YACd,uBAAuB;gBAAC;gBAAmB;aAAkB;YAC7D,2BAA2BV;YAC3B,+BAA+B;QACjC;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/models/qwen.mjs","sources":["../../../../src/ai-model/models/qwen.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\nimport {\n type LocateResultValue,\n type PixelBbox,\n createLocateResultValue,\n isBboxLocateResultValue,\n unwrapCoordinateListLikeInput,\n} from '../shared/model-locate-result';\n\nconst defaultBboxSize = 20;\nconst qwen25BboxCoordinatesMeta = {\n shape: 'bbox',\n order: 'xy',\n} as const;\nconst qwen25PointCoordinatesMeta = {\n shape: 'point',\n order: 'xy',\n} as const;\nconst qwen3BboxCoordinatesMeta = {\n shape: 'bbox',\n order: 'xy',\n normalizedBy: 1000,\n} as const;\n\nfunction topLeftPointToPixelBbox(x: number, y: number): PixelBbox {\n return [\n Math.round(x),\n Math.round(y),\n Math.round(x + defaultBboxSize),\n Math.round(y + defaultBboxSize),\n ];\n}\n\nfunction parseQwen25RawLocateValue(input: unknown): LocateResultValue {\n const bbox = unwrapCoordinateListLikeInput(input as any) as number[];\n if (bbox.length < 2) {\n const msg = `invalid bbox data for qwen-vl mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n }\n\n if (typeof bbox[2] === 'number' && typeof bbox[3] === 'number') {\n return createLocateResultValue(qwen25BboxCoordinatesMeta, [\n bbox[0],\n bbox[1],\n bbox[2],\n bbox[3],\n ]);\n }\n\n return createLocateResultValue(qwen25PointCoordinatesMeta, [\n bbox[0],\n bbox[1],\n ]);\n}\n\nfunction normalizeQwen25ResultToPixelBbox(\n result: LocateResultValue,\n): PixelBbox {\n if (isBboxLocateResultValue(result)) {\n const { coordinates } = result;\n return [\n Math.round(coordinates[0]),\n Math.round(coordinates[1]),\n Math.round(coordinates[2]),\n Math.round(coordinates[3]),\n ];\n }\n\n const { coordinates } = result;\n return topLeftPointToPixelBbox(coordinates[0], coordinates[1]);\n}\n\nconst buildQwenChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const { reasoningEnabled, reasoningBudget } = userConfig;\n\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n const modelSpecificConfig: Record<string, unknown> = {};\n\n if (reasoningEnabled !== 'default') {\n modelSpecificConfig.enable_thinking = reasoningEnabled ?? false;\n if (reasoningBudget !== undefined) {\n modelSpecificConfig.thinking_budget = reasoningBudget;\n }\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nconst buildQwen25ChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n vl_high_resolution_images: true,\n },\n };\n};\n\nconst qwen3Adapter: ModelAdapterDefinition = {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningEffort'],\n buildChatCompletionParams: buildQwenChatCompletionParams,\n messageExtraction: {\n kind: 'default',\n // DashScope returns Qwen thinking as `reasoning_content`. vLLM's\n // OpenAI-compatible server is migrating the recommended field to\n // `reasoning`, so Qwen adapters accept both serving conventions:\n // https://github.com/vllm-project/vllm/issues/27755\n reasoningContentKeys: ['reasoning_content', 'reasoning'],\n },\n useReasoningAsContentFallback: true,\n },\n locate: {\n resultAdapter: {\n coordinates: qwen3BboxCoordinatesMeta,\n },\n },\n};\n\nexport const qwenAdapters = {\n 'qwen2.5-vl': {\n chatCompletion: {\n unsupportedUserConfig: [\n 'reasoningEnabled',\n 'reasoningEffort',\n 'reasoningBudget',\n ],\n buildChatCompletionParams: buildQwen25ChatCompletionParams,\n },\n imagePreprocess: {\n padBlockSize: 28,\n },\n locate: {\n resultAdapter: {\n coordinates: qwen25BboxCoordinatesMeta,\n parseRawLocateValue: parseQwen25RawLocateValue,\n mapLocateResultToPixelBbox: normalizeQwen25ResultToPixelBbox,\n },\n },\n },\n 'qwen3-vl': qwen3Adapter,\n qwen3: qwen3Adapter,\n 'qwen3.5': qwen3Adapter,\n 'qwen3.6': qwen3Adapter,\n} satisfies Pick<\n Record<TModelFamily, ModelAdapterDefinition>,\n 'qwen2.5-vl' | 'qwen3-vl' | 'qwen3' | 'qwen3.5' | 'qwen3.6'\n>;\n"],"names":["defaultBboxSize","qwen25BboxCoordinatesMeta","qwen25PointCoordinatesMeta","qwen3BboxCoordinatesMeta","topLeftPointToPixelBbox","x","y","Math","parseQwen25RawLocateValue","input","bbox","unwrapCoordinateListLikeInput","msg","JSON","Error","createLocateResultValue","normalizeQwen25ResultToPixelBbox","result","isBboxLocateResultValue","coordinates","buildQwenChatCompletionParams","midsceneDefaults","userConfig","reasoningEnabled","reasoningBudget","commonOverrideConfig","undefined","modelSpecificConfig","buildQwen25ChatCompletionParams","qwen3Adapter","qwenAdapters"],"mappings":"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"}
1
+ {"version":3,"file":"ai-model/models/qwen.mjs","sources":["../../../../src/ai-model/models/qwen.ts"],"sourcesContent":["import type { TModelFamily } from '@midscene/shared/env';\nimport type {\n ChatCompletionCallContext,\n ChatCompletionParamsResult,\n ModelAdapterDefinition,\n} from '../model-adapter/types';\nimport {\n type LocateResultValue,\n type PixelBbox,\n createLocateResultValue,\n isBboxLocateResultValue,\n unwrapCoordinateListLikeInput,\n} from '../shared/model-locate-result';\n\nconst defaultBboxSize = 20;\nconst qwen25BboxCoordinatesMeta = {\n shape: 'bbox',\n order: 'xy',\n} as const;\nconst qwen25PointCoordinatesMeta = {\n shape: 'point',\n order: 'xy',\n} as const;\nconst qwen3BboxCoordinatesMeta = {\n shape: 'bbox',\n order: 'xy',\n normalizedBy: 1000,\n} as const;\n\nfunction topLeftPointToPixelBbox(x: number, y: number): PixelBbox {\n return [\n Math.round(x),\n Math.round(y),\n Math.round(x + defaultBboxSize),\n Math.round(y + defaultBboxSize),\n ];\n}\n\nfunction parseQwen25RawLocateValue(input: unknown): LocateResultValue {\n const bbox = unwrapCoordinateListLikeInput(input as any) as number[];\n if (bbox.length < 2) {\n const msg = `invalid bbox data for qwen-vl mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n }\n\n if (typeof bbox[2] === 'number' && typeof bbox[3] === 'number') {\n return createLocateResultValue(qwen25BboxCoordinatesMeta, [\n bbox[0],\n bbox[1],\n bbox[2],\n bbox[3],\n ]);\n }\n\n return createLocateResultValue(qwen25PointCoordinatesMeta, [\n bbox[0],\n bbox[1],\n ]);\n}\n\nfunction normalizeQwen25ResultToPixelBbox(\n result: LocateResultValue,\n): PixelBbox {\n if (isBboxLocateResultValue(result)) {\n const { coordinates } = result;\n return [\n Math.round(coordinates[0]),\n Math.round(coordinates[1]),\n Math.round(coordinates[2]),\n Math.round(coordinates[3]),\n ];\n }\n\n const { coordinates } = result;\n return topLeftPointToPixelBbox(coordinates[0], coordinates[1]);\n}\n\nconst buildQwenChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const { reasoningEnabled, reasoningBudget } = userConfig;\n\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n // Alibaba Cloud Model Studio JSON mode:\n // https://help.aliyun.com/zh/model-studio/json-mode\n // Observed in qwen3.6 grounding runs: enabling this can make the model\n // return only [\"bbox_2d\"] without coordinates.\n // if (isLocateIntent(input.intent)) {\n // commonOverrideConfig.response_format = { type: 'json_object' };\n // }\n\n const modelSpecificConfig: Record<string, unknown> = {};\n\n if (reasoningEnabled !== 'default') {\n modelSpecificConfig.enable_thinking = reasoningEnabled ?? false;\n if (reasoningBudget !== undefined) {\n modelSpecificConfig.thinking_budget = reasoningBudget;\n }\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n ...modelSpecificConfig,\n },\n };\n};\n\nconst buildQwen25ChatCompletionParams = (\n input: ChatCompletionCallContext,\n): ChatCompletionParamsResult => {\n const { midsceneDefaults, userConfig } = input;\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n vl_high_resolution_images: true,\n },\n };\n};\n\nconst qwen3Adapter: ModelAdapterDefinition = {\n chatCompletion: {\n unsupportedUserConfig: ['reasoningEffort'],\n buildChatCompletionParams: buildQwenChatCompletionParams,\n messageExtraction: {\n kind: 'default',\n // DashScope returns Qwen thinking as `reasoning_content`. vLLM's\n // OpenAI-compatible server is migrating the recommended field to\n // `reasoning`, so Qwen adapters accept both serving conventions:\n // https://github.com/vllm-project/vllm/issues/27755\n reasoningContentKeys: ['reasoning_content', 'reasoning'],\n },\n useReasoningAsContentFallback: true,\n },\n locate: {\n resultAdapter: {\n coordinates: qwen3BboxCoordinatesMeta,\n },\n },\n};\n\nexport const qwenAdapters = {\n 'qwen2.5-vl': {\n chatCompletion: {\n unsupportedUserConfig: [\n 'reasoningEnabled',\n 'reasoningEffort',\n 'reasoningBudget',\n ],\n buildChatCompletionParams: buildQwen25ChatCompletionParams,\n },\n imagePreprocess: {\n padBlockSize: 28,\n },\n locate: {\n resultAdapter: {\n coordinates: qwen25BboxCoordinatesMeta,\n parseRawLocateValue: parseQwen25RawLocateValue,\n mapLocateResultToPixelBbox: normalizeQwen25ResultToPixelBbox,\n },\n },\n },\n 'qwen3-vl': qwen3Adapter,\n qwen3: qwen3Adapter,\n 'qwen3.5': qwen3Adapter,\n 'qwen3.6': qwen3Adapter,\n} satisfies Pick<\n Record<TModelFamily, ModelAdapterDefinition>,\n 'qwen2.5-vl' | 'qwen3-vl' | 'qwen3' | 'qwen3.5' | 'qwen3.6'\n>;\n"],"names":["defaultBboxSize","qwen25BboxCoordinatesMeta","qwen25PointCoordinatesMeta","qwen3BboxCoordinatesMeta","topLeftPointToPixelBbox","x","y","Math","parseQwen25RawLocateValue","input","bbox","unwrapCoordinateListLikeInput","msg","JSON","Error","createLocateResultValue","normalizeQwen25ResultToPixelBbox","result","isBboxLocateResultValue","coordinates","buildQwenChatCompletionParams","midsceneDefaults","userConfig","reasoningEnabled","reasoningBudget","commonOverrideConfig","undefined","modelSpecificConfig","buildQwen25ChatCompletionParams","qwen3Adapter","qwenAdapters"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  import { UITarsModelVersion } from "@midscene/shared/env";
2
2
  import { assert } from "@midscene/shared/utils";
3
- import { jsonrepair } from "jsonrepair";
4
- import { extractJSONFromCodeBlock, safeParseJson } from "../../service-caller/json.mjs";
3
+ import { parseModelResponseJson } from "../../service-caller/json.mjs";
5
4
  import { createLocateResultValue, unwrapCoordinateListLikeInput } from "../../shared/model-locate-result/index.mjs";
6
5
  import { createUiTarsPlanner } from "./planning.mjs";
7
6
  const defaultVlmUiTarsReplanningCycleLimit = 40;
@@ -15,44 +14,6 @@ const uiTarsPointCoordinatesMeta = {
15
14
  order: 'xy',
16
15
  normalizedBy: 1000
17
16
  };
18
- function normalizeJsonObject(obj, context = {}) {
19
- if (null == obj) return obj;
20
- if (Array.isArray(obj)) return obj.map((item)=>normalizeJsonObject(item, context));
21
- if ('object' == typeof obj) {
22
- const normalized = {};
23
- for (const [key, value] of Object.entries(obj)){
24
- const trimmedKey = key.trim();
25
- const preserveStringValue = context.preserveStringValueKeys?.includes(trimmedKey) ?? false;
26
- const normalizedValue = 'string' == typeof value ? preserveStringValue ? value : value.trim() : normalizeJsonObject(value, context);
27
- normalized[trimmedKey] = normalizedValue;
28
- }
29
- return normalized;
30
- }
31
- return 'string' == typeof obj ? obj.trim() : obj;
32
- }
33
- function shouldRepairUiTarsLocateJson(source) {
34
- return 'locate' === source || 'section-locator' === source || 'planning-action-param' === source;
35
- }
36
- function preprocessUiTarsLocateJson(input) {
37
- if (input.includes('bbox')) while(/\d+\s+\d+/.test(input))input = input.replace(/(\d+)\s+(\d+)/g, '$1,$2');
38
- return input;
39
- }
40
- const uiTarsJsonParser = (raw, context = {
41
- source: 'generic-object'
42
- })=>{
43
- const { source } = context;
44
- try {
45
- return safeParseJson(raw, context);
46
- } catch (firstError) {
47
- if (!shouldRepairUiTarsLocateJson(source)) throw firstError;
48
- const jsonString = preprocessUiTarsLocateJson(extractJSONFromCodeBlock(raw));
49
- try {
50
- return normalizeJsonObject(JSON.parse(jsonrepair(jsonString)), context);
51
- } catch (error) {
52
- throw Error(`failed to parse LLM response into JSON. Error - ${String(error ?? firstError ?? 'unknown error')}. Response - \n ${raw}`);
53
- }
54
- }
55
- };
56
17
  function parseUiTarsRawLocateValue(input) {
57
18
  const bbox = unwrapCoordinateListLikeInput(input);
58
19
  if ('string' == typeof bbox) {
@@ -98,7 +59,7 @@ function parseUiTarsRawLocateValue(input) {
98
59
  }
99
60
  function createUiTarsAdapter(uiTarsModelVersion) {
100
61
  return {
101
- jsonParser: uiTarsJsonParser,
62
+ jsonParser: parseModelResponseJson,
102
63
  chatCompletion: {
103
64
  unsupportedUserConfig: [
104
65
  'reasoningEnabled',
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/models/ui-tars/adapter.mjs","sources":["../../../../../src/ai-model/models/ui-tars/adapter.ts"],"sourcesContent":["import { type TModelFamily, UITarsModelVersion } from '@midscene/shared/env';\nimport { assert } from '@midscene/shared/utils';\nimport { jsonrepair } from 'jsonrepair';\nimport type {\n JsonParserContext,\n JsonParserSource,\n ModelAdapterDefinition,\n} from '../../model-adapter/types';\nimport {\n extractJSONFromCodeBlock,\n safeParseJson,\n} from '../../service-caller/json';\nimport {\n type LocateResultValue,\n createLocateResultValue,\n unwrapCoordinateListLikeInput,\n} from '../../shared/model-locate-result';\nimport { createUiTarsPlanner } from './planning';\n\nconst defaultVlmUiTarsReplanningCycleLimit = 40;\nconst uiTarsBboxCoordinatesMeta = {\n shape: 'bbox',\n order: 'xy',\n normalizedBy: 1000,\n} as const;\nconst uiTarsPointCoordinatesMeta = {\n shape: 'point',\n order: 'xy',\n normalizedBy: 1000,\n} as const;\n\nfunction normalizeJsonObject(\n obj: any,\n context: Pick<JsonParserContext, 'preserveStringValueKeys'> = {},\n): any {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map((item) => normalizeJsonObject(item, context));\n }\n\n if (typeof obj === 'object') {\n const normalized: any = {};\n for (const [key, value] of Object.entries(obj)) {\n const trimmedKey = key.trim();\n const preserveStringValue =\n context.preserveStringValueKeys?.includes(trimmedKey) ?? false;\n const normalizedValue =\n typeof value === 'string'\n ? preserveStringValue\n ? value\n : value.trim()\n : normalizeJsonObject(value, context);\n normalized[trimmedKey] = normalizedValue;\n }\n return normalized;\n }\n\n return typeof obj === 'string' ? obj.trim() : obj;\n}\n\nfunction shouldRepairUiTarsLocateJson(source: JsonParserSource) {\n return (\n source === 'locate' ||\n source === 'section-locator' ||\n source === 'planning-action-param'\n );\n}\n\nfunction preprocessUiTarsLocateJson(input: string) {\n if (input.includes('bbox')) {\n while (/\\d+\\s+\\d+/.test(input)) {\n input = input.replace(/(\\d+)\\s+(\\d+)/g, '$1,$2');\n }\n }\n return input;\n}\n\nconst uiTarsJsonParser: ModelAdapterDefinition['jsonParser'] = (\n raw,\n context = { source: 'generic-object' },\n) => {\n const { source } = context;\n try {\n return safeParseJson(raw, context);\n } catch (firstError) {\n if (!shouldRepairUiTarsLocateJson(source)) {\n throw firstError;\n }\n\n const jsonString = preprocessUiTarsLocateJson(\n extractJSONFromCodeBlock(raw),\n );\n try {\n return normalizeJsonObject(JSON.parse(jsonrepair(jsonString)), context);\n } catch (error) {\n throw Error(\n `failed to parse LLM response into JSON. Error - ${String(\n error ?? firstError ?? 'unknown error',\n )}. Response - \\n ${raw}`,\n );\n }\n }\n};\n\n// UI-TARS has not received active updates for a long time, so this parser is\n// intentionally kept separate from Doubao even though the current logic is the\n// same. This avoids coupling UI-TARS behavior to future Doubao adapter changes.\nfunction parseUiTarsRawLocateValue(input: unknown): LocateResultValue {\n const bbox = unwrapCoordinateListLikeInput(input as any);\n if (typeof bbox === 'string') {\n assert(\n /^(\\d+)\\s(\\d+)\\s(\\d+)\\s(\\d+)$/.test(bbox.trim()),\n `invalid bbox data string for ui-tars mode: ${bbox}`,\n );\n const splitted = bbox.split(' ');\n if (splitted.length === 4) {\n return createLocateResultValue(uiTarsBboxCoordinatesMeta, [\n Number(splitted[0]),\n Number(splitted[1]),\n Number(splitted[2]),\n Number(splitted[3]),\n ]);\n }\n throw new Error(`invalid bbox data string for ui-tars mode: ${bbox}`);\n }\n\n let bboxList: number[] = [];\n if (Array.isArray(bbox) && typeof bbox[0] === 'string') {\n bbox.forEach((item) => {\n if (typeof item === 'string' && item.includes(',')) {\n const [x, y] = item.split(',');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else if (typeof item === 'string' && item.includes(' ')) {\n const [x, y] = item.split(' ');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else {\n bboxList.push(Number(item));\n }\n });\n } else {\n bboxList = bbox as number[];\n }\n\n if (bboxList.length === 4 || bboxList.length === 5) {\n return createLocateResultValue(uiTarsBboxCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n bboxList[2],\n bboxList[3],\n ]);\n }\n\n if (\n bboxList.length === 6 ||\n bboxList.length === 2 ||\n bboxList.length === 3 ||\n bboxList.length === 7\n ) {\n return createLocateResultValue(uiTarsPointCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n ]);\n }\n\n if (bbox.length === 8) {\n return createLocateResultValue(uiTarsBboxCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n bboxList[4],\n bboxList[5],\n ]);\n }\n\n const msg = `invalid bbox data for ui-tars mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n}\n\nfunction createUiTarsAdapter(\n uiTarsModelVersion: UITarsModelVersion,\n): ModelAdapterDefinition {\n return {\n jsonParser: uiTarsJsonParser,\n chatCompletion: {\n unsupportedUserConfig: [\n 'reasoningEnabled',\n 'reasoningEffort',\n 'reasoningBudget',\n ],\n buildChatCompletionParams: ({ midsceneDefaults, userConfig }) => {\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n },\n };\n },\n },\n planning: {\n kind: 'custom',\n cacheEnabled: false,\n defaultReplanningCycleLimit: defaultVlmUiTarsReplanningCycleLimit,\n planner: createUiTarsPlanner(uiTarsModelVersion),\n },\n locate: {\n resultAdapter: {\n coordinates: uiTarsBboxCoordinatesMeta,\n parseRawLocateValue: parseUiTarsRawLocateValue,\n },\n },\n };\n}\n\nconst uiTarsDoubao15Adapter = createUiTarsAdapter(\n UITarsModelVersion.DOUBAO_1_5_20B,\n);\n\nexport const uiTarsAdapters = {\n 'vlm-ui-tars': createUiTarsAdapter(UITarsModelVersion.V1_0),\n 'vlm-ui-tars-doubao': uiTarsDoubao15Adapter,\n 'vlm-ui-tars-doubao-1.5': uiTarsDoubao15Adapter,\n} satisfies Pick<\n Record<TModelFamily, ModelAdapterDefinition>,\n 'vlm-ui-tars' | 'vlm-ui-tars-doubao' | 'vlm-ui-tars-doubao-1.5'\n>;\n"],"names":["defaultVlmUiTarsReplanningCycleLimit","uiTarsBboxCoordinatesMeta","uiTarsPointCoordinatesMeta","normalizeJsonObject","obj","context","Array","item","normalized","key","value","Object","trimmedKey","preserveStringValue","normalizedValue","shouldRepairUiTarsLocateJson","source","preprocessUiTarsLocateJson","input","uiTarsJsonParser","raw","safeParseJson","firstError","jsonString","extractJSONFromCodeBlock","JSON","jsonrepair","error","Error","String","parseUiTarsRawLocateValue","bbox","unwrapCoordinateListLikeInput","assert","splitted","createLocateResultValue","Number","bboxList","x","y","msg","createUiTarsAdapter","uiTarsModelVersion","midsceneDefaults","userConfig","commonOverrideConfig","undefined","createUiTarsPlanner","uiTarsDoubao15Adapter","UITarsModelVersion","uiTarsAdapters"],"mappings":";;;;;;AAmBA,MAAMA,uCAAuC;AAC7C,MAAMC,4BAA4B;IAChC,OAAO;IACP,OAAO;IACP,cAAc;AAChB;AACA,MAAMC,6BAA6B;IACjC,OAAO;IACP,OAAO;IACP,cAAc;AAChB;AAEA,SAASC,oBACPC,GAAQ,EACRC,UAA8D,CAAC,CAAC;IAEhE,IAAID,QAAAA,KACF,OAAOA;IAGT,IAAIE,MAAM,OAAO,CAACF,MAChB,OAAOA,IAAI,GAAG,CAAC,CAACG,OAASJ,oBAAoBI,MAAMF;IAGrD,IAAI,AAAe,YAAf,OAAOD,KAAkB;QAC3B,MAAMI,aAAkB,CAAC;QACzB,KAAK,MAAM,CAACC,KAAKC,MAAM,IAAIC,OAAO,OAAO,CAACP,KAAM;YAC9C,MAAMQ,aAAaH,IAAI,IAAI;YAC3B,MAAMI,sBACJR,QAAQ,uBAAuB,EAAE,SAASO,eAAe;YAC3D,MAAME,kBACJ,AAAiB,YAAjB,OAAOJ,QACHG,sBACEH,QACAA,MAAM,IAAI,KACZP,oBAAoBO,OAAOL;YACjCG,UAAU,CAACI,WAAW,GAAGE;QAC3B;QACA,OAAON;IACT;IAEA,OAAO,AAAe,YAAf,OAAOJ,MAAmBA,IAAI,IAAI,KAAKA;AAChD;AAEA,SAASW,6BAA6BC,MAAwB;IAC5D,OACEA,AAAW,aAAXA,UACAA,AAAW,sBAAXA,UACAA,AAAW,4BAAXA;AAEJ;AAEA,SAASC,2BAA2BC,KAAa;IAC/C,IAAIA,MAAM,QAAQ,CAAC,SACjB,MAAO,YAAY,IAAI,CAACA,OACtBA,QAAQA,MAAM,OAAO,CAAC,kBAAkB;IAG5C,OAAOA;AACT;AAEA,MAAMC,mBAAyD,CAC7DC,KACAf,UAAU;IAAE,QAAQ;AAAiB,CAAC;IAEtC,MAAM,EAAEW,MAAM,EAAE,GAAGX;IACnB,IAAI;QACF,OAAOgB,cAAcD,KAAKf;IAC5B,EAAE,OAAOiB,YAAY;QACnB,IAAI,CAACP,6BAA6BC,SAChC,MAAMM;QAGR,MAAMC,aAAaN,2BACjBO,yBAAyBJ;QAE3B,IAAI;YACF,OAAOjB,oBAAoBsB,KAAK,KAAK,CAACC,WAAWH,cAAclB;QACjE,EAAE,OAAOsB,OAAO;YACd,MAAMC,MACJ,CAAC,gDAAgD,EAAEC,OACjDF,SAASL,cAAc,iBACvB,gBAAgB,EAAEF,KAAK;QAE7B;IACF;AACF;AAKA,SAASU,0BAA0BZ,KAAc;IAC/C,MAAMa,OAAOC,8BAA8Bd;IAC3C,IAAI,AAAgB,YAAhB,OAAOa,MAAmB;QAC5BE,OACE,+BAA+B,IAAI,CAACF,KAAK,IAAI,KAC7C,CAAC,2CAA2C,EAAEA,MAAM;QAEtD,MAAMG,WAAWH,KAAK,KAAK,CAAC;QAC5B,IAAIG,AAAoB,MAApBA,SAAS,MAAM,EACjB,OAAOC,wBAAwBlC,2BAA2B;YACxDmC,OAAOF,QAAQ,CAAC,EAAE;YAClBE,OAAOF,QAAQ,CAAC,EAAE;YAClBE,OAAOF,QAAQ,CAAC,EAAE;YAClBE,OAAOF,QAAQ,CAAC,EAAE;SACnB;QAEH,MAAM,IAAIN,MAAM,CAAC,2CAA2C,EAAEG,MAAM;IACtE;IAEA,IAAIM,WAAqB,EAAE;IAC3B,IAAI/B,MAAM,OAAO,CAACyB,SAAS,AAAmB,YAAnB,OAAOA,IAAI,CAAC,EAAE,EACvCA,KAAK,OAAO,CAAC,CAACxB;QACZ,IAAI,AAAgB,YAAhB,OAAOA,QAAqBA,KAAK,QAAQ,CAAC,MAAM;YAClD,MAAM,CAAC+B,GAAGC,EAAE,GAAGhC,KAAK,KAAK,CAAC;YAC1B8B,SAAS,IAAI,CAACD,OAAOE,EAAE,IAAI,KAAKF,OAAOG,EAAE,IAAI;QAC/C,OAAO,IAAI,AAAgB,YAAhB,OAAOhC,QAAqBA,KAAK,QAAQ,CAAC,MAAM;YACzD,MAAM,CAAC+B,GAAGC,EAAE,GAAGhC,KAAK,KAAK,CAAC;YAC1B8B,SAAS,IAAI,CAACD,OAAOE,EAAE,IAAI,KAAKF,OAAOG,EAAE,IAAI;QAC/C,OACEF,SAAS,IAAI,CAACD,OAAO7B;IAEzB;SAEA8B,WAAWN;IAGb,IAAIM,AAAoB,MAApBA,SAAS,MAAM,IAAUA,AAAoB,MAApBA,SAAS,MAAM,EAC1C,OAAOF,wBAAwBlC,2BAA2B;QACxDoC,QAAQ,CAAC,EAAE;QACXA,QAAQ,CAAC,EAAE;QACXA,QAAQ,CAAC,EAAE;QACXA,QAAQ,CAAC,EAAE;KACZ;IAGH,IACEA,AAAoB,MAApBA,SAAS,MAAM,IACfA,AAAoB,MAApBA,SAAS,MAAM,IACfA,AAAoB,MAApBA,SAAS,MAAM,IACfA,AAAoB,MAApBA,SAAS,MAAM,EAEf,OAAOF,wBAAwBjC,4BAA4B;QACzDmC,QAAQ,CAAC,EAAE;QACXA,QAAQ,CAAC,EAAE;KACZ;IAGH,IAAIN,AAAgB,MAAhBA,KAAK,MAAM,EACb,OAAOI,wBAAwBlC,2BAA2B;QACxDoC,QAAQ,CAAC,EAAE;QACXA,QAAQ,CAAC,EAAE;QACXA,QAAQ,CAAC,EAAE;QACXA,QAAQ,CAAC,EAAE;KACZ;IAGH,MAAMG,MAAM,CAAC,oCAAoC,EAAEf,KAAK,SAAS,CAACM,MAAM,CAAC,CAAC;IAC1E,MAAM,IAAIH,MAAMY;AAClB;AAEA,SAASC,oBACPC,kBAAsC;IAEtC,OAAO;QACL,YAAYvB;QACZ,gBAAgB;YACd,uBAAuB;gBACrB;gBACA;gBACA;aACD;YACD,2BAA2B,CAAC,EAAEwB,gBAAgB,EAAEC,UAAU,EAAE;gBAC1D,MAAMC,uBAAgD,CAAC;gBAEvD,IAAID,AAA2BE,WAA3BF,WAAW,WAAW,EACxBC,qBAAqB,WAAW,GAAGD,WAAW,WAAW;gBAG3D,OAAO;oBACL,QAAQ;wBACN,GAAGD,gBAAgB;wBACnB,GAAGE,oBAAoB;oBACzB;gBACF;YACF;QACF;QACA,UAAU;YACR,MAAM;YACN,cAAc;YACd,6BAA6B7C;YAC7B,SAAS+C,oBAAoBL;QAC/B;QACA,QAAQ;YACN,eAAe;gBACb,aAAazC;gBACb,qBAAqB6B;YACvB;QACF;IACF;AACF;AAEA,MAAMkB,wBAAwBP,oBAC5BQ,mBAAmB,cAAc;AAG5B,MAAMC,iBAAiB;IAC5B,eAAeT,oBAAoBQ,mBAAmB,IAAI;IAC1D,sBAAsBD;IACtB,0BAA0BA;AAC5B"}
1
+ {"version":3,"file":"ai-model/models/ui-tars/adapter.mjs","sources":["../../../../../src/ai-model/models/ui-tars/adapter.ts"],"sourcesContent":["import { type TModelFamily, UITarsModelVersion } from '@midscene/shared/env';\nimport { assert } from '@midscene/shared/utils';\nimport type { ModelAdapterDefinition } from '../../model-adapter/types';\nimport { parseModelResponseJson } from '../../service-caller/json';\nimport {\n type LocateResultValue,\n createLocateResultValue,\n unwrapCoordinateListLikeInput,\n} from '../../shared/model-locate-result';\nimport { createUiTarsPlanner } from './planning';\n\nconst defaultVlmUiTarsReplanningCycleLimit = 40;\nconst uiTarsBboxCoordinatesMeta = {\n shape: 'bbox',\n order: 'xy',\n normalizedBy: 1000,\n} as const;\nconst uiTarsPointCoordinatesMeta = {\n shape: 'point',\n order: 'xy',\n normalizedBy: 1000,\n} as const;\n\n// UI-TARS has not received active updates for a long time, so this parser is\n// intentionally kept separate from Doubao even though the current logic is the\n// same. This avoids coupling UI-TARS behavior to future Doubao adapter changes.\nfunction parseUiTarsRawLocateValue(input: unknown): LocateResultValue {\n const bbox = unwrapCoordinateListLikeInput(input as any);\n if (typeof bbox === 'string') {\n assert(\n /^(\\d+)\\s(\\d+)\\s(\\d+)\\s(\\d+)$/.test(bbox.trim()),\n `invalid bbox data string for ui-tars mode: ${bbox}`,\n );\n const splitted = bbox.split(' ');\n if (splitted.length === 4) {\n return createLocateResultValue(uiTarsBboxCoordinatesMeta, [\n Number(splitted[0]),\n Number(splitted[1]),\n Number(splitted[2]),\n Number(splitted[3]),\n ]);\n }\n throw new Error(`invalid bbox data string for ui-tars mode: ${bbox}`);\n }\n\n let bboxList: number[] = [];\n if (Array.isArray(bbox) && typeof bbox[0] === 'string') {\n bbox.forEach((item) => {\n if (typeof item === 'string' && item.includes(',')) {\n const [x, y] = item.split(',');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else if (typeof item === 'string' && item.includes(' ')) {\n const [x, y] = item.split(' ');\n bboxList.push(Number(x.trim()), Number(y.trim()));\n } else {\n bboxList.push(Number(item));\n }\n });\n } else {\n bboxList = bbox as number[];\n }\n\n if (bboxList.length === 4 || bboxList.length === 5) {\n return createLocateResultValue(uiTarsBboxCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n bboxList[2],\n bboxList[3],\n ]);\n }\n\n if (\n bboxList.length === 6 ||\n bboxList.length === 2 ||\n bboxList.length === 3 ||\n bboxList.length === 7\n ) {\n return createLocateResultValue(uiTarsPointCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n ]);\n }\n\n if (bbox.length === 8) {\n return createLocateResultValue(uiTarsBboxCoordinatesMeta, [\n bboxList[0],\n bboxList[1],\n bboxList[4],\n bboxList[5],\n ]);\n }\n\n const msg = `invalid bbox data for ui-tars mode: ${JSON.stringify(bbox)} `;\n throw new Error(msg);\n}\n\nfunction createUiTarsAdapter(\n uiTarsModelVersion: UITarsModelVersion,\n): ModelAdapterDefinition {\n return {\n jsonParser: parseModelResponseJson,\n chatCompletion: {\n unsupportedUserConfig: [\n 'reasoningEnabled',\n 'reasoningEffort',\n 'reasoningBudget',\n ],\n buildChatCompletionParams: ({ midsceneDefaults, userConfig }) => {\n const commonOverrideConfig: Record<string, unknown> = {};\n\n if (userConfig.temperature !== undefined) {\n commonOverrideConfig.temperature = userConfig.temperature;\n }\n\n return {\n config: {\n ...midsceneDefaults,\n ...commonOverrideConfig,\n },\n };\n },\n },\n planning: {\n kind: 'custom',\n cacheEnabled: false,\n defaultReplanningCycleLimit: defaultVlmUiTarsReplanningCycleLimit,\n planner: createUiTarsPlanner(uiTarsModelVersion),\n },\n locate: {\n resultAdapter: {\n coordinates: uiTarsBboxCoordinatesMeta,\n parseRawLocateValue: parseUiTarsRawLocateValue,\n },\n },\n };\n}\n\nconst uiTarsDoubao15Adapter = createUiTarsAdapter(\n UITarsModelVersion.DOUBAO_1_5_20B,\n);\n\nexport const uiTarsAdapters = {\n 'vlm-ui-tars': createUiTarsAdapter(UITarsModelVersion.V1_0),\n 'vlm-ui-tars-doubao': uiTarsDoubao15Adapter,\n 'vlm-ui-tars-doubao-1.5': uiTarsDoubao15Adapter,\n} satisfies Pick<\n Record<TModelFamily, ModelAdapterDefinition>,\n 'vlm-ui-tars' | 'vlm-ui-tars-doubao' | 'vlm-ui-tars-doubao-1.5'\n>;\n"],"names":["defaultVlmUiTarsReplanningCycleLimit","uiTarsBboxCoordinatesMeta","uiTarsPointCoordinatesMeta","parseUiTarsRawLocateValue","input","bbox","unwrapCoordinateListLikeInput","assert","splitted","createLocateResultValue","Number","Error","bboxList","Array","item","x","y","msg","JSON","createUiTarsAdapter","uiTarsModelVersion","parseModelResponseJson","midsceneDefaults","userConfig","commonOverrideConfig","undefined","createUiTarsPlanner","uiTarsDoubao15Adapter","UITarsModelVersion","uiTarsAdapters"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ function isLocateIntent(intent) {
2
+ return 'default' === intent;
3
+ }
4
+ export { isLocateIntent };
5
+
6
+ //# sourceMappingURL=intent.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-model/models/utils/intent.mjs","sources":["../../../../../src/ai-model/models/utils/intent.ts"],"sourcesContent":["import type { TIntent } from '@midscene/shared/env';\n\nexport function isLocateIntent(intent?: TIntent): boolean {\n return intent === 'default';\n}\n"],"names":["isLocateIntent","intent"],"mappings":"AAEO,SAASA,eAAeC,MAAgB;IAC7C,OAAOA,AAAW,cAAXA;AACT"}