devboy_yougile/
enricher.rs1use devboy_core::{ToolCategory, ToolEnricher, ToolSchema};
4use serde_json::Value;
5
6use crate::metadata::YouGileMetadata;
7
8pub struct YouGileSchemaEnricher {
13 metadata: YouGileMetadata,
14}
15
16impl YouGileSchemaEnricher {
17 pub fn new(metadata: YouGileMetadata) -> Self {
18 Self { metadata }
19 }
20}
21
22impl ToolEnricher for YouGileSchemaEnricher {
23 fn supported_categories(&self) -> &[ToolCategory] {
24 &[ToolCategory::IssueTracker]
25 }
26
27 fn enrich_schema(&self, tool_name: &str, schema: &mut ToolSchema) {
28 const REMOVE_PARAMS: &[&str] = &["issueType", "components", "projectId", "points"];
29 const GET_ISSUES_REMOVE_PARAMS: &[&str] = &["projectKey", "nativeQuery"];
30
31 schema.remove_params(REMOVE_PARAMS);
32
33 if tool_name == "get_issues" {
34 schema.remove_params(GET_ISSUES_REMOVE_PARAMS);
35 schema.add_enum_param(
36 "stateCategory",
37 &["backlog", "todo", "in_progress", "done", "cancelled"],
38 "Filter by semantic status category. Maps YouGile board columns to shared status buckets using column-title heuristics.",
39 );
40 schema.set_description(
43 "assignee",
44 "Filter by assignee **user id** (UUID) — YouGile does not match names or emails",
45 );
46 schema.set_description(
49 "sort_by",
50 "YouGile stores one timestamp per task; `created_at` and `updated_at` order by it identically",
51 );
52 }
53
54 let statuses: Vec<String> = self
55 .metadata
56 .columns
57 .iter()
58 .map(|column| column.title.clone())
59 .collect();
60 if !statuses.is_empty() {
61 schema.set_enum("status", &statuses);
62 schema.set_description(
63 "status",
64 &format!(
65 "Filter by exact board column title. Available: {}",
66 statuses.join(", ")
67 ),
68 );
69 }
70 }
71
72 fn transform_args(&self, _tool_name: &str, _args: &mut Value) {}
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use crate::metadata::{YouGileBoard, YouGileColumn};
79
80 #[test]
81 fn enrich_schema_sets_status_enum_and_state_category() {
82 let enricher = YouGileSchemaEnricher::new(YouGileMetadata {
83 boards: vec![YouGileBoard {
84 id: "board-1".to_string(),
85 title: "Platform".to_string(),
86 }],
87 columns: vec![
88 YouGileColumn {
89 id: "col-1".to_string(),
90 title: "Backlog".to_string(),
91 board_id: Some("board-1".to_string()),
92 },
93 YouGileColumn {
94 id: "col-2".to_string(),
95 title: "In Progress".to_string(),
96 board_id: Some("board-1".to_string()),
97 },
98 ],
99 });
100
101 let mut schema = ToolSchema::from_json(&serde_json::json!({
102 "type": "object",
103 "properties": {
104 "status": { "type": "string" },
105 "projectKey": { "type": "string" }
106 }
107 }));
108
109 enricher.enrich_schema("get_issues", &mut schema);
110
111 assert_eq!(
112 schema.properties["status"].enum_values.as_ref().unwrap(),
113 &vec!["Backlog".to_string(), "In Progress".to_string()]
114 );
115 assert!(schema.properties.contains_key("stateCategory"));
116 assert!(!schema.properties.contains_key("projectKey"));
117 }
118}