1
0
Files
shell/src/llm/provider.rs
Claude a50fef9182 feat: Implement aishell - AI-powered shell automation tool
Implemented a generic alternative to Claude Code with the following features:

Core Implementation:
- Multi-LLM provider support (OpenAI compatible APIs)
- Function calling for direct tool execution by LLM
- Interactive REPL shell interface
- MCP server mode for Claude Desktop integration
- Shell executor with bash, read, write, list tools

Architecture:
- src/cli: Interactive REPL implementation
- src/llm: LLM provider abstraction (OpenAI compatible)
- src/shell: Shell execution engine with duct
- src/mcp: MCP server for Claude Desktop
- src/config: Configuration management

Technical Stack:
- Rust 2021 with tokio async runtime
- clap for CLI framework
- reqwest for HTTP client
- duct for shell execution
- rustyline for REPL interface

This tool integrates with aigpt to form AIOS (AI Operating System),
enabling AI-driven OS management and automation.

Based on aigpt architecture for CLI and MCP patterns.
2025-11-09 07:12:08 +00:00

105 lines
2.5 KiB
Rust

use anyhow::Result;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Role {
System,
User,
Assistant,
Tool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
pub role: Role,
pub content: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_calls: Option<Vec<ToolCall>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_call_id: Option<String>,
}
impl Message {
pub fn system(content: impl Into<String>) -> Self {
Self {
role: Role::System,
content: content.into(),
tool_calls: None,
tool_call_id: None,
}
}
pub fn user(content: impl Into<String>) -> Self {
Self {
role: Role::User,
content: content.into(),
tool_calls: None,
tool_call_id: None,
}
}
pub fn assistant(content: impl Into<String>) -> Self {
Self {
role: Role::Assistant,
content: content.into(),
tool_calls: None,
tool_call_id: None,
}
}
pub fn tool(content: impl Into<String>, tool_call_id: String) -> Self {
Self {
role: Role::Tool,
content: content.into(),
tool_calls: None,
tool_call_id: Some(tool_call_id),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolCall {
pub id: String,
#[serde(rename = "type")]
pub call_type: String,
pub function: FunctionCall,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionCall {
pub name: String,
pub arguments: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolDefinition {
#[serde(rename = "type")]
pub tool_type: String,
pub function: FunctionDefinition,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FunctionDefinition {
pub name: String,
pub description: String,
pub parameters: serde_json::Value,
}
#[derive(Debug)]
pub struct ChatResponse {
pub content: String,
pub tool_calls: Option<Vec<ToolCall>>,
pub finish_reason: String,
}
#[async_trait]
pub trait LLMProvider: Send + Sync {
/// Send a chat completion request
async fn chat(&self, messages: Vec<Message>, tools: Option<Vec<ToolDefinition>>) -> Result<ChatResponse>;
/// Get the model name
fn model_name(&self) -> &str;
}