(self, node: Node, inputs: List[Message])
| 23 | STATE_KEY = "loop_timer" |
| 24 | |
| 25 | def execute(self, node: Node, inputs: List[Message]) -> List[Message]: |
| 26 | config = node.as_config(LoopTimerConfig) |
| 27 | if config is None: |
| 28 | raise ValueError(f"Node {node.id} missing loop_timer configuration") |
| 29 | |
| 30 | state = self._get_state() |
| 31 | timer_state = state.setdefault(node.id, {}) |
| 32 | |
| 33 | # Initialize timer on first execution |
| 34 | current_time = time.time() |
| 35 | if "start_time" not in timer_state: |
| 36 | timer_state["start_time"] = current_time |
| 37 | timer_state["emitted"] = False |
| 38 | |
| 39 | start_time = timer_state["start_time"] |
| 40 | elapsed_time = current_time - start_time |
| 41 | |
| 42 | # Convert max_duration to seconds based on unit |
| 43 | max_duration_seconds = self._convert_to_seconds( |
| 44 | config.max_duration, config.duration_unit |
| 45 | ) |
| 46 | |
| 47 | # Check if time limit has been reached |
| 48 | limit_reached = elapsed_time >= max_duration_seconds |
| 49 | |
| 50 | # Terminal Gate Mode (passthrough=True) |
| 51 | if config.passthrough: |
| 52 | if not limit_reached: |
| 53 | # Before limit: pass input through unchanged |
| 54 | self.log_manager.debug( |
| 55 | f"LoopTimer {node.id}: {elapsed_time:.1f}s / {max_duration_seconds:.1f}s " |
| 56 | f"(passthrough mode: forwarding input)" |
| 57 | ) |
| 58 | return inputs |
| 59 | elif not timer_state["emitted"]: |
| 60 | # At limit: emit configured message, suppress original input |
| 61 | timer_state["emitted"] = True |
| 62 | if config.reset_on_emit: |
| 63 | timer_state["start_time"] = current_time |
| 64 | |
| 65 | content = ( |
| 66 | config.message |
| 67 | or f"Time limit reached ({config.max_duration} {config.duration_unit})" |
| 68 | ) |
| 69 | metadata = { |
| 70 | "loop_timer": { |
| 71 | "elapsed_time": elapsed_time, |
| 72 | "max_duration": config.max_duration, |
| 73 | "duration_unit": config.duration_unit, |
| 74 | "reset_on_emit": config.reset_on_emit, |
| 75 | "passthrough": True, |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | self.log_manager.debug( |
| 80 | f"LoopTimer {node.id}: {elapsed_time:.1f}s / {max_duration_seconds:.1f}s " |
| 81 | f"(passthrough mode: emitting limit message)" |
| 82 | ) |
nothing calls this directly
no test coverage detected