@midscene/core 1.12.4-beta-20260904041024.0 → 1.12.4

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 (65) hide show
  1. package/dist/es/agent/agent.mjs +72 -25
  2. package/dist/es/agent/agent.mjs.map +1 -1
  3. package/dist/es/agent/index.mjs +2 -1
  4. package/dist/es/agent/insight.mjs +26 -10
  5. package/dist/es/agent/insight.mjs.map +1 -1
  6. package/dist/es/agent/prompt-context.mjs +12 -7
  7. package/dist/es/agent/prompt-context.mjs.map +1 -1
  8. package/dist/es/agent/run-gherkin-scenario.mjs +1 -1
  9. package/dist/es/agent/run-gherkin-scenario.mjs.map +1 -1
  10. package/dist/es/agent/tasks.mjs +2 -1
  11. package/dist/es/agent/tasks.mjs.map +1 -1
  12. package/dist/es/agent/test-runner-nodes.mjs +274 -0
  13. package/dist/es/agent/test-runner-nodes.mjs.map +1 -0
  14. package/dist/es/agent/utils.mjs +1 -1
  15. package/dist/es/ai-model/prompt/insight/user-prompt.mjs +1 -1
  16. package/dist/es/ai-model/prompt/insight/user-prompt.mjs.map +1 -1
  17. package/dist/es/ai-model/workflows/insight/extraction.mjs +3 -1
  18. package/dist/es/ai-model/workflows/insight/extraction.mjs.map +1 -1
  19. package/dist/es/ai-model/workflows/planning/custom-planning.mjs +3 -3
  20. package/dist/es/ai-model/workflows/planning/custom-planning.mjs.map +1 -1
  21. package/dist/es/ai-model/workflows/planning/standard-planning.mjs +1 -1
  22. package/dist/es/ai-model/workflows/planning/standard-planning.mjs.map +1 -1
  23. package/dist/es/report-html-template.mjs +1 -1
  24. package/dist/es/types.mjs.map +1 -1
  25. package/dist/es/utils.mjs +1 -1
  26. package/dist/es/yaml/player.mjs +0 -5
  27. package/dist/es/yaml/player.mjs.map +1 -1
  28. package/dist/es/yaml.mjs.map +1 -1
  29. package/dist/lib/agent/agent.js +72 -25
  30. package/dist/lib/agent/agent.js.map +1 -1
  31. package/dist/lib/agent/index.js +57 -8
  32. package/dist/lib/agent/insight.js +26 -10
  33. package/dist/lib/agent/insight.js.map +1 -1
  34. package/dist/lib/agent/prompt-context.js +16 -8
  35. package/dist/lib/agent/prompt-context.js.map +1 -1
  36. package/dist/lib/agent/run-gherkin-scenario.js +1 -1
  37. package/dist/lib/agent/run-gherkin-scenario.js.map +1 -1
  38. package/dist/lib/agent/tasks.js +2 -1
  39. package/dist/lib/agent/tasks.js.map +1 -1
  40. package/dist/lib/agent/test-runner-nodes.js +353 -0
  41. package/dist/lib/agent/test-runner-nodes.js.map +1 -0
  42. package/dist/lib/agent/utils.js +1 -1
  43. package/dist/lib/ai-model/prompt/insight/user-prompt.js +1 -1
  44. package/dist/lib/ai-model/prompt/insight/user-prompt.js.map +1 -1
  45. package/dist/lib/ai-model/workflows/insight/extraction.js +3 -1
  46. package/dist/lib/ai-model/workflows/insight/extraction.js.map +1 -1
  47. package/dist/lib/ai-model/workflows/planning/custom-planning.js +3 -3
  48. package/dist/lib/ai-model/workflows/planning/custom-planning.js.map +1 -1
  49. package/dist/lib/ai-model/workflows/planning/standard-planning.js +1 -1
  50. package/dist/lib/ai-model/workflows/planning/standard-planning.js.map +1 -1
  51. package/dist/lib/report-html-template.js +1 -1
  52. package/dist/lib/types.js.map +1 -1
  53. package/dist/lib/utils.js +1 -1
  54. package/dist/lib/yaml/player.js +0 -5
  55. package/dist/lib/yaml/player.js.map +1 -1
  56. package/dist/lib/yaml.js.map +1 -1
  57. package/dist/types/agent/agent.d.ts +26 -3
  58. package/dist/types/agent/index.d.ts +3 -1
  59. package/dist/types/agent/insight.d.ts +5 -1
  60. package/dist/types/agent/prompt-context.d.ts +2 -0
  61. package/dist/types/agent/run-gherkin-scenario.d.ts +1 -0
  62. package/dist/types/agent/test-runner-nodes.d.ts +192 -0
  63. package/dist/types/types.d.ts +28 -0
  64. package/dist/types/yaml.d.ts +12 -4
  65. package/package.json +10 -2
