1use serde_json::{Map, Value, json};
4
5fn schema_ref(name: &str) -> Value {
6 json!({ "$ref": format!("#/components/schemas/{name}") })
7}
8
9fn json_response(schema: &str) -> Value {
10 json!({
11 "description": "OK",
12 "content": {
13 "application/json": { "schema": schema_ref(schema) }
14 }
15 })
16}
17
18fn sse_response() -> Value {
19 json!({
20 "description": "Server-Sent Events stream",
21 "content": {
22 "text/event-stream": { "schema": { "type": "string" } }
23 }
24 })
25}
26
27fn operation(
28 method: &str,
29 operation_id: &str,
30 summary: &str,
31 body: Option<&str>,
32 response: Value,
33 secured: bool,
34) -> (String, Value) {
35 let mut op = Map::new();
36 op.insert("operationId".into(), json!(operation_id));
37 op.insert("summary".into(), json!(summary));
38 if let Some(body_schema) = body {
39 op.insert(
40 "requestBody".into(),
41 json!({
42 "required": true,
43 "content": {
44 "application/json": { "schema": schema_ref(body_schema) }
45 }
46 }),
47 );
48 }
49 op.insert("responses".into(), json!({ "200": response }));
50 if secured {
51 op.insert("security".into(), json!([{ "BearerAuth": [] }]));
52 }
53 (method.into(), Value::Object(op))
54}
55
56fn json_op(
57 method: &str,
58 operation_id: &str,
59 summary: &str,
60 body: Option<&str>,
61 schema: &str,
62 secured: bool,
63) -> (String, Value) {
64 operation(
65 method,
66 operation_id,
67 summary,
68 body,
69 json_response(schema),
70 secured,
71 )
72}
73
74fn path_item(ops: Vec<(String, Value)>) -> Value {
75 let mut m = Map::new();
76 for (k, v) in ops {
77 m.insert(k, v);
78 }
79 Value::Object(m)
80}
81
82pub fn build_paths() -> Map<String, Value> {
84 let mut paths = Map::new();
85 let u = true;
86 let mut add = |path: &str, ops: Vec<(String, Value)>| {
87 paths.insert(path.into(), path_item(ops));
88 };
89
90 add(
91 "/health",
92 vec![json_op(
93 "get",
94 "health",
95 "Liveness probe",
96 None,
97 "ErrorBody",
98 false,
99 )],
100 );
101 add(
102 "/internal/probe",
103 vec![json_op(
104 "get",
105 "internalProbe",
106 "Internal readiness probe",
107 None,
108 "ErrorBody",
109 false,
110 )],
111 );
112 add(
113 "/v1/sessions",
114 vec![json_op(
115 "get",
116 "listSessions",
117 "List saved sessions",
118 None,
119 "SessionsListResponse",
120 u,
121 )],
122 );
123 add(
124 "/v1/sessions/{id}",
125 vec![
126 json_op(
127 "get",
128 "getSession",
129 "Load session detail",
130 None,
131 "SessionDetailResponse",
132 u,
133 ),
134 operation(
135 "delete",
136 "deleteSession",
137 "Delete saved session",
138 None,
139 json!({ "description": "Deleted" }),
140 u,
141 ),
142 ],
143 );
144 add(
145 "/v1/sessions/{id}/resume-thread",
146 vec![json_op(
147 "post",
148 "resumeSessionThread",
149 "Resume session into runtime thread",
150 None,
151 "ResumeSessionResponse",
152 u,
153 )],
154 );
155 add(
156 "/v1/resume-tasks/{thread_id}",
157 vec![json_op(
158 "get",
159 "getResumeTask",
160 "Resume seeding status",
161 None,
162 "ResumeSessionResponse",
163 u,
164 )],
165 );
166 add(
167 "/v1/workspace/status",
168 vec![json_op(
169 "get",
170 "workspaceStatus",
171 "Workspace status",
172 None,
173 "ErrorBody",
174 u,
175 )],
176 );
177 add(
178 "/v1/workspace/browse",
179 vec![json_op(
180 "get",
181 "browseWorkspace",
182 "Browse workspace",
183 None,
184 "ErrorBody",
185 u,
186 )],
187 );
188 add(
189 "/v1/workspace/file",
190 vec![json_op(
191 "get",
192 "readWorkspaceFile",
193 "Read workspace file",
194 None,
195 "ErrorBody",
196 u,
197 )],
198 );
199 add(
200 "/v1/stream",
201 vec![operation(
202 "post",
203 "streamTurn",
204 "Create thread and stream turn (SSE)",
205 Some("StreamTurnRequest"),
206 sse_response(),
207 u,
208 )],
209 );
210 add(
211 "/v1/threads",
212 vec![
213 json_op(
214 "get",
215 "listThreads",
216 "List threads",
217 None,
218 "ThreadRecord",
219 u,
220 ),
221 json_op(
222 "post",
223 "createThread",
224 "Create thread",
225 Some("CreateThreadRequest"),
226 "ThreadRecord",
227 u,
228 ),
229 ],
230 );
231 add(
232 "/v1/threads/summary",
233 vec![json_op(
234 "get",
235 "listThreadsSummary",
236 "Thread summaries",
237 None,
238 "ThreadSummary",
239 u,
240 )],
241 );
242 add(
243 "/v1/threads/{id}",
244 vec![
245 json_op("get", "getThread", "Thread detail", None, "ThreadDetail", u),
246 json_op(
247 "patch",
248 "updateThread",
249 "Patch thread",
250 Some("UpdateThreadRequest"),
251 "ThreadRecord",
252 u,
253 ),
254 ],
255 );
256 add(
257 "/v1/threads/{id}/checklist",
258 vec![json_op(
259 "get",
260 "getThreadChecklist",
261 "Thread checklist",
262 None,
263 "ErrorBody",
264 u,
265 )],
266 );
267 add(
268 "/v1/threads/{id}/scratchpad/status",
269 vec![json_op(
270 "get",
271 "getThreadScratchpadStatus",
272 "Scratchpad status",
273 None,
274 "ErrorBody",
275 u,
276 )],
277 );
278 add(
279 "/v1/threads/{id}/context",
280 vec![json_op(
281 "get",
282 "getThreadContext",
283 "Thread context",
284 None,
285 "ErrorBody",
286 u,
287 )],
288 );
289 add(
290 "/v1/threads/{id}/resume",
291 vec![json_op(
292 "post",
293 "resumeThread",
294 "Resume thread",
295 None,
296 "ThreadRecord",
297 u,
298 )],
299 );
300 add(
301 "/v1/threads/{id}/fork",
302 vec![json_op(
303 "post",
304 "forkThread",
305 "Fork thread",
306 None,
307 "ThreadRecord",
308 u,
309 )],
310 );
311 add(
312 "/v1/threads/{id}/fork-at-user-message",
313 vec![json_op(
314 "post",
315 "forkThreadAtUserMessage",
316 "Fork at user message",
317 None,
318 "ThreadRecord",
319 u,
320 )],
321 );
322 add(
323 "/v1/threads/{id}/edit-last-turn",
324 vec![json_op(
325 "post",
326 "editLastThreadTurn",
327 "Edit last turn",
328 None,
329 "StartTurnResponse",
330 u,
331 )],
332 );
333 add(
334 "/v1/threads/{id}/turns",
335 vec![json_op(
336 "post",
337 "startThreadTurn",
338 "Start turn",
339 Some("StartTurnRequest"),
340 "StartTurnResponse",
341 u,
342 )],
343 );
344 add(
345 "/v1/threads/{id}/turns/{turn_id}/steer",
346 vec![json_op(
347 "post",
348 "steerThreadTurn",
349 "Steer in-flight turn",
350 Some("SteerTurnRequest"),
351 "TurnRecord",
352 u,
353 )],
354 );
355 add(
356 "/v1/threads/{id}/turns/{turn_id}/resolve-approval",
357 vec![json_op(
358 "post",
359 "resolveApproval",
360 "Resolve exec approval",
361 None,
362 "ErrorBody",
363 u,
364 )],
365 );
366 add(
367 "/v1/threads/{id}/turns/{turn_id}/interrupt",
368 vec![json_op(
369 "post",
370 "interruptThreadTurn",
371 "Interrupt turn",
372 None,
373 "TurnRecord",
374 u,
375 )],
376 );
377 add(
378 "/v1/threads/{id}/compact",
379 vec![json_op(
380 "post",
381 "compactThread",
382 "Compact thread context",
383 None,
384 "ErrorBody",
385 u,
386 )],
387 );
388 add(
389 "/v1/threads/{id}/persist-session",
390 vec![json_op(
391 "post",
392 "persistThreadSession",
393 "Persist thread to session file",
394 None,
395 "ErrorBody",
396 u,
397 )],
398 );
399 add(
400 "/v1/threads/{id}/snapshots",
401 vec![json_op(
402 "get",
403 "listThreadSnapshots",
404 "List snapshots",
405 None,
406 "ErrorBody",
407 u,
408 )],
409 );
410 add(
411 "/v1/threads/{id}/snapshots/restore",
412 vec![json_op(
413 "post",
414 "restoreThreadSnapshot",
415 "Restore snapshot",
416 None,
417 "ThreadDetail",
418 u,
419 )],
420 );
421 add(
422 "/v1/threads/{id}/workspace/browse",
423 vec![json_op(
424 "get",
425 "browseThreadWorkspace",
426 "Browse thread workspace",
427 None,
428 "ErrorBody",
429 u,
430 )],
431 );
432 add(
433 "/v1/threads/{id}/workspace/file",
434 vec![json_op(
435 "get",
436 "readThreadWorkspaceFile",
437 "Read thread workspace file",
438 None,
439 "ErrorBody",
440 u,
441 )],
442 );
443 add(
444 "/v1/threads/{id}/events",
445 vec![operation(
446 "get",
447 "streamThreadEvents",
448 "Thread events SSE",
449 None,
450 sse_response(),
451 u,
452 )],
453 );
454 add(
455 "/v1/tasks",
456 vec![
457 json_op("get", "listTasks", "List tasks", None, "TasksResponse", u),
458 json_op("post", "createTask", "Create task", None, "TaskRecord", u),
459 ],
460 );
461 add(
462 "/v1/tasks/clear",
463 vec![json_op(
464 "post",
465 "clearTasks",
466 "Clear tasks",
467 None,
468 "ErrorBody",
469 u,
470 )],
471 );
472 add(
473 "/v1/tasks/{id}",
474 vec![json_op("get", "getTask", "Get task", None, "TaskRecord", u)],
475 );
476 add(
477 "/v1/tasks/{id}/cancel",
478 vec![json_op(
479 "post",
480 "cancelTask",
481 "Cancel task",
482 None,
483 "TaskRecord",
484 u,
485 )],
486 );
487 add(
488 "/v1/blackboards",
489 vec![json_op(
490 "get",
491 "listBlackboards",
492 "List blackboards",
493 None,
494 "ErrorBody",
495 u,
496 )],
497 );
498 add(
499 "/v1/blackboards/{id}",
500 vec![json_op(
501 "get",
502 "getBlackboard",
503 "Get blackboard",
504 None,
505 "ErrorBody",
506 u,
507 )],
508 );
509 add(
510 "/v1/topic-memory",
511 vec![json_op(
512 "get",
513 "getTopicMemory",
514 "Topic memory graph",
515 None,
516 "ErrorBody",
517 u,
518 )],
519 );
520 add(
521 "/v1/skills",
522 vec![
523 json_op("get", "listSkills", "List skills", None, "ErrorBody", u),
524 json_op("post", "createSkill", "Create skill", None, "ErrorBody", u),
525 ],
526 );
527 add(
528 "/v1/skills/import",
529 vec![json_op(
530 "post",
531 "importSkillLocal",
532 "Import local skill",
533 None,
534 "ErrorBody",
535 u,
536 )],
537 );
538 add(
539 "/v1/skills/install",
540 vec![json_op(
541 "post",
542 "installSkillRemote",
543 "Install remote skill",
544 None,
545 "ErrorBody",
546 u,
547 )],
548 );
549 add(
550 "/v1/apps/mcp/servers",
551 vec![
552 json_op(
553 "get",
554 "listMcpServers",
555 "List MCP servers",
556 None,
557 "ErrorBody",
558 u,
559 ),
560 json_op(
561 "post",
562 "addMcpServer",
563 "Add MCP server",
564 None,
565 "ErrorBody",
566 u,
567 ),
568 ],
569 );
570 add(
571 "/v1/apps/mcp/servers/{name}",
572 vec![
573 json_op(
574 "get",
575 "getMcpServer",
576 "Get MCP server",
577 None,
578 "ErrorBody",
579 u,
580 ),
581 json_op(
582 "put",
583 "updateMcpServer",
584 "Update MCP server",
585 None,
586 "ErrorBody",
587 u,
588 ),
589 operation(
590 "delete",
591 "deleteMcpServer",
592 "Delete MCP server",
593 None,
594 json!({ "description": "Deleted" }),
595 u,
596 ),
597 ],
598 );
599 add(
600 "/v1/apps/mcp/config/merge",
601 vec![json_op(
602 "post",
603 "mergeMcpConfig",
604 "Merge MCP config JSON",
605 None,
606 "ErrorBody",
607 u,
608 )],
609 );
610 add(
611 "/v1/apps/mcp/tools",
612 vec![json_op(
613 "get",
614 "listMcpTools",
615 "List MCP tools",
616 None,
617 "ErrorBody",
618 u,
619 )],
620 );
621 add(
622 "/v1/automations",
623 vec![
624 json_op(
625 "get",
626 "listAutomations",
627 "List automations",
628 None,
629 "ErrorBody",
630 u,
631 ),
632 json_op(
633 "post",
634 "createAutomation",
635 "Create automation",
636 None,
637 "ErrorBody",
638 u,
639 ),
640 ],
641 );
642 add(
643 "/v1/automations/{id}",
644 vec![
645 json_op(
646 "get",
647 "getAutomation",
648 "Get automation",
649 None,
650 "ErrorBody",
651 u,
652 ),
653 json_op(
654 "patch",
655 "updateAutomation",
656 "Update automation",
657 None,
658 "ErrorBody",
659 u,
660 ),
661 operation(
662 "delete",
663 "deleteAutomation",
664 "Delete automation",
665 None,
666 json!({ "description": "Deleted" }),
667 u,
668 ),
669 ],
670 );
671 add(
672 "/v1/automations/{id}/run",
673 vec![json_op(
674 "post",
675 "runAutomation",
676 "Run automation",
677 None,
678 "ErrorBody",
679 u,
680 )],
681 );
682 add(
683 "/v1/automations/{id}/pause",
684 vec![json_op(
685 "post",
686 "pauseAutomation",
687 "Pause automation",
688 None,
689 "ErrorBody",
690 u,
691 )],
692 );
693 add(
694 "/v1/automations/{id}/resume",
695 vec![json_op(
696 "post",
697 "resumeAutomation",
698 "Resume automation",
699 None,
700 "ErrorBody",
701 u,
702 )],
703 );
704 add(
705 "/v1/automations/{id}/runs",
706 vec![json_op(
707 "get",
708 "listAutomationRuns",
709 "List automation runs",
710 None,
711 "ErrorBody",
712 u,
713 )],
714 );
715 add(
716 "/v1/usage",
717 vec![json_op(
718 "get",
719 "getUsage",
720 "Usage aggregation",
721 None,
722 "UsageAggregation",
723 u,
724 )],
725 );
726 add(
727 "/v1/apps/routing/rules",
728 vec![
729 json_op(
730 "get",
731 "getRoutingRules",
732 "Get routing rules",
733 None,
734 "RoutingRulesDoc",
735 u,
736 ),
737 json_op(
738 "put",
739 "setRoutingRules",
740 "Set routing rules",
741 Some("RoutingRulesDoc"),
742 "RoutingRulesDoc",
743 u,
744 ),
745 ],
746 );
747 add(
748 "/v1/symbol-index/rebuild",
749 vec![json_op(
750 "post",
751 "rebuildSymbolIndex",
752 "Rebuild symbol index",
753 None,
754 "ErrorBody",
755 u,
756 )],
757 );
758
759 paths
760}
761
762pub fn path_template_count() -> usize {
764 build_paths().len()
765}