//! Tool: project_list_members use agent::{ToolContext, ToolDefinition, ToolError, ToolSchema}; use models::projects::project_members; use models::users::User; use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; pub async fn list_members_exec( ctx: ToolContext, _args: serde_json::Value, ) -> Result { let project_id = ctx.project_id(); let db = ctx.db(); let members = project_members::Entity::find() .filter(project_members::Column::Project.eq(project_id)) .all(db) .await .map_err(|e| ToolError::ExecutionError(e.to_string()))?; let user_ids: Vec<_> = members.iter().map(|m| m.user).collect(); let users = User::find() .filter(models::users::user::Column::Uid.is_in(user_ids)) .all(db) .await .map_err(|e| ToolError::ExecutionError(e.to_string()))?; let user_map: std::collections::HashMap<_, _> = users.into_iter().map(|u| (u.uid, u)).collect(); let result: Vec<_> = members .into_iter() .filter_map(|m| { let user = user_map.get(&m.user)?; let role = m .scope_role() .map(|r| r.to_string()) .unwrap_or_else(|_| "member".to_string()); Some(serde_json::json!({ "id": m.user.to_string(), "username": user.username, "display_name": user.display_name, "organization": user.organization, "role": role, "joined_at": m.joined_at.to_rfc3339(), })) }) .collect(); Ok(serde_json::to_value(result).map_err(|e| ToolError::ExecutionError(e.to_string()))?) } pub fn tool_definition() -> ToolDefinition { ToolDefinition::new("project_list_members") .description( "List all members in the current project. \ Returns username, display name, organization, role, and join time.", ) .parameters(ToolSchema { schema_type: "object".into(), properties: None, required: None, }) }