@@ -0,0 +1,274 @@
1
+ import { z } from "zod/v4";
2
+ const createAgentTestRunnerNodeDefinition = (agentLabel = 'an Agent')=>(definition)=>({
3
+ name: definition.name ?? definition.method,
4
+ ...void 0 === definition.title ? {} : {
5
+ title: definition.title
6
+ },
7
+ ...void 0 === definition.description ? {} : {
8
+ description: definition.description
9
+ },
10
+ ...void 0 === definition.stringInputKey ? {} : {
11
+ stringInputKey: definition.stringInputKey
12
+ },
13
+ inputSchema: definition.inputSchema,
14
+ async execute (agent, input, context) {
15
+ if ('object' != typeof agent || null === agent || 'function' != typeof agent[definition.method]) throw new TypeError(`getAgent() must return ${agentLabel} with ${definition.method}().`);
16
+ const typedAgent = agent;
17
+ const method = typedAgent[definition.method];
18
+ const typedInput = input;
19
+ const result = await method.apply(typedAgent, definition.toArgs(typedInput, context));
20
+ return definition.toResult?.(result, typedInput);
21
+ }
22
+ });
23
+ const nonBlankText = (description)=>z.string().regex(/\S/, 'value must contain a non-whitespace character').describe(description);
24
+ const promptImageInputSchema = z.strictObject({
25
+ name: nonBlankText('The name used to identify this reference image.'),
26
+ url: nonBlankText('The URL, data URL, or file path of this reference image.')
27
+ });
28
+ const structuredUserPromptInputSchema = z.strictObject({
29
+ prompt: nonBlankText('The natural-language prompt.'),
30
+ images: z.array(promptImageInputSchema).min(1).optional(),
31
+ convertHttpImage2Base64: z.boolean().optional().describe('Whether HTTP reference images are converted to base64 first.')
32
+ });
33
+ const userPromptInputSchema = z.union([
34
+ nonBlankText('The natural-language prompt.'),
35
+ structuredUserPromptInputSchema
36
+ ]);
37
+ const aiActOptionsInputSchema = z.strictObject({
38
+ cacheable: z.boolean().optional().describe('Whether this action may use the Midscene cache.'),
39
+ fileChooserAccept: z.union([
40
+ z.string(),
41
+ z.array(z.string())
42
+ ]).optional().describe('Accepted file types for a file chooser.'),
43
+ fileChooserAllowedDir: z.string().optional().describe('Directory allowed for prompt-driven file uploads.'),
44
+ deepThink: z.union([
45
+ z.literal('unset'),
46
+ z.boolean()
47
+ ]).optional().describe('Whether to enable deep thinking for this action.'),
48
+ deepLocate: z.boolean().optional().describe('Whether to use deep element location.'),
49
+ context: z.string().optional().describe('Additional facts, rules, constraints, or output requirements for this AI call. Overrides inherited aiContexts; an empty string disables inherited user context.')
50
+ });
51
+ const aiActInputSchema = z.strictObject({
52
+ prompt: userPromptInputSchema,
53
+ options: aiActOptionsInputSchema.optional()
54
+ });
55
+ const insightOptionsInputSchema = z.strictObject({
56
+ domIncluded: z.union([
57
+ z.boolean(),
58
+ z.literal('visible-only')
59
+ ]).optional().describe('How DOM information is included.'),
60
+ screenshotIncluded: z.boolean().optional().describe('Whether the request includes a screenshot.'),
61
+ context: z.string().optional().describe('Additional facts, rules, constraints, or output requirements for this AI call. Overrides inherited aiContexts; an empty string disables inherited user context.')
62
+ });
63
+ const aiAssertOptionsInputSchema = insightOptionsInputSchema.extend({
64
+ keepRawResponse: z.boolean().optional().describe('Whether the Agent returns the structured assertion result.')
65
+ });
66
+ const aiAssertInputSchema = z.strictObject({
67
+ prompt: userPromptInputSchema,
68
+ message: z.string().optional().describe('The assertion failure message.'),
69
+ options: aiAssertOptionsInputSchema.optional()
70
+ });
71
+ const locateOptionsInputSchema = z.strictObject({
72
+ context: z.string().optional().describe('Additional facts, rules, constraints, or output requirements for this AI call. Overrides inherited aiContexts; an empty string disables inherited user context.'),
73
+ deepLocate: z.boolean().optional().describe('Whether to use deep element location.'),
74
+ deepThink: z.boolean().optional().describe('Deprecated alias for deepLocate.'),
75
+ cacheable: z.boolean().optional().describe('Whether this location may use the Midscene cache.'),
76
+ xpath: z.string().optional().describe('A web XPath location hint.'),
77
+ fileChooserAccept: z.union([
78
+ z.string(),
79
+ z.array(z.string())
80
+ ]).optional().describe('Files accepted when tapping opens a file chooser.')
81
+ });
82
+ const aiTapInputSchema = z.strictObject({
83
+ prompt: userPromptInputSchema,
84
+ options: locateOptionsInputSchema.optional()
85
+ });
86
+ const insightInputSchema = z.strictObject({
87
+ prompt: userPromptInputSchema,
88
+ options: insightOptionsInputSchema.optional()
89
+ });
90
+ const reportScreenshotInputSchema = z.strictObject({
91
+ base64: z.string().min(1).describe('A base64-encoded screenshot.'),
92
+ description: z.string().optional().describe('What the screenshot shows.')
93
+ });
94
+ const recordToReportOptionsInputSchema = z.strictObject({
95
+ content: z.string().optional().describe('The report text content.'),
96
+ screenshotBase64: z.string().optional().describe('One base64-encoded screenshot.'),
97
+ screenshots: z.array(reportScreenshotInputSchema).min(1).optional().describe('Screenshots attached to the report section.')
98
+ }).superRefine((input, context)=>{
99
+ if (void 0 !== input.screenshotBase64 && void 0 !== input.screenshots) context.addIssue({
100
+ code: 'custom',
101
+ message: 'screenshotBase64 and screenshots are mutually exclusive'
102
+ });
103
+ });
104
+ const recordToReportInputSchema = z.strictObject({
105
+ title: z.string().optional().describe('The report section title.'),
106
+ options: recordToReportOptionsInputSchema.optional()
107
+ });
108
+ const defineCommonAgentNode = createAgentTestRunnerNodeDefinition('an Agent');
109
+ const promptText = (prompt)=>'string' == typeof prompt ? prompt : prompt.prompt;
110
+ const aiActNode = defineCommonAgentNode({
111
+ method: 'aiAct',
112
+ description: 'Perform a natural-language task with a Midscene UI Agent.',
113
+ stringInputKey: 'prompt',
114
+ inputSchema: aiActInputSchema,
115
+ toArgs (input, context) {
116
+ return [
117
+ input.prompt,
118
+ {
119
+ ...input.options,
120
+ abortSignal: context.signal
121
+ }
122
+ ];
123
+ },
124
+ toResult (output) {
125
+ return void 0 === output ? void 0 : {
126
+ summary: output
127
+ };
128
+ }
129
+ });
130
+ const aiTapNode = defineCommonAgentNode({
131
+ method: 'aiTap',
132
+ description: 'Locate and tap an element with a Midscene UI Agent.',
133
+ stringInputKey: 'prompt',
134
+ inputSchema: aiTapInputSchema,
135
+ toArgs (input) {
136
+ return [
137
+ input.prompt,
138
+ input.options
139
+ ];
140
+ },
141
+ toResult (_output, input) {
142
+ return {
143
+ summary: `Tapped: ${promptText(input.prompt)}`
144
+ };
145
+ }
146
+ });
147
+ const aiAssertNode = defineCommonAgentNode({
148
+ method: 'aiAssert',
149
+ description: 'Assert a natural-language condition with a Midscene UI Agent.',
150
+ stringInputKey: 'prompt',
151
+ inputSchema: aiAssertInputSchema,
152
+ toArgs (input, context) {
153
+ return [
154
+ input.prompt,
155
+ input.message,
156
+ {
157
+ ...input.options,
158
+ abortSignal: context.signal
159
+ }
160
+ ];
161
+ },
162
+ toResult (output, input) {
163
+ return {
164
+ summary: `Assertion passed: ${promptText(input.prompt)}`,
165
+ ...void 0 === output ? {} : {
166
+ data: {
167
+ pass: output.pass,
168
+ ...void 0 === output.thought ? {} : {
169
+ thought: output.thought
170
+ },
171
+ ...void 0 === output.message ? {} : {
172
+ message: output.message
173
+ }
174
+ }
175
+ }
176
+ };
177
+ }
178
+ });
179
+ const insightNode = (method)=>{
180
+ if ('aiBoolean' === method) return defineCommonAgentNode({
181
+ method,
182
+ description: `Run ${method} with a Midscene UI Agent and store its value.`,
183
+ stringInputKey: 'prompt',
184
+ inputSchema: insightInputSchema,
185
+ toArgs: (input)=>[
186
+ input.prompt,
187
+ input.options
188
+ ],
189
+ toResult: (value)=>({
190
+ summary: `${method} returned ${value}`,
191
+ data: {
192
+ value
193
+ }
194
+ })
195
+ });
196
+ if ('aiNumber' === method) return defineCommonAgentNode({
197
+ method,
198
+ description: `Run ${method} with a Midscene UI Agent and store its value.`,
199
+ stringInputKey: 'prompt',
200
+ inputSchema: insightInputSchema,
201
+ toArgs: (input)=>[
202
+ input.prompt,
203
+ input.options
204
+ ],
205
+ toResult: (value)=>({
206
+ summary: `${method} returned ${value}`,
207
+ data: {
208
+ value
209
+ }
210
+ })
211
+ });
212
+ if ('aiString' === method) return defineCommonAgentNode({
213
+ method,
214
+ description: `Run ${method} with a Midscene UI Agent and store its value.`,
215
+ stringInputKey: 'prompt',
216
+ inputSchema: insightInputSchema,
217
+ toArgs: (input)=>[
218
+ input.prompt,
219
+ input.options
220
+ ],
221
+ toResult: (value)=>({
222
+ summary: `${method} returned ${JSON.stringify(value)}`,
223
+ data: {
224
+ value
225
+ }
226
+ })
227
+ });
228
+ return defineCommonAgentNode({
229
+ method,
230
+ description: `Run ${method} with a Midscene UI Agent and store its value.`,
231
+ stringInputKey: 'prompt',
232
+ inputSchema: insightInputSchema,
233
+ toArgs: (input)=>[
234
+ input.prompt,
235
+ input.options
236
+ ],
237
+ toResult: (value)=>({
238
+ summary: `${method} returned ${JSON.stringify(value)}`,
239
+ data: {
240
+ value
241
+ }
242
+ })
243
+ });
244
+ };
245
+ const recordToReportNode = defineCommonAgentNode({
246
+ method: 'recordToReport',
247
+ description: 'Add text or screenshots to the current Midscene report.',
248
+ stringInputKey: 'title',
249
+ inputSchema: recordToReportInputSchema,
250
+ toArgs (input) {
251
+ return [
252
+ input.title,
253
+ input.options
254
+ ];
255
+ },
256
+ toResult (_output, input) {
257
+ return {
258
+ summary: `Recorded to report: ${input.title ?? 'untitled'}`
259
+ };
260
+ }
261
+ });
262
+ const commonAgentTestRunnerNodeDefinitions = [
263
+ aiActNode,
264
+ aiTapNode,
265
+ aiAssertNode,
266
+ insightNode('aiBoolean'),
267
+ insightNode('aiNumber'),
268
+ insightNode('aiString'),
269
+ insightNode('aiAsk'),
270
+ recordToReportNode
271
+ ];
272
+ export { aiActInputSchema, aiActOptionsInputSchema, aiAssertInputSchema, aiAssertOptionsInputSchema, aiTapInputSchema, commonAgentTestRunnerNodeDefinitions, createAgentTestRunnerNodeDefinition, insightInputSchema, insightOptionsInputSchema, locateOptionsInputSchema, promptImageInputSchema, recordToReportInputSchema, recordToReportOptionsInputSchema, reportScreenshotInputSchema, structuredUserPromptInputSchema, userPromptInputSchema };
273
+
274
+ //# sourceMappingURL=test-runner-nodes.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent/test-runner-nodes.mjs","sources":["../../../src/agent/test-runner-nodes.ts"],"sourcesContent":["import { z } from 'zod/v4';\nimport type { Agent } from './agent';\n\nexport interface AgentTestRunnerNodeResult<TData = unknown> {\n summary?: string;\n data?: TData;\n}\n\nexport interface AgentTestRunnerNodeExecutionContext {\n signal: AbortSignal;\n}\n\n/** Agent-owned Node description consumed by Test Runner adapters. */\nexport interface AgentTestRunnerNodeDefinition<\n TInput extends Record<string, unknown> = Record<string, unknown>,\n TData = unknown,\n> {\n name: string;\n title?: string;\n description?: string;\n /** Node input field populated by YAML string shorthand; omit to disable. */\n stringInputKey?: string | false;\n inputSchema: z.ZodObject;\n execute(\n agent: unknown,\n input: TInput,\n context: AgentTestRunnerNodeExecutionContext,\n ):\n | Promise<AgentTestRunnerNodeResult<TData> | undefined>\n | AgentTestRunnerNodeResult<TData>\n | undefined;\n}\n\n/** Static capability implemented by Agent classes that expose Runner Nodes. */\nexport interface AgentTestRunnerNodeProvider {\n getTestRunnerNodeDefinitions(): readonly AgentTestRunnerNodeDefinition[];\n}\n\ntype AnyAgentMethod = (...args: any[]) => unknown;\ntype AgentMethodName<TAgent extends object> = {\n [TKey in keyof TAgent]-?: TAgent[TKey] extends AnyAgentMethod ? TKey : never;\n}[keyof TAgent] &\n string;\ntype AgentMethod<\n TAgent extends object,\n TMethod extends AgentMethodName<TAgent>,\n> = Extract<TAgent[TMethod], AnyAgentMethod>;\n\nexport interface DefineAgentTestRunnerNodeOptions<\n TAgent extends object,\n TMethod extends AgentMethodName<TAgent>,\n TSchema extends z.ZodObject,\n TData = unknown,\n> {\n method: TMethod;\n name?: string;\n title?: string;\n description?: string;\n stringInputKey?: (keyof z.output<TSchema> & string) | false;\n inputSchema: TSchema;\n toArgs(\n input: z.output<TSchema>,\n context: AgentTestRunnerNodeExecutionContext,\n ): Parameters<AgentMethod<TAgent, TMethod>>;\n toResult?(\n result: Awaited<ReturnType<AgentMethod<TAgent, TMethod>>>,\n input: z.output<TSchema>,\n ): AgentTestRunnerNodeResult<TData> | undefined;\n}\n\n/** Create a Node factory whose adapters are checked against an Agent API. */\nexport const createAgentTestRunnerNodeDefinition =\n <TAgent extends object>(agentLabel = 'an Agent') =>\n <\n TMethod extends AgentMethodName<TAgent>,\n TSchema extends z.ZodObject,\n TData = unknown,\n >(\n definition: DefineAgentTestRunnerNodeOptions<\n TAgent,\n TMethod,\n TSchema,\n TData\n >,\n ): AgentTestRunnerNodeDefinition => ({\n name: definition.name ?? definition.method,\n ...(definition.title === undefined ? {} : { title: definition.title }),\n ...(definition.description === undefined\n ? {}\n : { description: definition.description }),\n ...(definition.stringInputKey === undefined\n ? {}\n : { stringInputKey: definition.stringInputKey }),\n inputSchema: definition.inputSchema,\n async execute(agent, input, context) {\n if (\n typeof agent !== 'object' ||\n agent === null ||\n typeof (agent as Record<string, unknown>)[definition.method] !==\n 'function'\n ) {\n throw new TypeError(\n `getAgent() must return ${agentLabel} with ${definition.method}().`,\n );\n }\n\n const typedAgent = agent as TAgent;\n const method = typedAgent[definition.method] as AgentMethod<\n TAgent,\n TMethod\n >;\n const typedInput = input as z.output<TSchema>;\n const result = (await method.apply(\n typedAgent,\n definition.toArgs(typedInput, context),\n )) as Awaited<ReturnType<AgentMethod<TAgent, TMethod>>>;\n return definition.toResult?.(result, typedInput);\n },\n });\n\nconst nonBlankText = (description: string) =>\n z\n .string()\n .regex(/\\S/, 'value must contain a non-whitespace character')\n .describe(description);\n\nexport const promptImageInputSchema = z.strictObject({\n name: nonBlankText('The name used to identify this reference image.'),\n url: nonBlankText('The URL, data URL, or file path of this reference image.'),\n});\n\nexport const structuredUserPromptInputSchema = z.strictObject({\n prompt: nonBlankText('The natural-language prompt.'),\n images: z.array(promptImageInputSchema).min(1).optional(),\n convertHttpImage2Base64: z\n .boolean()\n .optional()\n .describe('Whether HTTP reference images are converted to base64 first.'),\n});\n\nexport const userPromptInputSchema = z.union([\n nonBlankText('The natural-language prompt.'),\n structuredUserPromptInputSchema,\n]);\n\nexport const aiActOptionsInputSchema = z.strictObject({\n cacheable: z\n .boolean()\n .optional()\n .describe('Whether this action may use the Midscene cache.'),\n fileChooserAccept: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('Accepted file types for a file chooser.'),\n fileChooserAllowedDir: z\n .string()\n .optional()\n .describe('Directory allowed for prompt-driven file uploads.'),\n deepThink: z\n .union([z.literal('unset'), z.boolean()])\n .optional()\n .describe('Whether to enable deep thinking for this action.'),\n deepLocate: z\n .boolean()\n .optional()\n .describe('Whether to use deep element location.'),\n context: z\n .string()\n .optional()\n .describe(\n 'Additional facts, rules, constraints, or output requirements for this AI call. Overrides inherited aiContexts; an empty string disables inherited user context.',\n ),\n});\n\nexport const aiActInputSchema = z.strictObject({\n prompt: userPromptInputSchema,\n options: aiActOptionsInputSchema.optional(),\n});\n\nexport const insightOptionsInputSchema = z.strictObject({\n domIncluded: z\n .union([z.boolean(), z.literal('visible-only')])\n .optional()\n .describe('How DOM information is included.'),\n screenshotIncluded: z\n .boolean()\n .optional()\n .describe('Whether the request includes a screenshot.'),\n context: z\n .string()\n .optional()\n .describe(\n 'Additional facts, rules, constraints, or output requirements for this AI call. Overrides inherited aiContexts; an empty string disables inherited user context.',\n ),\n});\n\nexport const aiAssertOptionsInputSchema = insightOptionsInputSchema.extend({\n keepRawResponse: z\n .boolean()\n .optional()\n .describe('Whether the Agent returns the structured assertion result.'),\n});\n\nexport const aiAssertInputSchema = z.strictObject({\n prompt: userPromptInputSchema,\n message: z.string().optional().describe('The assertion failure message.'),\n options: aiAssertOptionsInputSchema.optional(),\n});\n\nexport const locateOptionsInputSchema = z.strictObject({\n context: z\n .string()\n .optional()\n .describe(\n 'Additional facts, rules, constraints, or output requirements for this AI call. Overrides inherited aiContexts; an empty string disables inherited user context.',\n ),\n deepLocate: z\n .boolean()\n .optional()\n .describe('Whether to use deep element location.'),\n deepThink: z\n .boolean()\n .optional()\n .describe('Deprecated alias for deepLocate.'),\n cacheable: z\n .boolean()\n .optional()\n .describe('Whether this location may use the Midscene cache.'),\n xpath: z.string().optional().describe('A web XPath location hint.'),\n fileChooserAccept: z\n .union([z.string(), z.array(z.string())])\n .optional()\n .describe('Files accepted when tapping opens a file chooser.'),\n});\n\nexport const aiTapInputSchema = z.strictObject({\n prompt: userPromptInputSchema,\n options: locateOptionsInputSchema.optional(),\n});\n\nexport const insightInputSchema = z.strictObject({\n prompt: userPromptInputSchema,\n options: insightOptionsInputSchema.optional(),\n});\n\nexport const reportScreenshotInputSchema = z.strictObject({\n base64: z.string().min(1).describe('A base64-encoded screenshot.'),\n description: z.string().optional().describe('What the screenshot shows.'),\n});\n\nexport const recordToReportOptionsInputSchema = z\n .strictObject({\n content: z.string().optional().describe('The report text content.'),\n screenshotBase64: z\n .string()\n .optional()\n .describe('One base64-encoded screenshot.'),\n screenshots: z\n .array(reportScreenshotInputSchema)\n .min(1)\n .optional()\n .describe('Screenshots attached to the report section.'),\n })\n .superRefine((input, context) => {\n if (\n input.screenshotBase64 !== undefined &&\n input.screenshots !== undefined\n ) {\n context.addIssue({\n code: 'custom',\n message: 'screenshotBase64 and screenshots are mutually exclusive',\n });\n }\n });\n\nexport const recordToReportInputSchema = z.strictObject({\n title: z.string().optional().describe('The report section title.'),\n options: recordToReportOptionsInputSchema.optional(),\n});\n\nexport type UserPromptNodeInput = z.infer<typeof userPromptInputSchema>;\nexport type AiActNodeOptions = z.infer<typeof aiActOptionsInputSchema>;\nexport type AiActNodeInput = z.infer<typeof aiActInputSchema>;\nexport type AiAssertNodeOptions = z.infer<typeof aiAssertOptionsInputSchema>;\nexport type AiAssertNodeInput = z.infer<typeof aiAssertInputSchema>;\nexport type AiTapNodeOptions = z.infer<typeof locateOptionsInputSchema>;\nexport type AiTapNodeInput = z.infer<typeof aiTapInputSchema>;\nexport type InsightNodeOptions = z.infer<typeof insightOptionsInputSchema>;\nexport type InsightNodeInput = z.infer<typeof insightInputSchema>;\nexport type RecordToReportNodeOptions = z.infer<\n typeof recordToReportOptionsInputSchema\n>;\nexport type RecordToReportNodeInput = z.infer<typeof recordToReportInputSchema>;\n\nexport type CommonAgentTestRunnerApi = Pick<\n Agent,\n | 'aiAct'\n | 'aiTap'\n | 'aiAssert'\n | 'aiBoolean'\n | 'aiNumber'\n | 'aiString'\n | 'aiAsk'\n | 'recordToReport'\n>;\n\nconst defineCommonAgentNode =\n createAgentTestRunnerNodeDefinition<CommonAgentTestRunnerApi>('an Agent');\n\nconst promptText = (prompt: UserPromptNodeInput): string =>\n typeof prompt === 'string' ? prompt : prompt.prompt;\n\nconst aiActNode = defineCommonAgentNode({\n method: 'aiAct',\n description: 'Perform a natural-language task with a Midscene UI Agent.',\n stringInputKey: 'prompt',\n inputSchema: aiActInputSchema,\n toArgs(input, context) {\n return [\n input.prompt,\n {\n ...input.options,\n abortSignal: context.signal,\n },\n ];\n },\n toResult(output) {\n return output === undefined ? undefined : { summary: output };\n },\n});\n\nconst aiTapNode = defineCommonAgentNode({\n method: 'aiTap',\n description: 'Locate and tap an element with a Midscene UI Agent.',\n stringInputKey: 'prompt',\n inputSchema: aiTapInputSchema,\n toArgs(input) {\n return [input.prompt, input.options];\n },\n toResult(_output, input) {\n return { summary: `Tapped: ${promptText(input.prompt)}` };\n },\n});\n\nconst aiAssertNode = defineCommonAgentNode({\n method: 'aiAssert',\n description: 'Assert a natural-language condition with a Midscene UI Agent.',\n stringInputKey: 'prompt',\n inputSchema: aiAssertInputSchema,\n toArgs(input, context) {\n return [\n input.prompt,\n input.message,\n {\n ...input.options,\n abortSignal: context.signal,\n },\n ];\n },\n toResult(output, input) {\n return {\n summary: `Assertion passed: ${promptText(input.prompt)}`,\n ...(output === undefined\n ? {}\n : {\n data: {\n pass: output.pass,\n ...(output.thought === undefined\n ? {}\n : { thought: output.thought }),\n ...(output.message === undefined\n ? {}\n : { message: output.message }),\n },\n }),\n };\n },\n});\n\nconst insightNode = (\n method: 'aiBoolean' | 'aiNumber' | 'aiString' | 'aiAsk',\n) => {\n if (method === 'aiBoolean') {\n return defineCommonAgentNode({\n method,\n description: `Run ${method} with a Midscene UI Agent and store its value.`,\n stringInputKey: 'prompt',\n inputSchema: insightInputSchema,\n toArgs: (input) => [input.prompt, input.options],\n toResult: (value) => ({\n summary: `${method} returned ${value}`,\n data: { value },\n }),\n });\n }\n if (method === 'aiNumber') {\n return defineCommonAgentNode({\n method,\n description: `Run ${method} with a Midscene UI Agent and store its value.`,\n stringInputKey: 'prompt',\n inputSchema: insightInputSchema,\n toArgs: (input) => [input.prompt, input.options],\n toResult: (value) => ({\n summary: `${method} returned ${value}`,\n data: { value },\n }),\n });\n }\n if (method === 'aiString') {\n return defineCommonAgentNode({\n method,\n description: `Run ${method} with a Midscene UI Agent and store its value.`,\n stringInputKey: 'prompt',\n inputSchema: insightInputSchema,\n toArgs: (input) => [input.prompt, input.options],\n toResult: (value) => ({\n summary: `${method} returned ${JSON.stringify(value)}`,\n data: { value },\n }),\n });\n }\n return defineCommonAgentNode({\n method,\n description: `Run ${method} with a Midscene UI Agent and store its value.`,\n stringInputKey: 'prompt',\n inputSchema: insightInputSchema,\n toArgs: (input) => [input.prompt, input.options],\n toResult: (value) => ({\n summary: `${method} returned ${JSON.stringify(value)}`,\n data: { value },\n }),\n });\n};\n\nconst recordToReportNode = defineCommonAgentNode({\n method: 'recordToReport',\n description: 'Add text or screenshots to the current Midscene report.',\n stringInputKey: 'title',\n inputSchema: recordToReportInputSchema,\n toArgs(input) {\n return [input.title, input.options];\n },\n toResult(_output, input) {\n return { summary: `Recorded to report: ${input.title ?? 'untitled'}` };\n },\n});\n\nexport const commonAgentTestRunnerNodeDefinitions: readonly AgentTestRunnerNodeDefinition[] =\n [\n aiActNode,\n aiTapNode,\n aiAssertNode,\n insightNode('aiBoolean'),\n insightNode('aiNumber'),\n insightNode('aiString'),\n insightNode('aiAsk'),\n recordToReportNode,\n ];\n"],"names":["createAgentTestRunnerNodeDefinition","agentLabel","definition","undefined","agent","input","context","TypeError","typedAgent","method","typedInput","result","nonBlankText","description","z","promptImageInputSchema","structuredUserPromptInputSchema","userPromptInputSchema","aiActOptionsInputSchema","aiActInputSchema","insightOptionsInputSchema","aiAssertOptionsInputSchema","aiAssertInputSchema","locateOptionsInputSchema","aiTapInputSchema","insightInputSchema","reportScreenshotInputSchema","recordToReportOptionsInputSchema","recordToReportInputSchema","defineCommonAgentNode","promptText","prompt","aiActNode","output","aiTapNode","_output","aiAssertNode","insightNode","value","JSON","recordToReportNode","commonAgentTestRunnerNodeDefinitions"],"mappings":"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"}
@@ -154,7 +154,7 @@ async function matchElementFromCache(context, cacheEntry, cachePrompt, cacheable
154
154
  return;
155
155
  }
