rl-simulator-core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,512 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/index.js
30
+ var index_exports = {};
31
+ __export(index_exports, {
32
+ runAgent: () => runAgent,
33
+ runTaskLoop: () => runTaskLoop
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+ var import_fs2 = __toESM(require("fs"));
37
+ var import_path3 = __toESM(require("path"));
38
+
39
+ // src/runner.js
40
+ var import_playwright = require("playwright");
41
+ var import_fs = __toESM(require("fs"));
42
+ var import_path2 = __toESM(require("path"));
43
+
44
+ // src/ai.js
45
+ var import_openai = require("@ai-sdk/openai");
46
+ var import_ai = require("ai");
47
+
48
+ // src/config.js
49
+ var import_dotenv = __toESM(require("dotenv"));
50
+ import_dotenv.default.config();
51
+ var API_KEY = process.env.ARK_API_KEY;
52
+ var ENDPOINT = process.env.EP;
53
+ var BASE_URL = process.env.BASE_URL;
54
+ if (!API_KEY || !ENDPOINT || !BASE_URL) {
55
+ console.warn("Missing environment variables (ARK_API_KEY, EP, BASE_URL). Agent may fail if not provided later.");
56
+ }
57
+ var SYSTEM_PROMPT = `
58
+ Intro to Think Mode
59
+ To explore the performance of our model with different styles of thinking, we introduce four modes of thinking: budgted, efficient, no think, and unrestricted. The model is default to unrestricted think mode.
60
+ - Budgeted think mode: Limit model's internal reasoning and reflections to stay within the specified token budget.
61
+ - Efficient think mode: Model provides a concise internal thinking process with efficient reasoning and reflections. It doesn't have a strict token budget, but should be less verbose and more direct in your thinking.
62
+ - No think mode: Model responds directly to the question without any internal reasoning process or extra thinking tokens. Still follows the template with the minimum required thinking tokens to justify the answer.
63
+ - Unrestricted think mode: Model engages in an internal thinking process with thorough reasoning and reflections. There's an unlimited budget for thinking tokens and can continue thinking until you fully solve the problem.
64
+ Think Mode Assignment
65
+ As the "think mode" sp is not encapsulated yet, you need to manually sew in different sp for different modes of thinking. Here are the sp's:
66
+ NOTE: You should disable "thinking" first: (I know it's a bit counterintuitive.)
67
+ "thinking": {
68
+ "type": "disabled"
69
+ }
70
+ - Unrestricted think mode
71
+ You should begin by detailing the internal reasoning process, and then present the answer to the user. The reasoning process should be enclosed within <think_never_used_51bce0c785ca2f68081bfa7d91973934> and </think_never_used_51bce0c785ca2f68081bfa7d91973934> tags, as follows:
72
+ <think_never_used_51bce0c785ca2f68081bfa7d91973934> reasoning process here </think_never_used_51bce0c785ca2f68081bfa7d91973934> answer here.
73
+ You have different modes of thinking:
74
+ Unrestricted think mode: Engage in an internal thinking process with thorough reasoning and reflections. You have an unlimited budget for thinking tokens and can continue thinking until you fully solve the problem.
75
+ Efficient think mode: Provide a concise internal thinking process with efficient reasoning and reflections. You don't have a strict token budget but be less verbose and more direct in your thinking.
76
+ No think mode: Respond directly to the question without any internal reasoning process or extra thinking tokens. Still follow the template with the minimum required thinking tokens to justify the answer.
77
+ Budgeted think mode: Limit your internal reasoning and reflections to stay within the specified token budget
78
+ Based on the complexity of the problem, select the appropriate mode for reasoning among the provided options listed below.
79
+ Provided Mode(s):
80
+ Unrestricted think
81
+ Action Space
82
+ """
83
+ ## Function Definition
84
+ - You have access to the following functions:
85
+ {"type": "function", "name": "click", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Click coordinates. The format is: x y"}}, "required": ["point"]}, "description": "Mouse left single click action."}
86
+ {"type": "function", "name": "left_double", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Click coordinates. The format is: x y"}}, "required": ["point"]}, "description": "Mouse left double click action."}
87
+ {"type": "function", "name": "left_triple", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Click coordinates. The format is: x y"}}, "required": ["point"]}, "description": "Mouse left triple click action."}
88
+ {"type": "function", "name": "right_single", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Click coordinates. The format is: x y"}}, "required": ["point"]}, "description": "Mouse right single click action."}
89
+ {"type": "function", "name": "drag", "parameters": {"type": "object", "properties": {"start_point": {"type": "string", "description": "Drag start point. The format is: x y"}, "end_point": {"type": "string", "description": "Drag end point. The format is: x y"}}, "required": ["start_point", "end_point"]}, "description": "Mouse left button drag action."}
90
+ {"type": "function", "name": "scroll", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Scroll start position. If not specified, default to execute on the current mouse position. The format is: x y"}, "direction": {"type": "string", "description": "Scroll direction.", "enum": ["up", "down", "left", "right"]}}, "required": ["direction"]}, "description": "Scroll action."}
91
+ {"type": "function", "name": "move_to", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Target coordinates. The format is: x y"}}, "required": ["point"]}, "description": "Mouse move action."}
92
+ {"type": "function", "name": "mouse_down", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Mouse down position. If not specified, default to execute on the current mouse position. The format is: x y"}, "button": {"type": "string", "description": "Down button. Default to left.", "enum": ["left", "right"]}}, "required": []}, "description": "Mouse down action."}
93
+ {"type": "function", "name": "mouse_up", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Mouse up position. If not specified, default to execute on the current mouse position. The format is: x y"}, "button": {"type": "string", "description": "Up button. Default to left.", "enum": ["left", "right"]}}, "required": []}, "description": "Mouse up action."}
94
+ {"type": "function", "name": "type", "parameters": {"type": "object", "properties": {"content": {"type": "string", "description": "Type content. If you want to submit your input, use \\n at the end of content."}}, "required": ["content"]}, "description": "Type content."}
95
+ {"type": "function", "name": "hotkey", "parameters": {"type": "object", "properties": {"key": {"type": "string", "description": "Hotkeys you want to press. Split keys with a space and use lowercase."}}, "required": ["key"]}, "description": "Press hotkey."}
96
+ {"type": "function", "name": "press", "parameters": {"type": "object", "properties": {"key": {"type": "string", "description": "Key you want to press. Only one key can be pressed at one time."}}, "required": ["key"]}, "description": "Press key."}
97
+ {"type": "function", "name": "call_user", "parameters": {"type": "object", "properties": {"content": {"type": "string", "description": "Message or information displayed to the user to request their input, feedback, or guidance."}}, "required": []}, "description": "This function is used to interact with the user by displaying a message and requesting their input, feedback, or guidance."}
98
+ {"type": "function", "name": "wait", "parameters": {"type": "object", "properties": {"time": {"type": "string", "description": "Wait time in seconds."}}, "required": []}, "description": "Wait for a while."}
99
+ {"type": "function", "name": "finished", "parameters": {"type": "object", "properties": {"content": {"type": "string", "description": "Provide the final answer or response to complete the task."}}, "required": []}, "description": "This function is used to indicate the completion of a task by providing the final answer or response."}
100
+
101
+ - To call a function, use the following structure without any suffix:
102
+
103
+ <gui_think> reasoning process </gui_think>
104
+ <seed:tool_call_never_used_51bce0c785ca2f68081bfa7d91973934><function_never_used_51bce0c785ca2f68081bfa7d91973934=example_function_name><parameter_never_used_51bce0c785ca2f68081bfa7d91973934=example_parameter_1>value_1</parameter_never_used_51bce0c785ca2f68081bfa7d91973934><parameter_never_used_51bce0c785ca2f68081bfa7d91973934=example_parameter_2>
105
+ This is the value for the second parameter
106
+ that can span
107
+ multiple lines
108
+ </parameter_never_used_51bce0c785ca2f68081bfa7d91973934></function_never_used_51bce0c785ca2f68081bfa7d91973934></seed:tool_call_never_used_51bce0c785ca2f68081bfa7d91973934>
109
+
110
+ ## Important Notes
111
+ - Function calls must begin with <function_never_used_51bce0c785ca2f68081bfa7d91973934= and end with </function_never_used_51bce0c785ca2f68081bfa7d91973934>.
112
+ - All required parameters must be explicitly provided.
113
+
114
+ ## Additional Notes
115
+ - You can execute multiple actions within a single tool call. For example:
116
+ <seed:tool_call_never_used_51bce0c785ca2f68081bfa7d91973934><function_never_used_51bce0c785ca2f68081bfa7d91973934=example_function_1><parameter_never_used_51bce0c785ca2f68081bfa7d91973934=example_parameter_1>value_1</parameter_never_used_51bce0c785ca2f68081bfa7d91973934><parameter_never_used_51bce0c785ca2f68081bfa7d91973934=example_parameter_2>
117
+ This is the value for the second parameter
118
+ that can span
119
+ multiple lines
120
+ </parameter_never_used_51bce0c785ca2f68081bfa7d91973934></function_never_used_51bce0c785ca2f68081bfa7d91973934><function_never_used_51bce0c785ca2f68081bfa7d91973934=example_function_2><parameter_never_used_51bce0c785ca2f68081bfa7d91973934=example_parameter_3>value_4</parameter_never_used_51bce0c785ca2f68081bfa7d91973934></function_never_used_51bce0c785ca2f68081bfa7d91973934></seed:tool_call_never_used_51bce0c785ca2f68081bfa7d91973934>
121
+ """`;
122
+
123
+ // src/ai.js
124
+ var import_path = __toESM(require("path"));
125
+ var logFile = import_path.default.join(process.cwd(), "ai_traffic.log");
126
+ var openai = (0, import_openai.createOpenAI)({
127
+ baseURL: BASE_URL,
128
+ apiKey: API_KEY,
129
+ compatibility: "compatible"
130
+ });
131
+ async function queryAI(messages) {
132
+ console.log("Querying AI with history length:", messages.length);
133
+ try {
134
+ console.log("\u23F3 \u53D1\u9001\u8BF7\u6C42\u4E2D...");
135
+ const startTime = Date.now();
136
+ const { text } = await (0, import_ai.generateText)({
137
+ model: openai.chat(ENDPOINT),
138
+ system: SYSTEM_PROMPT,
139
+ messages,
140
+ temperature: 0.1,
141
+ topP: 0.7
142
+ });
143
+ const endTime = Date.now();
144
+ console.log("\u2705 \u8BF7\u6C42\u6210\u529F! \u8017\u65F6:", (endTime - startTime) / 1e3, "\u79D2");
145
+ console.log("\u{1F4E5} \u54CD\u5E94\u5185\u5BB9:", text.substring(0, 500) + "...");
146
+ return text;
147
+ } catch (error) {
148
+ console.error("\u274C AI \u8BF7\u6C42\u5931\u8D25!", error);
149
+ return null;
150
+ }
151
+ }
152
+ function parseActions(aiContent) {
153
+ const actions = [];
154
+ const functionRegex = /<function[^>]*=([^>]+)>([\s\S]*?)<\/function[^>]*>/g;
155
+ let functionMatch;
156
+ while ((functionMatch = functionRegex.exec(aiContent)) !== null) {
157
+ const functionName = functionMatch[1];
158
+ const functionBody = functionMatch[2];
159
+ const params = {};
160
+ const paramRegex = /<parameter[^>]*=([^>]+)>([\s\S]*?)<\/parameter[^>]*>/g;
161
+ let paramMatch;
162
+ while ((paramMatch = paramRegex.exec(functionBody)) !== null) {
163
+ const paramName = paramMatch[1];
164
+ let paramValue = paramMatch[2].trim();
165
+ const cleanedValue = paramValue.replace(/<[^>]+>/g, "").trim();
166
+ params[paramName] = cleanedValue;
167
+ }
168
+ actions.push({
169
+ name: functionName,
170
+ params
171
+ });
172
+ }
173
+ return actions;
174
+ }
175
+
176
+ // src/actions.js
177
+ async function executeAction(page, action) {
178
+ console.log(`Executing action: ${action.name}`, action.params);
179
+ const { name, params } = action;
180
+ const viewport = page.viewportSize();
181
+ const transformPoint = (pointStr) => {
182
+ if (!pointStr) return null;
183
+ const [x, y] = pointStr.split(" ").map(Number);
184
+ if (!viewport) return { x, y };
185
+ const actualX = x / 1e3 * viewport.width;
186
+ const actualY = y / 1e3 * viewport.height;
187
+ return { x: actualX, y: actualY };
188
+ };
189
+ try {
190
+ switch (name) {
191
+ case "click":
192
+ if (params.point) {
193
+ const { x, y } = transformPoint(params.point);
194
+ console.log(`Executing click action: (${x}, ${y}) [Original: ${params.point}]`);
195
+ await page.mouse.click(x, y);
196
+ }
197
+ break;
198
+ case "left_double":
199
+ if (params.point) {
200
+ const { x, y } = transformPoint(params.point);
201
+ await page.mouse.dblclick(x, y);
202
+ }
203
+ break;
204
+ case "left_triple":
205
+ if (params.point) {
206
+ const { x, y } = transformPoint(params.point);
207
+ await page.mouse.click(x, y, { clickCount: 3 });
208
+ }
209
+ break;
210
+ case "right_single":
211
+ if (params.point) {
212
+ const { x, y } = transformPoint(params.point);
213
+ await page.mouse.click(x, y, { button: "right" });
214
+ }
215
+ break;
216
+ case "drag":
217
+ if (params.start_point && params.end_point) {
218
+ const start = transformPoint(params.start_point);
219
+ const end = transformPoint(params.end_point);
220
+ await page.mouse.move(start.x, start.y);
221
+ await page.mouse.down();
222
+ await page.mouse.move(end.x, end.y);
223
+ await page.mouse.up();
224
+ }
225
+ break;
226
+ case "move_to":
227
+ if (params.point) {
228
+ const { x, y } = transformPoint(params.point);
229
+ await page.mouse.move(x, y);
230
+ }
231
+ break;
232
+ case "mouse_down":
233
+ if (params.point) {
234
+ const { x, y } = transformPoint(params.point);
235
+ await page.mouse.move(x, y);
236
+ await page.mouse.down({ button: params.button || "left" });
237
+ } else {
238
+ await page.mouse.down({ button: params.button || "left" });
239
+ }
240
+ break;
241
+ case "mouse_up":
242
+ if (params.point) {
243
+ const { x, y } = transformPoint(params.point);
244
+ await page.mouse.move(x, y);
245
+ await page.mouse.up({ button: params.button || "left" });
246
+ } else {
247
+ await page.mouse.up({ button: params.button || "left" });
248
+ }
249
+ break;
250
+ case "type":
251
+ if (params.content) {
252
+ const content = params.content;
253
+ await page.keyboard.type(content);
254
+ }
255
+ break;
256
+ case "hotkey":
257
+ if (params.key) {
258
+ const keys = params.key.split(" ").join("+");
259
+ await page.keyboard.press(keys);
260
+ }
261
+ break;
262
+ case "press":
263
+ if (params.key) {
264
+ await page.keyboard.press(params.key);
265
+ }
266
+ break;
267
+ case "scroll":
268
+ const direction = params.direction;
269
+ if (direction === "down") {
270
+ await page.evaluate(() => window.scrollBy(0, 500));
271
+ } else if (direction === "up") {
272
+ await page.evaluate(() => window.scrollBy(0, -500));
273
+ }
274
+ break;
275
+ case "wait":
276
+ if (params.time) {
277
+ const ms = parseFloat(params.time) * 1e3;
278
+ await page.waitForTimeout(ms);
279
+ }
280
+ break;
281
+ case "finished":
282
+ console.log("AI Task Finished:", params.content);
283
+ return "FINISHED";
284
+ case "call_user":
285
+ console.log("AI requests user input:", params.content);
286
+ return "FINISHED";
287
+ default:
288
+ console.warn(`Unknown action: ${name}`);
289
+ }
290
+ } catch (e) {
291
+ console.error(`Failed to execute action ${name}:`, e);
292
+ }
293
+ return "CONTINUE";
294
+ }
295
+
296
+ // src/runner.js
297
+ async function runAgent({ targetUrl, taskInput, sessionId, simulatedUserKnownInfo }) {
298
+ console.log(`[Agent] Starting task: ${taskInput} on ${targetUrl} (Session: ${sessionId})`);
299
+ const screenshotsDir = import_path2.default.join(process.cwd(), "screenshots");
300
+ if (!import_fs.default.existsSync(screenshotsDir)) {
301
+ import_fs.default.mkdirSync(screenshotsDir, { recursive: true });
302
+ console.log(`\u{1F4C1} \u521B\u5EFA\u622A\u56FE\u76EE\u5F55: ${screenshotsDir}`);
303
+ }
304
+ const browser = await import_playwright.chromium.launch({
305
+ headless: true,
306
+ // Visible for demo/debug
307
+ args: ["--start-maximized"]
308
+ // Attempt to maximize
309
+ });
310
+ const context = await browser.newContext({
311
+ viewport: { width: 430, height: 800 }
312
+ // Set a reasonable fixed viewport
313
+ });
314
+ const page = await context.newPage();
315
+ let conversationHistory = [];
316
+ try {
317
+ let finalUrl = targetUrl;
318
+ if (!finalUrl.startsWith("http://") && !finalUrl.startsWith("https://")) {
319
+ finalUrl = "http://" + finalUrl;
320
+ }
321
+ const urlObj = new URL(finalUrl);
322
+ urlObj.searchParams.append("sessionId", sessionId);
323
+ finalUrl = urlObj.toString();
324
+ console.log(`Navigating to ${finalUrl}...`);
325
+ await page.goto(finalUrl, { waitUntil: "load" });
326
+ await page.waitForTimeout(2e3);
327
+ let isRunning = true;
328
+ let loopCount = 0;
329
+ const MAX_LOOPS = 20;
330
+ while (isRunning && loopCount < MAX_LOOPS) {
331
+ loopCount++;
332
+ console.log(`
333
+ --- Cycle ${loopCount} ---`);
334
+ const screenshotBuffer = await page.screenshot({ format: "png" });
335
+ const screenshotBase64 = screenshotBuffer.toString("base64");
336
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
337
+ const screenshotPath = import_path2.default.join(screenshotsDir, `screenshot_${sessionId}_${loopCount}_${timestamp}.png`);
338
+ import_fs.default.writeFileSync(screenshotPath, screenshotBuffer);
339
+ console.log(`\u{1F4F8} \u622A\u56FE\u5DF2\u4FDD\u5B58: ${screenshotPath}`);
340
+ const viewport = page.viewportSize();
341
+ console.log(`\u{1F4D0} Viewport\u5C3A\u5BF8: ${viewport.width}x${viewport.height}`);
342
+ console.log(`\u{1F4E6} \u622A\u56FE\u5927\u5C0F: ${screenshotBuffer.length} bytes`);
343
+ let promptText = `Task: ${taskInput}
344
+ `;
345
+ if (simulatedUserKnownInfo) {
346
+ promptText += `
347
+ Known User Info: ${JSON.stringify(simulatedUserKnownInfo, null, 2)}
348
+ `;
349
+ }
350
+ promptText += `
351
+ Please perform the next action based on the screenshot.`;
352
+ const userContent = [
353
+ { type: "text", text: promptText },
354
+ { type: "image", image: screenshotBase64 }
355
+ ];
356
+ conversationHistory.push({
357
+ role: "user",
358
+ content: userContent
359
+ });
360
+ console.log("Querying AI...");
361
+ const aiContent = await queryAI(conversationHistory);
362
+ if (!aiContent) {
363
+ console.error("Invalid AI response. Retrying...");
364
+ await page.waitForTimeout(2e3);
365
+ continue;
366
+ }
367
+ conversationHistory.push({
368
+ role: "assistant",
369
+ content: aiContent
370
+ });
371
+ console.log("Raw AI Content (Excerpt):", aiContent);
372
+ const actions = parseActions(aiContent);
373
+ if (actions.length === 0) {
374
+ console.log("No actions parsed from AI response.");
375
+ }
376
+ console.log("Actions:", actions);
377
+ for (const action of actions) {
378
+ const result = await executeAction(page, action);
379
+ console.log("Action result:", result);
380
+ if (result === "FINISHED") {
381
+ isRunning = false;
382
+ break;
383
+ }
384
+ }
385
+ if (isRunning) {
386
+ await page.waitForTimeout(3e3);
387
+ }
388
+ }
389
+ return { status: "success", message: "Task completed", messages: conversationHistory };
390
+ } catch (error) {
391
+ console.error("Runtime Custom Error:", error);
392
+ return { status: "error", message: error.message };
393
+ } finally {
394
+ console.log("Closing browser...");
395
+ await browser.close();
396
+ }
397
+ }
398
+
399
+ // src/index.js
400
+ var import_adm_zip = __toESM(require("adm-zip"));
401
+ var import_dotenv2 = __toESM(require("dotenv"));
402
+ import_dotenv2.default.config();
403
+ function getFormattedDate() {
404
+ const now = /* @__PURE__ */ new Date();
405
+ const pad = (n) => String(n).padStart(2, "0");
406
+ return `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}_${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
407
+ }
408
+ async function runTaskLoop(targetWeb, targetServer, taskId) {
409
+ const results = [];
410
+ const datetime = getFormattedDate();
411
+ const folderName = `${taskId}_${datetime}`;
412
+ const outputDir = import_path3.default.join(process.cwd(), folderName);
413
+ if (!import_fs2.default.existsSync(outputDir)) {
414
+ import_fs2.default.mkdirSync(outputDir, { recursive: true });
415
+ console.log(`Created output directory: ${outputDir}`);
416
+ }
417
+ if (!targetWeb.startsWith("http")) targetWeb = "http://" + targetWeb;
418
+ if (!targetServer.startsWith("http")) targetServer = "http://" + targetServer;
419
+ console.log(`Starting Task Loop for ${taskId}`);
420
+ for (let i = 1; i <= 2; i++) {
421
+ console.log(`
422
+ === Starting Iteration ${i}/5 ===`);
423
+ try {
424
+ const data = await executeSingleCycle(targetWeb, targetServer, taskId, i);
425
+ const { sessionId, agentMessages, ...rest } = data;
426
+ const sessionDir = import_path3.default.join(outputDir, sessionId);
427
+ if (!import_fs2.default.existsSync(sessionDir)) {
428
+ import_fs2.default.mkdirSync(sessionDir, { recursive: true });
429
+ }
430
+ import_fs2.default.writeFileSync(
431
+ import_path3.default.join(sessionDir, "messages.json"),
432
+ JSON.stringify(agentMessages, null, 2)
433
+ );
434
+ import_fs2.default.writeFileSync(
435
+ import_path3.default.join(sessionDir, "result.json"),
436
+ JSON.stringify(rest, null, 2)
437
+ );
438
+ results.push({ sessionId, ...rest });
439
+ console.log(`Iteration ${i} completed. Saved to ${sessionDir}`);
440
+ } catch (e) {
441
+ console.error(`Iteration ${i} failed:`, e.stack || e.message);
442
+ results.push({ iteration: i, error: e.message });
443
+ }
444
+ }
445
+ const finalResultPath = import_path3.default.join(outputDir, "final-results.json");
446
+ import_fs2.default.writeFileSync(finalResultPath, JSON.stringify(results, null, 2));
447
+ console.log(`Saved consolidated results to ${finalResultPath}`);
448
+ console.log("Packaging results into ZIP...");
449
+ const zipName = `${folderName}.zip`;
450
+ const zipPath = import_path3.default.join(process.cwd(), zipName);
451
+ try {
452
+ const zip = new import_adm_zip.default();
453
+ zip.addLocalFolder(outputDir, folderName);
454
+ zip.writeZip(zipPath);
455
+ console.log(`
456
+ \u2705 All done! Zip saved to: ${zipPath}`);
457
+ } catch (zipError) {
458
+ console.error("Failed to create zip:", zipError);
459
+ }
460
+ return zipPath;
461
+ }
462
+ async function executeSingleCycle(targetWeb, targetServer, taskId, iteration) {
463
+ const fetchJson = async (url, opts) => {
464
+ const res = await fetch(url, opts);
465
+ if (!res.ok) {
466
+ const text = await res.text();
467
+ throw new Error(`API ${url} failed: ${res.status} ${text}`);
468
+ }
469
+ return await res.json();
470
+ };
471
+ console.log("Calling Start API...");
472
+ const startUrl = `${targetServer}/api/tasks/${taskId}/start`;
473
+ const startData = await fetchJson(startUrl, { method: "POST" });
474
+ if (startData.code !== 200) {
475
+ throw new Error(`Start API failed: ${JSON.stringify(startData)}`);
476
+ }
477
+ const { session_id: sessionId, TaskJson } = startData.data;
478
+ console.log(`Setup for session ${sessionId}...`);
479
+ const setupUrl = `${targetServer}/api/setup/run`;
480
+ await fetchJson(setupUrl, {
481
+ method: "POST",
482
+ headers: { "Content-Type": "application/json" },
483
+ body: JSON.stringify({ task_id: taskId, session_id: sessionId })
484
+ });
485
+ console.log("Running Agent...");
486
+ const agentResult = await runAgent({
487
+ taskInput: TaskJson.task.instruction,
488
+ targetUrl: targetWeb,
489
+ sessionId,
490
+ simulatedUserKnownInfo: TaskJson.task.simulated_user_known_info
491
+ });
492
+ console.log("Verifying result...");
493
+ const verifyUrl = `${targetServer}/api/verify/run`;
494
+ const verifyData = await fetchJson(verifyUrl, {
495
+ method: "POST",
496
+ headers: { "Content-Type": "application/json" },
497
+ body: JSON.stringify({ task_id: taskId, session_id: sessionId })
498
+ });
499
+ console.log("Verifying result...", verifyData);
500
+ return {
501
+ iteration,
502
+ sessionId,
503
+ agentStatus: agentResult.status,
504
+ agentMessages: agentResult.messages || [],
505
+ verifyResult: verifyData.data
506
+ };
507
+ }
508
+ // Annotate the CommonJS export names for ESM import in node:
509
+ 0 && (module.exports = {
510
+ runAgent,
511
+ runTaskLoop
512
+ });