Skip to content

Commit 5bd68ef

Browse files
authored
feat: add user input handling with command parsing and validation (#143)
1 parent 24d7048 commit 5bd68ef

File tree

9 files changed

+154
-169
lines changed

9 files changed

+154
-169
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/forge_domain/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ serde = "1.0.217"
1919
serde_json = "1.0.134"
2020
strum = "0.26.3"
2121
strum_macros = "0.26.4"
22+
thiserror = "2.0.11"
2223
tokio = { version = "1.42.0", features = ["full", "test-util"] }
2324
tokio-stream = "0.1.17"
2425
uuid = { version = "1.11.0", features = [

crates/forge_domain/src/error.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
use std::pin::Pin;
22

3-
use derive_more::derive::{Display, Error, From};
3+
use derive_more::derive::From;
4+
use thiserror::Error;
45

5-
#[derive(From, Debug, Display, Error)]
6+
#[derive(From, Debug, Error)]
67
pub enum Error {
8+
#[error("Tool name was not provided")]
79
ToolCallMissingName,
10+
11+
#[error("Serde Error: {0}")]
812
Serde(serde_json::Error),
9-
Uuid(uuid::Error),
13+
14+
#[error("Invalid UUID: {0}")]
15+
InvalidUuid(uuid::Error),
16+
17+
#[error("Invalid user command: {0}")]
18+
InvalidUserCommand(String),
1019
}
1120

1221
pub type Result<A> = std::result::Result<A, Error>;

crates/forge_domain/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ mod tool_name;
2121
mod tool_result;
2222
mod tool_service;
2323
mod tool_usage;
24+
mod user;
2425
mod user_interaction;
2526

2627
pub use chat_request::*;
@@ -46,4 +47,5 @@ pub use tool_name::*;
4647
pub use tool_result::*;
4748
pub use tool_service::*;
4849
pub use tool_usage::*;
50+
pub use user::*;
4951
pub use user_interaction::*;

crates/forge_domain/src/user.rs

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use std::path::PathBuf;
2+
3+
use async_trait::async_trait;
4+
5+
use crate::error::{Error, Result};
6+
7+
/// Represents user input types in the chat application.
8+
///
9+
/// This enum encapsulates all forms of input including:
10+
/// - System commands (starting with '/')
11+
/// - Regular chat messages
12+
/// - File content
13+
#[derive(Debug, Clone, PartialEq, Eq)]
14+
pub enum Input {
15+
/// End the current session and exit the application.
16+
/// This can be triggered with the '/end' command.
17+
End,
18+
/// Start a new conversation while preserving history.
19+
/// This can be triggered with the '/new' command.
20+
New,
21+
/// Reload the conversation with the original prompt.
22+
/// This can be triggered with the '/reload' command.
23+
Reload,
24+
/// A regular text message from the user to be processed by the chat system.
25+
/// Any input that doesn't start with '/' is treated as a message.
26+
Message(String),
27+
}
28+
29+
impl Input {
30+
/// Returns a list of all available command strings.
31+
///
32+
/// These commands are used for:
33+
/// - Command validation
34+
/// - Autocompletion
35+
/// - Help display
36+
pub fn available_commands() -> Vec<String> {
37+
vec![
38+
"/end".to_string(),
39+
"/new".to_string(),
40+
"/reload".to_string(),
41+
]
42+
}
43+
44+
/// Parses a string input into an Input.
45+
///
46+
/// This function:
47+
/// - Trims whitespace from the input
48+
/// - Recognizes and validates commands (starting with '/')
49+
/// - Converts regular text into messages
50+
///
51+
/// # Returns
52+
/// - `Ok(Input)` - Successfully parsed input
53+
/// - `Err` - Input was an invalid command
54+
pub fn parse(input: &str) -> Result<Self> {
55+
let trimmed = input.trim();
56+
match trimmed {
57+
"/end" => Ok(Input::End),
58+
"/new" => Ok(Input::New),
59+
"/reload" => Ok(Input::Reload),
60+
cmd if cmd.starts_with('/') => Err(Error::InvalidUserCommand(cmd.to_string())),
61+
text => Ok(Input::Message(text.to_string())),
62+
}
63+
}
64+
}
65+
66+
/// A trait for handling user input in the application.
67+
///
68+
/// This trait defines the core functionality needed for processing
69+
/// user input, whether it comes from a command line interface,
70+
/// GUI, or file system.
71+
#[async_trait]
72+
pub trait UserInput {
73+
/// Read content from a file and convert it to the input type.
74+
///
75+
/// # Arguments
76+
/// * `path` - The path to the file to read
77+
///
78+
/// # Returns
79+
/// * `Ok(Input)` - Successfully read and parsed file content
80+
/// * `Err` - Failed to read or parse file
81+
async fn upload<P: Into<PathBuf> + Send>(&self, path: P) -> anyhow::Result<Input>;
82+
83+
/// Prompts for user input with optional help text and initial value.
84+
///
85+
/// # Arguments
86+
/// * `help_text` - Optional help text to display with the prompt
87+
/// * `initial_text` - Optional initial text to populate the input with
88+
///
89+
/// # Returns
90+
/// * `Ok(Input)` - Successfully processed input
91+
/// * `Err` - An error occurred during input processing
92+
async fn prompt(
93+
&self,
94+
help_text: Option<&str>,
95+
initial_text: Option<&str>,
96+
) -> anyhow::Result<Input>;
97+
}

crates/forge_main/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ forge_domain = { path = "../forge_domain" }
1111
tokio = { version = "1.0", features = ["full"] }
1212
tokio-stream = "0.1.17"
1313
colored = "3.0.0"
14+
async-trait = "0.1"
1415
inquire = "0.7.5"
1516
regex = "1.10.2"
1617
strum = "0.26.3"

0 commit comments

Comments
 (0)