HongzeFu commited on
Commit
8aaa540
·
1 Parent(s): cf030f7

system log executing!

Browse files
gradio-web/config.py CHANGED
@@ -65,6 +65,7 @@ UI_TEXT = {
65
  "log": {
66
  "action_selection_prompt": "Please select the action.\nActions with 🎯 need to select a point on the image as input",
67
  "point_selection_prompt": "Current action needs location input, please click on the image to select key pixel",
 
68
  "demo_video_prompt": 'Press "Watch Video Input 🎬" to watch a video\nNote: you can only watch the video once',
69
  "session_error": "Session expired. Please refresh the page and try again.",
70
  "reference_action_error": "Ground Truth Action Error: {error}",
 
65
  "log": {
66
  "action_selection_prompt": "Please select the action.\nActions with 🎯 need to select a point on the image as input",
67
  "point_selection_prompt": "Current action needs location input, please click on the image to select key pixel",
68
+ "execute_action_prompt": "Executing Action {label}",
69
  "demo_video_prompt": 'Press "Watch Video Input 🎬" to watch a video\nNote: you can only watch the video once',
70
  "session_error": "Session expired. Please refresh the page and try again.",
71
  "reference_action_error": "Ground Truth Action Error: {error}",
gradio-web/gradio_callbacks.py CHANGED
@@ -62,10 +62,41 @@ def _point_selection_log():
62
  return format_log_markdown(_ui_text("log", "point_selection_prompt"))
63
 
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  def _default_post_execute_log_state():
66
  return {
67
  "preserve_terminal_log": False,
68
  "terminal_log_value": None,
 
 
69
  }
70
 
71
 
@@ -78,9 +109,17 @@ def _normalize_post_execute_log_state(state):
78
  preserve_terminal_log = False
79
  else:
80
  terminal_log_value = str(terminal_log_value)
 
 
 
 
 
 
81
  return {
82
  "preserve_terminal_log": preserve_terminal_log,
83
  "terminal_log_value": terminal_log_value,
 
 
84
  }
85
  return _default_post_execute_log_state()
86
 
@@ -487,9 +526,11 @@ def on_execute_video_end_transition(
487
  """Transition from execute video phase back to the action phase."""
488
  controls_state = _normalize_post_execute_controls_state(post_execute_controls_state)
489
  log_state = _normalize_post_execute_log_state(post_execute_log_state)
490
- log_update = gr.update()
 
491
  if log_state["preserve_terminal_log"]:
492
  log_update = gr.update(value=log_state["terminal_log_value"])
 
493
  LOGGER.debug(
494
  "on_execute_video_end_transition uid=%s controls_state=%s log_state=%s",
495
  _uid_for_log(uid),
@@ -508,6 +549,7 @@ def on_execute_video_end_transition(
508
  log_update, # log_output
509
  gr.update(interactive=controls_state["reference_action_interactive"]), # reference_action_btn
510
  gr.update(interactive=True), # task_hint_display
 
511
  "action_point", # ui_phase_state
512
  )
513
 
@@ -928,6 +970,20 @@ def on_option_select(
928
  False,
929
  normalized_post_execute_log_state,
930
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
931
 
932
  if option_value is None:
933
  LOGGER.debug("on_option_select uid=%s option=None", _uid_for_log(uid))
@@ -1445,10 +1501,20 @@ def execute_step(uid, option_idx, coords_str):
1445
 
1446
  # 格式化日志消息为 HTML 格式(支持颜色显示)
1447
  formatted_status = format_log_markdown(status)
 
 
 
 
 
 
 
 
1448
  if done:
1449
  post_execute_log_state = {
1450
  "preserve_terminal_log": True,
1451
  "terminal_log_value": formatted_status,
 
 
1452
  }
1453
  LOGGER.debug(
1454
  "execute_step done uid=%s env=%s ep=%s done=%s post_execute_controls=%s post_execute_log=%s show_execution_video=%s",
 
62
  return format_log_markdown(_ui_text("log", "point_selection_prompt"))
63
 
64
 
65
+ def _get_raw_option_label(session, option_idx):
66
+ try:
67
+ option_index = int(option_idx)
68
+ except (TypeError, ValueError):
69
+ return None
70
+
71
+ raw_solve_options = getattr(session, "raw_solve_options", None)
72
+ if not isinstance(raw_solve_options, list):
73
+ return None
74
+ if not (0 <= option_index < len(raw_solve_options)):
75
+ return None
76
+
77
+ raw_option = raw_solve_options[option_index]
78
+ if not isinstance(raw_option, dict):
79
+ return None
80
+
81
+ label = str(raw_option.get("label", "")).strip()
82
+ return label or None
83
+
84
+
85
+ def _execution_video_log(session, option_idx, fallback_status=None):
86
+ label = _get_raw_option_label(session, option_idx)
87
+ if label:
88
+ return format_log_markdown(_ui_text("log", "execute_action_prompt", label=label))
89
+ if fallback_status is None:
90
+ return None
91
+ return format_log_markdown(fallback_status)
92
+
93
+
94
  def _default_post_execute_log_state():
95
  return {
96
  "preserve_terminal_log": False,
97
  "terminal_log_value": None,
98
+ "preserve_execute_video_log": False,
99
+ "execute_video_log_value": None,
100
  }
101
 
102
 
 
109
  preserve_terminal_log = False
110
  else:
111
  terminal_log_value = str(terminal_log_value)
112
+ preserve_execute_video_log = bool(state.get("preserve_execute_video_log", False))
113
+ execute_video_log_value = state.get("execute_video_log_value")
114
+ if execute_video_log_value is None:
115
+ preserve_execute_video_log = False
116
+ else:
117
+ execute_video_log_value = str(execute_video_log_value)
118
  return {
119
  "preserve_terminal_log": preserve_terminal_log,
120
  "terminal_log_value": terminal_log_value,
121
+ "preserve_execute_video_log": preserve_execute_video_log,
122
+ "execute_video_log_value": execute_video_log_value,
123
  }
124
  return _default_post_execute_log_state()
125
 
 
526
  """Transition from execute video phase back to the action phase."""
527
  controls_state = _normalize_post_execute_controls_state(post_execute_controls_state)
528
  log_state = _normalize_post_execute_log_state(post_execute_log_state)
529
+ next_log_state = _default_post_execute_log_state()
530
+ log_update = gr.update(value=_action_selection_log())
531
  if log_state["preserve_terminal_log"]:
532
  log_update = gr.update(value=log_state["terminal_log_value"])
533
+ next_log_state = log_state
534
  LOGGER.debug(
535
  "on_execute_video_end_transition uid=%s controls_state=%s log_state=%s",
536
  _uid_for_log(uid),
 
549
  log_update, # log_output
550
  gr.update(interactive=controls_state["reference_action_interactive"]), # reference_action_btn
551
  gr.update(interactive=True), # task_hint_display
552
+ next_log_state, # post_execute_log_state
553
  "action_point", # ui_phase_state
554
  )
555
 
 
970
  False,
971
  normalized_post_execute_log_state,
972
  )
973
+
974
+ if normalized_post_execute_log_state["preserve_execute_video_log"]:
975
+ LOGGER.debug(
976
+ "on_option_select preserving execution-video log uid=%s option=%s",
977
+ _uid_for_log(uid),
978
+ option_value,
979
+ )
980
+ return (
981
+ gr.update(),
982
+ gr.update(),
983
+ gr.update(value=normalized_post_execute_log_state["execute_video_log_value"]),
984
+ False,
985
+ normalized_post_execute_log_state,
986
+ )
987
 
988
  if option_value is None:
989
  LOGGER.debug("on_option_select uid=%s option=None", _uid_for_log(uid))
 
1501
 
1502
  # 格式化日志消息为 HTML 格式(支持颜色显示)
1503
  formatted_status = format_log_markdown(status)
1504
+ if show_execution_video and not done:
1505
+ formatted_status = _execution_video_log(session, option_idx, fallback_status=status) or formatted_status
1506
+ post_execute_log_state = {
1507
+ "preserve_terminal_log": False,
1508
+ "terminal_log_value": None,
1509
+ "preserve_execute_video_log": True,
1510
+ "execute_video_log_value": formatted_status,
1511
+ }
1512
  if done:
1513
  post_execute_log_state = {
1514
  "preserve_terminal_log": True,
1515
  "terminal_log_value": formatted_status,
1516
+ "preserve_execute_video_log": False,
1517
+ "execute_video_log_value": None,
1518
  }
1519
  LOGGER.debug(
1520
  "execute_step done uid=%s env=%s ep=%s done=%s post_execute_controls=%s post_execute_log=%s show_execution_video=%s",
gradio-web/test/test_live_obs_refresh.py CHANGED
@@ -7,7 +7,7 @@ class _FakeSession:
7
  def __init__(self):
8
  self.env_id = "BinFill"
9
  self.episode_idx = 1
10
- self.raw_solve_options = [{"available": False}]
11
  self.available_options = [("pick", 0)]
12
  self.base_frames = []
13
  self.last_execution_frames = []
@@ -63,8 +63,19 @@ def test_execute_step_builds_video_from_last_execution_frames(monkeypatch, reloa
63
  assert result[11]["value"] is None
64
  assert result[11]["interactive"] is False
65
  assert result[14]["interactive"] is False
66
- assert result[15] is True
67
- assert result[16] == "execution_video"
 
 
 
 
 
 
 
 
 
 
 
68
 
69
 
70
  def test_execute_step_falls_back_to_single_frame_clip_when_no_new_frames(monkeypatch, reload_module):
@@ -98,7 +109,7 @@ def test_execute_step_falls_back_to_single_frame_clip_when_no_new_frames(monkeyp
98
  assert int(captured["frames"][0][0, 0, 0]) == 33
99
  assert result[7]["visible"] is True
100
  assert result[10]["visible"] is True
101
- assert result[16] == "execution_video"
102
 
103
 
104
  def test_switch_phase_toggles_live_obs_interactive_without_refresh_queue(reload_module):
 
7
  def __init__(self):
8
  self.env_id = "BinFill"
9
  self.episode_idx = 1
10
+ self.raw_solve_options = [{"label": "a", "available": False}]
11
  self.available_options = [("pick", 0)]
12
  self.base_frames = []
13
  self.last_execution_frames = []
 
63
  assert result[11]["value"] is None
64
  assert result[11]["interactive"] is False
65
  assert result[14]["interactive"] is False
66
+ expected_log = callbacks.UI_TEXT["log"]["execute_action_prompt"].format(label="a")
67
+ assert result[1] == expected_log
68
+ assert result[15] == {
69
+ "exec_btn_interactive": True,
70
+ "reference_action_interactive": True,
71
+ }
72
+ assert result[16] == {
73
+ "preserve_terminal_log": False,
74
+ "terminal_log_value": None,
75
+ "preserve_execute_video_log": True,
76
+ "execute_video_log_value": expected_log,
77
+ }
78
+ assert result[17] == "execution_video"
79
 
80
 
81
  def test_execute_step_falls_back_to_single_frame_clip_when_no_new_frames(monkeypatch, reload_module):
 
109
  assert int(captured["frames"][0][0, 0, 0]) == 33
110
  assert result[7]["visible"] is True
111
  assert result[10]["visible"] is True
112
+ assert result[17] == "execution_video"
113
 
114
 
115
  def test_switch_phase_toggles_live_obs_interactive_without_refresh_queue(reload_module):
gradio-web/test/test_ui_phase_machine_runtime_e2e.py CHANGED
@@ -2576,7 +2576,10 @@ def _run_local_execute_video_transition_test(
2576
  self.episode_idx = 1
2577
  self.language_goal = "place cube on target"
2578
  self.available_options = [("pick", 0), ("point", 1)]
2579
- self.raw_solve_options = [{"available": False}, {"available": [object()]}]
 
 
 
2580
  self.demonstration_frames = []
2581
  self.last_execution_frames = []
2582
  self.base_frames = [fake_obs.copy()]
@@ -2624,6 +2627,8 @@ def _run_local_execute_video_transition_test(
2624
  value={
2625
  "preserve_terminal_log": False,
2626
  "terminal_log_value": None,
 
 
2627
  }
2628
  )
2629
  suppress_state = gr.State(value=False)
@@ -2705,6 +2710,12 @@ def _run_local_execute_video_transition_test(
2705
  outputs=[coords_box, img_display, log_output, suppress_state, post_execute_log_state],
2706
  queue=False,
2707
  )
 
 
 
 
 
 
2708
 
2709
  execute_video_display.end(
2710
  fn=cb.on_execute_video_end_transition,
@@ -2721,6 +2732,7 @@ def _run_local_execute_video_transition_test(
2721
  log_output,
2722
  reference_action_btn,
2723
  task_hint_display,
 
2724
  phase_state,
2725
  ],
2726
  queue=False,
@@ -2740,6 +2752,7 @@ def _run_local_execute_video_transition_test(
2740
  log_output,
2741
  reference_action_btn,
2742
  task_hint_display,
 
2743
  phase_state,
2744
  ],
2745
  queue=False,
@@ -2764,7 +2777,39 @@ def _run_local_execute_video_transition_test(
2764
  page = browser.new_page(viewport={"width": 1280, "height": 900})
2765
  page.goto(root_url, wait_until="domcontentloaded")
2766
  page.wait_for_selector("#main_interface", state="visible", timeout=20000)
2767
- page.locator("#action_radio input[type='radio']").first.check(force=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2768
  page.locator("#exec_btn button, button#exec_btn").first.click()
2769
  page.wait_for_selector("#execute_video video", timeout=5000)
2770
  page.wait_for_function(
@@ -2788,6 +2833,10 @@ def _run_local_execute_video_transition_test(
2788
  }""",
2789
  timeout=10000,
2790
  )
 
 
 
 
2791
  controls_after_execute = _read_demo_video_controls(page, elem_id="execute_video", button_elem_id=None)
2792
  assert controls_after_execute["autoplay"] is True
2793
  assert controls_after_execute["paused"] is False
@@ -2881,30 +2930,7 @@ def _run_local_execute_video_transition_test(
2881
  "execDisabled": False,
2882
  "refDisabled": False,
2883
  }
2884
- page.locator("#action_radio input[type='radio']").nth(1).check(force=True)
2885
- page.wait_for_function(
2886
- """(state) => {
2887
- const liveObs = document.getElementById('live_obs');
2888
- const coordsRoot = document.getElementById('coords_box');
2889
- const coordsField = coordsRoot?.querySelector('textarea, input');
2890
- const logRoot = document.getElementById('log_output');
2891
- const logField = logRoot?.querySelector('textarea, input');
2892
- const coordsValue = coordsField ? coordsField.value.trim() : '';
2893
- const logValue = logField ? logField.value.trim() : (logRoot?.textContent || '').trim();
2894
- return (
2895
- !!liveObs &&
2896
- liveObs.classList.contains(state.waitClass) &&
2897
- coordsValue === state.coordsPrompt &&
2898
- logValue === state.waitLog
2899
- );
2900
- }""",
2901
- arg={
2902
- "waitClass": config_module.LIVE_OBS_POINT_WAIT_CLASS,
2903
- "coordsPrompt": config_module.UI_TEXT["coords"]["select_point"],
2904
- "waitLog": config_module.UI_TEXT["log"]["point_selection_prompt"],
2905
- },
2906
- timeout=5000,
2907
- )
2908
 
2909
  browser.close()
2910
  finally:
@@ -3039,6 +3065,8 @@ def test_phase_machine_runtime_stopcube_remain_static_merges_short_tail(monkeypa
3039
  value={
3040
  "preserve_terminal_log": False,
3041
  "terminal_log_value": None,
 
 
3042
  }
3043
  )
3044
  suppress_state = gr.State(value=False)
@@ -3140,6 +3168,7 @@ def test_phase_machine_runtime_stopcube_remain_static_merges_short_tail(monkeypa
3140
  log_output,
3141
  reference_action_btn,
3142
  task_hint_display,
 
3143
  phase_state,
3144
  ],
3145
  queue=False,
@@ -3159,6 +3188,7 @@ def test_phase_machine_runtime_stopcube_remain_static_merges_short_tail(monkeypa
3159
  log_output,
3160
  reference_action_btn,
3161
  task_hint_display,
 
3162
  phase_state,
3163
  ],
3164
  queue=False,
 
2576
  self.episode_idx = 1
2577
  self.language_goal = "place cube on target"
2578
  self.available_options = [("pick", 0), ("point", 1)]
2579
+ self.raw_solve_options = [
2580
+ {"label": "a", "action": "pick", "available": False},
2581
+ {"label": "b", "action": "point", "available": [object()]},
2582
+ ]
2583
  self.demonstration_frames = []
2584
  self.last_execution_frames = []
2585
  self.base_frames = [fake_obs.copy()]
 
2627
  value={
2628
  "preserve_terminal_log": False,
2629
  "terminal_log_value": None,
2630
+ "preserve_execute_video_log": False,
2631
+ "execute_video_log_value": None,
2632
  }
2633
  )
2634
  suppress_state = gr.State(value=False)
 
2710
  outputs=[coords_box, img_display, log_output, suppress_state, post_execute_log_state],
2711
  queue=False,
2712
  )
2713
+ img_display.select(
2714
+ fn=cb.on_map_click,
2715
+ inputs=[uid_state, options_radio],
2716
+ outputs=[img_display, coords_box, log_output],
2717
+ queue=False,
2718
+ )
2719
 
2720
  execute_video_display.end(
2721
  fn=cb.on_execute_video_end_transition,
 
2732
  log_output,
2733
  reference_action_btn,
2734
  task_hint_display,
2735
+ post_execute_log_state,
2736
  phase_state,
2737
  ],
2738
  queue=False,
 
2752
  log_output,
2753
  reference_action_btn,
2754
  task_hint_display,
2755
+ post_execute_log_state,
2756
  phase_state,
2757
  ],
2758
  queue=False,
 
2777
  page = browser.new_page(viewport={"width": 1280, "height": 900})
2778
  page.goto(root_url, wait_until="domcontentloaded")
2779
  page.wait_for_selector("#main_interface", state="visible", timeout=20000)
2780
+ page.locator("#action_radio input[type='radio']").nth(1).check(force=True)
2781
+ page.wait_for_function(
2782
+ """(state) => {
2783
+ const coordsRoot = document.getElementById('coords_box');
2784
+ const coordsField = coordsRoot?.querySelector('textarea, input');
2785
+ const logRoot = document.getElementById('log_output');
2786
+ const logField = logRoot?.querySelector('textarea, input');
2787
+ const coordsValue = coordsField ? coordsField.value.trim() : '';
2788
+ const logValue = logField ? logField.value.trim() : (logRoot?.textContent || '').trim();
2789
+ return coordsValue === state.coordsPrompt && logValue === state.waitLog;
2790
+ }""",
2791
+ arg={
2792
+ "coordsPrompt": config_module.UI_TEXT["coords"]["select_point"],
2793
+ "waitLog": config_module.UI_TEXT["log"]["point_selection_prompt"],
2794
+ },
2795
+ timeout=5000,
2796
+ )
2797
+ box = page.locator("#live_obs img").bounding_box()
2798
+ assert box is not None
2799
+ page.mouse.click(box["x"] + box["width"] / 2, box["y"] + box["height"] / 2)
2800
+ page.wait_for_function(
2801
+ """(state) => {
2802
+ const coordsRoot = document.getElementById('coords_box');
2803
+ const coordsField = coordsRoot?.querySelector('textarea, input');
2804
+ const logRoot = document.getElementById('log_output');
2805
+ const logField = logRoot?.querySelector('textarea, input');
2806
+ const coordsValue = coordsField ? coordsField.value.trim() : '';
2807
+ const logValue = logField ? logField.value.trim() : (logRoot?.textContent || '').trim();
2808
+ return /^\\d+\\s*,\\s*\\d+$/.test(coordsValue) && logValue === state.actionLog;
2809
+ }""",
2810
+ arg={"actionLog": config_module.UI_TEXT["log"]["action_selection_prompt"]},
2811
+ timeout=5000,
2812
+ )
2813
  page.locator("#exec_btn button, button#exec_btn").first.click()
2814
  page.wait_for_selector("#execute_video video", timeout=5000)
2815
  page.wait_for_function(
 
2833
  }""",
2834
  timeout=10000,
2835
  )
2836
+ if not done:
2837
+ execution_log = _read_log_output_value(page)
2838
+ assert execution_log == config_module.UI_TEXT["log"]["execute_action_prompt"].format(label="b")
2839
+ assert execution_log != config_module.UI_TEXT["log"]["point_selection_prompt"]
2840
  controls_after_execute = _read_demo_video_controls(page, elem_id="execute_video", button_elem_id=None)
2841
  assert controls_after_execute["autoplay"] is True
2842
  assert controls_after_execute["paused"] is False
 
2930
  "execDisabled": False,
2931
  "refDisabled": False,
2932
  }
2933
+ assert _read_log_output_value(page) == config_module.UI_TEXT["log"]["action_selection_prompt"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2934
 
2935
  browser.close()
2936
  finally:
 
3065
  value={
3066
  "preserve_terminal_log": False,
3067
  "terminal_log_value": None,
3068
+ "preserve_execute_video_log": False,
3069
+ "execute_video_log_value": None,
3070
  }
3071
  )
3072
  suppress_state = gr.State(value=False)
 
3168
  log_output,
3169
  reference_action_btn,
3170
  task_hint_display,
3171
+ post_execute_log_state,
3172
  phase_state,
3173
  ],
3174
  queue=False,
 
3188
  log_output,
3189
  reference_action_btn,
3190
  task_hint_display,
3191
+ post_execute_log_state,
3192
  phase_state,
3193
  ],
3194
  queue=False,
gradio-web/test/test_ui_text_config.py CHANGED
@@ -103,10 +103,33 @@ def test_on_execute_video_end_transition_restores_controls_for_non_terminal_stat
103
  assert result[4]["interactive"] is True
104
  assert result[5]["interactive"] is True
105
  assert result[6]["interactive"] is True
106
- assert result[8].get("__type__") == "update"
107
  assert result[9]["interactive"] is True
108
  assert result[10]["interactive"] is True
109
- assert result[11] == "action_point"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
 
112
  def test_on_execute_video_end_transition_keeps_terminal_buttons_disabled(reload_module):
@@ -134,7 +157,13 @@ def test_on_execute_video_end_transition_keeps_terminal_buttons_disabled(reload_
134
  assert result[8]["value"] == "terminal banner"
135
  assert result[9]["interactive"] is False
136
  assert result[10]["interactive"] is True
137
- assert result[11] == "action_point"
 
 
 
 
 
 
138
 
139
 
140
  def test_on_option_select_preserves_terminal_log_state(reload_module):
@@ -158,6 +187,36 @@ def test_on_option_select_preserves_terminal_log_state(reload_module):
158
  assert log_state == {
159
  "preserve_terminal_log": True,
160
  "terminal_log_value": "episode success banner",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  }
162
 
163
 
 
103
  assert result[4]["interactive"] is True
104
  assert result[5]["interactive"] is True
105
  assert result[6]["interactive"] is True
106
+ assert result[8]["value"] == callbacks.UI_TEXT["log"]["action_selection_prompt"]
107
  assert result[9]["interactive"] is True
108
  assert result[10]["interactive"] is True
109
+ assert result[11] == callbacks._default_post_execute_log_state()
110
+ assert result[12] == "action_point"
111
+
112
+
113
+ def test_on_execute_video_end_transition_clears_execution_video_log_state(reload_module):
114
+ callbacks = reload_module("gradio_callbacks")
115
+
116
+ result = callbacks.on_execute_video_end_transition(
117
+ "uid-1",
118
+ {
119
+ "exec_btn_interactive": True,
120
+ "reference_action_interactive": True,
121
+ },
122
+ {
123
+ "preserve_terminal_log": False,
124
+ "terminal_log_value": None,
125
+ "preserve_execute_video_log": True,
126
+ "execute_video_log_value": "Executing Action b",
127
+ },
128
+ )
129
+
130
+ assert result[8]["value"] == callbacks.UI_TEXT["log"]["action_selection_prompt"]
131
+ assert result[11] == callbacks._default_post_execute_log_state()
132
+ assert result[12] == "action_point"
133
 
134
 
135
  def test_on_execute_video_end_transition_keeps_terminal_buttons_disabled(reload_module):
 
157
  assert result[8]["value"] == "terminal banner"
158
  assert result[9]["interactive"] is False
159
  assert result[10]["interactive"] is True
160
+ assert result[11] == callbacks._normalize_post_execute_log_state(
161
+ {
162
+ "preserve_terminal_log": True,
163
+ "terminal_log_value": "terminal banner",
164
+ }
165
+ )
166
+ assert result[12] == "action_point"
167
 
168
 
169
  def test_on_option_select_preserves_terminal_log_state(reload_module):
 
187
  assert log_state == {
188
  "preserve_terminal_log": True,
189
  "terminal_log_value": "episode success banner",
190
+ "preserve_execute_video_log": False,
191
+ "execute_video_log_value": None,
192
+ }
193
+
194
+
195
+ def test_on_option_select_preserves_execution_video_log_state(reload_module):
196
+ callbacks = reload_module("gradio_callbacks")
197
+
198
+ coords_update, img_update, log_update, suppress_flag, log_state = callbacks.on_option_select(
199
+ "uid-1",
200
+ 1,
201
+ callbacks.UI_TEXT["coords"]["select_point"],
202
+ False,
203
+ {
204
+ "preserve_terminal_log": False,
205
+ "terminal_log_value": None,
206
+ "preserve_execute_video_log": True,
207
+ "execute_video_log_value": "Executing Action b",
208
+ },
209
+ )
210
+
211
+ assert coords_update.get("__type__") == "update"
212
+ assert img_update.get("__type__") == "update"
213
+ assert log_update["value"] == "Executing Action b"
214
+ assert suppress_flag is False
215
+ assert log_state == {
216
+ "preserve_terminal_log": False,
217
+ "terminal_log_value": None,
218
+ "preserve_execute_video_log": True,
219
+ "execute_video_log_value": "Executing Action b",
220
  }
221
 
222
 
gradio-web/ui_layout.py CHANGED
@@ -969,6 +969,8 @@ def create_ui_blocks():
969
  value={
970
  "preserve_terminal_log": False,
971
  "terminal_log_value": None,
 
 
972
  }
973
  )
974
  current_task_env_state = gr.State(value=None)
@@ -1425,6 +1427,7 @@ def create_ui_blocks():
1425
  log_output,
1426
  reference_action_btn,
1427
  task_hint_display,
 
1428
  ui_phase_state,
1429
  ],
1430
  queue=False,
@@ -1451,6 +1454,7 @@ def create_ui_blocks():
1451
  log_output,
1452
  reference_action_btn,
1453
  task_hint_display,
 
1454
  ui_phase_state,
1455
  ],
1456
  queue=False,
 
969
  value={
970
  "preserve_terminal_log": False,
971
  "terminal_log_value": None,
972
+ "preserve_execute_video_log": False,
973
+ "execute_video_log_value": None,
974
  }
975
  )
976
  current_task_env_state = gr.State(value=None)
 
1427
  log_output,
1428
  reference_action_btn,
1429
  task_hint_display,
1430
+ post_execute_log_state,
1431
  ui_phase_state,
1432
  ],
1433
  queue=False,
 
1454
  log_output,
1455
  reference_action_btn,
1456
  task_hint_display,
1457
+ post_execute_log_state,
1458
  ui_phase_state,
1459
  ],
1460
  queue=False,