Skip to main content

aios_spec/
intent.rs

1//! 意图与动作 — "what the LLM tells us to do"
2//!
3//! Cloud LLM 返回的结构化决策, 从 agent 流向 core。
4
5use serde::{Deserialize, Serialize};
6
7use crate::event::ExtensionCategory;
8
9/// 云端 LLM 返回的结构化决策
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct IntentBatch {
12    /// 请求对应的窗口 ID
13    pub window_id: String,
14    /// 候选意图列表 (按置信度降序)
15    pub intents: Vec<Intent>,
16    /// 生成时间 (epoch ms)
17    pub generated_at_ms: i64,
18    /// 模型标识
19    pub model: String,
20}
21
22/// 推理路由选择。
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
24pub enum DecisionRoute {
25    RuleBased,
26    LocalEvaluator,
27    CloudLlm,
28    FallbackNoOp,
29    Mock,
30}
31
32/// 单个推理后端的统一输出。
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct DecisionBackendResult {
35    pub route: DecisionRoute,
36    pub intent_batch: IntentBatch,
37    pub rationale_tags: Vec<String>,
38    pub latency_us: u64,
39    pub error: Option<String>,
40}
41
42/// 单条意图
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct Intent {
45    /// 意图唯一 ID
46    pub intent_id: String,
47    /// 意图类型
48    pub intent_type: IntentType,
49    /// 置信度 (0.0 ~ 1.0)
50    pub confidence: f32,
51    /// 风险等级
52    pub risk_level: RiskLevel,
53    /// 该意图的推荐动作列表
54    pub suggested_actions: Vec<SuggestedAction>,
55    /// LLM 给出的理由标签 (简短, 不用自然语言)
56    pub rationale_tags: Vec<String>,
57}
58
59/// 意图类型
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
61pub enum IntentType {
62    /// 用户将打开某个 app
63    OpenApp(String),
64    /// 用户将切换到某个 app
65    SwitchToApp(String),
66    /// 用户将查看某条通知
67    CheckNotification(String),
68    /// 用户将处理某类文件
69    HandleFile(ExtensionCategory),
70    /// 用户即将进入某个物理场景
71    EnterContext(String),
72    /// 无明确意图, 保持观察
73    Idle,
74}
75
76/// 风险等级
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
78pub enum RiskLevel {
79    /// 可自动执行
80    Low,
81    /// 需要策略引擎二次确认后执行
82    Medium,
83    /// 仅建议, 不自动执行
84    High,
85}
86
87/// 推荐动作
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct SuggestedAction {
90    pub action_type: ActionType,
91    /// 目标标识 (app package 或其他)
92    pub target: Option<String>,
93    /// 紧迫度
94    pub urgency: ActionUrgency,
95}
96
97/// 已经由 `PolicyEngine` 审查通过、允许交给 executor 的动作。
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct AuthorizedAction {
100    pub intent_id: String,
101    pub action: SuggestedAction,
102    pub authorized_at_ms: i64,
103}
104
105/// 动作类型
106#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
107pub enum ActionType {
108    /// 预热应用进程
109    PreWarmProcess,
110    /// 预加载热点文件到页缓存
111    PrefetchFile,
112    /// 保活当前前台进程
113    KeepAlive,
114    /// 释放指定进程的非关键内存
115    ReleaseMemory,
116    /// 不执行任何操作
117    NoOp,
118}
119
120/// 动作紧迫度
121#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
122pub enum ActionUrgency {
123    /// 立即执行
124    Immediate,
125    /// 空闲时执行
126    IdleTime,
127    /// 延迟执行
128    Deferred,
129}
130
131// ============================================================
132// CapabilityLevel — 后端能力上限
133// ============================================================
134
135/// 推理后端的能力上限。
136///
137/// 每个 `DecisionRoute` 变体绑定一个 `CapabilityLevel`,
138/// 声明该后端能产出的最大风险等级和允许的动作类型。
139/// `PolicyEngine` 在审查时据此拒绝越权意图。
140#[derive(Debug, Clone)]
141pub struct CapabilityLevel {
142    pub max_risk: RiskLevel,
143    pub allowed_actions: Vec<ActionType>,
144}
145
146/// Structured rejection reason emitted by `PolicyEngine`.
147///
148/// Replaces the previous `Option<String>` channel so downstream consumers
149/// (replay summary, golden tests, observability) can count denials per
150/// reason without parsing free-form strings. `BTreeMap` keying requires
151/// `Ord`; `Hash` keeps the door open for `HashMap` callers.
152#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
153pub enum DenialReason {
154    /// Intent risk exceeds the engine's configured `max_auto_risk`.
155    RiskExceedsConfig,
156    /// Intent risk exceeds the decision backend's `CapabilityLevel.max_risk`.
157    RiskExceedsCapability,
158    /// Intent confidence is below the engine's floor.
159    ConfidenceTooLow,
160    /// Action type matches the engine's blocked-action substring list.
161    ActionTypeBlocked,
162    /// Action urgency is `Deferred` — not in scope for this batch.
163    ActionUrgencyDeferred,
164    /// Action type is not in the backend `CapabilityLevel.allowed_actions`.
165    ActionCapabilityDenied,
166    /// Action targets a package or path that was not observed in the
167    /// `StructuredContext` that produced this batch.
168    TargetNotInContext,
169    /// Per-intent action count is above the engine's `max_actions_per_batch`.
170    BatchActionCapExceeded,
171}
172
173impl CapabilityLevel {
174    /// 根据路由选择返回对应的能力等级。
175    pub fn for_route(route: DecisionRoute) -> Self {
176        use ActionType::*;
177        match route {
178            DecisionRoute::RuleBased => Self {
179                max_risk: RiskLevel::Low,
180                allowed_actions: vec![NoOp, ReleaseMemory, KeepAlive],
181            },
182            DecisionRoute::LocalEvaluator => Self {
183                max_risk: RiskLevel::Low,
184                allowed_actions: vec![NoOp, PreWarmProcess, PrefetchFile, ReleaseMemory, KeepAlive],
185            },
186            DecisionRoute::CloudLlm => Self {
187                max_risk: RiskLevel::Medium,
188                allowed_actions: vec![NoOp, PreWarmProcess, PrefetchFile, KeepAlive, ReleaseMemory],
189            },
190            DecisionRoute::FallbackNoOp => Self {
191                max_risk: RiskLevel::Low,
192                allowed_actions: vec![NoOp],
193            },
194            DecisionRoute::Mock => Self {
195                max_risk: RiskLevel::Medium,
196                allowed_actions: vec![NoOp, PreWarmProcess, PrefetchFile, KeepAlive, ReleaseMemory],
197            },
198        }
199    }
200
201    /// 检查给定意图的风险等级是否在后端能力范围内。
202    pub fn allows_risk(&self, risk: RiskLevel) -> bool {
203        risk as u8 <= self.max_risk as u8
204    }
205
206    /// 检查给定动作类型是否在后端允许的白名单内。
207    pub fn allows_action(&self, action: &ActionType) -> bool {
208        self.allowed_actions.contains(action)
209    }
210}