mecha10-core 0.8.0

Mecha10 core runtime and foundational types
Documentation
# Behavior Interrupt System

Reusable system for nodes to interrupt and resume behavior tree execution.

## Overview

The behavior interrupt system provides a configurable, reusable way for any node to pause autonomous behaviors when issuing direct commands. This ensures that user commands take priority over autonomous behaviors.

## Key Components

### 1. BehaviorControl Message

Enhanced control message for behavior tree lifecycle:

```rust
pub struct BehaviorControl {
    pub action: String,               // "enable", "disable", "interrupt", "resume"
    pub source: Option<String>,       // Node that triggered the command
    pub duration_secs: Option<u64>,   // Auto-resume duration
    pub timestamp: u64,
}
```

**Actions:**
- **`enable`**: Enable behavior tree (from dashboard)
- **`disable`**: Disable behavior tree (from dashboard)
- **`interrupt`**: Pause behavior tree (from node command)
- **`resume`**: Resume behavior tree (manual or auto)

### 2. BehaviorInterruptTrigger

Reusable trigger that nodes can embed to manage behavior interruption:

```rust
pub struct BehaviorInterruptTrigger {
    source: String,
    config: BehaviorInterruptConfig,
    // ... internal state
}
```

**Features:**
- Automatic interrupt on command
- Configurable auto-resume with timeout
- Optional completion detection
- Source tracking

### 3. BehaviorInterruptConfig

Configuration for interrupt behavior:

```rust
pub struct BehaviorInterruptConfig {
    pub enabled: bool,                      // Enable/disable interruption
    pub mode: InterruptMode,                // Interrupt behavior
    pub timeout_secs: u64,                  // Auto-resume timeout
    pub await_completion: bool,             // Wait for completion
    pub completion_topic: Option<String>,   // Topic to monitor
    pub control_topic: String,              // Where to send commands
}
```

### 4. InterruptMode

```rust
pub enum InterruptMode {
    Disabled,                    // No interruption
    InterruptOnly,              // Interrupt without auto-resume
    InterruptWithAutoResume,    // Interrupt with auto-resume
}
```

## Usage

### Basic Usage in a Node

```rust
use mecha10_core::behavior_interrupt::{BehaviorInterruptTrigger, BehaviorInterruptConfig};
use mecha10_core::prelude::*;

pub struct MyNode {
    behavior_trigger: BehaviorInterruptTrigger,
    // ... other fields
}

impl MyNode {
    pub fn new(config: MyNodeConfig) -> Result<Self> {
        // Create trigger from config
        let behavior_trigger = BehaviorInterruptTrigger::new(
            "my-node",
            config.behavior_interrupt,
        );

        Ok(Self {
            behavior_trigger,
            // ... other fields
        })
    }

    async fn send_motor_command(&mut self, ctx: &Context, cmd: MotorCommand) -> Result<()> {
        // Interrupt behavior tree before sending command
        self.behavior_trigger.interrupt(ctx).await?;

        // Send motor command
        ctx.publish(&cmd).await?;

        // Optionally resume manually (or let auto-resume handle it)
        // self.behavior_trigger.resume(ctx).await?;

        Ok(())
    }
}
```

### Configuration Example

```toml
[behavior_interrupt]
enabled = true
mode = "interrupt_with_auto_resume"
timeout_secs = 30
await_completion = false
control_topic = "/behavior/control"
```

### Interrupt Modes Explained

**Disabled**
```toml
mode = "disabled"
```
- Behavior tree is never interrupted
- Use when autonomous behaviors should have priority

**Interrupt Only**
```toml
mode = "interrupt_only"
```
- Pauses behavior tree when command is issued
- No automatic resumption
- Requires manual re-enable from dashboard

**Interrupt with Auto-Resume**
```toml
mode = "interrupt_with_auto_resume"
timeout_secs = 30
```
- Pauses behavior tree when command is issued
- Automatically resumes after timeout
- Ideal for seamless manual/autonomous switching

## Advanced Features

### Check Interrupt Status

```rust
if trigger.is_interrupted() {
    println!("Behavior tree is currently interrupted");

    if let Some(duration) = trigger.interrupt_duration() {
        println!("Interrupted for {}s", duration.as_secs());
    }
}
```

### Manual Resume

```rust
// Resume behavior tree immediately
trigger.resume(ctx).await?;
```

### Completion Detection (Future)

```toml
[behavior_interrupt]
await_completion = true
completion_topic = "/motor/status"
```

When implemented, the trigger will wait for a message on `completion_topic` before auto-resuming.

## Integration with Behavior Executor

The behavior-executor node listens to `/behavior/control` and handles these actions:

```rust
match control_msg.action.as_str() {
    "enable" => /* Enable behavior tree */,
    "disable" => /* Disable behavior tree */,
    "interrupt" => {
        // Pause execution
        // Schedule auto-resume if duration_secs is set
    },
    "resume" => /* Resume behavior tree */,
}
```

## Example: LLM Command Node

The `llm-command` node uses this system to interrupt behaviors when issuing motor/navigation commands:

```rust
pub struct OpenAIReasoningNode {
    llm: LlmNode,
    behavior_trigger: BehaviorInterruptTrigger,
    // ...
}

impl OpenAIReasoningNode {
    async fn publish_action(&mut self, ctx: &Context, action: ParsedAction) -> Result<()> {
        // Interrupt for motor/navigation commands
        match &action {
            ParsedAction::Navigate { .. } | ParsedAction::Motor { .. } => {
                self.behavior_trigger.interrupt(ctx).await?;
            }
            _ => {}
        }

        // Publish the action
        // ...
    }
}
```

## Thread Safety

The `BehaviorInterruptTrigger` manages auto-resume tasks internally and cleans them up on drop. The auto-resume task is automatically cancelled when:
- A new interrupt is triggered
- The trigger is manually resumed
- The trigger is dropped

## Testing

```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_config_default() {
        let config = BehaviorInterruptConfig::default();
        assert!(config.enabled);
        assert_eq!(config.mode, InterruptMode::InterruptOnly);
        assert_eq!(config.timeout_secs, 30);
    }

    #[test]
    fn test_control_message_creation() {
        let interrupt = BehaviorControl::interrupt("test-node");
        assert_eq!(interrupt.action, "interrupt");
        assert_eq!(interrupt.source, Some("test-node".to_string()));

        let interrupt_with_duration = BehaviorControl::interrupt_with_duration("test-node", 60);
        assert_eq!(interrupt_with_duration.duration_secs, Some(60));
    }
}
```

## See Also

- [llm-command README]../../../nodes/llm-command/README.md - Example usage
- [behavior-executor README]../../../nodes/behavior-executor/README.md - Control message handling