# Call Agent
Call Agent is a library implemented in Rust for handling call-related functions and integrating with AI. This library supports processing user prompts, executing function calls, defining and executing tools, and interacting via APIs.
## Features
- High-performance prompt management and chat response generation
- Ability to define and execute custom tools (functions)
- Flexible error handling and detailed response analysis
- Easy integration with JSON through internal serialization/deserialization
## Module Structure
- **client**: Handles communication with the OpenAI API, registers and calls tools, and processes responses.
- **prompt**: Manages user prompts, assistant messages, and function call messages.
- **function**: Provides tool (function) definition, execution, and argument parsing.
- **err**: Defines error types and manages error messages.
- **api**: Implements the structures for API requests/responses and serialization/deserialization.
## Installation
Add the following to your
Cargo.toml
to use it as a dependency:
```toml
[dependencies]
call-agent = "1.0.0"
```
## Usage
### Example of Creating a Client and Registering Tools
```rust
// create a new OpenAI client
let mut client = OpenAIClient::new(
"https://api.openai.com/v1/",
Some("YOUR_API_KEY"),
);
// register the custom tool
client.def_tool(Arc::new(TextLengthTool::new()));
// create a model configuration
let config = ModelConfig {
model: "gpt-4o-mini".to_string(),
strict: None,
max_completion_tokens: Some(1000),
temperature: Some(0.8),
top_p: Some(1.0),
parallel_tool_calls: None,
presence_penalty: Some(0.0),
model_name: None,
reasoning_effort: None,
web_search_options: None,
};
// set the model configuration
client.set_model_config(&config);
```
### Methods in `client.rs`
- `new(end_point: &str, api_key: Option<&str>)`
→ Creates a new `OpenAIClient`. Normalizes the endpoint and sets the API key.
- `def_tool<T: Tool + Send + Sync + 'static>(tool: Arc<T>)`
→ Registers a tool. Overwrites if a tool with the same name exists.
- `list_tools()`
→ Returns a list of registered tools as tuples (tool name, description, enabled status).
- `switch_tool(tool_name: &str, t_enable: bool)`
→ Enables or disables the specified tool.
- `export_tool_def()`
→ Returns a list of function definitions (`FunctionDef`) for enabled tools.
- `send(model: &ModelConfig, prompt: &Vec<Message>)`
→ Makes an API request with the specified model and returns the response.
- `send_can_use_tool(model: &ModelConfig, prompt: &Vec<Message>)`
→ Makes an API request using the "auto" tool call specification.
- `send_with_tool(model: &ModelConfig, prompt: &Vec<Message>, tool_name: &str)`
→ Makes an API request forcing the use of a specific tool.
- `call_api(...)`
→ Internal method that sends a request to the endpoint and returns an `APIResult`. Serializes header information and the response body.
- `create_prompt()`
→ Generates an `OpenAIClientState` for prompt management.
### Basic Usage
Below is an example of usage in `main.rs`.
It receives user input, adds it to the prompt, and generates AI responses and tool actions in a chain.
```rust
// ...existing code in main.rs...
// Add user input and image message to the prompt
let prompt = vec![Message::User {
content: vec![
MessageContext::Text("Hello".to_string()),
MessageContext::Image(MessageImage {
url: "https://example.com/image.jpg".to_string(),
detail: None,
}),
],
}];
// Add to the prompt stream and generate response (with tool usage)
prompt_stream.add(prompt).await;
let result = prompt_stream.generate_use_tool(&config).await;
```
### Example of Using a Chat Loop
```rust
// create a prompt stream
let mut prompt_stream = client.create_prompt();
// chat loop: Get user input → Add to prompt → Generate response with tool usage
loop {
// Get user input
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
// Create the prompt
let prompt = vec![Message::User {
name: Some("user".to_string()),
content: vec![
MessageContext::Text(input.trim().to_string()),
],
}];
// Add to the prompt
prompt_stream.add(prompt).await;
// Generate response using `generate_can_use_tool`
let result = prompt_stream.generate_can_use_tool(None).await;
println!("{:?}", result);
// Optionally check the latest state of the prompt
let response = prompt_stream.prompt.clone();
println!("{:?}", response);
}
```
### Defining Custom Tools
You can define any tool by implementing the `Tool` trait in the `function` module.
Below is an example of defining a tool that calculates the length of a text.
```rust
// ...existing code in main.rs...
impl Tool for TextLengthTool {
fn def_name(&self) -> &str {
"text_length_tool"
}
fn def_description(&self) -> &str {
"Returns the length of the input text."
}
fn def_parameters(&self) -> serde_json::Value {
serde_json::json!({
"type": "object",
"properties": {
"text": {
"type": "string",
"description": "Input text to calculate its length"
}
},
"required": ["text"]
})
}
fn run(&self, args: serde_json::Value) -> Result<String, String> {
let text = args["text"]
.as_str()
.ok_or_else(|| "Missing 'text' parameter".to_string())?;
let length = text.len();
Ok(serde_json::json!({ "length": length }).to_string())
}
}
```
## API Specifications
### Request
- Requests are defined by the `APIRequest` structure, which includes the model name, messages, function definitions, function call information, temperature, maximum token count, and top_p.
### Response
- Responses are received in the `APIResponse` structure, where you can check choices, model information, error messages, and the number of tokens used.
- Rate limit information can also be obtained from the headers.
## Error Handling
- `ClientError` provides various errors such as file not found, input errors, network errors, and tool not registered.
- Each error has its own `Display` implementation, useful for debugging and user notifications.
## Build and Run
1. Clone or place it as a Cargo project.
2. Build with `cargo build` and run with `cargo run`.
3. Use the chat loop described in `main.rs` to interactively check AI responses and tool execution.
## Contribution
We welcome issue reports, improvement suggestions, and pull requests.
For detailed specifications and changes, please refer to the comments in each module.
## License
This project is licensed under the MIT License. See the LICENSE file for details.