156
156
  }
157
- const getMidsceneVersion = ()=>"1.12.4-beta-20260904041024.0";
157
+ const getMidsceneVersion = ()=>"1.12.4";
158
158
  const parsePrompt = (prompt)=>{
159
159
  if ('string' == typeof prompt) return {
160
160
  textPrompt: prompt,
@@ -7,7 +7,7 @@ function buildTypeQueryDemandValue(type, demand) {
7
7
  const extractDataQueryPrompt = (pageDescription, dataQuery, context)=>{
8
8
  const dataQueryText = 'string' == typeof dataQuery ? dataQuery : JSON.stringify(dataQuery, null, 2);
9
9
  const trimmedContext = context?.trim();
10
- const contextSection = trimmedContext ? `\n<CONTEXT>\n${trimmedContext}\n</CONTEXT>\n` : '';
10
+ const contextSection = trimmedContext ? `\n${trimmedContext}\n` : '';
11
11
  return `
12
12
  <PageDescription>
13
13
  ${pageDescription}
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/prompt/insight/user-prompt.mjs","sources":["../../../../../src/ai-model/prompt/insight/user-prompt.ts"],"sourcesContent":["import type { ServiceExtractParam } from '@/types';\n\nexport function buildTypeQueryDemandValue(\n type: 'Boolean' | 'Number' | 'String' | 'Assert' | 'WaitFor',\n demand: ServiceExtractParam,\n) {\n const currentScreenshotConstraint =\n 'based on the current screenshot and its contents if provided, unless the user explicitly asks to compare with reference images';\n\n if (type === 'Assert') {\n return `Boolean, ${currentScreenshotConstraint}, whether the following statement is true: ${demand}`;\n }\n\n if (type === 'WaitFor') {\n return `Boolean, the user wants to do some 'wait for' operation. ${currentScreenshotConstraint}, please check whether the following statement is true: ${demand}`;\n }\n\n return `${type}, ${currentScreenshotConstraint}, ${demand}`;\n}\n\nexport const extractDataQueryPrompt = (\n pageDescription: string,\n dataQuery: string | Record<string, string>,\n context?: string,\n) => {\n const dataQueryText =\n typeof dataQuery === 'string'\n ? dataQuery\n : JSON.stringify(dataQuery, null, 2);\n\n const trimmedContext = context?.trim();\n const contextSection = trimmedContext\n ? `\\n<CONTEXT>\\n${trimmedContext}\\n</CONTEXT>\\n`\n : '';\n\n return `\n<PageDescription>\n${pageDescription}\n</PageDescription>\n${contextSection}\n<DATA_DEMAND>\n${dataQueryText}\n</DATA_DEMAND>\n `;\n};\n"],"names":["buildTypeQueryDemandValue","type","demand","currentScreenshotConstraint","extractDataQueryPrompt","pageDescription","dataQuery","context","dataQueryText","JSON","trimmedContext","contextSection"],"mappings":"AAEO,SAASA,0BACdC,IAA4D,EAC5DC,MAA2B;IAE3B,MAAMC,8BACJ;IAEF,IAAIF,AAAS,aAATA,MACF,OAAO,CAAC,SAAS,EAAEE,4BAA4B,2CAA2C,EAAED,QAAQ;IAGtG,IAAID,AAAS,cAATA,MACF,OAAO,CAAC,yDAAyD,EAAEE,4BAA4B,wDAAwD,EAAED,QAAQ;IAGnK,OAAO,GAAGD,KAAK,EAAE,EAAEE,4BAA4B,EAAE,EAAED,QAAQ;AAC7D;AAEO,MAAME,yBAAyB,CACpCC,iBACAC,WACAC;IAEA,MAAMC,gBACJ,AAAqB,YAArB,OAAOF,YACHA,YACAG,KAAK,SAAS,CAACH,WAAW,MAAM;IAEtC,MAAMI,iBAAiBH,SAAS;IAChC,MAAMI,iBAAiBD,iBACnB,CAAC,aAAa,EAAEA,eAAe,cAAc,CAAC,GAC9C;IAEJ,OAAO,CAAC;;AAEV,EAAEL,gBAAgB;;AAElB,EAAEM,eAAe;;AAEjB,EAAEH,cAAc;;EAEd,CAAC;AACH"}
1
+ {"version":3,"file":"ai-model/prompt/insight/user-prompt.mjs","sources":["../../../../../src/ai-model/prompt/insight/user-prompt.ts"],"sourcesContent":["import type { ServiceExtractParam } from '@/types';\n\nexport function buildTypeQueryDemandValue(\n type: 'Boolean' | 'Number' | 'String' | 'Assert' | 'WaitFor',\n demand: ServiceExtractParam,\n) {\n const currentScreenshotConstraint =\n 'based on the current screenshot and its contents if provided, unless the user explicitly asks to compare with reference images';\n\n if (type === 'Assert') {\n return `Boolean, ${currentScreenshotConstraint}, whether the following statement is true: ${demand}`;\n }\n\n if (type === 'WaitFor') {\n return `Boolean, the user wants to do some 'wait for' operation. ${currentScreenshotConstraint}, please check whether the following statement is true: ${demand}`;\n }\n\n return `${type}, ${currentScreenshotConstraint}, ${demand}`;\n}\n\nexport const extractDataQueryPrompt = (\n pageDescription: string,\n dataQuery: string | Record<string, string>,\n context?: string,\n) => {\n const dataQueryText =\n typeof dataQuery === 'string'\n ? dataQuery\n : JSON.stringify(dataQuery, null, 2);\n\n const trimmedContext = context?.trim();\n const contextSection = trimmedContext ? `\\n${trimmedContext}\\n` : '';\n\n return `\n<PageDescription>\n${pageDescription}\n</PageDescription>\n${contextSection}\n<DATA_DEMAND>\n${dataQueryText}\n</DATA_DEMAND>\n `;\n};\n"],"names":["buildTypeQueryDemandValue","type","demand","currentScreenshotConstraint","extractDataQueryPrompt","pageDescription","dataQuery","context","dataQueryText","JSON","trimmedContext","contextSection"],"mappings":"AAEO,SAASA,0BACdC,IAA4D,EAC5DC,MAA2B;IAE3B,MAAMC,8BACJ;IAEF,IAAIF,AAAS,aAATA,MACF,OAAO,CAAC,SAAS,EAAEE,4BAA4B,2CAA2C,EAAED,QAAQ;IAGtG,IAAID,AAAS,cAATA,MACF,OAAO,CAAC,yDAAyD,EAAEE,4BAA4B,wDAAwD,EAAED,QAAQ;IAGnK,OAAO,GAAGD,KAAK,EAAE,EAAEE,4BAA4B,EAAE,EAAED,QAAQ;AAC7D;AAEO,MAAME,yBAAyB,CACpCC,iBACAC,WACAC;IAEA,MAAMC,gBACJ,AAAqB,YAArB,OAAOF,YACHA,YACAG,KAAK,SAAS,CAACH,WAAW,MAAM;IAEtC,MAAMI,iBAAiBH,SAAS;IAChC,MAAMI,iBAAiBD,iBAAiB,CAAC,EAAE,EAAEA,eAAe,EAAE,CAAC,GAAG;IAElE,OAAO,CAAC;;AAEV,EAAEL,gBAAgB;;AAElB,EAAEM,eAAe;;AAEjB,EAAEH,cAAc;;EAEd,CAAC;AACH"}
@@ -1,4 +1,5 @@
1
1
  import { getDebug } from "@midscene/shared/logger";
2
+ import { renderAIContext } from "../../../agent/prompt-context.mjs";
2
3
  import { buildInsightSystemPrompt, extractDataQueryPrompt } from "../../prompt/insight/index.mjs";
3
4
  import { AIResponseParseError, callAI } from "../../service-caller/index.mjs";
4
5
  import { callAiAndParseWithRetry, withSemanticRetryFeedback } from "../../service-caller/semantic-retry.mjs";
@@ -14,7 +15,8 @@ async function AiExtractElementInfo(options) {
14
15
  insightProtocol
15
16
  });
16
17
  const screenshotBase64 = context.screenshot.base64;
17
- const extractDataPromptText = extractDataQueryPrompt(options.pageDescription || '', dataQuery, extractOption?.context);
18
+ const renderedContext = renderAIContext(extractOption?.context);
19
+ const extractDataPromptText = extractDataQueryPrompt(options.pageDescription || '', dataQuery, renderedContext);
18
20
  const userContent = [];
19
21
  if (extractOption?.screenshotIncluded !== false) {
20
22
  const screenshotSequence = context.screenshotSequence;
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/workflows/insight/extraction.mjs","sources":["../../../../../src/ai-model/workflows/insight/extraction.ts"],"sourcesContent":["import type { ServiceExtractOption, UIContext } from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport type {\n ChatCompletionSystemMessageParam,\n ChatCompletionUserMessageParam,\n} from 'openai/resources/index';\nimport type { TMultimodalPrompt } from '../../../common';\nimport type { ModelRuntime } from '../../models';\nimport {\n buildInsightSystemPrompt,\n extractDataQueryPrompt,\n} from '../../prompt/insight';\nimport { AIResponseParseError, callAI } from '../../service-caller/index';\nimport {\n callAiAndParseWithRetry,\n withSemanticRetryFeedback,\n} from '../../service-caller/semantic-retry';\nimport { multimodalPromptToChatMessages } from '../../shared/multimodal-prompt';\nimport { parseInsightResponse } from './insight-response-parser';\n\ntype InsightAIArgs = [\n ChatCompletionSystemMessageParam,\n ...ChatCompletionUserMessageParam[],\n];\n\nconst debugInsight = getDebug('ai:insight');\n\nexport async function AiExtractElementInfo<T>(options: {\n dataQuery: string | Record<string, string>;\n multimodalPrompt?: TMultimodalPrompt;\n context: UIContext;\n pageDescription?: string;\n extractOption?: ServiceExtractOption;\n modelRuntime: ModelRuntime;\n abortSignal?: AbortSignal;\n}) {\n const { dataQuery, context, extractOption, multimodalPrompt, modelRuntime } =\n options;\n const insightProtocol = modelRuntime.adapter.insight.protocol;\n const systemPrompt = buildInsightSystemPrompt({\n screenshotIncluded: extractOption?.screenshotIncluded !== false,\n referenceImagesIncluded: !!multimodalPrompt?.images?.length,\n insightProtocol,\n });\n const screenshotBase64 = context.screenshot.base64;\n const extractDataPromptText = extractDataQueryPrompt(\n options.pageDescription || '',\n dataQuery,\n extractOption?.context,\n );\n\n const userContent: ChatCompletionUserMessageParam['content'] = [];\n\n if (extractOption?.screenshotIncluded !== false) {\n const screenshotSequence = context.screenshotSequence;\n if (screenshotSequence && screenshotSequence.length > 1) {\n userContent.push({\n type: 'text',\n text: `The following ${screenshotSequence.length} images are consecutive screenshots captured over a time window, ordered from earliest to latest (Frame 1 is first, Frame ${screenshotSequence.length} is last). They record what appeared on screen during that window. Some UI elements such as toasts, banners, or transitions may appear only in certain frames and be gone by later ones. Interpret the temporal scope from the statement or question itself: if it asks whether something appeared at any point, inspect the whole sequence; if it asks about the final or current state, use the relevant later frame; if it asks about a change or sequence, compare frames in order. Unless <DATA_DEMAND> explicitly asks for comparison or matching against reference images, base your answer on these screenshots and their contents.`,\n });\n\n screenshotSequence.forEach((frame, index) => {\n userContent.push({\n type: 'text',\n text: `Frame ${index + 1}/${screenshotSequence.length}`,\n });\n userContent.push({\n type: 'image_url',\n image_url: {\n url: frame.base64,\n detail: 'high',\n },\n });\n });\n } else {\n userContent.push({\n type: 'text',\n text: 'This is the current screenshot to evaluate. Unless <DATA_DEMAND> explicitly asks for comparison or matching against reference images, base your answer on this screenshot and its contents when provided.',\n });\n\n userContent.push({\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high',\n },\n });\n }\n }\n\n userContent.push({\n type: 'text',\n text: extractDataPromptText,\n });\n\n const msgs: InsightAIArgs = [\n { role: 'system', content: systemPrompt },\n {\n role: 'user',\n content: userContent,\n },\n ];\n\n if (multimodalPrompt) {\n const addOns = await multimodalPromptToChatMessages(multimodalPrompt);\n msgs.push(...addOns);\n }\n\n return callAiAndParseWithRetry({\n callAi: (retryAttempt, previousParseError) =>\n callAI(\n withSemanticRetryFeedback(msgs, previousParseError),\n modelRuntime,\n {\n abortSignal: options.abortSignal,\n semanticRetryAttempt: retryAttempt,\n },\n ),\n parseResponse: (response) => {\n const {\n content: rawResponse,\n usage,\n reasoning_content,\n rawChoiceMessage,\n } = response;\n const parseResult = parseInsightResponse<T>(\n rawResponse,\n insightProtocol.dataOutput,\n modelRuntime.adapter.jsonParser,\n );\n return {\n parseResult,\n rawResponse,\n rawChoiceMessage,\n usage,\n reasoning_content,\n };\n },\n toParseError: (parseError, response) => {\n const errorMessage =\n parseError instanceof Error ? parseError.message : String(parseError);\n return new AIResponseParseError(\n `XML parse error: ${errorMessage}`,\n response.content,\n response.usage,\n response.rawChoiceMessage,\n );\n },\n parseRetryTimes: modelRuntime.config.retryCount,\n parseRetryInterval: modelRuntime.config.retryInterval,\n abortSignal: options.abortSignal,\n onParseRetry: (error) => {\n debugInsight(\n 'retrying insight after XML parsing failed: %s',\n error instanceof Error ? error.message : String(error),\n );\n },\n });\n}\n"],"names":["debugInsight","getDebug","AiExtractElementInfo","options","dataQuery","context","extractOption","multimodalPrompt","modelRuntime","insightProtocol","systemPrompt","buildInsightSystemPrompt","screenshotBase64","extractDataPromptText","extractDataQueryPrompt","userContent","screenshotSequence","frame","index","msgs","addOns","multimodalPromptToChatMessages","callAiAndParseWithRetry","retryAttempt","previousParseError","callAI","withSemanticRetryFeedback","response","rawResponse","usage","reasoning_content","rawChoiceMessage","parseResult","parseInsightResponse","parseError","errorMessage","Error","String","AIResponseParseError","error"],"mappings":";;;;;;AAyBA,MAAMA,eAAeC,SAAS;AAEvB,eAAeC,qBAAwBC,OAQ7C;IACC,MAAM,EAAEC,SAAS,EAAEC,OAAO,EAAEC,aAAa,EAAEC,gBAAgB,EAAEC,YAAY,EAAE,GACzEL;IACF,MAAMM,kBAAkBD,aAAa,OAAO,CAAC,OAAO,CAAC,QAAQ;IAC7D,MAAME,eAAeC,yBAAyB;QAC5C,oBAAoBL,eAAe,uBAAuB;QAC1D,yBAAyB,CAAC,CAACC,kBAAkB,QAAQ;QACrDE;IACF;IACA,MAAMG,mBAAmBP,QAAQ,UAAU,CAAC,MAAM;IAClD,MAAMQ,wBAAwBC,uBAC5BX,QAAQ,eAAe,IAAI,IAC3BC,WACAE,eAAe;IAGjB,MAAMS,cAAyD,EAAE;IAEjE,IAAIT,eAAe,uBAAuB,OAAO;QAC/C,MAAMU,qBAAqBX,QAAQ,kBAAkB;QACrD,IAAIW,sBAAsBA,mBAAmB,MAAM,GAAG,GAAG;YACvDD,YAAY,IAAI,CAAC;gBACf,MAAM;gBACN,MAAM,CAAC,cAAc,EAAEC,mBAAmB,MAAM,CAAC,0HAA0H,EAAEA,mBAAmB,MAAM,CAAC,2mBAA2mB,CAAC;YACrzB;YAEAA,mBAAmB,OAAO,CAAC,CAACC,OAAOC;gBACjCH,YAAY,IAAI,CAAC;oBACf,MAAM;oBACN,MAAM,CAAC,MAAM,EAAEG,QAAQ,EAAE,CAAC,EAAEF,mBAAmB,MAAM,EAAE;gBACzD;gBACAD,YAAY,IAAI,CAAC;oBACf,MAAM;oBACN,WAAW;wBACT,KAAKE,MAAM,MAAM;wBACjB,QAAQ;oBACV;gBACF;YACF;QACF,OAAO;YACLF,YAAY,IAAI,CAAC;gBACf,MAAM;gBACN,MAAM;YACR;YAEAA,YAAY,IAAI,CAAC;gBACf,MAAM;gBACN,WAAW;oBACT,KAAKH;oBACL,QAAQ;gBACV;YACF;QACF;IACF;IAEAG,YAAY,IAAI,CAAC;QACf,MAAM;QACN,MAAMF;IACR;IAEA,MAAMM,OAAsB;QAC1B;YAAE,MAAM;YAAU,SAAST;QAAa;QACxC;YACE,MAAM;YACN,SAASK;QACX;KACD;IAED,IAAIR,kBAAkB;QACpB,MAAMa,SAAS,MAAMC,+BAA+Bd;QACpDY,KAAK,IAAI,IAAIC;IACf;IAEA,OAAOE,wBAAwB;QAC7B,QAAQ,CAACC,cAAcC,qBACrBC,OACEC,0BAA0BP,MAAMK,qBAChChB,cACA;gBACE,aAAaL,QAAQ,WAAW;gBAChC,sBAAsBoB;YACxB;QAEJ,eAAe,CAACI;YACd,MAAM,EACJ,SAASC,WAAW,EACpBC,KAAK,EACLC,iBAAiB,EACjBC,gBAAgB,EACjB,GAAGJ;YACJ,MAAMK,cAAcC,qBAClBL,aACAnB,gBAAgB,UAAU,EAC1BD,aAAa,OAAO,CAAC,UAAU;YAEjC,OAAO;gBACLwB;gBACAJ;gBACAG;gBACAF;gBACAC;YACF;QACF;QACA,cAAc,CAACI,YAAYP;YACzB,MAAMQ,eACJD,sBAAsBE,QAAQF,WAAW,OAAO,GAAGG,OAAOH;YAC5D,OAAO,IAAII,qBACT,CAAC,iBAAiB,EAAEH,cAAc,EAClCR,SAAS,OAAO,EAChBA,SAAS,KAAK,EACdA,SAAS,gBAAgB;QAE7B;QACA,iBAAiBnB,aAAa,MAAM,CAAC,UAAU;QAC/C,oBAAoBA,aAAa,MAAM,CAAC,aAAa;QACrD,aAAaL,QAAQ,WAAW;QAChC,cAAc,CAACoC;YACbvC,aACE,iDACAuC,iBAAiBH,QAAQG,MAAM,OAAO,GAAGF,OAAOE;QAEpD;IACF;AACF"}
1
+ {"version":3,"file":"ai-model/workflows/insight/extraction.mjs","sources":["../../../../../src/ai-model/workflows/insight/extraction.ts"],"sourcesContent":["import type { ServiceExtractOption, UIContext } from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport type {\n ChatCompletionSystemMessageParam,\n ChatCompletionUserMessageParam,\n} from 'openai/resources/index';\nimport { renderAIContext } from '../../../agent/prompt-context';\nimport type { TMultimodalPrompt } from '../../../common';\nimport type { ModelRuntime } from '../../models';\nimport {\n buildInsightSystemPrompt,\n extractDataQueryPrompt,\n} from '../../prompt/insight';\nimport { AIResponseParseError, callAI } from '../../service-caller/index';\nimport {\n callAiAndParseWithRetry,\n withSemanticRetryFeedback,\n} from '../../service-caller/semantic-retry';\nimport { multimodalPromptToChatMessages } from '../../shared/multimodal-prompt';\nimport { parseInsightResponse } from './insight-response-parser';\n\ntype InsightAIArgs = [\n ChatCompletionSystemMessageParam,\n ...ChatCompletionUserMessageParam[],\n];\n\nconst debugInsight = getDebug('ai:insight');\n\nexport async function AiExtractElementInfo<T>(options: {\n dataQuery: string | Record<string, string>;\n multimodalPrompt?: TMultimodalPrompt;\n context: UIContext;\n pageDescription?: string;\n extractOption?: ServiceExtractOption;\n modelRuntime: ModelRuntime;\n abortSignal?: AbortSignal;\n}) {\n const { dataQuery, context, extractOption, multimodalPrompt, modelRuntime } =\n options;\n const insightProtocol = modelRuntime.adapter.insight.protocol;\n const systemPrompt = buildInsightSystemPrompt({\n screenshotIncluded: extractOption?.screenshotIncluded !== false,\n referenceImagesIncluded: !!multimodalPrompt?.images?.length,\n insightProtocol,\n });\n const screenshotBase64 = context.screenshot.base64;\n\n const renderedContext = renderAIContext(extractOption?.context);\n const extractDataPromptText = extractDataQueryPrompt(\n options.pageDescription || '',\n dataQuery,\n renderedContext,\n );\n\n const userContent: ChatCompletionUserMessageParam['content'] = [];\n\n if (extractOption?.screenshotIncluded !== false) {\n const screenshotSequence = context.screenshotSequence;\n if (screenshotSequence && screenshotSequence.length > 1) {\n userContent.push({\n type: 'text',\n text: `The following ${screenshotSequence.length} images are consecutive screenshots captured over a time window, ordered from earliest to latest (Frame 1 is first, Frame ${screenshotSequence.length} is last). They record what appeared on screen during that window. Some UI elements such as toasts, banners, or transitions may appear only in certain frames and be gone by later ones. Interpret the temporal scope from the statement or question itself: if it asks whether something appeared at any point, inspect the whole sequence; if it asks about the final or current state, use the relevant later frame; if it asks about a change or sequence, compare frames in order. Unless <DATA_DEMAND> explicitly asks for comparison or matching against reference images, base your answer on these screenshots and their contents.`,\n });\n\n screenshotSequence.forEach((frame, index) => {\n userContent.push({\n type: 'text',\n text: `Frame ${index + 1}/${screenshotSequence.length}`,\n });\n userContent.push({\n type: 'image_url',\n image_url: {\n url: frame.base64,\n detail: 'high',\n },\n });\n });\n } else {\n userContent.push({\n type: 'text',\n text: 'This is the current screenshot to evaluate. Unless <DATA_DEMAND> explicitly asks for comparison or matching against reference images, base your answer on this screenshot and its contents when provided.',\n });\n\n userContent.push({\n type: 'image_url',\n image_url: {\n url: screenshotBase64,\n detail: 'high',\n },\n });\n }\n }\n\n userContent.push({\n type: 'text',\n text: extractDataPromptText,\n });\n\n const msgs: InsightAIArgs = [\n { role: 'system', content: systemPrompt },\n {\n role: 'user',\n content: userContent,\n },\n ];\n\n if (multimodalPrompt) {\n const addOns = await multimodalPromptToChatMessages(multimodalPrompt);\n msgs.push(...addOns);\n }\n\n return callAiAndParseWithRetry({\n callAi: (retryAttempt, previousParseError) =>\n callAI(\n withSemanticRetryFeedback(msgs, previousParseError),\n modelRuntime,\n {\n abortSignal: options.abortSignal,\n semanticRetryAttempt: retryAttempt,\n },\n ),\n parseResponse: (response) => {\n const {\n content: rawResponse,\n usage,\n reasoning_content,\n rawChoiceMessage,\n } = response;\n const parseResult = parseInsightResponse<T>(\n rawResponse,\n insightProtocol.dataOutput,\n modelRuntime.adapter.jsonParser,\n );\n return {\n parseResult,\n rawResponse,\n rawChoiceMessage,\n usage,\n reasoning_content,\n };\n },\n toParseError: (parseError, response) => {\n const errorMessage =\n parseError instanceof Error ? parseError.message : String(parseError);\n return new AIResponseParseError(\n `XML parse error: ${errorMessage}`,\n response.content,\n response.usage,\n response.rawChoiceMessage,\n );\n },\n parseRetryTimes: modelRuntime.config.retryCount,\n parseRetryInterval: modelRuntime.config.retryInterval,\n abortSignal: options.abortSignal,\n onParseRetry: (error) => {\n debugInsight(\n 'retrying insight after XML parsing failed: %s',\n error instanceof Error ? error.message : String(error),\n );\n },\n });\n}\n"],"names":["debugInsight","getDebug","AiExtractElementInfo","options","dataQuery","context","extractOption","multimodalPrompt","modelRuntime","insightProtocol","systemPrompt","buildInsightSystemPrompt","screenshotBase64","renderedContext","renderAIContext","extractDataPromptText","extractDataQueryPrompt","userContent","screenshotSequence","frame","index","msgs","addOns","multimodalPromptToChatMessages","callAiAndParseWithRetry","retryAttempt","previousParseError","callAI","withSemanticRetryFeedback","response","rawResponse","usage","reasoning_content","rawChoiceMessage","parseResult","parseInsightResponse","parseError","errorMessage","Error","String","AIResponseParseError","error"],"mappings":";;;;;;;AA0BA,MAAMA,eAAeC,SAAS;AAEvB,eAAeC,qBAAwBC,OAQ7C;IACC,MAAM,EAAEC,SAAS,EAAEC,OAAO,EAAEC,aAAa,EAAEC,gBAAgB,EAAEC,YAAY,EAAE,GACzEL;IACF,MAAMM,kBAAkBD,aAAa,OAAO,CAAC,OAAO,CAAC,QAAQ;IAC7D,MAAME,eAAeC,yBAAyB;QAC5C,oBAAoBL,eAAe,uBAAuB;QAC1D,yBAAyB,CAAC,CAACC,kBAAkB,QAAQ;QACrDE;IACF;IACA,MAAMG,mBAAmBP,QAAQ,UAAU,CAAC,MAAM;IAElD,MAAMQ,kBAAkBC,gBAAgBR,eAAe;IACvD,MAAMS,wBAAwBC,uBAC5Bb,QAAQ,eAAe,IAAI,IAC3BC,WACAS;IAGF,MAAMI,cAAyD,EAAE;IAEjE,IAAIX,eAAe,uBAAuB,OAAO;QAC/C,MAAMY,qBAAqBb,QAAQ,kBAAkB;QACrD,IAAIa,sBAAsBA,mBAAmB,MAAM,GAAG,GAAG;YACvDD,YAAY,IAAI,CAAC;gBACf,MAAM;gBACN,MAAM,CAAC,cAAc,EAAEC,mBAAmB,MAAM,CAAC,0HAA0H,EAAEA,mBAAmB,MAAM,CAAC,2mBAA2mB,CAAC;YACrzB;YAEAA,mBAAmB,OAAO,CAAC,CAACC,OAAOC;gBACjCH,YAAY,IAAI,CAAC;oBACf,MAAM;oBACN,MAAM,CAAC,MAAM,EAAEG,QAAQ,EAAE,CAAC,EAAEF,mBAAmB,MAAM,EAAE;gBACzD;gBACAD,YAAY,IAAI,CAAC;oBACf,MAAM;oBACN,WAAW;wBACT,KAAKE,MAAM,MAAM;wBACjB,QAAQ;oBACV;gBACF;YACF;QACF,OAAO;YACLF,YAAY,IAAI,CAAC;gBACf,MAAM;gBACN,MAAM;YACR;YAEAA,YAAY,IAAI,CAAC;gBACf,MAAM;gBACN,WAAW;oBACT,KAAKL;oBACL,QAAQ;gBACV;YACF;QACF;IACF;IAEAK,YAAY,IAAI,CAAC;QACf,MAAM;QACN,MAAMF;IACR;IAEA,MAAMM,OAAsB;QAC1B;YAAE,MAAM;YAAU,SAASX;QAAa;QACxC;YACE,MAAM;YACN,SAASO;QACX;KACD;IAED,IAAIV,kBAAkB;QACpB,MAAMe,SAAS,MAAMC,+BAA+BhB;QACpDc,KAAK,IAAI,IAAIC;IACf;IAEA,OAAOE,wBAAwB;QAC7B,QAAQ,CAACC,cAAcC,qBACrBC,OACEC,0BAA0BP,MAAMK,qBAChClB,cACA;gBACE,aAAaL,QAAQ,WAAW;gBAChC,sBAAsBsB;YACxB;QAEJ,eAAe,CAACI;YACd,MAAM,EACJ,SAASC,WAAW,EACpBC,KAAK,EACLC,iBAAiB,EACjBC,gBAAgB,EACjB,GAAGJ;YACJ,MAAMK,cAAcC,qBAClBL,aACArB,gBAAgB,UAAU,EAC1BD,aAAa,OAAO,CAAC,UAAU;YAEjC,OAAO;gBACL0B;gBACAJ;gBACAG;gBACAF;gBACAC;YACF;QACF;QACA,cAAc,CAACI,YAAYP;YACzB,MAAMQ,eACJD,sBAAsBE,QAAQF,WAAW,OAAO,GAAGG,OAAOH;YAC5D,OAAO,IAAII,qBACT,CAAC,iBAAiB,EAAEH,cAAc,EAClCR,SAAS,OAAO,EAChBA,SAAS,KAAK,EACdA,SAAS,gBAAgB;QAE7B;QACA,iBAAiBrB,aAAa,MAAM,CAAC,UAAU;QAC/C,oBAAoBA,aAAa,MAAM,CAAC,aAAa;QACrD,aAAaL,QAAQ,WAAW;QAChC,cAAc,CAACsC;YACbzC,aACE,iDACAyC,iBAAiBH,QAAQG,MAAM,OAAO,GAAGF,OAAOE;QAEpD;IACF;AACF"}
@@ -3,13 +3,13 @@ import { prepareModelImage } from "../../model-adapter/image-preprocess.mjs";
3
3
  import { AIResponseParseError, callAIWithStringResponse } from "../../service-caller/index.mjs";
4
4
  import { preparedReferenceImagesToChatMessages } from "../../shared/multimodal-prompt.mjs";
5
5
  import { normalizePlanningActionLocateFields } from "./locate-normalization.mjs";
6
- function appendHighPriorityKnowledge(systemPrompt, actionContext) {
7
- return systemPrompt + (actionContext ? `<high_priority_knowledge>${actionContext}</high_priority_knowledge>\n` : '');
6
+ function appendActionContext(systemPrompt, actionContext) {
7
+ return systemPrompt + (actionContext ? `${actionContext}\n` : '');
8
8
  }
9
9
  function buildCustomPlanningMessages(input, config) {
10
10
  const { options } = input;
11
11
  const { conversationHistory, context, actionContext } = options;
12
- const systemPrompt = appendHighPriorityKnowledge(config.buildSystemPrompt(), actionContext);
12
+ const systemPrompt = appendActionContext(config.buildSystemPrompt(), actionContext);
13
13
  const userInstructionText = input.userInstruction.text;
14
14
  const userInstruction = config.buildUserInstruction ? config.buildUserInstruction(userInstructionText) : userInstructionText;
15
15
  const referenceImageMessages = preparedReferenceImagesToChatMessages(input.userInstruction.referenceImages);
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/workflows/planning/custom-planning.mjs","sources":["../../../../../src/ai-model/workflows/planning/custom-planning.ts"],"sourcesContent":["import type { PlanningAIResponse, PlanningAction } from '@/types';\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\nimport { ScreenshotItem } from '../../../screenshot-item';\nimport type {\n CustomPlanningInput,\n CustomPlanningMessageConfig,\n ResolvedCustomPlanningDefinition,\n} from '../../model-adapter/custom-planning-types';\nimport { prepareModelImage } from '../../model-adapter/image-preprocess';\nimport type { ParsedPlanningLocateParameter } from '../../model-adapter/planning-protocol';\nimport {\n AIResponseParseError,\n callAIWithStringResponse,\n} from '../../service-caller/index';\nimport {\n type PreparedUserPrompt,\n preparedReferenceImagesToChatMessages,\n} from '../../shared/multimodal-prompt';\nimport { normalizePlanningActionLocateFields } from './locate-normalization';\nimport type { PlanOptions } from './types';\n\nfunction appendHighPriorityKnowledge(\n systemPrompt: string,\n actionContext?: string,\n): string {\n return (\n systemPrompt +\n (actionContext\n ? `<high_priority_knowledge>${actionContext}</high_priority_knowledge>\\n`\n : '')\n );\n}\n\nexport function buildCustomPlanningMessages<TParsed>(\n input: CustomPlanningInput,\n config: CustomPlanningMessageConfig<TParsed>,\n): ChatCompletionMessageParam[] {\n const { options } = input;\n const { conversationHistory, context, actionContext } = options;\n const systemPrompt = appendHighPriorityKnowledge(\n config.buildSystemPrompt(),\n actionContext,\n );\n const userInstructionText = input.userInstruction.text;\n const userInstruction = config.buildUserInstruction\n ? config.buildUserInstruction(userInstructionText)\n : userInstructionText;\n const referenceImageMessages = preparedReferenceImagesToChatMessages(\n input.userInstruction.referenceImages,\n );\n\n if (conversationHistory.pendingFeedbackMessage) {\n conversationHistory.append({\n role: 'user',\n content: [\n {\n type: 'text',\n text: `${conversationHistory.pendingFeedbackMessage}. The previous action has been executed, here is the latest screenshot. Please continue according to the instruction.`,\n },\n ],\n });\n conversationHistory.resetPendingFeedbackMessageIfExists();\n }\n\n conversationHistory.append({\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: { url: context.screenshot.base64 },\n },\n ],\n });\n\n if (config.systemPromptPlacement === 'system-message') {\n return [\n { role: 'system', content: systemPrompt },\n {\n role: 'user',\n content: [{ type: 'text', text: userInstruction }],\n },\n ...referenceImageMessages,\n ...conversationHistory.snapshot(config.historyImageLimit),\n ];\n }\n\n return [\n {\n role: 'user',\n content: `${systemPrompt}${userInstruction}`,\n },\n ...referenceImageMessages,\n ...conversationHistory.snapshot(config.historyImageLimit),\n ];\n}\n\nexport async function runCustomPlanning<TParsed>(\n userInstruction: PreparedUserPrompt,\n options: PlanOptions,\n config: ResolvedCustomPlanningDefinition<TParsed>,\n): Promise<PlanningAIResponse> {\n const { context } = options;\n const preparedImage = await prepareModelImage({\n imageBase64: context.screenshot.base64,\n width: context.shotSize.width,\n height: context.shotSize.height,\n policy: options.modelRuntime.adapter.imagePreprocess,\n });\n const preparedOptions: PlanOptions = {\n ...options,\n context: {\n ...context,\n screenshot: ScreenshotItem.create(\n preparedImage.imageBase64,\n context.screenshot.capturedAt,\n ),\n shotSize: preparedImage.preparedSize,\n },\n };\n const input: CustomPlanningInput = {\n userInstruction,\n options: preparedOptions,\n coordinateSystem: config.coordinateSystem,\n };\n\n const messages = buildCustomPlanningMessages(input, config.messages);\n const { content, usage, rawChoiceMessage } = await callAIWithStringResponse(\n messages,\n preparedOptions.modelRuntime,\n {\n abortSignal: preparedOptions.abortSignal,\n requiresOriginalImageDetail: preparedOptions.includeLocateInPlanning,\n },\n );\n\n let parsed: TParsed;\n let actions: PlanningAction[];\n let shouldContinuePlanning: boolean;\n\n try {\n parsed = config.parseResponse(content, input);\n actions = config.transformActions(parsed, input);\n normalizePlanningActionLocateFields(actions, {\n actionSpace: preparedOptions.actionSpace,\n includeLocateInPlanning: preparedOptions.includeLocateInPlanning,\n locateResultCodec: config.coordinateNormalizer,\n locateResultContext: {\n preparedSize: preparedImage.preparedSize,\n contentSize: preparedImage.contentSize,\n },\n acceptBbox2dAlias: preparedOptions.modelRuntime.adapter.acceptBbox2dAlias,\n parseRawLocateParameter: (value) =>\n value as ParsedPlanningLocateParameter,\n });\n shouldContinuePlanning = config.shouldContinuePlanning(parsed, actions);\n } catch (parseError) {\n const errorMessage = `Parse error: ${\n parseError instanceof Error ? parseError.message : String(parseError)\n }`;\n throw new AIResponseParseError(\n errorMessage,\n JSON.stringify(content, undefined, 2),\n usage,\n rawChoiceMessage,\n );\n }\n\n const assistantContent = config.messages.buildAssistantContent?.(\n parsed,\n content,\n input,\n );\n // UI-TARS and Auto-GLM define their own assistant history format.\n if (assistantContent) {\n options.conversationHistory.append({\n role: 'assistant',\n content: assistantContent,\n });\n }\n\n return {\n actions,\n log: config.buildResponseLog(parsed, content),\n usage,\n shouldContinuePlanning,\n rawResponse: JSON.stringify(content, undefined, 2),\n rawChoiceMessage,\n };\n}\n"],"names":["appendHighPriorityKnowledge","systemPrompt","actionContext","buildCustomPlanningMessages","input","config","options","conversationHistory","context","userInstructionText","userInstruction","referenceImageMessages","preparedReferenceImagesToChatMessages","runCustomPlanning","preparedImage","prepareModelImage","preparedOptions","ScreenshotItem","messages","content","usage","rawChoiceMessage","callAIWithStringResponse","parsed","actions","shouldContinuePlanning","normalizePlanningActionLocateFields","value","parseError","errorMessage","Error","String","AIResponseParseError","JSON","undefined","assistantContent"],"mappings":"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"}
1
+ {"version":3,"file":"ai-model/workflows/planning/custom-planning.mjs","sources":["../../../../../src/ai-model/workflows/planning/custom-planning.ts"],"sourcesContent":["import type { PlanningAIResponse, PlanningAction } from '@/types';\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\nimport { ScreenshotItem } from '../../../screenshot-item';\nimport type {\n CustomPlanningInput,\n CustomPlanningMessageConfig,\n ResolvedCustomPlanningDefinition,\n} from '../../model-adapter/custom-planning-types';\nimport { prepareModelImage } from '../../model-adapter/image-preprocess';\nimport type { ParsedPlanningLocateParameter } from '../../model-adapter/planning-protocol';\nimport {\n AIResponseParseError,\n callAIWithStringResponse,\n} from '../../service-caller/index';\nimport {\n type PreparedUserPrompt,\n preparedReferenceImagesToChatMessages,\n} from '../../shared/multimodal-prompt';\nimport { normalizePlanningActionLocateFields } from './locate-normalization';\nimport type { PlanOptions } from './types';\n\nfunction appendActionContext(\n systemPrompt: string,\n actionContext?: string,\n): string {\n return systemPrompt + (actionContext ? `${actionContext}\\n` : '');\n}\n\nexport function buildCustomPlanningMessages<TParsed>(\n input: CustomPlanningInput,\n config: CustomPlanningMessageConfig<TParsed>,\n): ChatCompletionMessageParam[] {\n const { options } = input;\n const { conversationHistory, context, actionContext } = options;\n const systemPrompt = appendActionContext(\n config.buildSystemPrompt(),\n actionContext,\n );\n const userInstructionText = input.userInstruction.text;\n const userInstruction = config.buildUserInstruction\n ? config.buildUserInstruction(userInstructionText)\n : userInstructionText;\n const referenceImageMessages = preparedReferenceImagesToChatMessages(\n input.userInstruction.referenceImages,\n );\n\n if (conversationHistory.pendingFeedbackMessage) {\n conversationHistory.append({\n role: 'user',\n content: [\n {\n type: 'text',\n text: `${conversationHistory.pendingFeedbackMessage}. The previous action has been executed, here is the latest screenshot. Please continue according to the instruction.`,\n },\n ],\n });\n conversationHistory.resetPendingFeedbackMessageIfExists();\n }\n\n conversationHistory.append({\n role: 'user',\n content: [\n {\n type: 'image_url',\n image_url: { url: context.screenshot.base64 },\n },\n ],\n });\n\n if (config.systemPromptPlacement === 'system-message') {\n return [\n { role: 'system', content: systemPrompt },\n {\n role: 'user',\n content: [{ type: 'text', text: userInstruction }],\n },\n ...referenceImageMessages,\n ...conversationHistory.snapshot(config.historyImageLimit),\n ];\n }\n\n return [\n {\n role: 'user',\n content: `${systemPrompt}${userInstruction}`,\n },\n ...referenceImageMessages,\n ...conversationHistory.snapshot(config.historyImageLimit),\n ];\n}\n\nexport async function runCustomPlanning<TParsed>(\n userInstruction: PreparedUserPrompt,\n options: PlanOptions,\n config: ResolvedCustomPlanningDefinition<TParsed>,\n): Promise<PlanningAIResponse> {\n const { context } = options;\n const preparedImage = await prepareModelImage({\n imageBase64: context.screenshot.base64,\n width: context.shotSize.width,\n height: context.shotSize.height,\n policy: options.modelRuntime.adapter.imagePreprocess,\n });\n const preparedOptions: PlanOptions = {\n ...options,\n context: {\n ...context,\n screenshot: ScreenshotItem.create(\n preparedImage.imageBase64,\n context.screenshot.capturedAt,\n ),\n shotSize: preparedImage.preparedSize,\n },\n };\n const input: CustomPlanningInput = {\n userInstruction,\n options: preparedOptions,\n coordinateSystem: config.coordinateSystem,\n };\n\n const messages = buildCustomPlanningMessages(input, config.messages);\n const { content, usage, rawChoiceMessage } = await callAIWithStringResponse(\n messages,\n preparedOptions.modelRuntime,\n {\n abortSignal: preparedOptions.abortSignal,\n requiresOriginalImageDetail: preparedOptions.includeLocateInPlanning,\n },\n );\n\n let parsed: TParsed;\n let actions: PlanningAction[];\n let shouldContinuePlanning: boolean;\n\n try {\n parsed = config.parseResponse(content, input);\n actions = config.transformActions(parsed, input);\n normalizePlanningActionLocateFields(actions, {\n actionSpace: preparedOptions.actionSpace,\n includeLocateInPlanning: preparedOptions.includeLocateInPlanning,\n locateResultCodec: config.coordinateNormalizer,\n locateResultContext: {\n preparedSize: preparedImage.preparedSize,\n contentSize: preparedImage.contentSize,\n },\n acceptBbox2dAlias: preparedOptions.modelRuntime.adapter.acceptBbox2dAlias,\n parseRawLocateParameter: (value) =>\n value as ParsedPlanningLocateParameter,\n });\n shouldContinuePlanning = config.shouldContinuePlanning(parsed, actions);\n } catch (parseError) {\n const errorMessage = `Parse error: ${\n parseError instanceof Error ? parseError.message : String(parseError)\n }`;\n throw new AIResponseParseError(\n errorMessage,\n JSON.stringify(content, undefined, 2),\n usage,\n rawChoiceMessage,\n );\n }\n\n const assistantContent = config.messages.buildAssistantContent?.(\n parsed,\n content,\n input,\n );\n // UI-TARS and Auto-GLM define their own assistant history format.\n if (assistantContent) {\n options.conversationHistory.append({\n role: 'assistant',\n content: assistantContent,\n });\n }\n\n return {\n actions,\n log: config.buildResponseLog(parsed, content),\n usage,\n shouldContinuePlanning,\n rawResponse: JSON.stringify(content, undefined, 2),\n rawChoiceMessage,\n };\n}\n"],"names":["appendActionContext","systemPrompt","actionContext","buildCustomPlanningMessages","input","config","options","conversationHistory","context","userInstructionText","userInstruction","referenceImageMessages","preparedReferenceImagesToChatMessages","runCustomPlanning","preparedImage","prepareModelImage","preparedOptions","ScreenshotItem","messages","content","usage","rawChoiceMessage","callAIWithStringResponse","parsed","actions","shouldContinuePlanning","normalizePlanningActionLocateFields","value","parseError","errorMessage","Error","String","AIResponseParseError","JSON","undefined","assistantContent"],"mappings":"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"}
@@ -101,7 +101,7 @@ async function standardPlan(userInstruction, opts) {
101
101
  policy: adapter.imagePreprocess
102
102
  });
103
103
  const imagePayload = preparedImage.imageBase64;
104
- const actionContext = opts.actionContext ? `<high_priority_knowledge>${opts.actionContext}</high_priority_knowledge>\n` : '';
104
+ const actionContext = opts.actionContext ? `${opts.actionContext}\n` : '';
105
105
  const referenceImageMessages = preparedReferenceImagesToChatMessages(userInstruction.referenceImages);
106
106
  const instruction = [
107
107
  {
@@ -1 +1 @@
1
- {"version":3,"file":"ai-model/workflows/planning/standard-planning.mjs","sources":["../../../../../src/ai-model/workflows/planning/standard-planning.ts"],"sourcesContent":["import type {\n PlanningAIResponse,\n PlanningAction,\n RawResponsePlanningAIResponse,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\nimport { buildYamlFlowFromPlans } from '../../../common';\nimport { prepareModelImage } from '../../model-adapter/image-preprocess';\nimport { buildStandardPlanningSystemPrompt } from '../../prompt/planning';\nimport { AIResponseParseError, callAI } from '../../service-caller/index';\nimport {\n callAiAndParseWithRetry,\n withSemanticRetryFeedback,\n} from '../../service-caller/semantic-retry';\nimport type {\n LocateResultCodec,\n LocateResultContext,\n} from '../../shared/model-locate-result';\nimport { planningModelFamilyRequiredForLocateMessage } from '../../shared/model-locate-result/errors';\nimport {\n type PreparedUserPrompt,\n preparedReferenceImagesToChatMessages,\n} from '../../shared/multimodal-prompt';\nimport { normalizePlanningActionLocateFields } from './locate-normalization';\nimport { parseStandardPlanningResponse } from './standard-planning-parser';\nimport type { PlanOptions } from './types';\n\nconst debug = getDebug('planning');\nconst warnLog = getDebug('planning', { console: true });\n\nconst noPreviousActionsText =\n 'No previous actions have been executed in this aiAct execution yet. If the instruction asks for actions, choose the first action to execute.';\ntype PlanningCallResponse = Awaited<ReturnType<typeof callAI>>;\n\ntype CallAndParsePlanningResponseOptions = {\n messages: ChatCompletionMessageParam[];\n modelRuntime: PlanOptions['modelRuntime'];\n abortSignal?: AbortSignal;\n includeLocateInPlanning: boolean;\n actionSpace: PlanOptions['actionSpace'];\n locateResultCodec?: LocateResultCodec;\n locateResultContext: LocateResultContext;\n includeThought: boolean;\n includeLog: boolean;\n};\n\nasync function callAndParsePlanningResponse(\n options: CallAndParsePlanningResponseOptions,\n): Promise<{\n response: PlanningCallResponse;\n planFromAI: RawResponsePlanningAIResponse;\n actions: PlanningAction[];\n yamlFlow: ReturnType<typeof buildYamlFlowFromPlans>;\n}> {\n const {\n messages,\n modelRuntime,\n abortSignal,\n includeLocateInPlanning,\n actionSpace,\n locateResultCodec,\n locateResultContext,\n includeThought,\n includeLog,\n } = options;\n assert(\n modelRuntime.adapter.planning.kind === 'standard',\n 'callAndParsePlanningResponse requires a standard planning adapter',\n );\n const actionOutputProtocol =\n modelRuntime.adapter.planning.protocol.actionOutputProtocol;\n\n return callAiAndParseWithRetry({\n callAi: (retryAttempt, previousParseError) =>\n callAI(\n withSemanticRetryFeedback(messages, previousParseError),\n modelRuntime,\n {\n abortSignal,\n requiresOriginalImageDetail: includeLocateInPlanning,\n semanticRetryAttempt: retryAttempt,\n },\n ),\n parseResponse: (response) => {\n const planFromAI = parseStandardPlanningResponse(response.content, {\n includeThought,\n actionOutputProtocol,\n actionSpace,\n logSource: includeLog ? 'model' : 'action',\n });\n if (planFromAI.action && planFromAI.finalizeSuccess !== undefined) {\n warnLog(\n 'Planning response included both an action and <complete>; ignoring <complete> output.',\n );\n planFromAI.finalizeMessage = undefined;\n planFromAI.finalizeSuccess = undefined;\n }\n\n const actions = planFromAI.action ? [planFromAI.action] : [];\n normalizePlanningActionLocateFields(actions, {\n actionSpace,\n includeLocateInPlanning,\n locateResultCodec,\n locateResultContext,\n acceptBbox2dAlias: modelRuntime.adapter.acceptBbox2dAlias,\n parseRawLocateParameter: actionOutputProtocol.parseRawLocateParameter,\n });\n // dumpActionParam keeps only the locator prompt, so runtime-only\n // locatedPixelBbox fields added during normalization are not serialized.\n const yamlFlow = buildYamlFlowFromPlans(actions, actionSpace);\n return { response, planFromAI, actions, yamlFlow };\n },\n toParseError: (parseError, response) => {\n const errorMessage =\n parseError instanceof Error ? parseError.message : String(parseError);\n return new AIResponseParseError(\n `XML parse error: ${errorMessage}`,\n response.content,\n response.usage,\n response.rawChoiceMessage,\n response.reasoning_content,\n );\n },\n parseRetryTimes: modelRuntime.config.retryCount,\n parseRetryInterval: modelRuntime.config.retryInterval,\n abortSignal,\n onParseRetry: (parseError) => {\n debug(\n 'retrying plan after response parsing failed: %s',\n parseError instanceof Error ? parseError.message : String(parseError),\n );\n },\n });\n}\n\nexport async function standardPlan(\n userInstruction: PreparedUserPrompt,\n opts: PlanOptions,\n): Promise<PlanningAIResponse> {\n const { context, conversationHistory } = opts;\n const modelRuntime = opts.modelRuntime;\n const { adapter } = modelRuntime;\n const { shotSize } = context;\n const screenshotBase64 = context.screenshot.base64;\n assert(\n adapter.planning.kind === 'standard',\n 'standardPlan requires a standard planning adapter',\n );\n const planningProtocol = adapter.planning.protocol;\n\n if (opts.includeLocateInPlanning && !modelRuntime.config.modelFamily) {\n throw new Error(\n planningModelFamilyRequiredForLocateMessage(modelRuntime.config.slot),\n );\n }\n\n const locateResultCodec = modelRuntime.config.modelFamily\n ? adapter.planning.locateResultCodec\n : undefined;\n\n // Only enable sub-goals when aiAct is in deep-thinking planning mode.\n const includeSubGoals = opts.effort === 'deepThink';\n const includeThought = opts.effort !== 'fast';\n const includeLog = opts.effort !== 'fast';\n\n if (opts.includeLocateInPlanning && !locateResultCodec) {\n throw new Error(\n planningModelFamilyRequiredForLocateMessage(modelRuntime.config.slot),\n );\n }\n\n const systemPrompt = await buildStandardPlanningSystemPrompt({\n actionSpace: opts.actionSpace,\n includeThought,\n includeLog,\n includeSubGoals,\n planningProtocol,\n ...(opts.includeLocateInPlanning && locateResultCodec\n ? {\n includeLocateInPlanning: true,\n locatePromptSpec: locateResultCodec.promptSpec,\n }\n : { includeLocateInPlanning: false }),\n });\n\n const preparedImage = await prepareModelImage({\n imageBase64: screenshotBase64,\n width: shotSize.width,\n height: shotSize.height,\n policy: adapter.imagePreprocess,\n });\n const imagePayload = preparedImage.imageBase64;\n\n const actionContext = opts.actionContext\n ? `<high_priority_knowledge>${opts.actionContext}</high_priority_knowledge>\\n`\n : '';\n\n const referenceImageMessages = preparedReferenceImagesToChatMessages(\n userInstruction.referenceImages,\n );\n const instruction: ChatCompletionMessageParam[] = [\n {\n role: 'user',\n content: [\n {\n type: 'text',\n text: `${actionContext}<user_instruction>${userInstruction.text}</user_instruction>`,\n },\n ],\n },\n ...referenceImageMessages,\n ];\n\n let latestFeedbackMessage: ChatCompletionMessageParam;\n\n // Build sub-goal status text to include in the message\n // In planning deep-think mode: show full sub-goals with logs\n // Otherwise: show historical execution logs\n const executionProgressText = includeSubGoals\n ? conversationHistory.subGoalsToText()\n : conversationHistory.historicalLogsToText();\n const executionProgressSection = executionProgressText\n ? `\\n\\n${executionProgressText}`\n : conversationHistory.pendingFeedbackMessage\n ? ''\n : `\\n\\n${noPreviousActionsText}`;\n\n // Build memories text to include in the message\n const memoriesText = conversationHistory.memoriesToText();\n const memoriesSection = memoriesText ? `\\n\\n${memoriesText}` : '';\n\n if (conversationHistory.pendingFeedbackMessage) {\n latestFeedbackMessage = {\n role: 'user',\n content: [\n {\n type: 'text',\n text: `${conversationHistory.pendingFeedbackMessage}. The previous action has been executed, here is the latest screenshot. Please continue according to the instruction.${memoriesSection}${executionProgressSection}`,\n },\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high',\n },\n },\n ],\n };\n\n conversationHistory.resetPendingFeedbackMessageIfExists();\n } else {\n latestFeedbackMessage = {\n role: 'user',\n content: [\n {\n type: 'text',\n text: `This is the current screenshot.${memoriesSection}${executionProgressSection}`,\n },\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high',\n },\n },\n ],\n };\n }\n conversationHistory.append(latestFeedbackMessage);\n\n // Compress history if it exceeds the threshold to avoid context overflow\n conversationHistory.compressHistory(50, 20);\n\n const historyLog = conversationHistory.snapshot(opts.imagesIncludeCount);\n\n const msgs: ChatCompletionMessageParam[] = [\n { role: 'system', content: systemPrompt },\n ...instruction,\n ...historyLog,\n ];\n\n const {\n response: {\n content: rawResponse,\n usage,\n reasoning_content,\n rawChoiceMessage,\n },\n planFromAI,\n actions,\n yamlFlow,\n } = await callAndParsePlanningResponse({\n messages: msgs,\n modelRuntime,\n abortSignal: opts.abortSignal,\n includeLocateInPlanning: opts.includeLocateInPlanning,\n actionSpace: opts.actionSpace,\n locateResultCodec,\n locateResultContext: {\n preparedSize: preparedImage.preparedSize,\n contentSize: preparedImage.contentSize,\n },\n includeThought,\n includeLog,\n });\n\n let shouldContinuePlanning = true;\n\n // Check if task is completed via <complete> tag\n if (planFromAI.finalizeSuccess !== undefined) {\n debug('task completed via <complete> tag, stop planning');\n shouldContinuePlanning = false;\n // Mark all sub-goals as finished when goal is completed in planning deep-think mode.\n if (includeSubGoals) {\n conversationHistory.markAllSubGoalsFinished();\n }\n }\n\n const returnValue: PlanningAIResponse = {\n ...planFromAI,\n actions,\n rawResponse,\n rawChoiceMessage,\n usage,\n reasoning_content,\n yamlFlow,\n shouldContinuePlanning,\n };\n\n assert(planFromAI, \"can't get plans from AI\");\n\n // TODO: The plan log is recorded before its action has executed, so a failed\n // action may still appear in the next round as an action already performed.\n // Move this write to the successful action execution path in TaskExecutor.action.\n // Update sub-goals in conversation history only in planning deep-think mode.\n if (includeSubGoals) {\n if (planFromAI.updateSubGoals?.length) {\n conversationHistory.mergeSubGoals(planFromAI.updateSubGoals);\n }\n if (planFromAI.markFinishedIndexes?.length) {\n for (const index of planFromAI.markFinishedIndexes) {\n conversationHistory.markSubGoalFinished(index);\n }\n }\n // Append the planning log to the currently running sub-goal\n if (planFromAI.log) {\n conversationHistory.appendSubGoalLog(planFromAI.log);\n }\n } else {\n // Without planning deep-think mode, accumulate logs as historical execution steps.\n if (planFromAI.log) {\n conversationHistory.appendHistoricalLog(planFromAI.log);\n }\n }\n\n // Append memory to conversation history if present\n if (planFromAI.memory) {\n conversationHistory.appendMemory(planFromAI.memory);\n }\n\n // Some model providers require opaque assistant fields to be replayed\n // verbatim in later turns. Keep this opt-in per model adapter so that an\n // unverified provider does not receive non-standard response fields.\n if (\n modelRuntime.adapter.chatCompletion.replayRawAssistantMessage &&\n rawChoiceMessage\n ) {\n conversationHistory.append(rawChoiceMessage as ChatCompletionMessageParam);\n } else {\n conversationHistory.append({\n role: 'assistant',\n content: [\n {\n type: 'text',\n text: rawResponse,\n },\n ],\n });\n }\n\n return returnValue;\n}\n"],"names":["debug","getDebug","warnLog","noPreviousActionsText","callAndParsePlanningResponse","options","messages","modelRuntime","abortSignal","includeLocateInPlanning","actionSpace","locateResultCodec","locateResultContext","includeThought","includeLog","assert","actionOutputProtocol","callAiAndParseWithRetry","retryAttempt","previousParseError","callAI","withSemanticRetryFeedback","response","planFromAI","parseStandardPlanningResponse","undefined","actions","normalizePlanningActionLocateFields","yamlFlow","buildYamlFlowFromPlans","parseError","errorMessage","Error","String","AIResponseParseError","standardPlan","userInstruction","opts","context","conversationHistory","adapter","shotSize","screenshotBase64","planningProtocol","planningModelFamilyRequiredForLocateMessage","includeSubGoals","systemPrompt","buildStandardPlanningSystemPrompt","preparedImage","prepareModelImage","imagePayload","actionContext","referenceImageMessages","preparedReferenceImagesToChatMessages","instruction","latestFeedbackMessage","executionProgressText","executionProgressSection","memoriesText","memoriesSection","historyLog","msgs","rawResponse","usage","reasoning_content","rawChoiceMessage","shouldContinuePlanning","returnValue","index"],"mappings":"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"}
1
+ {"version":3,"file":"ai-model/workflows/planning/standard-planning.mjs","sources":["../../../../../src/ai-model/workflows/planning/standard-planning.ts"],"sourcesContent":["import type {\n PlanningAIResponse,\n PlanningAction,\n RawResponsePlanningAIResponse,\n} from '@/types';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\nimport { buildYamlFlowFromPlans } from '../../../common';\nimport { prepareModelImage } from '../../model-adapter/image-preprocess';\nimport { buildStandardPlanningSystemPrompt } from '../../prompt/planning';\nimport { AIResponseParseError, callAI } from '../../service-caller/index';\nimport {\n callAiAndParseWithRetry,\n withSemanticRetryFeedback,\n} from '../../service-caller/semantic-retry';\nimport type {\n LocateResultCodec,\n LocateResultContext,\n} from '../../shared/model-locate-result';\nimport { planningModelFamilyRequiredForLocateMessage } from '../../shared/model-locate-result/errors';\nimport {\n type PreparedUserPrompt,\n preparedReferenceImagesToChatMessages,\n} from '../../shared/multimodal-prompt';\nimport { normalizePlanningActionLocateFields } from './locate-normalization';\nimport { parseStandardPlanningResponse } from './standard-planning-parser';\nimport type { PlanOptions } from './types';\n\nconst debug = getDebug('planning');\nconst warnLog = getDebug('planning', { console: true });\n\nconst noPreviousActionsText =\n 'No previous actions have been executed in this aiAct execution yet. If the instruction asks for actions, choose the first action to execute.';\ntype PlanningCallResponse = Awaited<ReturnType<typeof callAI>>;\n\ntype CallAndParsePlanningResponseOptions = {\n messages: ChatCompletionMessageParam[];\n modelRuntime: PlanOptions['modelRuntime'];\n abortSignal?: AbortSignal;\n includeLocateInPlanning: boolean;\n actionSpace: PlanOptions['actionSpace'];\n locateResultCodec?: LocateResultCodec;\n locateResultContext: LocateResultContext;\n includeThought: boolean;\n includeLog: boolean;\n};\n\nasync function callAndParsePlanningResponse(\n options: CallAndParsePlanningResponseOptions,\n): Promise<{\n response: PlanningCallResponse;\n planFromAI: RawResponsePlanningAIResponse;\n actions: PlanningAction[];\n yamlFlow: ReturnType<typeof buildYamlFlowFromPlans>;\n}> {\n const {\n messages,\n modelRuntime,\n abortSignal,\n includeLocateInPlanning,\n actionSpace,\n locateResultCodec,\n locateResultContext,\n includeThought,\n includeLog,\n } = options;\n assert(\n modelRuntime.adapter.planning.kind === 'standard',\n 'callAndParsePlanningResponse requires a standard planning adapter',\n );\n const actionOutputProtocol =\n modelRuntime.adapter.planning.protocol.actionOutputProtocol;\n\n return callAiAndParseWithRetry({\n callAi: (retryAttempt, previousParseError) =>\n callAI(\n withSemanticRetryFeedback(messages, previousParseError),\n modelRuntime,\n {\n abortSignal,\n requiresOriginalImageDetail: includeLocateInPlanning,\n semanticRetryAttempt: retryAttempt,\n },\n ),\n parseResponse: (response) => {\n const planFromAI = parseStandardPlanningResponse(response.content, {\n includeThought,\n actionOutputProtocol,\n actionSpace,\n logSource: includeLog ? 'model' : 'action',\n });\n if (planFromAI.action && planFromAI.finalizeSuccess !== undefined) {\n warnLog(\n 'Planning response included both an action and <complete>; ignoring <complete> output.',\n );\n planFromAI.finalizeMessage = undefined;\n planFromAI.finalizeSuccess = undefined;\n }\n\n const actions = planFromAI.action ? [planFromAI.action] : [];\n normalizePlanningActionLocateFields(actions, {\n actionSpace,\n includeLocateInPlanning,\n locateResultCodec,\n locateResultContext,\n acceptBbox2dAlias: modelRuntime.adapter.acceptBbox2dAlias,\n parseRawLocateParameter: actionOutputProtocol.parseRawLocateParameter,\n });\n // dumpActionParam keeps only the locator prompt, so runtime-only\n // locatedPixelBbox fields added during normalization are not serialized.\n const yamlFlow = buildYamlFlowFromPlans(actions, actionSpace);\n return { response, planFromAI, actions, yamlFlow };\n },\n toParseError: (parseError, response) => {\n const errorMessage =\n parseError instanceof Error ? parseError.message : String(parseError);\n return new AIResponseParseError(\n `XML parse error: ${errorMessage}`,\n response.content,\n response.usage,\n response.rawChoiceMessage,\n response.reasoning_content,\n );\n },\n parseRetryTimes: modelRuntime.config.retryCount,\n parseRetryInterval: modelRuntime.config.retryInterval,\n abortSignal,\n onParseRetry: (parseError) => {\n debug(\n 'retrying plan after response parsing failed: %s',\n parseError instanceof Error ? parseError.message : String(parseError),\n );\n },\n });\n}\n\nexport async function standardPlan(\n userInstruction: PreparedUserPrompt,\n opts: PlanOptions,\n): Promise<PlanningAIResponse> {\n const { context, conversationHistory } = opts;\n const modelRuntime = opts.modelRuntime;\n const { adapter } = modelRuntime;\n const { shotSize } = context;\n const screenshotBase64 = context.screenshot.base64;\n assert(\n adapter.planning.kind === 'standard',\n 'standardPlan requires a standard planning adapter',\n );\n const planningProtocol = adapter.planning.protocol;\n\n if (opts.includeLocateInPlanning && !modelRuntime.config.modelFamily) {\n throw new Error(\n planningModelFamilyRequiredForLocateMessage(modelRuntime.config.slot),\n );\n }\n\n const locateResultCodec = modelRuntime.config.modelFamily\n ? adapter.planning.locateResultCodec\n : undefined;\n\n // Only enable sub-goals when aiAct is in deep-thinking planning mode.\n const includeSubGoals = opts.effort === 'deepThink';\n const includeThought = opts.effort !== 'fast';\n const includeLog = opts.effort !== 'fast';\n\n if (opts.includeLocateInPlanning && !locateResultCodec) {\n throw new Error(\n planningModelFamilyRequiredForLocateMessage(modelRuntime.config.slot),\n );\n }\n\n const systemPrompt = await buildStandardPlanningSystemPrompt({\n actionSpace: opts.actionSpace,\n includeThought,\n includeLog,\n includeSubGoals,\n planningProtocol,\n ...(opts.includeLocateInPlanning && locateResultCodec\n ? {\n includeLocateInPlanning: true,\n locatePromptSpec: locateResultCodec.promptSpec,\n }\n : { includeLocateInPlanning: false }),\n });\n\n const preparedImage = await prepareModelImage({\n imageBase64: screenshotBase64,\n width: shotSize.width,\n height: shotSize.height,\n policy: adapter.imagePreprocess,\n });\n const imagePayload = preparedImage.imageBase64;\n\n const actionContext = opts.actionContext ? `${opts.actionContext}\\n` : '';\n\n const referenceImageMessages = preparedReferenceImagesToChatMessages(\n userInstruction.referenceImages,\n );\n const instruction: ChatCompletionMessageParam[] = [\n {\n role: 'user',\n content: [\n {\n type: 'text',\n text: `${actionContext}<user_instruction>${userInstruction.text}</user_instruction>`,\n },\n ],\n },\n ...referenceImageMessages,\n ];\n\n let latestFeedbackMessage: ChatCompletionMessageParam;\n\n // Build sub-goal status text to include in the message\n // In planning deep-think mode: show full sub-goals with logs\n // Otherwise: show historical execution logs\n const executionProgressText = includeSubGoals\n ? conversationHistory.subGoalsToText()\n : conversationHistory.historicalLogsToText();\n const executionProgressSection = executionProgressText\n ? `\\n\\n${executionProgressText}`\n : conversationHistory.pendingFeedbackMessage\n ? ''\n : `\\n\\n${noPreviousActionsText}`;\n\n // Build memories text to include in the message\n const memoriesText = conversationHistory.memoriesToText();\n const memoriesSection = memoriesText ? `\\n\\n${memoriesText}` : '';\n\n if (conversationHistory.pendingFeedbackMessage) {\n latestFeedbackMessage = {\n role: 'user',\n content: [\n {\n type: 'text',\n text: `${conversationHistory.pendingFeedbackMessage}. The previous action has been executed, here is the latest screenshot. Please continue according to the instruction.${memoriesSection}${executionProgressSection}`,\n },\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high',\n },\n },\n ],\n };\n\n conversationHistory.resetPendingFeedbackMessageIfExists();\n } else {\n latestFeedbackMessage = {\n role: 'user',\n content: [\n {\n type: 'text',\n text: `This is the current screenshot.${memoriesSection}${executionProgressSection}`,\n },\n {\n type: 'image_url',\n image_url: {\n url: imagePayload,\n detail: 'high',\n },\n },\n ],\n };\n }\n conversationHistory.append(latestFeedbackMessage);\n\n // Compress history if it exceeds the threshold to avoid context overflow\n conversationHistory.compressHistory(50, 20);\n\n const historyLog = conversationHistory.snapshot(opts.imagesIncludeCount);\n\n const msgs: ChatCompletionMessageParam[] = [\n { role: 'system', content: systemPrompt },\n ...instruction,\n ...historyLog,\n ];\n\n const {\n response: {\n content: rawResponse,\n usage,\n reasoning_content,\n rawChoiceMessage,\n },\n planFromAI,\n actions,\n yamlFlow,\n } = await callAndParsePlanningResponse({\n messages: msgs,\n modelRuntime,\n abortSignal: opts.abortSignal,\n includeLocateInPlanning: opts.includeLocateInPlanning,\n actionSpace: opts.actionSpace,\n locateResultCodec,\n locateResultContext: {\n preparedSize: preparedImage.preparedSize,\n contentSize: preparedImage.contentSize,\n },\n includeThought,\n includeLog,\n });\n\n let shouldContinuePlanning = true;\n\n // Check if task is completed via <complete> tag\n if (planFromAI.finalizeSuccess !== undefined) {\n debug('task completed via <complete> tag, stop planning');\n shouldContinuePlanning = false;\n // Mark all sub-goals as finished when goal is completed in planning deep-think mode.\n if (includeSubGoals) {\n conversationHistory.markAllSubGoalsFinished();\n }\n }\n\n const returnValue: PlanningAIResponse = {\n ...planFromAI,\n actions,\n rawResponse,\n rawChoiceMessage,\n usage,\n reasoning_content,\n yamlFlow,\n shouldContinuePlanning,\n };\n\n assert(planFromAI, \"can't get plans from AI\");\n\n // TODO: The plan log is recorded before its action has executed, so a failed\n // action may still appear in the next round as an action already performed.\n // Move this write to the successful action execution path in TaskExecutor.action.\n // Update sub-goals in conversation history only in planning deep-think mode.\n if (includeSubGoals) {\n if (planFromAI.updateSubGoals?.length) {\n conversationHistory.mergeSubGoals(planFromAI.updateSubGoals);\n }\n if (planFromAI.markFinishedIndexes?.length) {\n for (const index of planFromAI.markFinishedIndexes) {\n conversationHistory.markSubGoalFinished(index);\n }\n }\n // Append the planning log to the currently running sub-goal\n if (planFromAI.log) {\n conversationHistory.appendSubGoalLog(planFromAI.log);\n }\n } else {\n // Without planning deep-think mode, accumulate logs as historical execution steps.\n if (planFromAI.log) {\n conversationHistory.appendHistoricalLog(planFromAI.log);\n }\n }\n\n // Append memory to conversation history if present\n if (planFromAI.memory) {\n conversationHistory.appendMemory(planFromAI.memory);\n }\n\n // Some model providers require opaque assistant fields to be replayed\n // verbatim in later turns. Keep this opt-in per model adapter so that an\n // unverified provider does not receive non-standard response fields.\n if (\n modelRuntime.adapter.chatCompletion.replayRawAssistantMessage &&\n rawChoiceMessage\n ) {\n conversationHistory.append(rawChoiceMessage as ChatCompletionMessageParam);\n } else {\n conversationHistory.append({\n role: 'assistant',\n content: [\n {\n type: 'text',\n text: rawResponse,\n },\n ],\n });\n }\n\n return returnValue;\n}\n"],"names":["debug","getDebug","warnLog","noPreviousActionsText","callAndParsePlanningResponse","options","messages","modelRuntime","abortSignal","includeLocateInPlanning","actionSpace","locateResultCodec","locateResultContext","includeThought","includeLog","assert","actionOutputProtocol","callAiAndParseWithRetry","retryAttempt","previousParseError","callAI","withSemanticRetryFeedback","response","planFromAI","parseStandardPlanningResponse","undefined","actions","normalizePlanningActionLocateFields","yamlFlow","buildYamlFlowFromPlans","parseError","errorMessage","Error","String","AIResponseParseError","standardPlan","userInstruction","opts","context","conversationHistory","adapter","shotSize","screenshotBase64","planningProtocol","planningModelFamilyRequiredForLocateMessage","includeSubGoals","systemPrompt","buildStandardPlanningSystemPrompt","preparedImage","prepareModelImage","imagePayload","actionContext","referenceImageMessages","preparedReferenceImagesToChatMessages","instruction","latestFeedbackMessage","executionProgressText","executionProgressSection","memoriesText","memoriesSection","historyLog","msgs","rawResponse","usage","reasoning_content","rawChoiceMessage","shouldContinuePlanning","returnValue","index"],"mappings":"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"}