1use serde::{Deserialize, Serialize};
41use std::collections::HashMap;
42
43use super::enums::{AuthScheme, MetaToolSlug, TagType};
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct SessionConfig {
87 pub user_id: String,
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub toolkits: Option<ToolkitFilter>,
90 #[serde(skip_serializing_if = "Option::is_none")]
91 pub auth_configs: Option<HashMap<String, String>>,
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub connected_accounts: Option<HashMap<String, String>>,
94 #[serde(skip_serializing_if = "Option::is_none")]
95 pub manage_connections: Option<ManageConnectionsConfig>,
96 #[serde(skip_serializing_if = "Option::is_none")]
97 pub tools: Option<ToolsConfig>,
98 #[serde(skip_serializing_if = "Option::is_none")]
99 pub tags: Option<TagsConfig>,
100 #[serde(skip_serializing_if = "Option::is_none")]
101 pub workbench: Option<WorkbenchConfig>,
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub experimental: Option<ExperimentalConfig>,
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub toolkit_versions: Option<super::versioning::ToolkitVersionParam>,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
133#[serde(untagged)]
134pub enum ManageConnectionsConfig {
135 Bool(bool),
137 Detailed {
139 enabled: bool,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 enable_wait_for_connections: Option<bool>,
142 },
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
169#[serde(untagged)]
170pub enum ToolkitFilter {
171 Enable(Vec<String>),
172 Disable { disable: Vec<String> },
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
178pub struct ToolsConfig(pub HashMap<String, ToolFilter>);
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
182#[serde(untagged)]
183pub enum ToolFilter {
184 Enable { enable: Vec<String> },
186 Disable { disable: Vec<String> },
188 EnableList(Vec<String>),
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct TagsConfig {
196 #[serde(skip_serializing_if = "Option::is_none")]
198 pub enabled: Option<Vec<TagType>>,
199 #[serde(skip_serializing_if = "Option::is_none")]
201 pub disabled: Option<Vec<TagType>>,
202}
203
204#[derive(Debug, Clone, Serialize, Deserialize)]
206pub struct WorkbenchConfig {
207 #[serde(skip_serializing_if = "Option::is_none")]
208 #[serde(alias = "proxy_execution_enabled")]
209 pub proxy_execution: Option<bool>,
210 #[serde(skip_serializing_if = "Option::is_none")]
211 pub auto_offload_threshold: Option<u32>,
212}
213
214#[derive(Debug, Clone, Serialize, Deserialize)]
218pub struct AssistivePromptConfig {
219 #[serde(skip_serializing_if = "Option::is_none")]
222 pub user_timezone: Option<String>,
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize)]
229pub struct ExperimentalConfig {
230 #[serde(skip_serializing_if = "Option::is_none")]
232 pub assistive_prompt: Option<AssistivePromptConfig>,
233}
234
235#[derive(Debug, Clone, Serialize, Default)]
270pub struct ToolExecutionRequest {
271 pub tool_slug: String,
273
274 #[serde(skip_serializing_if = "Option::is_none")]
276 pub arguments: Option<serde_json::Value>,
277
278 #[serde(skip_serializing_if = "Option::is_none")]
280 pub connected_account_id: Option<String>,
281
282 #[serde(skip_serializing_if = "Option::is_none")]
284 pub custom_auth_params: Option<serde_json::Value>,
285
286 #[serde(skip_serializing_if = "Option::is_none")]
288 pub custom_connection_data: Option<serde_json::Value>,
289
290 #[serde(skip_serializing_if = "Option::is_none")]
292 pub user_id: Option<String>,
293
294 #[serde(skip_serializing_if = "Option::is_none")]
296 pub text: Option<String>,
297
298 #[serde(skip_serializing_if = "Option::is_none")]
300 pub version: Option<String>,
301
302 #[serde(skip_serializing_if = "Option::is_none")]
304 pub dangerously_skip_version_check: Option<bool>,
305}
306
307#[derive(Debug, Clone, Serialize)]
309pub struct MetaToolExecutionRequest {
310 pub slug: MetaToolSlug,
311 #[serde(skip_serializing_if = "Option::is_none")]
312 pub arguments: Option<serde_json::Value>,
313}
314
315#[derive(Debug, Clone, Serialize)]
317pub struct LinkRequest {
318 pub toolkit: String,
319 #[serde(skip_serializing_if = "Option::is_none")]
320 pub callback_url: Option<String>,
321}
322
323#[derive(Debug, Clone, Serialize)]
352pub struct AuthConfigCreateParams {
353 pub toolkit: String,
355 pub auth_config: AuthConfigData,
357}
358
359#[derive(Debug, Clone, Serialize)]
361pub struct AuthConfigData {
362 #[serde(rename = "type")]
364 pub auth_type: AuthScheme,
365 pub credentials: serde_json::Value,
367 #[serde(skip_serializing_if = "Option::is_none")]
369 pub restrict_to_following_tools: Option<Vec<String>>,
370}
371
372#[derive(Debug, Clone, Serialize, Default)]
389pub struct AuthConfigListParams {
390 #[serde(skip_serializing_if = "Option::is_none")]
392 pub is_composio_managed: Option<bool>,
393 #[serde(skip_serializing_if = "Option::is_none")]
395 pub toolkit_slug: Option<String>,
396 #[serde(skip_serializing_if = "Option::is_none")]
398 pub show_disabled: Option<bool>,
399 #[serde(skip_serializing_if = "Option::is_none")]
401 pub search: Option<String>,
402 #[serde(skip_serializing_if = "Option::is_none")]
404 pub limit: Option<u32>,
405 #[serde(skip_serializing_if = "Option::is_none")]
407 pub cursor: Option<String>,
408}
409
410#[derive(Debug, Clone, Serialize, Default)]
428pub struct AuthConfigUpdateParams {
429 #[serde(skip_serializing_if = "Option::is_none")]
431 pub name: Option<String>,
432 #[serde(skip_serializing_if = "Option::is_none")]
434 pub credentials: Option<serde_json::Value>,
435 #[serde(skip_serializing_if = "Option::is_none")]
437 pub proxy_config: Option<serde_json::Value>,
438 #[serde(skip_serializing_if = "Option::is_none")]
440 pub tool_access_config: Option<serde_json::Value>,
441}
442
443#[derive(Debug, Clone, Serialize)]
470pub struct ConnectedAccountCreateParams {
471 pub auth_config: AuthConfigReference,
473 pub connection: ConnectionData,
475 #[serde(skip_serializing_if = "Option::is_none")]
477 pub validate_credentials: Option<bool>,
478}
479
480#[derive(Debug, Clone, Serialize)]
482pub struct AuthConfigReference {
483 pub id: String,
485}
486
487#[derive(Debug, Clone, Serialize)]
489pub struct ConnectionData {
490 #[serde(skip_serializing_if = "Option::is_none")]
492 pub state: Option<serde_json::Value>,
493 #[serde(skip_serializing_if = "Option::is_none")]
495 pub data: Option<serde_json::Value>,
496 pub user_id: String,
498 #[serde(skip_serializing_if = "Option::is_none")]
500 pub callback_url: Option<String>,
501}
502
503#[derive(Debug, Clone, Serialize, Default)]
520pub struct ConnectedAccountListParams {
521 #[serde(skip_serializing_if = "Option::is_none")]
523 pub toolkit_slugs: Option<Vec<String>>,
524 #[serde(skip_serializing_if = "Option::is_none")]
526 pub statuses: Option<Vec<String>>,
527 #[serde(skip_serializing_if = "Option::is_none")]
529 pub cursor: Option<String>,
530 #[serde(skip_serializing_if = "Option::is_none")]
532 pub limit: Option<u32>,
533 #[serde(skip_serializing_if = "Option::is_none")]
535 pub user_ids: Option<Vec<String>>,
536 #[serde(skip_serializing_if = "Option::is_none")]
538 pub auth_config_ids: Option<Vec<String>>,
539}
540
541#[derive(Debug, Clone, Serialize)]
565pub struct ToolProxyParams {
566 pub endpoint: String,
568 #[serde(skip_serializing_if = "Option::is_none")]
570 pub method: Option<String>,
571 #[serde(skip_serializing_if = "Option::is_none")]
573 pub headers: Option<serde_json::Value>,
574 #[serde(skip_serializing_if = "Option::is_none")]
576 pub body: Option<serde_json::Value>,
577 #[serde(skip_serializing_if = "Option::is_none")]
579 pub query_params: Option<serde_json::Value>,
580}
581
582#[cfg(test)]
583mod tests {
584 use super::*;
585 use serde_json;
586
587 #[test]
588 fn test_session_config_minimal_serialization() {
589 let config = SessionConfig {
590 user_id: "user_123".to_string(),
591 toolkits: None,
592 auth_configs: None,
593 connected_accounts: None,
594 manage_connections: None,
595 tools: None,
596 tags: None,
597 workbench: None,
598 experimental: None,
599 toolkit_versions: None,
600 };
601
602 let json = serde_json::to_string(&config).unwrap();
603 assert!(json.contains("user_123"));
604 assert!(!json.contains("toolkits"));
605 assert!(!json.contains("auth_configs"));
606 }
607
608 #[test]
609 fn test_session_config_with_toolkits_enable() {
610 let config = SessionConfig {
611 user_id: "user_123".to_string(),
612 toolkits: Some(ToolkitFilter::Enable(vec!["github".to_string(), "gmail".to_string()])),
613 auth_configs: None,
614 connected_accounts: None,
615 manage_connections: None,
616 tools: None,
617 tags: None,
618 workbench: None,
619 experimental: None,
620 toolkit_versions: None,
621 };
622
623 let json = serde_json::to_string(&config).unwrap();
624 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
625
626 assert!(parsed["toolkits"].is_array());
627 let toolkits = parsed["toolkits"].as_array().unwrap();
628 assert_eq!(toolkits.len(), 2);
629 }
630
631 #[test]
632 fn test_session_config_with_toolkits_disable() {
633 let config = SessionConfig {
634 user_id: "user_123".to_string(),
635 toolkits: Some(ToolkitFilter::Disable {
636 disable: vec!["exa".to_string(), "firecrawl".to_string()],
637 }),
638 auth_configs: None,
639 connected_accounts: None,
640 manage_connections: None,
641 tools: None,
642 tags: None,
643 workbench: None,
644 experimental: None,
645 toolkit_versions: None,
646 };
647
648 let json = serde_json::to_string(&config).unwrap();
649 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
650
651 assert!(parsed["toolkits"].is_object());
652 assert!(parsed["toolkits"]["disable"].is_array());
653 }
654
655 #[test]
656 fn test_session_config_with_auth_configs() {
657 let mut auth_configs = HashMap::new();
658 auth_configs.insert("github".to_string(), "ac_custom".to_string());
659
660 let config = SessionConfig {
661 user_id: "user_123".to_string(),
662 toolkits: None,
663 auth_configs: Some(auth_configs),
664 connected_accounts: None,
665 manage_connections: None,
666 tools: None,
667 tags: None,
668 workbench: None,
669 experimental: None,
670 toolkit_versions: None,
671 };
672
673 let json = serde_json::to_string(&config).unwrap();
674 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
675
676 assert_eq!(parsed["auth_configs"]["github"], "ac_custom");
677 }
678
679 #[test]
680 fn test_session_config_with_manage_connections_bool() {
681 let config = SessionConfig {
682 user_id: "user_123".to_string(),
683 toolkits: None,
684 auth_configs: None,
685 connected_accounts: None,
686 manage_connections: Some(ManageConnectionsConfig::Bool(true)),
687 tools: None,
688 tags: None,
689 workbench: None,
690 experimental: None,
691 toolkit_versions: None,
692 };
693
694 let json = serde_json::to_string(&config).unwrap();
695 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
696
697 assert_eq!(parsed["manage_connections"], true);
698 }
699
700 #[test]
701 fn test_session_config_with_manage_connections_detailed() {
702 let config = SessionConfig {
703 user_id: "user_123".to_string(),
704 toolkits: None,
705 auth_configs: None,
706 connected_accounts: None,
707 manage_connections: Some(ManageConnectionsConfig::Detailed {
708 enabled: true,
709 enable_wait_for_connections: Some(false),
710 }),
711 tools: None,
712 tags: None,
713 workbench: None,
714 experimental: None,
715 toolkit_versions: None,
716 };
717
718 let json = serde_json::to_string(&config).unwrap();
719 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
720
721 assert_eq!(parsed["manage_connections"]["enabled"], true);
722 assert_eq!(parsed["manage_connections"]["enable_wait_for_connections"], false);
723 }
724
725 #[test]
726 fn test_session_config_with_tools() {
727 let mut tools_map = HashMap::new();
728 tools_map.insert(
729 "github".to_string(),
730 ToolFilter::EnableList(vec!["GITHUB_CREATE_ISSUE".to_string()]),
731 );
732
733 let config = SessionConfig {
734 user_id: "user_123".to_string(),
735 toolkits: None,
736 auth_configs: None,
737 connected_accounts: None,
738 manage_connections: None,
739 tools: Some(ToolsConfig(tools_map)),
740 tags: None,
741 workbench: None,
742 experimental: None,
743 toolkit_versions: None,
744 };
745
746 let json = serde_json::to_string(&config).unwrap();
747 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
748
749 assert!(parsed["tools"]["github"].is_array());
750 }
751
752 #[test]
753 fn test_session_config_with_tags() {
754 let config = SessionConfig {
755 user_id: "user_123".to_string(),
756 toolkits: None,
757 auth_configs: None,
758 connected_accounts: None,
759 manage_connections: None,
760 tools: None,
761 tags: Some(TagsConfig {
762 enabled: Some(vec![TagType::ReadOnlyHint]),
763 disabled: Some(vec![TagType::DestructiveHint]),
764 }),
765 workbench: None,
766 experimental: None,
767 toolkit_versions: None,
768 };
769
770 let json = serde_json::to_string(&config).unwrap();
771 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
772
773 assert!(parsed["tags"]["enabled"].is_array());
774 assert!(parsed["tags"]["disabled"].is_array());
775 }
776
777 #[test]
778 fn test_session_config_with_workbench() {
779 let config = SessionConfig {
780 user_id: "user_123".to_string(),
781 toolkits: None,
782 auth_configs: None,
783 connected_accounts: None,
784 manage_connections: None,
785 tools: None,
786 tags: None,
787 workbench: Some(WorkbenchConfig {
788 proxy_execution: Some(true),
789 auto_offload_threshold: Some(1000),
790 }),
791 experimental: None,
792 toolkit_versions: None,
793 };
794
795 let json = serde_json::to_string(&config).unwrap();
796 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
797
798 assert_eq!(parsed["workbench"]["proxy_execution"], true);
799 assert_eq!(parsed["workbench"]["auto_offload_threshold"], 1000);
800 }
801
802 #[test]
803 fn test_toolkit_filter_enable_serialization() {
804 let filter = ToolkitFilter::Enable(vec!["github".to_string(), "gmail".to_string()]);
805 let json = serde_json::to_string(&filter).unwrap();
806 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
807
808 assert!(parsed.is_array());
809 assert_eq!(parsed.as_array().unwrap().len(), 2);
810 }
811
812 #[test]
813 fn test_toolkit_filter_disable_serialization() {
814 let filter = ToolkitFilter::Disable {
815 disable: vec!["exa".to_string()],
816 };
817 let json = serde_json::to_string(&filter).unwrap();
818 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
819
820 assert!(parsed.is_object());
821 assert!(parsed["disable"].is_array());
822 }
823
824 #[test]
825 fn test_tool_filter_enable_serialization() {
826 let filter = ToolFilter::Enable {
827 enable: vec!["GITHUB_CREATE_ISSUE".to_string()],
828 };
829 let json = serde_json::to_string(&filter).unwrap();
830 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
831
832 assert!(parsed.is_object());
833 assert!(parsed["enable"].is_array());
834 }
835
836 #[test]
837 fn test_tool_filter_disable_serialization() {
838 let filter = ToolFilter::Disable {
839 disable: vec!["GITHUB_DELETE_REPO".to_string()],
840 };
841 let json = serde_json::to_string(&filter).unwrap();
842 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
843
844 assert!(parsed.is_object());
845 assert!(parsed["disable"].is_array());
846 }
847
848 #[test]
849 fn test_tool_filter_enable_list_serialization() {
850 let filter = ToolFilter::EnableList(vec!["GITHUB_CREATE_ISSUE".to_string()]);
851 let json = serde_json::to_string(&filter).unwrap();
852 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
853
854 assert!(parsed.is_array());
855 }
856
857 #[test]
858 fn test_tool_execution_request_serialization() {
859 let request = ToolExecutionRequest {
860 tool_slug: "GITHUB_CREATE_ISSUE".to_string(),
861 arguments: Some(serde_json::json!({
862 "owner": "composio",
863 "repo": "composio",
864 "title": "Test issue"
865 })),
866 ..Default::default()
867 };
868
869 let json = serde_json::to_string(&request).unwrap();
870 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
871
872 assert_eq!(parsed["tool_slug"], "GITHUB_CREATE_ISSUE");
873 assert!(parsed["arguments"].is_object());
874 assert_eq!(parsed["arguments"]["owner"], "composio");
875 }
876
877 #[test]
878 fn test_tool_execution_request_without_arguments() {
879 let request = ToolExecutionRequest {
880 tool_slug: "GITHUB_GET_USER".to_string(),
881 arguments: None,
882 ..Default::default()
883 };
884
885 let json = serde_json::to_string(&request).unwrap();
886 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
887
888 assert_eq!(parsed["tool_slug"], "GITHUB_GET_USER");
889 assert!(parsed.get("arguments").is_none());
890 }
891
892 #[test]
893 fn test_meta_tool_execution_request_serialization() {
894 let request = MetaToolExecutionRequest {
895 slug: MetaToolSlug::ComposioSearchTools,
896 arguments: Some(serde_json::json!({
897 "query": "create a GitHub issue"
898 })),
899 };
900
901 let json = serde_json::to_string(&request).unwrap();
902 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
903
904 assert_eq!(parsed["slug"], "COMPOSIO_SEARCH_TOOLS");
905 assert!(parsed["arguments"].is_object());
906 }
907
908 #[test]
909 fn test_link_request_serialization() {
910 let request = LinkRequest {
911 toolkit: "github".to_string(),
912 callback_url: Some("https://example.com/callback".to_string()),
913 };
914
915 let json = serde_json::to_string(&request).unwrap();
916 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
917
918 assert_eq!(parsed["toolkit"], "github");
919 assert_eq!(parsed["callback_url"], "https://example.com/callback");
920 }
921
922 #[test]
923 fn test_link_request_without_callback() {
924 let request = LinkRequest {
925 toolkit: "gmail".to_string(),
926 callback_url: None,
927 };
928
929 let json = serde_json::to_string(&request).unwrap();
930 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
931
932 assert_eq!(parsed["toolkit"], "gmail");
933 assert!(parsed.get("callback_url").is_none());
934 }
935
936 #[test]
937 fn test_tags_config_serialization() {
938 let config = TagsConfig {
939 enabled: Some(vec![TagType::ReadOnlyHint, TagType::IdempotentHint]),
940 disabled: Some(vec![TagType::DestructiveHint]),
941 };
942
943 let json = serde_json::to_string(&config).unwrap();
944 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
945
946 assert!(parsed["enabled"].is_array());
947 assert!(parsed["disabled"].is_array());
948 assert_eq!(parsed["enabled"].as_array().unwrap().len(), 2);
949 assert_eq!(parsed["disabled"].as_array().unwrap().len(), 1);
950 }
951
952 #[test]
953 fn test_workbench_config_serialization() {
954 let config = WorkbenchConfig {
955 proxy_execution: Some(true),
956 auto_offload_threshold: Some(500),
957 };
958
959 let json = serde_json::to_string(&config).unwrap();
960 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
961
962 assert_eq!(parsed["proxy_execution"], true);
963 assert_eq!(parsed["auto_offload_threshold"], 500);
964 }
965
966 #[test]
967 fn test_workbench_config_partial_serialization() {
968 let config = WorkbenchConfig {
969 proxy_execution: Some(false),
970 auto_offload_threshold: None,
971 };
972
973 let json = serde_json::to_string(&config).unwrap();
974 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
975
976 assert_eq!(parsed["proxy_execution"], false);
977 assert!(parsed.get("auto_offload_threshold").is_none());
978 }
979}