feat(config): add Lark/Feishu channel config support
* feat(config): add Lark/Feishu channel config support - Add LarkConfig struct with app_id, app_secret, encrypt_key, verification_token, allowed_users, use_feishu fields - Add lark field to ChannelsConfig - Export LarkConfig in config/mod.rs - Add 5 tests for LarkConfig serialization/deserialization Related to #164 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: apply cargo fmt formatting Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c8ca6ff059
commit
0e0b3644a8
4 changed files with 100 additions and 1 deletions
5
.cargo/config.toml
Normal file
5
.cargo/config.toml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
[target.x86_64-unknown-linux-musl]
|
||||||
|
rustflags = ["-C", "link-arg=-static"]
|
||||||
|
|
||||||
|
[target.aarch64-unknown-linux-musl]
|
||||||
|
rustflags = ["-C", "link-arg=-static"]
|
||||||
|
|
@ -3,7 +3,7 @@ pub mod schema;
|
||||||
pub use schema::{
|
pub use schema::{
|
||||||
AutonomyConfig, BrowserConfig, ChannelsConfig, ComposioConfig, Config, DelegateAgentConfig,
|
AutonomyConfig, BrowserConfig, ChannelsConfig, ComposioConfig, Config, DelegateAgentConfig,
|
||||||
DiscordConfig, DockerRuntimeConfig, GatewayConfig, HeartbeatConfig, IMessageConfig,
|
DiscordConfig, DockerRuntimeConfig, GatewayConfig, HeartbeatConfig, IMessageConfig,
|
||||||
IdentityConfig, MatrixConfig, MemoryConfig, ModelRouteConfig, ObservabilityConfig,
|
IdentityConfig, LarkConfig, MatrixConfig, MemoryConfig, ModelRouteConfig, ObservabilityConfig,
|
||||||
ReliabilityConfig, RuntimeConfig, SecretsConfig, SlackConfig, TelegramConfig, TunnelConfig,
|
ReliabilityConfig, RuntimeConfig, SecretsConfig, SlackConfig, TelegramConfig, TunnelConfig,
|
||||||
WebhookConfig,
|
WebhookConfig,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -741,6 +741,7 @@ pub struct ChannelsConfig {
|
||||||
pub whatsapp: Option<WhatsAppConfig>,
|
pub whatsapp: Option<WhatsAppConfig>,
|
||||||
pub email: Option<crate::channels::email_channel::EmailConfig>,
|
pub email: Option<crate::channels::email_channel::EmailConfig>,
|
||||||
pub irc: Option<IrcConfig>,
|
pub irc: Option<IrcConfig>,
|
||||||
|
pub lark: Option<LarkConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ChannelsConfig {
|
impl Default for ChannelsConfig {
|
||||||
|
|
@ -756,6 +757,7 @@ impl Default for ChannelsConfig {
|
||||||
whatsapp: None,
|
whatsapp: None,
|
||||||
email: None,
|
email: None,
|
||||||
irc: None,
|
irc: None,
|
||||||
|
lark: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -850,6 +852,28 @@ fn default_irc_port() -> u16 {
|
||||||
6697
|
6697
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lark/Feishu configuration for messaging integration
|
||||||
|
/// Lark is the international version, Feishu is the Chinese version
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct LarkConfig {
|
||||||
|
/// App ID from Lark/Feishu developer console
|
||||||
|
pub app_id: String,
|
||||||
|
/// App Secret from Lark/Feishu developer console
|
||||||
|
pub app_secret: String,
|
||||||
|
/// Encrypt key for webhook message decryption (optional)
|
||||||
|
#[serde(default)]
|
||||||
|
pub encrypt_key: Option<String>,
|
||||||
|
/// Verification token for webhook validation (optional)
|
||||||
|
#[serde(default)]
|
||||||
|
pub verification_token: Option<String>,
|
||||||
|
/// Allowed user IDs or union IDs (empty = deny all, "*" = allow all)
|
||||||
|
#[serde(default)]
|
||||||
|
pub allowed_users: Vec<String>,
|
||||||
|
/// Whether to use the Feishu (Chinese) endpoint instead of Lark (International)
|
||||||
|
#[serde(default)]
|
||||||
|
pub use_feishu: bool,
|
||||||
|
}
|
||||||
|
|
||||||
// ── Config impl ──────────────────────────────────────────────────
|
// ── Config impl ──────────────────────────────────────────────────
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
|
|
@ -1216,6 +1240,7 @@ mod tests {
|
||||||
whatsapp: None,
|
whatsapp: None,
|
||||||
email: None,
|
email: None,
|
||||||
irc: None,
|
irc: None,
|
||||||
|
lark: None,
|
||||||
},
|
},
|
||||||
memory: MemoryConfig::default(),
|
memory: MemoryConfig::default(),
|
||||||
tunnel: TunnelConfig::default(),
|
tunnel: TunnelConfig::default(),
|
||||||
|
|
@ -1464,6 +1489,7 @@ default_temperature = 0.7
|
||||||
whatsapp: None,
|
whatsapp: None,
|
||||||
email: None,
|
email: None,
|
||||||
irc: None,
|
irc: None,
|
||||||
|
lark: None,
|
||||||
};
|
};
|
||||||
let toml_str = toml::to_string_pretty(&c).unwrap();
|
let toml_str = toml::to_string_pretty(&c).unwrap();
|
||||||
let parsed: ChannelsConfig = toml::from_str(&toml_str).unwrap();
|
let parsed: ChannelsConfig = toml::from_str(&toml_str).unwrap();
|
||||||
|
|
@ -1622,6 +1648,7 @@ channel_id = "C123"
|
||||||
}),
|
}),
|
||||||
email: None,
|
email: None,
|
||||||
irc: None,
|
irc: None,
|
||||||
|
lark: None,
|
||||||
};
|
};
|
||||||
let toml_str = toml::to_string_pretty(&c).unwrap();
|
let toml_str = toml::to_string_pretty(&c).unwrap();
|
||||||
let parsed: ChannelsConfig = toml::from_str(&toml_str).unwrap();
|
let parsed: ChannelsConfig = toml::from_str(&toml_str).unwrap();
|
||||||
|
|
@ -2052,6 +2079,72 @@ default_temperature = 0.7
|
||||||
assert!(g.paired_tokens.is_empty());
|
assert!(g.paired_tokens.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Lark config ───────────────────────────────────────────────
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lark_config_serde() {
|
||||||
|
let lc = LarkConfig {
|
||||||
|
app_id: "cli_123456".into(),
|
||||||
|
app_secret: "secret_abc".into(),
|
||||||
|
encrypt_key: Some("encrypt_key".into()),
|
||||||
|
verification_token: Some("verify_token".into()),
|
||||||
|
allowed_users: vec!["user_123".into(), "user_456".into()],
|
||||||
|
use_feishu: true,
|
||||||
|
};
|
||||||
|
let json = serde_json::to_string(&lc).unwrap();
|
||||||
|
let parsed: LarkConfig = serde_json::from_str(&json).unwrap();
|
||||||
|
assert_eq!(parsed.app_id, "cli_123456");
|
||||||
|
assert_eq!(parsed.app_secret, "secret_abc");
|
||||||
|
assert_eq!(parsed.encrypt_key.as_deref(), Some("encrypt_key"));
|
||||||
|
assert_eq!(parsed.verification_token.as_deref(), Some("verify_token"));
|
||||||
|
assert_eq!(parsed.allowed_users.len(), 2);
|
||||||
|
assert!(parsed.use_feishu);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lark_config_toml_roundtrip() {
|
||||||
|
let lc = LarkConfig {
|
||||||
|
app_id: "cli_123456".into(),
|
||||||
|
app_secret: "secret_abc".into(),
|
||||||
|
encrypt_key: Some("encrypt_key".into()),
|
||||||
|
verification_token: Some("verify_token".into()),
|
||||||
|
allowed_users: vec!["*".into()],
|
||||||
|
use_feishu: false,
|
||||||
|
};
|
||||||
|
let toml_str = toml::to_string(&lc).unwrap();
|
||||||
|
let parsed: LarkConfig = toml::from_str(&toml_str).unwrap();
|
||||||
|
assert_eq!(parsed.app_id, "cli_123456");
|
||||||
|
assert_eq!(parsed.app_secret, "secret_abc");
|
||||||
|
assert!(!parsed.use_feishu);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lark_config_deserializes_without_optional_fields() {
|
||||||
|
let json = r#"{"app_id":"cli_123","app_secret":"secret"}"#;
|
||||||
|
let parsed: LarkConfig = serde_json::from_str(json).unwrap();
|
||||||
|
assert!(parsed.encrypt_key.is_none());
|
||||||
|
assert!(parsed.verification_token.is_none());
|
||||||
|
assert!(parsed.allowed_users.is_empty());
|
||||||
|
assert!(!parsed.use_feishu);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lark_config_defaults_to_lark_endpoint() {
|
||||||
|
let json = r#"{"app_id":"cli_123","app_secret":"secret"}"#;
|
||||||
|
let parsed: LarkConfig = serde_json::from_str(json).unwrap();
|
||||||
|
assert!(
|
||||||
|
!parsed.use_feishu,
|
||||||
|
"use_feishu should default to false (Lark)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lark_config_with_wildcard_allowed_users() {
|
||||||
|
let json = r#"{"app_id":"cli_123","app_secret":"secret","allowed_users":["*"]}"#;
|
||||||
|
let parsed: LarkConfig = serde_json::from_str(json).unwrap();
|
||||||
|
assert_eq!(parsed.allowed_users, vec!["*"]);
|
||||||
|
}
|
||||||
|
|
||||||
// ══════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════
|
||||||
// AGENT DELEGATION CONFIG TESTS
|
// AGENT DELEGATION CONFIG TESTS
|
||||||
// ══════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════
|
||||||
|
|
|
||||||
|
|
@ -1126,6 +1126,7 @@ fn setup_channels() -> Result<ChannelsConfig> {
|
||||||
whatsapp: None,
|
whatsapp: None,
|
||||||
email: None,
|
email: None,
|
||||||
irc: None,
|
irc: None,
|
||||||
|
lark: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue