Skip to main content

swarm_engine_core/learn/record/
action.rs

1//! ActionRecord - アクション実行の記録
2
3use serde::{Deserialize, Serialize};
4
5use crate::events::ActionEvent;
6use crate::types::{GroupId, TaskId};
7
8/// アクション実行の記録
9///
10/// ActionEvent から変換可能。
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct ActionRecord {
13    /// タスク ID(どのタスクの一部か)
14    pub task_id: TaskId,
15    /// グループ ID(同条件の複数試行をグループ化、Learn 用)
16    pub group_id: Option<GroupId>,
17    /// Tick
18    pub tick: u64,
19    /// Worker ID
20    pub worker_id: usize,
21    /// アクション名
22    pub action: String,
23    /// ターゲット
24    pub target: Option<String>,
25    /// 成功/失敗
26    pub success: bool,
27    /// エラーメッセージ
28    pub error: Option<String>,
29    /// 実行時間(ミリ秒)
30    pub duration_ms: u64,
31    /// 選択ロジック(UCB1, Greedy 等)
32    pub selection_logic: Option<String>,
33    /// Guidance からの指示だったか
34    pub from_guidance: bool,
35    /// 前回のアクション
36    pub previous_action: Option<String>,
37    /// 使用した LoRA
38    pub lora: Option<String>,
39}
40
41impl ActionRecord {
42    pub fn new(tick: u64, worker_id: usize, action: impl Into<String>) -> Self {
43        Self {
44            task_id: TaskId::new(),
45            group_id: None,
46            tick,
47            worker_id,
48            action: action.into(),
49            target: None,
50            success: true,
51            error: None,
52            duration_ms: 0,
53            selection_logic: None,
54            from_guidance: false,
55            previous_action: None,
56            lora: None,
57        }
58    }
59
60    /// タスク ID を設定
61    pub fn task_id(mut self, task_id: TaskId) -> Self {
62        self.task_id = task_id;
63        self
64    }
65
66    /// グループ ID を設定
67    pub fn group_id(mut self, group_id: GroupId) -> Self {
68        self.group_id = Some(group_id);
69        self
70    }
71
72    pub fn target(mut self, target: impl Into<String>) -> Self {
73        self.target = Some(target.into());
74        self
75    }
76
77    pub fn success(mut self, success: bool) -> Self {
78        self.success = success;
79        self
80    }
81
82    pub fn error(mut self, error: impl Into<String>) -> Self {
83        self.error = Some(error.into());
84        self.success = false;
85        self
86    }
87
88    pub fn duration_ms(mut self, duration_ms: u64) -> Self {
89        self.duration_ms = duration_ms;
90        self
91    }
92
93    pub fn selection_logic(mut self, logic: impl Into<String>) -> Self {
94        self.selection_logic = Some(logic.into());
95        self
96    }
97
98    pub fn from_guidance(mut self) -> Self {
99        self.from_guidance = true;
100        self
101    }
102
103    pub fn previous_action(mut self, action: impl Into<String>) -> Self {
104        self.previous_action = Some(action.into());
105        self
106    }
107
108    pub fn lora(mut self, lora: impl Into<String>) -> Self {
109        self.lora = Some(lora.into());
110        self
111    }
112
113    /// 終端アクション(タスク完了)かどうか
114    pub fn is_terminal(&self) -> bool {
115        self.action == "done"
116    }
117}
118
119impl From<&ActionEvent> for ActionRecord {
120    fn from(event: &ActionEvent) -> Self {
121        Self {
122            task_id: event.task_id,
123            group_id: event.group_id,
124            tick: event.tick,
125            worker_id: event.worker_id.0,
126            action: event.action.clone(),
127            target: event.target.clone(),
128            success: event.result.success,
129            error: event.result.error.clone(),
130            duration_ms: event.duration.as_millis() as u64,
131            selection_logic: event.context.selection_logic.clone(),
132            from_guidance: event.context.from_guidance,
133            previous_action: event.context.previous_action.clone(),
134            lora: event.context.lora.as_ref().and_then(|l| l.name.clone()),
135        }
136    }
137}