1use std::borrow::Borrow;
15use std::fmt;
16use std::str::FromStr;
17use std::sync::Arc;
18
19use serde::{Deserialize, Serialize};
20
21#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
60#[serde(transparent)]
61pub struct ToolName(Arc<str>);
62
63impl ToolName {
64 #[must_use]
78 pub fn new(s: impl Into<Arc<str>>) -> Self {
79 Self(s.into())
80 }
81
82 #[must_use]
96 pub fn as_str(&self) -> &str {
97 &self.0
98 }
99}
100
101impl Default for ToolName {
102 fn default() -> Self {
107 Self(Arc::from(""))
108 }
109}
110
111impl fmt::Display for ToolName {
112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 f.write_str(&self.0)
114 }
115}
116
117impl AsRef<str> for ToolName {
118 fn as_ref(&self) -> &str {
119 &self.0
120 }
121}
122
123impl Borrow<str> for ToolName {
124 fn borrow(&self) -> &str {
125 &self.0
126 }
127}
128
129impl From<&str> for ToolName {
130 fn from(s: &str) -> Self {
131 Self(Arc::from(s))
132 }
133}
134
135impl From<String> for ToolName {
136 fn from(s: String) -> Self {
137 Self(Arc::from(s.as_str()))
138 }
139}
140
141impl FromStr for ToolName {
142 type Err = std::convert::Infallible;
143
144 fn from_str(s: &str) -> Result<Self, Self::Err> {
145 Ok(Self::from(s))
146 }
147}
148
149impl PartialEq<str> for ToolName {
150 fn eq(&self, other: &str) -> bool {
151 self.0.as_ref() == other
152 }
153}
154
155impl PartialEq<&str> for ToolName {
156 fn eq(&self, other: &&str) -> bool {
157 self.0.as_ref() == *other
158 }
159}
160
161impl PartialEq<String> for ToolName {
162 fn eq(&self, other: &String) -> bool {
163 self.0.as_ref() == other.as_str()
164 }
165}
166
167impl PartialEq<ToolName> for str {
168 fn eq(&self, other: &ToolName) -> bool {
169 self == other.0.as_ref()
170 }
171}
172
173impl PartialEq<ToolName> for String {
174 fn eq(&self, other: &ToolName) -> bool {
175 self.as_str() == other.0.as_ref()
176 }
177}
178
179#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
211#[serde(transparent)]
212pub struct ProviderName(Arc<str>);
213
214impl ProviderName {
215 #[must_use]
226 pub fn new(s: impl Into<Arc<str>>) -> Self {
227 Self(s.into())
228 }
229
230 #[must_use]
241 pub fn as_str(&self) -> &str {
242 &self.0
243 }
244}
245
246impl Default for ProviderName {
247 fn default() -> Self {
252 Self(Arc::from(""))
253 }
254}
255
256impl fmt::Display for ProviderName {
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 f.write_str(&self.0)
259 }
260}
261
262impl AsRef<str> for ProviderName {
263 fn as_ref(&self) -> &str {
264 &self.0
265 }
266}
267
268impl Borrow<str> for ProviderName {
269 fn borrow(&self) -> &str {
270 &self.0
271 }
272}
273
274impl From<&str> for ProviderName {
275 fn from(s: &str) -> Self {
276 Self(Arc::from(s))
277 }
278}
279
280impl From<String> for ProviderName {
281 fn from(s: String) -> Self {
282 Self(Arc::from(s.as_str()))
283 }
284}
285
286impl FromStr for ProviderName {
287 type Err = std::convert::Infallible;
288
289 fn from_str(s: &str) -> Result<Self, Self::Err> {
290 Ok(Self::from(s))
291 }
292}
293
294impl PartialEq<str> for ProviderName {
295 fn eq(&self, other: &str) -> bool {
296 self.0.as_ref() == other
297 }
298}
299
300impl PartialEq<&str> for ProviderName {
301 fn eq(&self, other: &&str) -> bool {
302 self.0.as_ref() == *other
303 }
304}
305
306impl PartialEq<String> for ProviderName {
307 fn eq(&self, other: &String) -> bool {
308 self.0.as_ref() == other.as_str()
309 }
310}
311
312impl PartialEq<ProviderName> for str {
313 fn eq(&self, other: &ProviderName) -> bool {
314 self == other.0.as_ref()
315 }
316}
317
318impl PartialEq<ProviderName> for String {
319 fn eq(&self, other: &ProviderName) -> bool {
320 self.as_str() == other.0.as_ref()
321 }
322}
323
324#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
357#[serde(transparent)]
358pub struct SkillName(Arc<str>);
359
360impl SkillName {
361 #[must_use]
372 pub fn new(s: impl Into<Arc<str>>) -> Self {
373 Self(s.into())
374 }
375
376 #[must_use]
387 pub fn as_str(&self) -> &str {
388 &self.0
389 }
390}
391
392impl Default for SkillName {
393 fn default() -> Self {
398 Self(Arc::from(""))
399 }
400}
401
402impl fmt::Display for SkillName {
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 f.write_str(&self.0)
405 }
406}
407
408impl AsRef<str> for SkillName {
409 fn as_ref(&self) -> &str {
410 &self.0
411 }
412}
413
414impl Borrow<str> for SkillName {
415 fn borrow(&self) -> &str {
416 &self.0
417 }
418}
419
420impl From<&str> for SkillName {
421 fn from(s: &str) -> Self {
422 Self(Arc::from(s))
423 }
424}
425
426impl From<String> for SkillName {
427 fn from(s: String) -> Self {
428 Self(Arc::from(s.as_str()))
429 }
430}
431
432impl FromStr for SkillName {
433 type Err = std::convert::Infallible;
434
435 fn from_str(s: &str) -> Result<Self, Self::Err> {
436 Ok(Self::from(s))
437 }
438}
439
440impl PartialEq<str> for SkillName {
441 fn eq(&self, other: &str) -> bool {
442 self.0.as_ref() == other
443 }
444}
445
446impl PartialEq<&str> for SkillName {
447 fn eq(&self, other: &&str) -> bool {
448 self.0.as_ref() == *other
449 }
450}
451
452impl PartialEq<String> for SkillName {
453 fn eq(&self, other: &String) -> bool {
454 self.0.as_ref() == other.as_str()
455 }
456}
457
458impl PartialEq<SkillName> for str {
459 fn eq(&self, other: &SkillName) -> bool {
460 self == other.0.as_ref()
461 }
462}
463
464impl PartialEq<SkillName> for String {
465 fn eq(&self, other: &SkillName) -> bool {
466 self.as_str() == other.0.as_ref()
467 }
468}
469
470#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
504#[serde(transparent)]
505pub struct SessionId(String);
506
507impl SessionId {
508 pub fn new(s: impl Into<String>) -> Self {
527 let s = s.into();
528 debug_assert!(!s.is_empty(), "SessionId must not be empty");
529 Self(s)
530 }
531
532 #[must_use]
545 pub fn generate() -> Self {
546 Self(uuid::Uuid::new_v4().to_string())
547 }
548
549 #[must_use]
560 pub fn as_str(&self) -> &str {
561 &self.0
562 }
563}
564
565impl Default for SessionId {
566 fn default() -> Self {
568 Self::generate()
569 }
570}
571
572impl fmt::Display for SessionId {
573 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
574 f.write_str(&self.0)
575 }
576}
577
578impl AsRef<str> for SessionId {
579 fn as_ref(&self) -> &str {
580 &self.0
581 }
582}
583
584impl std::ops::Deref for SessionId {
585 type Target = str;
586
587 fn deref(&self) -> &str {
588 &self.0
589 }
590}
591
592impl From<String> for SessionId {
593 fn from(s: String) -> Self {
594 Self::new(s)
595 }
596}
597
598impl From<&str> for SessionId {
599 fn from(s: &str) -> Self {
600 Self::new(s)
601 }
602}
603
604impl From<uuid::Uuid> for SessionId {
605 fn from(u: uuid::Uuid) -> Self {
606 Self(u.to_string())
607 }
608}
609
610impl FromStr for SessionId {
611 type Err = std::convert::Infallible;
612
613 fn from_str(s: &str) -> Result<Self, Self::Err> {
614 Ok(Self::new(s))
615 }
616}
617
618impl PartialEq<str> for SessionId {
619 fn eq(&self, other: &str) -> bool {
620 self.0 == other
621 }
622}
623
624impl PartialEq<&str> for SessionId {
625 fn eq(&self, other: &&str) -> bool {
626 self.0 == *other
627 }
628}
629
630impl PartialEq<String> for SessionId {
631 fn eq(&self, other: &String) -> bool {
632 self.0 == *other
633 }
634}
635
636impl PartialEq<SessionId> for str {
637 fn eq(&self, other: &SessionId) -> bool {
638 self == other.0
639 }
640}
641
642impl PartialEq<SessionId> for String {
643 fn eq(&self, other: &SessionId) -> bool {
644 *self == other.0
645 }
646}
647
648#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
676pub struct ToolDefinition {
677 pub name: ToolName,
679 pub description: String,
681 pub parameters: serde_json::Value,
683 #[serde(default, skip_serializing_if = "Option::is_none")]
691 pub output_schema: Option<serde_json::Value>,
692}
693
694#[cfg(test)]
695mod tests {
696 use super::*;
697
698 #[test]
699 fn tool_name_construction_and_equality() {
700 let name = ToolName::new("shell");
701 assert_eq!(name.as_str(), "shell");
702 assert_eq!(name, "shell");
703 assert_eq!(name, "shell".to_owned());
704 assert_eq!(name, "shell"); }
706
707 #[test]
708 fn tool_name_clone_is_cheap() {
709 let name = ToolName::new("web_scrape");
710 let name2 = name.clone();
711 assert_eq!(name, name2);
712 assert!(Arc::ptr_eq(&name.0, &name2.0));
714 }
715
716 #[test]
717 fn tool_name_from_impls() {
718 let from_str: ToolName = ToolName::from("bash");
719 let from_string: ToolName = ToolName::from("bash".to_owned());
720 let parsed: ToolName = "bash".parse().unwrap();
721 assert_eq!(from_str, from_string);
722 assert_eq!(from_str, parsed);
723 }
724
725 #[test]
726 fn tool_name_as_hashmap_key() {
727 use std::collections::HashMap;
728 let mut map: HashMap<ToolName, u32> = HashMap::new();
729 map.insert(ToolName::new("shell"), 1);
730 assert_eq!(map.get("shell"), Some(&1));
732 }
733
734 #[test]
735 fn tool_name_display() {
736 let name = ToolName::new("my_tool");
737 assert_eq!(format!("{name}"), "my_tool");
738 }
739
740 #[test]
741 fn tool_name_serde_transparent() {
742 let name = ToolName::new("shell");
743 let json = serde_json::to_string(&name).unwrap();
744 assert_eq!(json, r#""shell""#);
745 let back: ToolName = serde_json::from_str(&json).unwrap();
746 assert_eq!(back, name);
747 }
748
749 #[test]
750 fn session_id_new_roundtrip() {
751 let id = SessionId::new("test-session");
752 assert_eq!(id.as_str(), "test-session");
753 assert_eq!(id.to_string(), "test-session");
754 }
755
756 #[test]
757 fn session_id_generate_is_uuid() {
758 let id = SessionId::generate();
759 assert_eq!(id.as_str().len(), 36);
760 assert!(uuid::Uuid::parse_str(id.as_str()).is_ok());
761 }
762
763 #[test]
764 fn session_id_default_is_generated() {
765 let id = SessionId::default();
766 assert!(!id.as_str().is_empty());
767 assert_eq!(id.as_str().len(), 36);
768 }
769
770 #[test]
771 fn session_id_from_uuid() {
772 let u = uuid::Uuid::new_v4();
773 let id = SessionId::from(u);
774 assert_eq!(id.as_str(), u.to_string());
775 }
776
777 #[test]
778 fn session_id_deref_slicing() {
779 let id = SessionId::new("abcdefgh");
780 assert_eq!(&id[..4], "abcd");
782 }
783
784 #[test]
785 fn session_id_serde_transparent() {
786 let id = SessionId::new("sess-abc");
787 let json = serde_json::to_string(&id).unwrap();
788 assert_eq!(json, r#""sess-abc""#);
789 let back: SessionId = serde_json::from_str(&json).unwrap();
790 assert_eq!(back, id);
791 }
792
793 #[test]
794 fn session_id_from_str_parses() {
795 let id: SessionId = "my-session".parse().unwrap();
796 assert_eq!(id.as_str(), "my-session");
797 }
798
799 #[test]
800 fn provider_name_construction_and_equality() {
801 let name = ProviderName::new("fast");
802 assert_eq!(name.as_str(), "fast");
803 assert_eq!(name, "fast");
804 assert_eq!(name, "fast".to_owned());
805 }
806
807 #[test]
808 fn provider_name_clone_is_cheap() {
809 let name = ProviderName::new("quality");
810 let name2 = name.clone();
811 assert_eq!(name, name2);
812 assert!(Arc::ptr_eq(&name.0, &name2.0));
813 }
814
815 #[test]
816 fn provider_name_from_impls() {
817 let from_str: ProviderName = ProviderName::from("fast");
818 let from_string: ProviderName = ProviderName::from("fast".to_owned());
819 let parsed: ProviderName = "fast".parse().unwrap();
820 assert_eq!(from_str, from_string);
821 assert_eq!(from_str, parsed);
822 }
823
824 #[test]
825 fn provider_name_as_hashmap_key() {
826 use std::collections::HashMap;
827 let mut map: HashMap<ProviderName, u32> = HashMap::new();
828 map.insert(ProviderName::new("fast"), 1);
829 assert_eq!(map.get("fast"), Some(&1));
830 }
831
832 #[test]
833 fn provider_name_display() {
834 let name = ProviderName::new("ollama-local");
835 assert_eq!(format!("{name}"), "ollama-local");
836 }
837
838 #[test]
839 fn provider_name_serde_transparent() {
840 let name = ProviderName::new("quality");
841 let json = serde_json::to_string(&name).unwrap();
842 assert_eq!(json, r#""quality""#);
843 let back: ProviderName = serde_json::from_str(&json).unwrap();
844 assert_eq!(back, name);
845 }
846
847 #[test]
848 fn skill_name_construction_and_equality() {
849 let name = SkillName::new("rust-agents");
850 assert_eq!(name.as_str(), "rust-agents");
851 assert_eq!(name, "rust-agents");
852 assert_eq!(name, "rust-agents".to_owned());
853 }
854
855 #[test]
856 fn skill_name_clone_is_cheap() {
857 let name = SkillName::new("readme-generator");
858 let name2 = name.clone();
859 assert_eq!(name, name2);
860 assert!(Arc::ptr_eq(&name.0, &name2.0));
861 }
862
863 #[test]
864 fn skill_name_from_impls() {
865 let from_str: SkillName = SkillName::from("rust-agents");
866 let from_string: SkillName = SkillName::from("rust-agents".to_owned());
867 let parsed: SkillName = "rust-agents".parse().unwrap();
868 assert_eq!(from_str, from_string);
869 assert_eq!(from_str, parsed);
870 }
871
872 #[test]
873 fn skill_name_as_hashmap_key() {
874 use std::collections::HashMap;
875 let mut map: HashMap<SkillName, u32> = HashMap::new();
876 map.insert(SkillName::new("rust-agents"), 1);
877 assert_eq!(map.get("rust-agents"), Some(&1));
878 }
879
880 #[test]
881 fn skill_name_display() {
882 let name = SkillName::new("readme-generator");
883 assert_eq!(format!("{name}"), "readme-generator");
884 }
885
886 #[test]
887 fn skill_name_serde_transparent() {
888 let name = SkillName::new("rust-agents");
889 let json = serde_json::to_string(&name).unwrap();
890 assert_eq!(json, r#""rust-agents""#);
891 let back: SkillName = serde_json::from_str(&json).unwrap();
892 assert_eq!(back, name);
893 }
894}