lybic-guiagents 0.3.0__py3-none-any.whl → 0.4.0__py3-none-any.whl
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.
Potentially problematic release.
This version of lybic-guiagents might be problematic. Click here for more details.
- gui_agents/__init__.py +1 -1
- gui_agents/agents/agent_s.py +28 -17
- gui_agents/agents/grounding.py +14 -4
- gui_agents/agents/manager.py +8 -1
- gui_agents/agents/worker.py +8 -2
- gui_agents/cli_app.py +236 -220
- gui_agents/grpc_app.py +118 -50
- gui_agents/service/agent_service.py +51 -34
- gui_agents/store/registry.py +114 -6
- {lybic_guiagents-0.3.0.dist-info → lybic_guiagents-0.4.0.dist-info}/METADATA +6 -6
- {lybic_guiagents-0.3.0.dist-info → lybic_guiagents-0.4.0.dist-info}/RECORD +15 -15
- {lybic_guiagents-0.3.0.dist-info → lybic_guiagents-0.4.0.dist-info}/WHEEL +0 -0
- {lybic_guiagents-0.3.0.dist-info → lybic_guiagents-0.4.0.dist-info}/entry_points.txt +0 -0
- {lybic_guiagents-0.3.0.dist-info → lybic_guiagents-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {lybic_guiagents-0.3.0.dist-info → lybic_guiagents-0.4.0.dist-info}/top_level.txt +0 -0
gui_agents/cli_app.py
CHANGED
|
@@ -107,7 +107,7 @@ def validate_backend_compatibility(backend, compatible_backends, incompatible_ba
|
|
|
107
107
|
return True, backend, f"Unknown backend '{backend}', compatibility cannot be determined."
|
|
108
108
|
|
|
109
109
|
logger = logging.getLogger()
|
|
110
|
-
logger.setLevel(
|
|
110
|
+
logger.setLevel(os.environ.get("LOG_LEVEL", "INFO").upper())
|
|
111
111
|
|
|
112
112
|
datetime_str: str = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
113
113
|
|
|
@@ -258,7 +258,7 @@ def scale_screenshot_dimensions(screenshot: Image.Image, hwi_para: HardwareInter
|
|
|
258
258
|
|
|
259
259
|
return screenshot
|
|
260
260
|
|
|
261
|
-
def run_agent_normal(agent, instruction: str, hwi_para: HardwareInterface, max_steps: int = 50, enable_takeover: bool = False):
|
|
261
|
+
def run_agent_normal(agent, instruction: str, hwi_para: HardwareInterface, max_steps: int = 50, enable_takeover: bool = False, task_id: str | None = None, task_registry: Registry | None = None):
|
|
262
262
|
"""
|
|
263
263
|
Run an agent in normal mode to iteratively observe, plan, and execute actions for a given instruction.
|
|
264
264
|
|
|
@@ -270,246 +270,262 @@ def run_agent_normal(agent, instruction: str, hwi_para: HardwareInterface, max_s
|
|
|
270
270
|
hwi_para (HardwareInterface): Hardware interface used to capture screenshots and dispatch actions.
|
|
271
271
|
max_steps (int): Maximum number of agent prediction/execute cycles to run.
|
|
272
272
|
enable_takeover (bool): If True, the agent may request a user takeover that pauses execution until the user resumes.
|
|
273
|
+
task_id (str | None): Optional task ID for context.
|
|
274
|
+
task_registry (Registry | None): Optional task-specific registry.
|
|
273
275
|
"""
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
276
|
+
if task_registry:
|
|
277
|
+
Registry.set_task_registry(task_id, task_registry)
|
|
278
|
+
|
|
279
|
+
try:
|
|
280
|
+
import time
|
|
281
|
+
obs = {}
|
|
282
|
+
traj = "Task:\n" + instruction
|
|
283
|
+
subtask_traj = ""
|
|
284
|
+
global_state: GlobalState = agent.global_state # type: ignore
|
|
285
|
+
global_state.set_Tu(instruction)
|
|
286
|
+
global_state.set_running_state("running")
|
|
287
|
+
hwi = hwi_para
|
|
288
|
+
|
|
289
|
+
total_start_time = time.time()
|
|
290
|
+
for _ in range(max_steps):
|
|
291
|
+
while global_state.get_running_state() == "stopped":
|
|
292
|
+
user_input = input(
|
|
293
|
+
"Agent execution is paused. Enter 'continue' to resume: ")
|
|
294
|
+
if user_input == "continue":
|
|
295
|
+
global_state.set_running_state("running")
|
|
296
|
+
logger.info("Agent execution resumed by user")
|
|
297
|
+
break
|
|
298
|
+
time.sleep(0.5)
|
|
299
|
+
|
|
300
|
+
screenshot: Image.Image = hwi.dispatch(Screenshot()) # type: ignore
|
|
301
|
+
global_state.set_screenshot(
|
|
302
|
+
scale_screenshot_dimensions(screenshot, hwi_para)) # type: ignore
|
|
303
|
+
obs = global_state.get_obs_for_manager()
|
|
304
|
+
|
|
305
|
+
predict_start = time.time()
|
|
306
|
+
info, code = agent.predict(instruction=instruction, observation=obs)
|
|
307
|
+
predict_time = time.time() - predict_start
|
|
308
|
+
logger.info(
|
|
309
|
+
f"[Step Timing] agent.predict execution time: {predict_time:.2f} seconds"
|
|
310
|
+
)
|
|
305
311
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
312
|
+
global_state.log_operation(module="agent",
|
|
313
|
+
operation="agent.predict",
|
|
314
|
+
data={"duration": predict_time})
|
|
315
|
+
|
|
316
|
+
if "done" in code[0]["type"].lower() or "fail" in code[0]["type"].lower(
|
|
317
|
+
):
|
|
318
|
+
if platform.system() == "Darwin":
|
|
319
|
+
os.system(
|
|
320
|
+
f'osascript -e \'display dialog "Task Completed" with title "OpenACI Agent" buttons "OK" default button "OK"\''
|
|
321
|
+
)
|
|
322
|
+
elif platform.system() == "Linux" and not (hwi_para.backend== "lybic" or isinstance(hwi_para.backend, LybicBackend)):
|
|
323
|
+
os.system(
|
|
324
|
+
f'zenity --info --title="OpenACI Agent" --text="Task Completed" --width=200 --height=100'
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
agent.update_narrative_memory(traj)
|
|
328
|
+
break
|
|
309
329
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
330
|
+
if "next" in code[0]["type"].lower():
|
|
331
|
+
continue
|
|
332
|
+
|
|
333
|
+
if "wait" in code[0]["type"].lower():
|
|
334
|
+
time.sleep(5)
|
|
335
|
+
continue
|
|
336
|
+
|
|
337
|
+
if enable_takeover and "usertakeover" in code[0]["type"].lower():
|
|
338
|
+
message = code[0].get("message", "need user takeover")
|
|
339
|
+
logger.info(f"User takeover request: {message}")
|
|
340
|
+
|
|
341
|
+
global_state.set_running_state("stopped")
|
|
342
|
+
|
|
343
|
+
if platform.system() == "Darwin":
|
|
344
|
+
os.system(
|
|
345
|
+
f'osascript -e \'display dialog "{message}" with title "User takeover request" buttons "Continue" default button "Continue"\''
|
|
346
|
+
)
|
|
347
|
+
elif platform.system() == "Linux":
|
|
348
|
+
os.system(
|
|
349
|
+
f'zenity --info --title="User takeover request" --text="{message}" --width=300 --height=150'
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
logger.info("Agent execution paused waiting for user takeover")
|
|
353
|
+
continue
|
|
354
|
+
elif not enable_takeover and "usertakeover" in code[0]["type"].lower():
|
|
355
|
+
logger.info(
|
|
356
|
+
f"User takeover request received but takeover is disabled. Continuing execution."
|
|
319
357
|
)
|
|
358
|
+
continue
|
|
320
359
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
if enable_takeover and "usertakeover" in code[0]["type"].lower():
|
|
332
|
-
message = code[0].get("message", "need user takeover")
|
|
333
|
-
logger.info(f"User takeover request: {message}")
|
|
334
|
-
|
|
335
|
-
global_state.set_running_state("stopped")
|
|
336
|
-
|
|
337
|
-
if platform.system() == "Darwin":
|
|
338
|
-
os.system(
|
|
339
|
-
f'osascript -e \'display dialog "{message}" with title "User takeover request" buttons "Continue" default button "Continue"\''
|
|
340
|
-
)
|
|
341
|
-
elif platform.system() == "Linux":
|
|
342
|
-
os.system(
|
|
343
|
-
f'zenity --info --title="User takeover request" --text="{message}" --width=300 --height=150'
|
|
360
|
+
else:
|
|
361
|
+
time.sleep(1.0)
|
|
362
|
+
logger.info(f"EXECUTING CODE: {code[0]}")
|
|
363
|
+
|
|
364
|
+
step_dispatch_start = time.time()
|
|
365
|
+
hwi.dispatchDict(code[0])
|
|
366
|
+
step_dispatch_time = time.time() - step_dispatch_start
|
|
367
|
+
logger.info(
|
|
368
|
+
f"[Step Timing] hwi.dispatchDict execution time: {step_dispatch_time:.2f} seconds"
|
|
344
369
|
)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
"\n\n----------------------\n\nPlan:\n" +
|
|
379
|
-
info.get("executor_plan", ""))
|
|
380
|
-
subtask_traj = agent.update_episodic_memory(info, subtask_traj)
|
|
381
|
-
|
|
382
|
-
total_end_time = time.time()
|
|
383
|
-
total_duration = total_end_time - total_start_time
|
|
384
|
-
logger.info(
|
|
385
|
-
f"[Total Timing] Total execution time for this task: {total_duration:.2f} seconds"
|
|
386
|
-
)
|
|
387
|
-
global_state.log_operation(module="other",
|
|
388
|
-
operation="total_execution_time",
|
|
389
|
-
data={"duration": total_duration})
|
|
390
|
-
|
|
391
|
-
# Auto-analyze execution statistics after task completion
|
|
392
|
-
timestamp_dir = os.path.join(log_dir, datetime_str)
|
|
393
|
-
auto_analyze_execution(timestamp_dir)
|
|
370
|
+
logger.info(f"HARDWARE INTERFACE: Executed")
|
|
371
|
+
|
|
372
|
+
# Record executed code and time
|
|
373
|
+
global_state.log_operation(module="hardware",
|
|
374
|
+
operation="executing_code",
|
|
375
|
+
data={"content": str(code[0])})
|
|
376
|
+
global_state.log_operation(module="hardware",
|
|
377
|
+
operation="hwi.dispatchDict",
|
|
378
|
+
data={"duration": step_dispatch_time})
|
|
379
|
+
|
|
380
|
+
time.sleep(1.0)
|
|
381
|
+
|
|
382
|
+
# Update task and subtask trajectories and optionally the episodic memory
|
|
383
|
+
traj += ("\n\nReflection:\n" + str(info.get("reflection", "")) +
|
|
384
|
+
"\n\n----------------------\n\nPlan:\n" +
|
|
385
|
+
info.get("executor_plan", ""))
|
|
386
|
+
subtask_traj = agent.update_episodic_memory(info, subtask_traj)
|
|
387
|
+
|
|
388
|
+
total_end_time = time.time()
|
|
389
|
+
total_duration = total_end_time - total_start_time
|
|
390
|
+
logger.info(
|
|
391
|
+
f"[Total Timing] Total execution time for this task: {total_duration:.2f} seconds"
|
|
392
|
+
)
|
|
393
|
+
global_state.log_operation(module="other",
|
|
394
|
+
operation="total_execution_time",
|
|
395
|
+
data={"duration": total_duration})
|
|
396
|
+
|
|
397
|
+
# Auto-analyze execution statistics after task completion
|
|
398
|
+
timestamp_dir = os.path.join(log_dir, datetime_str)
|
|
399
|
+
auto_analyze_execution(timestamp_dir)
|
|
400
|
+
finally:
|
|
401
|
+
if task_registry:
|
|
402
|
+
Registry.remove_task_registry(task_id)
|
|
394
403
|
|
|
395
404
|
|
|
396
405
|
def run_agent_fast(agent,
|
|
397
406
|
instruction: str,
|
|
398
407
|
hwi_para: HardwareInterface,
|
|
399
408
|
max_steps: int = 50,
|
|
400
|
-
enable_takeover: bool = False):
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
global_state.log_operation(module="agent_fast",
|
|
433
|
-
operation="agent.predict_fast",
|
|
434
|
-
data={
|
|
435
|
-
"duration": predict_time,
|
|
436
|
-
"step": step + 1
|
|
437
|
-
})
|
|
438
|
-
|
|
439
|
-
if "done" in code[0]["type"].lower() or "fail" in code[0]["type"].lower(
|
|
440
|
-
):
|
|
409
|
+
enable_takeover: bool = False, task_id: str | None = None, task_registry: Registry | None = None):
|
|
410
|
+
if task_registry:
|
|
411
|
+
Registry.set_task_registry(task_id, task_registry)
|
|
412
|
+
|
|
413
|
+
try:
|
|
414
|
+
import time
|
|
415
|
+
obs = {}
|
|
416
|
+
global_state: GlobalState = agent.global_state # type: ignore
|
|
417
|
+
global_state.set_Tu(instruction)
|
|
418
|
+
global_state.set_running_state("running")
|
|
419
|
+
hwi = hwi_para
|
|
420
|
+
|
|
421
|
+
total_start_time = time.time()
|
|
422
|
+
for step in range(max_steps):
|
|
423
|
+
while global_state.get_running_state() == "stopped":
|
|
424
|
+
user_input = input(
|
|
425
|
+
"Agent execution is paused. Enter 'continue' to resume: ")
|
|
426
|
+
if user_input == "continue":
|
|
427
|
+
global_state.set_running_state("running")
|
|
428
|
+
logger.info("[Fast Mode] Agent execution resumed by user")
|
|
429
|
+
break
|
|
430
|
+
time.sleep(0.5)
|
|
431
|
+
|
|
432
|
+
screenshot: Image.Image = hwi.dispatch(Screenshot()) # type: ignore
|
|
433
|
+
global_state.set_screenshot(
|
|
434
|
+
scale_screenshot_dimensions(screenshot, hwi_para)) # type: ignore
|
|
435
|
+
obs = global_state.get_obs_for_manager()
|
|
436
|
+
|
|
437
|
+
predict_start = time.time()
|
|
438
|
+
info, code = agent.predict(instruction=instruction,
|
|
439
|
+
observation=obs)
|
|
440
|
+
predict_time = time.time() - predict_start
|
|
441
441
|
logger.info(
|
|
442
|
-
f"[Fast Mode]
|
|
442
|
+
f"[Fast Mode] [Step {step+1}] Prediction time: {predict_time:.2f} seconds"
|
|
443
443
|
)
|
|
444
|
-
if platform.system() == "Darwin":
|
|
445
|
-
os.system(
|
|
446
|
-
f'osascript -e \'display dialog "Task Completed" with title "OpenACI Agent (Fast)" buttons "OK" default button "OK"\''
|
|
447
|
-
)
|
|
448
|
-
elif platform.system() == "Linux" and not (hwi_para.backend== "lybic" or isinstance(hwi_para.backend, LybicBackend)):
|
|
449
|
-
os.system(
|
|
450
|
-
f'zenity --info --title="OpenACI Agent (Fast)" --text="Task Completed" --width=200 --height=100'
|
|
451
|
-
)
|
|
452
|
-
break
|
|
453
|
-
|
|
454
|
-
if "wait" in code[0]["type"].lower():
|
|
455
|
-
wait_duration = code[0].get("duration", 5000) / 1000
|
|
456
|
-
logger.info(f"[Fast Mode] Waiting for {wait_duration} seconds")
|
|
457
|
-
time.sleep(wait_duration)
|
|
458
|
-
continue
|
|
459
444
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
445
|
+
global_state.log_operation(module="agent_fast",
|
|
446
|
+
operation="agent.predict_fast",
|
|
447
|
+
data={
|
|
448
|
+
"duration": predict_time,
|
|
449
|
+
"step": step + 1
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
if "done" in code[0]["type"].lower() or "fail" in code[0]["type"].lower(
|
|
453
|
+
):
|
|
454
|
+
logger.info(
|
|
455
|
+
f"[Fast Mode] Task {'completed' if 'done' in code[0]['type'].lower() else 'failed'}"
|
|
469
456
|
)
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
457
|
+
if platform.system() == "Darwin":
|
|
458
|
+
os.system(
|
|
459
|
+
f'osascript -e \'display dialog "Task Completed" with title "OpenACI Agent (Fast)" buttons "OK" default button "OK"\''
|
|
460
|
+
)
|
|
461
|
+
elif platform.system() == "Linux" and not (hwi_para.backend== "lybic" or isinstance(hwi_para.backend, LybicBackend)):
|
|
462
|
+
os.system(
|
|
463
|
+
f'zenity --info --title="OpenACI Agent (Fast)" --text="Task Completed" --width=200 --height=100'
|
|
464
|
+
)
|
|
465
|
+
break
|
|
466
|
+
|
|
467
|
+
if "wait" in code[0]["type"].lower():
|
|
468
|
+
wait_duration = code[0].get("duration", 5000) / 1000
|
|
469
|
+
logger.info(f"[Fast Mode] Waiting for {wait_duration} seconds")
|
|
470
|
+
time.sleep(wait_duration)
|
|
471
|
+
continue
|
|
472
|
+
|
|
473
|
+
if enable_takeover and "usertakeover" in code[0]["type"].lower():
|
|
474
|
+
message = code[0].get("message", "need user takeover")
|
|
475
|
+
logger.info(f"[Fast Mode] User takeover request: {message}")
|
|
476
|
+
|
|
477
|
+
global_state.set_running_state("stopped")
|
|
478
|
+
|
|
479
|
+
if platform.system() == "Darwin":
|
|
480
|
+
os.system(
|
|
481
|
+
f'osascript -e \'display dialog "{message}" with title "User takeover request (Fast)" buttons "Continue" default button "Continue"\''
|
|
482
|
+
)
|
|
483
|
+
elif platform.system() == "Linux":
|
|
484
|
+
os.system(
|
|
485
|
+
f'zenity --info --title="User takeover request (Fast)" --text="{message}" --width=300 --height=150'
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
logger.info(
|
|
489
|
+
"[Fast Mode] Agent execution paused waiting for user takeover")
|
|
490
|
+
continue
|
|
491
|
+
elif not enable_takeover and "usertakeover" in code[0]["type"].lower():
|
|
492
|
+
logger.info(
|
|
493
|
+
f"[Fast Mode] User takeover request received but takeover is disabled. Continuing execution."
|
|
473
494
|
)
|
|
495
|
+
continue
|
|
474
496
|
|
|
497
|
+
logger.info(f"[Fast Mode] Executing action: {code[0]}")
|
|
498
|
+
step_dispatch_start = time.time()
|
|
499
|
+
hwi.dispatchDict(code[0])
|
|
500
|
+
step_dispatch_time = time.time() - step_dispatch_start
|
|
475
501
|
logger.info(
|
|
476
|
-
"[Fast Mode]
|
|
477
|
-
continue
|
|
478
|
-
elif not enable_takeover and "usertakeover" in code[0]["type"].lower():
|
|
479
|
-
logger.info(
|
|
480
|
-
f"[Fast Mode] User takeover request received but takeover is disabled. Continuing execution."
|
|
502
|
+
f"[Fast Mode] Action execution time: {step_dispatch_time:.2f} seconds"
|
|
481
503
|
)
|
|
482
|
-
continue
|
|
483
504
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
505
|
+
global_state.log_operation(module="hardware_fast",
|
|
506
|
+
operation="executing_code_fast",
|
|
507
|
+
data={
|
|
508
|
+
"content": str(code[0]),
|
|
509
|
+
"duration": step_dispatch_time,
|
|
510
|
+
"step": step + 1
|
|
511
|
+
})
|
|
491
512
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
data={"duration": total_duration})
|
|
509
|
-
|
|
510
|
-
# Auto-analyze execution statistics after task completion
|
|
511
|
-
timestamp_dir = os.path.join(log_dir, datetime_str)
|
|
512
|
-
auto_analyze_execution(timestamp_dir)
|
|
513
|
+
time.sleep(0.5)
|
|
514
|
+
|
|
515
|
+
total_end_time = time.time()
|
|
516
|
+
total_duration = total_end_time - total_start_time
|
|
517
|
+
logger.info(
|
|
518
|
+
f"[Fast Mode] Total execution time: {total_duration:.2f} seconds")
|
|
519
|
+
global_state.log_operation(module="other",
|
|
520
|
+
operation="total_execution_time_fast",
|
|
521
|
+
data={"duration": total_duration})
|
|
522
|
+
|
|
523
|
+
# Auto-analyze execution statistics after task completion
|
|
524
|
+
timestamp_dir = os.path.join(log_dir, datetime_str)
|
|
525
|
+
auto_analyze_execution(timestamp_dir)
|
|
526
|
+
finally:
|
|
527
|
+
if task_registry:
|
|
528
|
+
Registry.remove_task_registry(task_id)
|
|
513
529
|
|
|
514
530
|
|
|
515
531
|
def main():
|