Added recipe discovery / execution to ACP server. (#8925)

Signed-off-by: Douwe Osinga <douwe@squareup.com>
Co-authored-by: Douwe Osinga <douwe@squareup.com>
This commit is contained in:
natelastname
2026-05-12 16:32:05 -04:00
committed by GitHub
parent a23bbf24b5
commit 69f591322b
2 changed files with 211 additions and 31 deletions
+56 -13
View File
@@ -43,6 +43,34 @@ static COMMANDS: &[CommandDef] = &[
},
];
pub struct ParsedSlashCommand<'a> {
pub command: &'a str,
pub params_str: &'a str,
}
pub fn parse_slash_command(message_text: &str) -> Option<ParsedSlashCommand<'_>> {
let mut trimmed = message_text.trim();
if COMPACT_TRIGGERS.contains(&trimmed) {
trimmed = COMPACT_TRIGGERS[0];
}
if !trimmed.starts_with('/') {
return None;
}
let command_str = trimmed.strip_prefix('/').unwrap_or(trimmed);
let (command, params_str) = command_str
.split_once(' ')
.map(|(cmd, p)| (cmd, p.trim()))
.unwrap_or((command_str, ""));
Some(ParsedSlashCommand {
command,
params_str,
})
}
pub fn list_commands() -> &'static [CommandDef] {
COMMANDS
}
@@ -53,21 +81,12 @@ impl Agent {
message_text: &str,
session_id: &str,
) -> Result<Option<Message>> {
let mut trimmed = message_text.trim().to_string();
if COMPACT_TRIGGERS.contains(&trimmed.as_str()) {
trimmed = COMPACT_TRIGGERS[0].to_string();
}
if !trimmed.starts_with('/') {
let Some(parsed) = parse_slash_command(message_text) else {
return Ok(None);
}
};
let command_str = trimmed.strip_prefix('/').unwrap_or(&trimmed);
let (command, params_str) = command_str
.split_once(' ')
.map(|(cmd, p)| (cmd, p.trim()))
.unwrap_or((command_str, ""));
let command = parsed.command;
let params_str = parsed.params_str;
let params: Vec<&str> = if params_str.is_empty() {
vec![]
@@ -442,3 +461,27 @@ impl Agent {
Ok(Some(Message::user().with_text(prompt)))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_slash_command_splits_on_literal_space() {
let parsed = parse_slash_command("/speckit.plan hello world").unwrap();
assert_eq!(parsed.command, "speckit.plan");
assert_eq!(parsed.params_str, "hello world");
}
#[test]
fn parse_slash_command_does_not_split_on_tab_or_newline() {
let parsed = parse_slash_command("/speckit.plan\thello").unwrap();
assert_eq!(parsed.command, "speckit.plan\thello");
assert_eq!(parsed.params_str, "");
let parsed = parse_slash_command("/speckit.plan\nhello").unwrap();
assert_eq!(parsed.command, "speckit.plan\nhello");
assert_eq!(parsed.params_str, "");
}
}