11# Using Codey as a Library
22
3- Codey can be used as a library to create AI agents with custom system prompts in your Rust projects.
3+ Codey can be used as a library to create AI agents with custom system prompts and tools in your Rust projects.
44
55## Installation
66
@@ -10,6 +10,7 @@ Add codey to your `Cargo.toml`:
1010[dependencies ]
1111codey = { git = " https://github.com/tcdent/codey" }
1212tokio = { version = " 1" , features = [" full" ] }
13+ serde_json = " 1"
1314```
1415
1516### Patched Dependencies
@@ -30,33 +31,26 @@ genai = { path = "../codey/lib/genai" }
3031
3132Note: Run ` make patch ` in the codey repository first to download and patch the dependencies.
3233
33- ## Basic Usage
34+ ## Basic Usage (No Tools)
3435
3536``` rust
3637use codey :: {Agent , AgentRuntimeConfig , AgentStep , RequestMode , ToolRegistry };
3738
3839#[tokio:: main]
3940async fn main () {
40- // Create an agent with a custom system prompt (no tools)
4141 let mut agent = Agent :: new (
4242 AgentRuntimeConfig :: default (),
43- " You are a helpful assistant. Answer questions concisely. " ,
44- None , // OAuth credentials ( uses ANTHROPIC_API_KEY env var)
43+ " You are a helpful assistant." ,
44+ None , // uses ANTHROPIC_API_KEY env var
4545 ToolRegistry :: empty (),
4646 );
4747
48- // Send a message
4948 agent . send_request (" What is the capital of France?" , RequestMode :: Normal );
5049
51- // Process streaming responses
5250 while let Some (step ) = agent . next (). await {
5351 match step {
5452 AgentStep :: TextDelta (text ) => print! (" {}" , text ),
55- AgentStep :: ThinkingDelta (_ ) => { /* extended thinking output */ }
56- AgentStep :: Finished { usage } => {
57- println! (" \ n\ n Tokens used: {}" , usage . output_tokens);
58- break ;
59- }
53+ AgentStep :: Finished { .. } => break ,
6054 AgentStep :: Error (e ) => {
6155 eprintln! (" Error: {}" , e );
6256 break ;
@@ -67,33 +61,143 @@ async fn main() {
6761}
6862```
6963
70- ## Public API
64+ ## Custom Tools
7165
72- ### ` Agent `
66+ You can define custom tools using ` SimpleTool ` and handle their execution yourself.
7367
74- The main agent type that handles conversations with Claude.
68+ ### Defining Tools
7569
7670``` rust
77- // Create a new agent
78- let mut agent = Agent :: new (
79- config , // AgentRuntimeConfig
80- system_prompt , // &str
81- oauth , // Option<OAuthCredentials>
82- tools , // ToolRegistry
71+ use codey :: {SimpleTool , ToolRegistry };
72+ use serde_json :: json;
73+ use std :: sync :: Arc ;
74+
75+ // Define a tool
76+ let weather_tool = SimpleTool :: new (
77+ " get_weather" ,
78+ " Get the current weather for a location" ,
79+ json! ({
80+ " type" : " object" ,
81+ " properties" : {
82+ " location" : {
83+ " type" : " string" ,
84+ " description" : " City name, e.g. 'San Francisco'"
85+ }
86+ },
87+ " required" : [" location" ]
88+ }),
8389);
8490
85- // Send a message
86- agent . send_request (" Hello!" , RequestMode :: Normal );
91+ // Register tools
92+ let mut tools = ToolRegistry :: empty ();
93+ tools . register (Arc :: new (weather_tool ));
94+ ```
95+
96+ ### Handling Tool Calls
97+
98+ When the LLM wants to use a tool, you'll receive an ` AgentStep::ToolRequest ` . You must execute the tool and submit the result back to the agent:
99+
100+ ``` rust
101+ use codey :: {Agent , AgentRuntimeConfig , AgentStep , RequestMode , SimpleTool , ToolCall , ToolRegistry };
102+ use serde_json :: json;
103+ use std :: sync :: Arc ;
104+
105+ #[tokio:: main]
106+ async fn main () {
107+ // Set up tools
108+ let weather_tool = SimpleTool :: new (
109+ " get_weather" ,
110+ " Get the current weather for a location" ,
111+ json! ({
112+ " type" : " object" ,
113+ " properties" : {
114+ " location" : { " type" : " string" }
115+ },
116+ " required" : [" location" ]
117+ }),
118+ );
119+
120+ let mut tools = ToolRegistry :: empty ();
121+ tools . register (Arc :: new (weather_tool ));
122+
123+ // Create agent with tools
124+ let mut agent = Agent :: new (
125+ AgentRuntimeConfig :: default (),
126+ " You are a helpful assistant with access to weather data." ,
127+ None ,
128+ tools ,
129+ );
130+
131+ agent . send_request (" What's the weather in Paris?" , RequestMode :: Normal );
87132
88- // Get streaming responses
89- while let Some (step ) = agent . next (). await {
90- // Handle AgentStep variants
133+ loop {
134+ match agent . next (). await {
135+ Some (AgentStep :: TextDelta (text )) => print! (" {}" , text ),
136+
137+ Some (AgentStep :: ToolRequest (calls )) => {
138+ // Handle each tool call
139+ for call in calls {
140+ let result = execute_tool (& call );
141+ agent . submit_tool_result (& call . call_id, result );
142+ }
143+ // Continue processing after submitting results
144+ }
145+
146+ Some (AgentStep :: Finished { .. }) => {
147+ println! ();
148+ break ;
149+ }
150+
151+ Some (AgentStep :: Error (e )) => {
152+ eprintln! (" Error: {}" , e );
153+ break ;
154+ }
155+
156+ None => break ,
157+ _ => {}
158+ }
159+ }
160+ }
161+
162+ fn execute_tool (call : & ToolCall ) -> String {
163+ match call . name. as_str () {
164+ " get_weather" => {
165+ let location = call . params[" location" ]. as_str (). unwrap_or (" unknown" );
166+ // Your actual implementation here
167+ format! (" Weather in {}: Sunny, 22°C" , location )
168+ }
169+ _ => format! (" Unknown tool: {}" , call . name),
170+ }
91171}
92172```
93173
94- ### ` AgentRuntimeConfig `
174+ ### ` ToolCall ` Structure
175+
176+ When you receive a tool request, each ` ToolCall ` contains:
177+
178+ ``` rust
179+ pub struct ToolCall {
180+ pub call_id : String , // Unique ID for this call (use with submit_tool_result)
181+ pub name : String , // Tool name
182+ pub params : serde_json :: Value , // Parameters from the LLM
183+ // ... other fields
184+ }
185+ ```
186+
187+ ## Public API Reference
188+
189+ ### ` Agent `
190+
191+ The main agent type for conversations with Claude.
95192
96- Configuration for the agent:
193+ ``` rust
194+ let mut agent = Agent :: new (config , system_prompt , oauth , tools );
195+ agent . send_request (" Hello!" , RequestMode :: Normal );
196+ while let Some (step ) = agent . next (). await { /* ... */ }
197+ agent . submit_tool_result (& call_id , result );
198+ ```
199+
200+ ### ` AgentRuntimeConfig `
97201
98202``` rust
99203let config = AgentRuntimeConfig {
@@ -110,34 +214,39 @@ let config = AgentRuntimeConfig::default();
110214
111215### ` AgentStep `
112216
113- Events emitted during agent processing:
217+ Events emitted during processing:
114218
115219- ` TextDelta(String) ` - Streaming text output
116220- ` ThinkingDelta(String) ` - Extended thinking output
221+ - ` ToolRequest(Vec<ToolCall>) ` - LLM wants to use tools
117222- ` Finished { usage: Usage } ` - Processing complete
118223- ` Error(String) ` - Error occurred
119224- ` Retrying { attempt, error } ` - Retrying after error
120- - ` ToolRequest(Vec<ToolCall>) ` - Tools requested (not used with empty registry)
121- - ` CompactionDelta(String) ` - Context compaction output
122225
123- ### ` RequestMode `
226+ ### ` SimpleTool `
124227
125- Controls agent behavior :
228+ Define a tool for the LLM to use :
126229
127- - ` RequestMode::Normal ` - Standard conversation
128- - ` RequestMode::Compaction ` - Context compaction mode
230+ ``` rust
231+ let tool = SimpleTool :: new (
232+ " tool_name" , // Name the LLM will use
233+ " Description of tool" , // Help the LLM understand when to use it
234+ json! ({ /* JSON Schema for parameters */ }),
235+ );
236+ ```
129237
130238### ` ToolRegistry `
131239
132- For library usage, create an empty registry :
240+ Manage available tools :
133241
134242``` rust
135- let tools = ToolRegistry :: empty ();
243+ let mut tools = ToolRegistry :: empty ();
244+ tools . register (Arc :: new (my_tool ));
136245```
137246
138247### ` Usage `
139248
140- Token usage statistics returned in ` AgentStep::Finished ` :
249+ Token usage statistics:
141250
142251``` rust
143252pub struct Usage {
@@ -155,61 +264,3 @@ Set the `ANTHROPIC_API_KEY` environment variable:
155264``` bash
156265export ANTHROPIC_API_KEY=sk-ant-...
157266```
158-
159- ## Example: Interactive Chat
160-
161- ``` rust
162- use codey :: {Agent , AgentRuntimeConfig , AgentStep , RequestMode , ToolRegistry };
163- use std :: io :: {self , Write };
164-
165- #[tokio:: main]
166- async fn main () -> anyhow :: Result <()> {
167- let mut agent = Agent :: new (
168- AgentRuntimeConfig :: default (),
169- " You are a helpful assistant." ,
170- None ,
171- ToolRegistry :: empty (),
172- );
173-
174- loop {
175- print! (" > " );
176- io :: stdout (). flush ()? ;
177-
178- let mut input = String :: new ();
179- io :: stdin (). read_line (& mut input )? ;
180- let input = input . trim ();
181-
182- if input == " quit" {
183- break ;
184- }
185-
186- agent . send_request (input , RequestMode :: Normal );
187-
188- while let Some (step ) = agent . next (). await {
189- match step {
190- AgentStep :: TextDelta (text ) => print! (" {}" , text ),
191- AgentStep :: Finished { .. } => {
192- println! ();
193- break ;
194- }
195- AgentStep :: Error (e ) => {
196- eprintln! (" \ n Error: {}" , e );
197- break ;
198- }
199- _ => {}
200- }
201- }
202- }
203-
204- Ok (())
205- }
206- ```
207-
208- ## Limitations
209-
210- The library exposes a minimal API focused on creating agents with custom system prompts. The built-in tools (file operations, shell, web search, etc.) are specific to the Codey binary and its UI, so they are not exposed in the library API.
211-
212- If you need tool capabilities, you can:
213- 1 . Implement tool-like behavior in your system prompt
214- 2 . Parse structured output from the agent
215- 3 . Build your own tool execution layer outside of codey
0 commit comments