use serde::{Deserialize, Serialize}; use serde_json::Value; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct ActionDefinition { pub action_id: String, pub aliases: Vec, pub description: String, pub intent_examples: Vec, pub payload_schema: Value, pub executable: ExecutableDefinition, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct ExecutableDefinition { pub kind: String, pub script: String, } pub fn registered_actions() -> Vec { vec![ action( "append_to_file", &["append", "append_file", "add_to_file"], "Append content to a project-local notes file.", &[ "append this line to notes.txt", "add content to a file", "append to a project note", ], object_schema( &[ ("filename", string_schema("Relative notes/ filename.")), ("content", string_schema("Content to append.")), ], &["filename", "content"], ), ), action( "calculate", &["calc", "evaluate_expression", "math"], "Evaluate a simple math expression.", &[ "calculate 2 + 2 * 3", "evaluate this expression", "what is 10 / 2 plus 8", ], object_schema( &[("expression", string_schema("Math expression to evaluate."))], &["expression"], ), ), action( "convert_units", &["convert", "unit_conversion", "convert_measurement"], "Convert a numeric distance value between supported units.", &[ "convert 100 km to miles", "convert meters to feet", "unit conversion for 12 inches to cm", ], object_schema( &[ ("value", number_schema("Numeric value to convert.")), ("from", string_schema("Source unit.")), ("to", string_schema("Target unit.")), ], &["value", "from", "to"], ), ), action( "count_words", &["word_count", "count_text_words"], "Count whitespace-delimited words in text.", &[ "count words in this text", "how many words are here", "word count this sentence", ], object_schema( &[("text", string_schema("Text to count words in."))], &["text"], ), ), action( "delete_file", &["delete_note", "remove_file", "remove_note"], "Delete a project-local notes file.", &[ "delete note.txt", "remove this note file", "delete a project note", ], object_schema( &[("filename", string_schema("Relative notes/ filename."))], &["filename"], ), ), action( "generate_uuid", &["uuid", "new_uuid", "create_uuid"], "Generate a random UUID v4.", &[ "generate a uuid", "create a new uuid", "give me a random uuid", ], object_schema(&[], &[]), ), action( "hash_string", &["hash", "digest_string", "string_hash"], "Hash text with sha256, md5, or sha1.", &[ "hash hello with sha256", "md5 this string", "sha1 digest for this text", ], object_schema( &[ ("text", string_schema("Text to hash.")), ( "algorithm", enum_schema("Hash algorithm.", &["sha256", "md5", "sha1"]), ), ], &["text", "algorithm"], ), ), action( "logger", &["log", "write_log", "record_message"], "Write a structured proof-of-concept log message.", &[ "log hello from codex", "record this message", "write a logger proof of concept entry", ], object_schema( &[( "message", string_schema("Message text to write into logs/controller-actions.jsonl."), )], &["message"], ), ), action( "random_number", &["random_int", "roll_number", "number_in_range"], "Generate a random integer in an inclusive range.", &[ "random number between 1 and 100", "roll a number in this range", "pick an integer from 5 to 10", ], object_schema( &[ ("min", integer_schema("Inclusive minimum.")), ("max", integer_schema("Inclusive maximum.")), ], &["min", "max"], ), ), action( "read_file", &["read_note", "open_file", "show_file"], "Read a project-local notes file.", &[ "read note.txt", "show the contents of this note", "open a project note file", ], object_schema( &[("filename", string_schema("Relative notes/ filename."))], &["filename"], ), ), action( "to_slug", &["slugify", "make_slug", "url_slug"], "Convert text to a URL-safe ASCII slug.", &[ "slugify this title", "make a url slug", "convert text to a slug", ], object_schema(&[("text", string_schema("Text to slugify."))], &["text"]), ), action( "truncate_text", &["truncate", "shorten_text", "clip_text"], "Truncate text to a maximum character count.", &[ "truncate this to 100 characters", "shorten this text", "clip text to a max length", ], object_schema( &[ ("text", string_schema("Text to truncate.")), ("max_chars", integer_schema("Maximum number of characters.")), ], &["text", "max_chars"], ), ), action( "write_note", &["write_file", "save_note", "create_note"], "Create or overwrite a project-local notes file.", &[ "write a note file", "save this note", "create a text file with this content", ], object_schema( &[ ("filename", string_schema("Relative notes/ filename.")), ("content", string_schema("Content to write.")), ], &["filename", "content"], ), ), ] } fn action( action_id: &str, aliases: &[&str], description: &str, intent_examples: &[&str], payload_schema: Value, ) -> ActionDefinition { ActionDefinition { action_id: action_id.to_string(), aliases: aliases.iter().map(|alias| alias.to_string()).collect(), description: description.to_string(), intent_examples: intent_examples .iter() .map(|example| example.to_string()) .collect(), payload_schema, executable: ExecutableDefinition { kind: "internal-rust-script".to_string(), script: action_id.to_string(), }, } } fn object_schema(properties: &[(&str, Value)], required: &[&str]) -> Value { let properties = properties .iter() .map(|(name, schema)| ((*name).to_string(), schema.clone())) .collect::>(); serde_json::json!({ "type": "object", "required": required, "properties": properties, "additionalProperties": false }) } fn string_schema(description: &str) -> Value { serde_json::json!({ "type": "string", "description": description }) } fn number_schema(description: &str) -> Value { serde_json::json!({ "type": "number", "description": description }) } fn integer_schema(description: &str) -> Value { serde_json::json!({ "type": "integer", "description": description }) } fn enum_schema(description: &str, values: &[&str]) -> Value { serde_json::json!({ "type": "string", "description": description, "enum": values }) }