oxios_kernel/program/
parser.rs1use std::collections::HashMap;
4use std::fs;
5use std::path::Path;
6
7use anyhow::{Context, Result};
8
9use super::types::{ArgumentDef, McpServerConfig, ProgramHostRequirements, ProgramMeta, ToolDef};
10
11#[derive(Debug, Clone, serde::Deserialize)]
13struct TomlProgram {
14 program: TomlProgramInfo,
15 tools: Option<HashMap<String, TomlTool>>,
16 #[serde(rename = "host_requirements")]
17 host_requirements: Option<TomlHostRequirements>,
18 #[serde(rename = "requires_tools")]
19 requires_tools: Option<TomlRequiresTools>,
20 #[serde(rename = "mcp", default)]
21 mcp: Option<Vec<McpServerConfig>>,
22}
23
24#[derive(Debug, Clone, serde::Deserialize)]
25struct TomlProgramInfo {
26 name: String,
27 version: String,
28 description: String,
29 author: String,
30}
31
32#[derive(Debug, Clone, serde::Deserialize)]
33struct TomlTool {
34 description: String,
35 #[serde(default)]
37 command: String,
38 arguments: Option<Vec<TomlArgument>>,
39}
40
41#[derive(Debug, Clone, serde::Deserialize)]
42struct TomlArgument {
43 name: String,
44 description: String,
45 required: Option<bool>,
46 default: Option<String>,
47}
48
49#[derive(Debug, Clone, serde::Deserialize)]
50struct TomlHostRequirements {
51 required: Option<Vec<String>>,
52 optional: Option<Vec<String>>,
53}
54
55#[derive(Debug, Clone, serde::Deserialize)]
57struct TomlRequiresTools {
58 names: Vec<String>,
59}
60
61impl ProgramMeta {
62 pub fn load_from_dir(path: &Path) -> Result<Self> {
64 let toml_path = path.join("program.toml");
65 let content = fs::read_to_string(&toml_path)
66 .with_context(|| format!("Failed to read {}", toml_path.display()))?;
67
68 let toml: TomlProgram = toml::from_str(&content)
69 .with_context(|| format!("Failed to parse {}", toml_path.display()))?;
70
71 let tools = toml
72 .tools
73 .map(|t| {
74 t.into_iter()
75 .map(|(name, tool)| {
76 let arguments = tool
77 .arguments
78 .unwrap_or_default()
79 .into_iter()
80 .map(|arg| ArgumentDef {
81 name: arg.name,
82 description: arg.description,
83 required: arg.required.unwrap_or(true),
84 default: arg.default,
85 })
86 .collect();
87 ToolDef {
88 name,
89 description: tool.description,
90 arguments,
91 command: tool.command,
92 }
93 })
94 .collect()
95 })
96 .unwrap_or_default();
97
98 let host_requirements = toml
99 .host_requirements
100 .map(|hr| ProgramHostRequirements {
101 required: hr.required.unwrap_or_default(),
102 optional: hr.optional.unwrap_or_default(),
103 })
104 .unwrap_or_default();
105
106 let dependencies = toml.requires_tools.map(|rt| rt.names).unwrap_or_default();
107
108 let mcp_servers = toml.mcp.unwrap_or_default();
109
110 Ok(ProgramMeta {
111 name: toml.program.name,
112 version: toml.program.version,
113 description: toml.program.description,
114 author: toml.program.author,
115 tools,
116 dependencies,
117 host_requirements,
118 mcp_servers,
119 })
120 }
121}