soma_codemode/types/
catalog.rs1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::snippet::store::{SnippetInfo, SnippetInputSpec};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
7#[serde(rename_all = "snake_case")]
8pub enum CodeModeCatalogKind {
9 Tool,
10 Snippet,
11}
12
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14pub struct CodeModeSnippetInputEntry {
15 pub name: String,
16 #[serde(flatten)]
17 pub spec: SnippetInputSpec,
18}
19
20#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21pub struct ToolDescriptor {
22 pub kind: CodeModeCatalogKind,
23 pub id: String,
24 pub name: String,
25 pub namespace: String,
26 pub description: String,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub schema: Option<Value>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub output_schema: Option<Value>,
31 pub signature: String,
32 pub dts: String,
33 #[serde(default, skip_serializing_if = "Vec::is_empty")]
34 pub tags: Vec<String>,
35 #[serde(default, skip_serializing_if = "Vec::is_empty")]
36 pub inputs: Vec<CodeModeSnippetInputEntry>,
37}
38
39impl ToolDescriptor {
40 #[must_use]
41 pub fn tool(
42 namespace: &str,
43 tool: &str,
44 description: &str,
45 schema: Option<Value>,
46 output_schema: Option<Value>,
47 ) -> Self {
48 let types = crate::ts_signatures::generate_tool_types(
49 namespace,
50 tool,
51 description,
52 schema.as_ref(),
53 output_schema.as_ref(),
54 );
55 Self {
56 kind: CodeModeCatalogKind::Tool,
57 id: super::id::namespaced_tool_id(namespace, tool),
58 name: tool.to_string(),
59 namespace: namespace.to_string(),
60 description: description.to_string(),
61 schema,
62 output_schema,
63 signature: types.signature,
64 dts: types.dts,
65 tags: Vec::new(),
66 inputs: Vec::new(),
67 }
68 }
69
70 #[must_use]
71 pub fn snippet(info: &SnippetInfo) -> Self {
72 let description = info
73 .description
74 .clone()
75 .unwrap_or_else(|| format!("Code Mode snippet `{}`", info.name));
76 let inputs = info
77 .inputs
78 .iter()
79 .map(|(name, spec)| CodeModeSnippetInputEntry {
80 name: name.clone(),
81 spec: spec.clone(),
82 })
83 .collect();
84 Self {
85 kind: CodeModeCatalogKind::Snippet,
86 id: super::id::namespaced_tool_id("snippet", &info.name),
87 name: info.name.clone(),
88 namespace: "snippet".into(),
89 description,
90 schema: None,
91 output_schema: None,
92 signature: format!("codemode.run({:?}, input?)", info.name),
93 dts: String::new(),
94 tags: Vec::new(),
95 inputs,
96 }
97 }
98}
99
100#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
101pub struct UiLink {
102 pub url: String,
103 #[serde(default, skip_serializing_if = "Option::is_none")]
104 pub title: Option<String>,
105}
106
107pub fn destructive_permitted(value: &Value) -> bool {
108 value
109 .get("confirm")
110 .and_then(Value::as_bool)
111 .unwrap_or(false)
112}