1use serde_json::json;
2use std::collections::HashMap;
3
4use crate::types::{ToolDefinition, ToolResult};
5use super::registry::EngineState;
6
7fn def(name: &str, desc: &str, props: serde_json::Value) -> ToolDefinition {
8 ToolDefinition {
9 name: name.to_string(),
10 description: desc.to_string(),
11 input_schema: json!({ "type": "object", "properties": props }),
12 }
13}
14
15fn s(d: &str) -> serde_json::Value { json!({ "type": "string", "description": d }) }
16
17pub fn definitions() -> Vec<ToolDefinition> {
18 vec![
19 def("workflow_template_list", "List available workflow templates",
21 json!({ "tag": s("Filter by tag") })),
22 def("workflow_template_use", "Instantiate a workflow from a template with parameters",
23 json!({ "template_id": s("Template ID"), "params": json!({ "type": "object", "description": "Template parameters" }) })),
24 def("workflow_template_create", "Create a reusable workflow template",
25 json!({ "name": s("Template name"), "description": s("Description"), "workflow_definition": json!({ "type": "object", "description": "Workflow JSON" }), "tags": json!({ "type": "array", "items": { "type": "string" } }), "author": s("Author") })),
26 def("workflow_template_share", "Share a template with the community",
27 json!({ "template_id": s("Template ID"), "shared_by": s("Sharer identity") })),
28 def("workflow_template_compose", "Compose multiple templates into a pipeline",
29 json!({ "template_ids": json!({ "type": "array", "items": { "type": "string" }, "description": "Template IDs to compose" }), "name": s("Composed workflow name") })),
30 def("workflow_natural_create", "Create a workflow from a natural language description",
32 json!({ "description": s("Plain-English workflow description") })),
33 def("workflow_natural_preview", "Preview the synthesized workflow from a natural language request",
34 json!({ "request_index": json!({ "type": "integer", "description": "Request index" }) })),
35 def("workflow_natural_clarify", "Add a clarification question to a natural language request",
36 json!({ "request_index": json!({ "type": "integer", "description": "Request index" }), "question": s("Clarification question"), "options": json!({ "type": "array", "items": { "type": "string" } }) })),
37 def("workflow_natural_refine", "Answer a clarification to refine the workflow",
38 json!({ "request_index": json!({ "type": "integer", "description": "Request index" }), "clarification_index": json!({ "type": "integer", "description": "Clarification index" }), "answer": s("Answer to clarification") })),
39 def("workflow_compose_sequence", "Compose workflows in sequence: A then B then C",
41 json!({ "name": s("Composition name"), "workflow_ids": json!({ "type": "array", "items": { "type": "string" }, "description": "Workflow IDs in order" }) })),
42 def("workflow_compose_parallel", "Compose workflows in parallel: A and B and C simultaneously",
43 json!({ "name": s("Composition name"), "workflow_ids": json!({ "type": "array", "items": { "type": "string" } }) })),
44 def("workflow_compose_conditional", "Compose workflows conditionally: if P then A else B",
45 json!({ "name": s("Composition name"), "predicate": s("Condition expression"), "if_true": s("Workflow if true"), "if_false": s("Workflow if false") })),
46 def("workflow_compose_validate", "Validate a composed meta-workflow",
47 json!({ "meta_id": s("Meta-workflow ID") })),
48 def("workflow_compose_run", "Execute a composed meta-workflow",
49 json!({ "meta_id": s("Meta-workflow ID") })),
50 def("workflow_collective_share", "Share a workflow with the collective community",
52 json!({ "name": s("Workflow name"), "description": s("Description"), "workflow_definition": json!({ "type": "object", "description": "Workflow JSON" }), "author": s("Author"), "tags": json!({ "type": "array", "items": { "type": "string" } }) })),
53 def("workflow_collective_search", "Search community-shared workflows",
54 json!({ "query": s("Search query") })),
55 def("workflow_collective_apply", "Download and apply a community workflow",
56 json!({ "id": s("Collective item ID") })),
57 def("workflow_collective_rate", "Rate a community workflow",
58 json!({ "id": s("Collective item ID"), "rating": json!({ "type": "number", "description": "Rating 0-5" }) })),
59 def("workflow_collective_private", "Verify no private data in a shared workflow",
60 json!({ "id": s("Collective item ID") })),
61 ]
62}
63
64pub fn dispatch(
65 name: &str,
66 params: serde_json::Value,
67 state: &mut EngineState,
68) -> Result<ToolResult, (i32, String)> {
69 match name {
70 "workflow_template_list" => {
72 let templates = if let Some(tag) = params["tag"].as_str() {
73 state.template.search_by_tag(tag)
74 } else {
75 state.template.list_templates()
76 };
77 let items: Vec<_> = templates.iter().map(|t| json!({
78 "id": t.id, "name": t.name, "tags": t.tags, "usage_count": t.usage_count
79 })).collect();
80 Ok(ToolResult::text(json!({ "templates": items }).to_string()))
81 }
82 "workflow_template_use" => {
83 let tid = params["template_id"].as_str().unwrap_or("");
84 let p: HashMap<String, serde_json::Value> = params["params"]
85 .as_object()
86 .map(|o| o.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
87 .unwrap_or_default();
88 match state.template.instantiate(tid, &p) {
89 Ok(wf) => Ok(ToolResult::text(json!({
90 "template_id": tid, "workflow": wf, "status": "instantiated"
91 }).to_string())),
92 Err(e) => Ok(ToolResult::error(format!("{}", e))),
93 }
94 }
95 "workflow_template_create" => {
96 let tname = params["name"].as_str().unwrap_or("");
97 let desc = params["description"].as_str().unwrap_or("");
98 let wf_def = params["workflow_definition"].clone();
99 let tags: Vec<String> = params["tags"].as_array()
100 .map(|a| a.iter().filter_map(|v| v.as_str().map(String::from)).collect())
101 .unwrap_or_default();
102 let author = params["author"].as_str().unwrap_or("anonymous");
103 match state.template.create_template(tname, desc, Vec::new(), wf_def, tags, author) {
104 Ok(tid) => Ok(ToolResult::text(json!({ "template_id": tid, "status": "created" }).to_string())),
105 Err(e) => Ok(ToolResult::error(format!("{}", e))),
106 }
107 }
108 "workflow_template_share" => {
109 let tid = params["template_id"].as_str().unwrap_or("");
110 let by = params["shared_by"].as_str().unwrap_or("anonymous");
111 match state.template.share_template(tid, by) {
112 Ok(sid) => Ok(ToolResult::text(json!({ "shared_id": sid, "status": "shared" }).to_string())),
113 Err(e) => Ok(ToolResult::error(format!("{}", e))),
114 }
115 }
116 "workflow_template_compose" => {
117 let ids: Vec<String> = params["template_ids"].as_array()
118 .map(|a| a.iter().filter_map(|v| v.as_str().map(String::from)).collect())
119 .unwrap_or_default();
120 let cname = params["name"].as_str().unwrap_or("composed");
121 match state.composer.sequence(cname, ids) {
122 Ok(mid) => Ok(ToolResult::text(json!({ "meta_id": mid, "status": "composed" }).to_string())),
123 Err(e) => Ok(ToolResult::error(format!("{}", e))),
124 }
125 }
126 "workflow_natural_create" => {
128 let desc = params["description"].as_str().unwrap_or("");
129 let idx = state.natural.create_request(desc);
130 Ok(ToolResult::text(json!({ "request_index": idx, "status": "created" }).to_string()))
131 }
132 "workflow_natural_preview" => {
133 let idx = params["request_index"].as_u64().unwrap_or(0) as usize;
134 match state.natural.get_request(idx) {
135 Some(req) => Ok(ToolResult::text(json!({
136 "description": req.description,
137 "clarifications": req.clarifications.len(),
138 "synthesized": req.synthesized_workflow.is_some()
139 }).to_string())),
140 None => Ok(ToolResult::error("Request not found")),
141 }
142 }
143 "workflow_natural_clarify" => {
144 let idx = params["request_index"].as_u64().unwrap_or(0) as usize;
145 let question = params["question"].as_str().unwrap_or("");
146 let options = params["options"].as_array().map(|a| {
147 a.iter().filter_map(|v| v.as_str().map(String::from)).collect()
148 });
149 match state.natural.add_clarification(idx, question, options) {
150 Ok(()) => Ok(ToolResult::text(json!({ "status": "clarification_added" }).to_string())),
151 Err(e) => Ok(ToolResult::error(format!("{}", e))),
152 }
153 }
154 "workflow_natural_refine" => {
155 let idx = params["request_index"].as_u64().unwrap_or(0) as usize;
156 let cidx = params["clarification_index"].as_u64().unwrap_or(0) as usize;
157 let answer = params["answer"].as_str().unwrap_or("");
158 match state.natural.answer_clarification(idx, cidx, answer) {
159 Ok(()) => Ok(ToolResult::text(json!({ "status": "refined" }).to_string())),
160 Err(e) => Ok(ToolResult::error(format!("{}", e))),
161 }
162 }
163 "workflow_compose_sequence" => {
165 let cname = params["name"].as_str().unwrap_or("sequence");
166 let ids: Vec<String> = params["workflow_ids"].as_array()
167 .map(|a| a.iter().filter_map(|v| v.as_str().map(String::from)).collect())
168 .unwrap_or_default();
169 match state.composer.sequence(cname, ids) {
170 Ok(mid) => Ok(ToolResult::text(json!({ "meta_id": mid, "status": "created" }).to_string())),
171 Err(e) => Ok(ToolResult::error(format!("{}", e))),
172 }
173 }
174 "workflow_compose_parallel" => {
175 let cname = params["name"].as_str().unwrap_or("parallel");
176 let ids: Vec<String> = params["workflow_ids"].as_array()
177 .map(|a| a.iter().filter_map(|v| v.as_str().map(String::from)).collect())
178 .unwrap_or_default();
179 match state.composer.parallel(cname, ids) {
180 Ok(mid) => Ok(ToolResult::text(json!({ "meta_id": mid, "status": "created" }).to_string())),
181 Err(e) => Ok(ToolResult::error(format!("{}", e))),
182 }
183 }
184 "workflow_compose_conditional" => {
185 let cname = params["name"].as_str().unwrap_or("conditional");
186 let pred = params["predicate"].as_str().unwrap_or("true");
187 let if_t = params["if_true"].as_str().unwrap_or("");
188 let if_f = params["if_false"].as_str().unwrap_or("");
189 match state.composer.conditional(cname, pred, if_t, if_f) {
190 Ok(mid) => Ok(ToolResult::text(json!({ "meta_id": mid, "status": "created" }).to_string())),
191 Err(e) => Ok(ToolResult::error(format!("{}", e))),
192 }
193 }
194 "workflow_compose_validate" => {
195 let mid = params["meta_id"].as_str().unwrap_or("");
196 match state.composer.validate(mid) {
197 Ok(warnings) => Ok(ToolResult::text(json!({
198 "meta_id": mid, "valid": warnings.is_empty(), "warnings": warnings
199 }).to_string())),
200 Err(e) => Ok(ToolResult::error(format!("{}", e))),
201 }
202 }
203 "workflow_compose_run" => {
204 let mid = params["meta_id"].as_str().unwrap_or("");
205 match state.composer.get_meta(mid) {
206 Ok(meta) => Ok(ToolResult::text(json!({
207 "meta_id": meta.id, "name": meta.name, "status": "execution_started"
208 }).to_string())),
209 Err(e) => Ok(ToolResult::error(format!("{}", e))),
210 }
211 }
212 "workflow_collective_share" => {
214 let cname = params["name"].as_str().unwrap_or("");
215 let desc = params["description"].as_str().unwrap_or("");
216 let wf_def = params["workflow_definition"].clone();
217 let author = params["author"].as_str().unwrap_or("anonymous");
218 let tags: Vec<String> = params["tags"].as_array()
219 .map(|a| a.iter().filter_map(|v| v.as_str().map(String::from)).collect())
220 .unwrap_or_default();
221 let id = state.collective.share(cname, desc, wf_def, author, tags);
222 Ok(ToolResult::text(json!({ "id": id, "status": "shared" }).to_string()))
223 }
224 "workflow_collective_search" => {
225 let query = params["query"].as_str().unwrap_or("");
226 let results = state.collective.search(query);
227 let items: Vec<_> = results.iter().map(|r| json!({
228 "id": r.id, "name": r.name, "rating": r.rating, "downloads": r.download_count
229 })).collect();
230 Ok(ToolResult::text(json!({ "results": items }).to_string()))
231 }
232 "workflow_collective_apply" => {
233 let id = params["id"].as_str().unwrap_or("");
234 match state.collective.apply(id) {
235 Some(wf) => Ok(ToolResult::text(json!({ "id": id, "workflow": wf, "status": "applied" }).to_string())),
236 None => Ok(ToolResult::error(format!("Collective item not found: {}", id))),
237 }
238 }
239 "workflow_collective_rate" => {
240 let id = params["id"].as_str().unwrap_or("");
241 let rating = params["rating"].as_f64().unwrap_or(3.0);
242 if state.collective.rate(id, rating) {
243 Ok(ToolResult::text(json!({ "id": id, "rating": rating, "status": "rated" }).to_string()))
244 } else {
245 Ok(ToolResult::error(format!("Collective item not found: {}", id)))
246 }
247 }
248 "workflow_collective_private" => {
249 let id = params["id"].as_str().unwrap_or("");
250 let clean = state.collective.verify_privacy(id);
251 Ok(ToolResult::text(json!({ "id": id, "privacy_verified": clean }).to_string()))
252 }
253 _ => Ok(ToolResult::error(format!("Unknown template tool: {}", name))),
254 }
255}