swarm-engine-core 0.1.6

Core types and orchestration for SwarmEngine
Documentation
//! ActionRecord - アクション実行の記録

use serde::{Deserialize, Serialize};

use crate::events::ActionEvent;
use crate::types::{GroupId, TaskId};

/// アクション実行の記録
///
/// ActionEvent から変換可能。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionRecord {
    /// タスク ID(どのタスクの一部か)
    pub task_id: TaskId,
    /// グループ ID(同条件の複数試行をグループ化、Learn 用)
    pub group_id: Option<GroupId>,
    /// Tick
    pub tick: u64,
    /// Worker ID
    pub worker_id: usize,
    /// アクション名
    pub action: String,
    /// ターゲット
    pub target: Option<String>,
    /// 成功/失敗
    pub success: bool,
    /// エラーメッセージ
    pub error: Option<String>,
    /// 実行時間(ミリ秒)
    pub duration_ms: u64,
    /// 選択ロジック(UCB1, Greedy 等)
    pub selection_logic: Option<String>,
    /// Guidance からの指示だったか
    pub from_guidance: bool,
    /// 前回のアクション
    pub previous_action: Option<String>,
    /// 使用した LoRA
    pub lora: Option<String>,
}

impl ActionRecord {
    pub fn new(tick: u64, worker_id: usize, action: impl Into<String>) -> Self {
        Self {
            task_id: TaskId::new(),
            group_id: None,
            tick,
            worker_id,
            action: action.into(),
            target: None,
            success: true,
            error: None,
            duration_ms: 0,
            selection_logic: None,
            from_guidance: false,
            previous_action: None,
            lora: None,
        }
    }

    /// タスク ID を設定
    pub fn task_id(mut self, task_id: TaskId) -> Self {
        self.task_id = task_id;
        self
    }

    /// グループ ID を設定
    pub fn group_id(mut self, group_id: GroupId) -> Self {
        self.group_id = Some(group_id);
        self
    }

    pub fn target(mut self, target: impl Into<String>) -> Self {
        self.target = Some(target.into());
        self
    }

    pub fn success(mut self, success: bool) -> Self {
        self.success = success;
        self
    }

    pub fn error(mut self, error: impl Into<String>) -> Self {
        self.error = Some(error.into());
        self.success = false;
        self
    }

    pub fn duration_ms(mut self, duration_ms: u64) -> Self {
        self.duration_ms = duration_ms;
        self
    }

    pub fn selection_logic(mut self, logic: impl Into<String>) -> Self {
        self.selection_logic = Some(logic.into());
        self
    }

    pub fn from_guidance(mut self) -> Self {
        self.from_guidance = true;
        self
    }

    pub fn previous_action(mut self, action: impl Into<String>) -> Self {
        self.previous_action = Some(action.into());
        self
    }

    pub fn lora(mut self, lora: impl Into<String>) -> Self {
        self.lora = Some(lora.into());
        self
    }

    /// 終端アクション(タスク完了)かどうか
    pub fn is_terminal(&self) -> bool {
        self.action == "done"
    }
}

impl From<&ActionEvent> for ActionRecord {
    fn from(event: &ActionEvent) -> Self {
        Self {
            task_id: event.task_id,
            group_id: event.group_id,
            tick: event.tick,
            worker_id: event.worker_id.0,
            action: event.action.clone(),
            target: event.target.clone(),
            success: event.result.success,
            error: event.result.error.clone(),
            duration_ms: event.duration.as_millis() as u64,
            selection_logic: event.context.selection_logic.clone(),
            from_guidance: event.context.from_guidance,
            previous_action: event.context.previous_action.clone(),
            lora: event.context.lora.as_ref().and_then(|l| l.name.clone()),
        }
    }
}