systemprompt_models/services/
slack.rs1use std::collections::BTreeMap;
12
13use schemars::JsonSchema;
14use serde::{Deserialize, Serialize};
15use systemprompt_identifiers::{AgentName, SecretName, SlackWorkspaceId};
16
17use crate::errors::ConfigValidationError;
18
19#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
21#[serde(deny_unknown_fields)]
22pub struct SlackAppConfig {
23 pub workspace_id: SlackWorkspaceId,
25 pub signing_secret_ref: SecretName,
27 pub bot_token_ref: SecretName,
29 #[serde(default = "default_enabled")]
30 pub enabled: bool,
31 #[serde(default, skip_serializing_if = "Option::is_none")]
33 pub default_agent: Option<AgentName>,
34 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
36 pub routing: BTreeMap<String, AgentName>,
37 #[serde(default)]
38 pub authz: SlackAuthzConfig,
39}
40
41#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
43#[serde(deny_unknown_fields)]
44pub struct SlackAuthzConfig {
45 #[serde(default)]
46 pub allowed_roles: Vec<String>,
47}
48
49const fn default_enabled() -> bool {
50 true
51}
52
53impl SlackAppConfig {
54 #[must_use]
57 pub fn agent_for(&self, key: &str) -> Option<&AgentName> {
58 self.routing.get(key).or(self.default_agent.as_ref())
59 }
60
61 pub fn validate(&self, name: &str) -> Result<(), ConfigValidationError> {
62 if self.workspace_id.as_str().is_empty() {
63 return Err(ConfigValidationError::invalid_field(format!(
64 "slack app '{name}' has an empty workspace_id"
65 )));
66 }
67 if self.default_agent.is_none() && self.routing.is_empty() {
68 return Err(ConfigValidationError::required(format!(
69 "slack app '{name}' must set default_agent or at least one routing entry"
70 )));
71 }
72 Ok(())
73 }
74}