use async_trait::async_trait; use erp_core::health_provider::TimeRange; use crate::agent::tool::{AgentTool, DisplayHint, ToolContext, ToolResult}; /// 查询患者最近体征数据(血压/血糖/心率等) pub struct QueryPatientVitalsTool; #[async_trait] impl AgentTool for QueryPatientVitalsTool { fn name(&self) -> &str { "query_patient_vitals" } fn description(&self) -> &str { "查询患者最近的体征数据(血压、血糖、心率、体重、血氧等)。需要提供天数范围(默认 7 天)。" } fn parameters_schema(&self) -> serde_json::Value { serde_json::json!({ "type": "object", "properties": { "days": { "type": "integer", "description": "查询最近多少天的数据,默认 7 天" } } }) } async fn execute(&self, ctx: &ToolContext, params: serde_json::Value) -> ToolResult { let patient_id = match ctx.patient_id { Some(id) => id, None => { return ToolResult { output: "未关联患者档案,无法查询体征数据".to_string(), display_hint: None, }; } }; let days = params["days"].as_i64().unwrap_or(7); let now = chrono::Utc::now(); let start = now - chrono::Duration::days(days); let range = TimeRange { start, end: now }; let metrics = vec![ "systolic_bp_morning".into(), "diastolic_bp_morning".into(), "heart_rate".into(), "blood_sugar".into(), ]; match ctx .health_provider .get_vital_signs(ctx.tenant_id, patient_id, &metrics, &range) .await { Ok(vitals) => { if vitals.is_empty() { return ToolResult { output: "该时间段内无体征数据".to_string(), display_hint: None, }; } let mut output = String::from("最近体征数据:\n"); for v in &vitals { output.push_str(&format!("- {}:", v.metric)); let values_str: Vec = v .values .iter() .take(10) .map(|(date, val)| format!("{}={}", date, val)) .collect(); output.push_str(&format!(" ({})\n", values_str.join(", "))); } let display_hint = vitals.first().map(|v| DisplayHint::VitalCard { indicator_type: v.metric.clone(), values: v.values.iter().take(10).cloned().collect(), unit: v.unit.clone(), }); ToolResult { output, display_hint, } } Err(e) => ToolResult { output: format!("查询体征数据失败: {}", e), display_hint: None, }, } } }