cellstate/entity/
summarization_policy.rs1use 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}