cellstate/entity/
summarization_policy.rs

1//! `cellstate summarization-policy` — Manage summarization policies.
2//!
3//! Subcommands: create, get, delete.
4
5use anyhow::{anyhow, Result};
6use clap::{Arg, ArgMatches, Command};
7
8use cellstate_core::api_types::{CreateSummarizationPolicyRequest, SummarizationPolicyResponse};
9
10use super::client::ApiClient;
11use super::output::OutputConfig;
12
13const BASE: &str = "/api/v1/summarization-policies";
14
15pub fn build_command() -> Command {
16    Command::new("summarization-policy")
17        .about("Manage summarization policies")
18        .subcommand_required(true)
19        .subcommand(
20            Command::new("create")
21                .about("Create a new summarization policy")
22                .arg(Arg::new("name").required(true).help("Policy name"))
23                .arg(
24                    Arg::new("source-level")
25                        .long("source-level")
26                        .required(true)
27                        .help("Source abstraction level (e.g., raw, summary, principle)"),
28                )
29                .arg(
30                    Arg::new("target-level")
31                        .long("target-level")
32                        .required(true)
33                        .help("Target abstraction level (e.g., raw, summary, principle)"),
34                )
35                .arg(
36                    Arg::new("max-sources")
37                        .long("max-sources")
38                        .default_value("10")
39                        .help("Maximum sources to summarize at once"),
40                )
41                .arg(
42                    Arg::new("create-edges")
43                        .long("create-edges")
44                        .action(clap::ArgAction::SetTrue)
45                        .help("Whether to create SynthesizedFrom edges"),
46                )
47                .arg(
48                    Arg::new("trajectory-id")
49                        .long("trajectory-id")
50                        .help("Optional trajectory ID to scope this policy"),
51                ),
52        )
53        .subcommand(
54            Command::new("get")
55                .about("Get summarization policy details")
56                .arg(
57                    Arg::new("id")
58                        .required(true)
59                        .help("Summarization policy ID"),
60                ),
61        )
62        .subcommand(
63            Command::new("delete")
64                .about("Delete a summarization policy")
65                .arg(
66                    Arg::new("id")
67                        .required(true)
68                        .help("Summarization policy ID"),
69                ),
70        )
71}
72
73pub async fn dispatch(
74    matches: &ArgMatches,
75    client: &ApiClient,
76    output: &OutputConfig,
77    _session: &crate::session::CliSession,
78) -> Result<()> {
79    match matches.subcommand() {
80        Some(("create", sub)) => {
81            let name = sub.get_one::<String>("name").unwrap().clone();
82            let source_level = sub
83                .get_one::<String>("source-level")
84                .unwrap()
85                .parse()
86                .map_err(|e: String| anyhow!(e))?;
87            let target_level = sub
88                .get_one::<String>("target-level")
89                .unwrap()
90                .parse()
91                .map_err(|e: String| anyhow!(e))?;
92            let max_sources: i32 = sub.get_one::<String>("max-sources").unwrap().parse()?;
93            let create_edges = sub.get_flag("create-edges");
94            let req = CreateSummarizationPolicyRequest {
95                name,
96                triggers: vec![],
97                source_level,
98                target_level,
99                max_sources,
100                create_edges,
101                trajectory_id: sub
102                    .get_one::<String>("trajectory-id")
103                    .map(|s| s.parse())
104                    .transpose()?,
105                metadata: None,
106            };
107            let resp: SummarizationPolicyResponse = client.post(BASE, &req).await?;
108            output.print(&resp);
109        }
110        Some(("get", sub)) => {
111            let id = sub.get_one::<String>("id").unwrap();
112            let resp: SummarizationPolicyResponse = client.get(&format!("{BASE}/{id}")).await?;
113            output.print(&resp);
114        }
115        Some(("delete", sub)) => {
116            let id = sub.get_one::<String>("id").unwrap();
117            client.delete(&format!("{BASE}/{id}")).await?;
118            if output.json {
119                println!(r#"{{"deleted": "{id}"}}"#);
120            } else {
121                println!("Deleted summarization policy {id}");
122            }
123        }
124        _ => unreachable!("subcommand_required(true) prevents this"),
125    }
126    Ok(())
127}