first commit

This commit is contained in:
aiyezi committed 2026-11-05 17:33:18 +08:00
commit 91b44fcc16
27 files changed
+4104

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
[package]
name = "agent-tui"
version = "0.1.0"
edition = "2024"
[dependencies]
agent-core = { path = "../agent-core" }
crossterm = { workspace = true }
ratatui = { workspace = true }
color-eyre = { workspace = true }
dotenvy = { workspace = true }
+13
View File
@@ -0,0 +1,13 @@
use std::sync::Arc;
use agent_core::ReActAgent;
use agent_providers::ChatCompletionsProvider;
use agent_tui::App;
use color_eyre::eyre::Ok;
fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
let app = App::default();
app.run()?;
Ok(())
}
+17
View File
@@ -0,0 +1,17 @@
mod ui;
pub use ui::App;
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
+139
View File
@@ -0,0 +1,139 @@
use std::time::Duration;
use crossterm::event::{Event, KeyCode, KeyEvent};
use ratatui::{
Frame,
layout::{Constraint, Direction, Layout},
text::Line,
widgets::{Block, List, ListItem, Paragraph},
};
#[derive(Default)]
pub struct App {
messages: Vec<Message>,
input: String,
pending: bool,
}
struct Message {
role: Role,
content: String,
}
#[derive(PartialEq, Eq)]
enum Role {
System,
User,
Assistant,
Tool,
}
#[derive(PartialEq, Eq)]
enum Flow {
Continue,
Quit,
}
impl App {
pub fn new() -> Self {
Self {
messages: vec![Message {
role: Role::System,
content: "hi there ~".into(),
}],
..Default::default()
}
}
pub fn resume(messages: Vec<Message>) -> Self {
Self {
messages,
..Default::default()
}
}
pub fn run(mut self, act: ) -> std::io::Result<()> {
ratatui::run(|terminal| {
loop {
terminal.draw(|frame| self.render(frame))?;
if crossterm::event::poll(Duration::from_millis(16))? {
match crossterm::event::read()? {
Event::Key(key) => {
if self.handle_key(key) == Flow::Quit {
break Ok(());
}
}
_ => {}
}
}
}
})
}
fn handle_key(&mut self, key: KeyEvent) -> Flow {
match key.code {
KeyCode::Esc => Flow::Quit,
KeyCode::Backspace => {
self.input.pop();
Flow::Continue
}
KeyCode::Char(ch) => {
self.input.push(ch);
Flow::Continue
}
KeyCode::Enter => {
self.submit();
Flow::Continue
}
_ => Flow::Continue,
}
}
fn submit(&mut self) {
self.messages.push(Message {
role: Role::User,
content: self.input.clone(),
});
self.input.clear();
}
fn render(&self, frame: &mut Frame) {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(3),
Constraint::Min(0),
Constraint::Length(3),
])
.split(frame.area());
let header = Paragraph::new("Agent Chat").block(Block::bordered().title("Title"));
frame.render_widget(header, chunks[0]);
let items: Vec<ListItem> = self
.messages
.iter()
.map(|msg| {
let name = match msg.role {
Role::System => "System",
Role::User => "User",
Role::Assistant => "Assistant",
Role::Tool => "Tool",
};
let mut lines = vec![Line::from(name)];
for line in msg.content.lines() {
lines.push(Line::from(line));
}
ListItem::new(lines)
})
.collect();
let messages = List::new(items).block(Block::bordered().title("Messages"));
frame.render_widget(messages, chunks[1]);
let input = Paragraph::new(self.input.as_str()).block(Block::bordered().title("Input"));
frame.render_widget(input, chunks[2]);
}
}