Add REPL effect detection and input handling to pipeline runner

- Detect REPL effect in pipeline and enable interactive mode
- Enable raw terminal mode for REPL input capture
- Add keyboard input loop for REPL commands (return, up/down arrows, backspace)
- Process commands and handle pipeline mutations from REPL
- Fix lint issues in graph and REPL modules (type annotations, imports)
This commit is contained in:
2026-03-21 21:19:30 -07:00
parent fb0dd4592f
commit 6646ed78b3
7 changed files with 89 additions and 52 deletions

View File

@@ -433,6 +433,16 @@ def run_pipeline_mode(preset_name: str = "demo", graph_config: str | None = None
ui_panel = None
render_ui_panel_in_terminal = False
# Check for REPL effect in pipeline
repl_effect = None
for stage in pipeline.stages.values():
if isinstance(stage, EffectPluginStage) and stage._effect.name == "repl":
repl_effect = stage._effect
print(
" \033[38;5;46mREPL effect detected - Interactive mode enabled\033[0m"
)
break
if need_ui_controller:
from engine.display import render_ui_panel
@@ -448,6 +458,10 @@ def run_pipeline_mode(preset_name: str = "demo", graph_config: str | None = None
if hasattr(display, "set_raw_mode"):
display.set_raw_mode(True)
# Enable raw mode for REPL if present and not already enabled
elif repl_effect and hasattr(display, "set_raw_mode"):
display.set_raw_mode(True)
# Register effect plugin stages from pipeline for UI control
for stage in pipeline.stages.values():
if isinstance(stage, EffectPluginStage):
@@ -966,6 +980,38 @@ def run_pipeline_mode(preset_name: str = "demo", graph_config: str | None = None
else:
display.show(result.data, border=show_border)
# --- REPL Input Handling ---
if repl_effect and hasattr(display, "get_input_keys"):
# Get keyboard input (non-blocking)
keys = display.get_input_keys(timeout=0.0)
for key in keys:
if key == "return":
# Get command string before processing
cmd_str = repl_effect.state.current_command
if cmd_str:
repl_effect.process_command(cmd_str, ctx)
# Check for pending pipeline mutations
pending = repl_effect.get_pending_command()
if pending:
_handle_pipeline_mutation(pipeline, pending)
# Broadcast state update if WebSocket is active
if web_control_active and isinstance(
display, WebSocketDisplay
):
state = display._get_state_snapshot()
if state:
display.broadcast_state(state)
elif key == "up":
repl_effect.navigate_history(-1)
elif key == "down":
repl_effect.navigate_history(1)
elif key == "backspace":
repl_effect.backspace()
elif len(key) == 1:
repl_effect.append_to_command(key)
# --- End REPL Input Handling ---
if hasattr(display, "is_quit_requested") and display.is_quit_requested():
if hasattr(display, "clear_quit_request"):
display.clear_quit_request()