assistants_basic/
assistants_basic.rs

1#![allow(clippy::uninlined_format_args)]
2//! Basic Assistants API example demonstrating assistant creation and thread management.
3//!
4//! This example showcases the Assistants API, which provides a way to build AI assistants
5//! with persistent conversation threads, custom instructions, and tool capabilities.
6//!
7//! ## Features Demonstrated
8//!
9//! - Creating and configuring assistants
10//! - Thread creation and management
11//! - Message handling within threads
12//! - Run creation and polling for responses
13//! - Tool integration (code interpreter, function calling)
14//! - Comprehensive error handling patterns
15//!
16//! ## Prerequisites
17//!
18//! Set your `OpenAI` API key:
19//! ```bash
20//! export OPENAI_API_KEY="your-key-here"
21//! ```
22//!
23//! ## Usage
24//!
25//! ```bash
26//! cargo run --example assistants_basic
27//! ```
28//!
29//! ## Note on Implementation Status
30//!
31//! **Important**: The Assistants API is not yet fully implemented in openai-ergonomic.
32//! This example demonstrates the intended API design and serves as a template for
33//! future implementation. Current code shows simulated functionality.
34
35use openai_ergonomic::{Client, Error};
36use std::io::{self, Write};
37
38#[tokio::main]
39async fn main() -> Result<(), Box<dyn std::error::Error>> {
40    println!(" OpenAI Ergonomic - Basic Assistants API Example\n");
41
42    // Initialize client from environment variables
43    let client = match Client::from_env() {
44        Ok(client_builder) => {
45            println!(" Client initialized successfully");
46            client_builder.build()
47        }
48        Err(e) => {
49            eprintln!(" Failed to initialize client: {e}");
50            eprintln!(" Make sure OPENAI_API_KEY is set in your environment");
51            return Err(e.into());
52        }
53    };
54
55    // Check current implementation status
56    check_implementation_status();
57
58    // Example 1: Creating an Assistant
59    println!("\n Example 1: Creating an Assistant");
60    println!("==================================");
61
62    create_assistant_example(&client);
63    println!(" Assistant creation example completed");
64
65    // Example 2: Managing Threads
66    println!("\n Example 2: Thread Management");
67    println!("==============================");
68
69    thread_management_example(&client);
70    println!(" Thread management example completed");
71
72    // Example 3: Message Handling
73    println!("\n Example 3: Message Handling");
74    println!("=============================");
75
76    match message_handling_example(&client).await {
77        Ok(()) => println!(" Message handling example completed"),
78        Err(e) => {
79            eprintln!(" Message handling example failed: {e}");
80            handle_api_error(&e);
81        }
82    }
83
84    // Example 4: Tool Integration
85    println!("\n Example 4: Tool Integration");
86    println!("=============================");
87
88    match tool_integration_example(&client).await {
89        Ok(()) => println!(" Tool integration example completed"),
90        Err(e) => {
91            eprintln!(" Tool integration example failed: {e}");
92            handle_api_error(&e);
93        }
94    }
95
96    // Example 5: Conversation Simulation
97    println!("\n Example 5: Complete Conversation Flow");
98    println!("========================================");
99
100    match conversation_flow_example(&client).await {
101        Ok(()) => println!(" Conversation flow example completed"),
102        Err(e) => {
103            eprintln!(" Conversation flow example failed: {e}");
104            handle_api_error(&e);
105        }
106    }
107
108    println!("\n All examples completed!");
109    println!("\n This example demonstrated the intended Assistants API usage:");
110    println!("  • Assistant creation with custom instructions");
111    println!("  • Thread lifecycle management");
112    println!("  • Message sending and retrieval");
113    println!("  • Run creation and status polling");
114    println!("  • Tool integration patterns");
115    println!("  • Error handling strategies");
116
117    println!("\n Implementation Status:");
118    println!("  • The Assistants API builders and response types are placeholders");
119    println!("  • This example serves as a design template for future implementation");
120    println!("  • Actual API calls will be available once the builders are implemented");
121
122    Ok(())
123}
124
125/// Check and display the current implementation status
126fn check_implementation_status() {
127    println!(" Implementation Status Check");
128    println!("=============================");
129    println!(" Client infrastructure: Ready");
130    println!(" Assistants builders: Not yet implemented");
131    println!(" Threads builders: Not yet implemented");
132    println!(" Assistants responses: Not yet implemented");
133    println!();
134    println!(" This example demonstrates the intended API design");
135    println!("   and will work once the builders are implemented.");
136}
137
138/// Example 1: Creating and configuring an assistant
139fn create_assistant_example(_client: &Client) {
140    println!("Creating a new assistant with custom instructions...");
141
142    // Future API design - this will work once assistants builders are implemented
143    /*
144    let assistant_builder = client
145        .assistants()
146        .create()
147        .model("gpt-4")
148        .name("Math Tutor")
149        .description("A helpful assistant that helps with math problems")
150        .instructions(
151            "You are a patient math tutor. Help students understand mathematical concepts \
152             by breaking down problems step by step. Always encourage learning and provide \
153             clear explanations."
154        )
155        .tools(vec![
156            tool_code_interpreter(),
157            tool_function(
158                "calculate_fibonacci",
159                "Calculate the nth Fibonacci number",
160                json!({
161                    "type": "object",
162                    "properties": {
163                        "n": {
164                            "type": "integer",
165                            "description": "The position in the Fibonacci sequence"
166                        }
167                    },
168                    "required": ["n"]
169                })
170            )
171        ])
172        .metadata(json!({
173            "example": "basic_assistants",
174            "created_by": "openai-ergonomic"
175        }));
176
177    let assistant = client.send_assistants(assistant_builder).await?;
178
179    println!(" Assistant created successfully!");
180    println!("   ID: {}", assistant.id());
181    println!("   Name: {}", assistant.name().unwrap_or("Unnamed"));
182    println!("   Model: {}", assistant.model());
183    println!("   Tools: {} configured", assistant.tools().len());
184    */
185
186    // Simulated output for now
187    println!(" [Simulated] Assistant created successfully!");
188    println!("   ID: asst_abc123def456");
189    println!("   Name: Math Tutor");
190    println!("   Model: gpt-4");
191    println!("   Tools: 2 configured (code_interpreter, calculate_fibonacci)");
192    println!("   Instructions: Custom math tutoring instructions set");
193
194    println!("\n Assistant Configuration:");
195    println!("   • Model: GPT-4 for advanced reasoning");
196    println!("   • Code Interpreter: Enabled for calculations");
197    println!("   • Custom Function: Fibonacci calculator");
198    println!("   • Metadata: Tagged for tracking");
199}
200
201/// Example 2: Thread creation and management
202fn thread_management_example(_client: &Client) {
203    println!("Creating and managing conversation threads...");
204
205    // Future API design for thread management
206    /*
207    // Create a new thread
208    let thread_builder = client
209        .threads()
210        .create()
211        .metadata(json!({
212            "user_id": "user_123",
213            "session": "math_help_session"
214        }));
215
216    let thread = client.send_threads(thread_builder).await?;
217
218    println!(" Thread created: {}", thread.id());
219
220    // Retrieve thread information
221    let thread_info = client
222        .threads()
223        .retrieve(thread.id())
224        .await?;
225
226    println!(" Thread info retrieved:");
227    println!("   Created: {}", thread_info.created_at());
228    println!("   Metadata: {}", thread_info.metadata());
229
230    // List threads (if supported)
231    let threads = client
232        .threads()
233        .list()
234        .limit(10)
235        .await?;
236
237    println!(" Found {} threads", threads.data().len());
238    */
239
240    // Simulated output
241    println!(" [Simulated] Thread created: thread_abc123xyz789");
242    println!(" Thread information:");
243    println!("   Status: Active");
244    println!("   Created: 2024-01-15T10:30:00Z");
245    println!("   Messages: 0 (new thread)");
246    println!("   Metadata: {{\"user_id\": \"user_123\", \"session\": \"math_help_session\"}}");
247
248    println!("\n Thread Management Features:");
249    println!("   • Unique thread ID for session tracking");
250    println!("   • Metadata for context preservation");
251    println!("   • Message history maintained automatically");
252    println!("   • Thread retrieval and listing capabilities");
253}
254
255/// Example 3: Adding messages to threads and getting responses
256async fn message_handling_example(_client: &Client) -> Result<(), Error> {
257    println!("Adding messages to thread and getting assistant responses...");
258
259    // Future API design for message handling
260    /*
261    // Add a user message to the thread
262    let message_builder = client
263        .threads()
264        .messages(thread_id)
265        .create()
266        .role("user")
267        .content("Can you help me solve this equation: 2x + 5 = 13?")
268        .metadata(json!({
269            "message_type": "math_problem",
270            "difficulty": "beginner"
271        }));
272
273    let message = client.send_thread_message(message_builder).await?;
274
275    println!(" Message added: {}", message.id());
276
277    // Create a run to get assistant response
278    let run_builder = client
279        .threads()
280        .runs(thread_id)
281        .create()
282        .assistant_id("asst_abc123def456")
283        .instructions("Focus on step-by-step explanation")
284        .additional_instructions("Show your work clearly");
285
286    let run = client.send_thread_run(run_builder).await?;
287
288    println!(" Run created: {}", run.id());
289
290    // Poll for completion
291    let completed_run = poll_run_completion(client, thread_id, run.id()).await?;
292
293    if completed_run.status() == "completed" {
294        // Retrieve messages
295        let messages = client
296            .threads()
297            .messages(thread_id)
298            .list()
299            .limit(10)
300            .await?;
301
302        for message in messages.data().iter().rev() {
303            println!(" {}: {}", message.role(), message.content());
304        }
305    }
306    */
307
308    let thread_id = "thread_abc123xyz789"; // From previous example
309
310    // Simulated conversation flow
311    println!(" [Simulated] Adding user message to thread: {thread_id}");
312    println!("   Message: 'Can you help me solve this equation: 2x + 5 = 13?'");
313    println!("   Message ID: msg_user123abc");
314
315    println!("\n [Simulated] Creating run for assistant response...");
316    print!("   Status: ");
317    io::stdout().flush()?;
318
319    // Simulate run status progression
320    let statuses = ["queued", "in_progress", "completed"];
321    for (i, status) in statuses.iter().enumerate() {
322        if i > 0 {
323            print!(" → ");
324        }
325        print!("{status}");
326        io::stdout().flush()?;
327        tokio::time::sleep(tokio::time::Duration::from_millis(800)).await;
328    }
329    println!();
330
331    println!("\n [Simulated] Assistant Response:");
332    println!("   I'd be happy to help you solve the equation 2x + 5 = 13!");
333    println!();
334    println!("   Let's solve this step by step:");
335    println!("   1. Start with: 2x + 5 = 13");
336    println!("   2. Subtract 5 from both sides: 2x = 13 - 5");
337    println!("   3. Simplify: 2x = 8");
338    println!("   4. Divide both sides by 2: x = 8/2");
339    println!("   5. Final answer: x = 4");
340    println!();
341    println!("   To verify: 2(4) + 5 = 8 + 5 = 13 ");
342
343    println!("\n Message Flow Summary:");
344    println!("   • User message successfully added to thread");
345    println!("   • Run created and executed with assistant");
346    println!("   • Step-by-step mathematical solution provided");
347    println!("   • Response includes verification of the answer");
348
349    Ok(())
350}
351
352/// Example 4: Tool integration with code interpreter and custom functions
353async fn tool_integration_example(_client: &Client) -> Result<(), Error> {
354    println!("Demonstrating tool integration with code interpreter and custom functions...");
355
356    // Future API design for tool integration
357    /*
358    // Add a message that would trigger tool usage
359    let message_builder = client
360        .threads()
361        .messages(thread_id)
362        .create()
363        .role("user")
364        .content("Calculate the 10th Fibonacci number and create a graph showing the first 10 numbers in the sequence");
365
366    let message = client.send_thread_message(message_builder).await?;
367
368    // Create a run that can use tools
369    let run_builder = client
370        .threads()
371        .runs(thread_id)
372        .create()
373        .assistant_id(assistant_id)
374        .tools_enabled(true)
375        .instructions("Use the fibonacci function and code interpreter to provide a complete answer");
376
377    let run = client.send_thread_run(run_builder).await?;
378
379    // Poll and handle tool calls
380    let completed_run = poll_run_with_tool_handling(client, thread_id, run.id()).await?;
381    */
382
383    let thread_id = "thread_abc123xyz789";
384    let assistant_id = "asst_abc123def456";
385
386    // Simulated tool integration
387    println!(" [Simulated] User request: Calculate 10th Fibonacci number with visualization");
388    println!("   Thread: {thread_id}, Assistant: {assistant_id}");
389
390    println!("\n [Simulated] Tool Execution Flow:");
391    println!("   1. Custom Function Call: calculate_fibonacci(n=10)");
392    print!("      Result: ");
393    io::stdout().flush()?;
394    tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
395    println!("55");
396
397    println!("\n   2. Code Interpreter: Generating Fibonacci sequence visualization");
398    print!("      Status: ");
399    io::stdout().flush()?;
400    let code_steps = [
401        "importing libraries",
402        "generating sequence",
403        "creating plot",
404        "complete",
405    ];
406    for (i, step) in code_steps.iter().enumerate() {
407        if i > 0 {
408            print!(" → ");
409        }
410        print!("{step}");
411        io::stdout().flush()?;
412        tokio::time::sleep(tokio::time::Duration::from_millis(600)).await;
413    }
414    println!();
415
416    println!("\n [Simulated] Assistant Response with Tool Results:");
417    println!("   I've calculated the 10th Fibonacci number and created a visualization for you!");
418    println!();
419    println!("    Results:");
420    println!("   • The 10th Fibonacci number is: 55");
421    println!("   • Complete sequence (1-10): [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]");
422    println!();
423    println!("    I've also generated a graph showing the exponential growth pattern");
424    println!("   of the Fibonacci sequence. The visualization clearly shows how each");
425    println!("   number rapidly increases as the sequence progresses.");
426    println!();
427    println!("    Tools Used:");
428    println!("   1. Custom fibonacci function for precise calculation");
429    println!("   2. Code interpreter for data visualization");
430
431    println!("\n Tool Integration Benefits:");
432    println!("   • Custom functions provide domain-specific capabilities");
433    println!("   • Code interpreter enables dynamic computation and visualization");
434    println!("   • Seamless integration in conversation flow");
435    println!("   • Automatic tool selection based on user needs");
436
437    Ok(())
438}
439
440/// Example 5: Complete conversation flow simulation
441async fn conversation_flow_example(_client: &Client) -> Result<(), Error> {
442    println!("Demonstrating a complete conversation flow with an assistant...");
443
444    // Simulate creating a new thread for a fresh conversation
445    println!(" [Simulated] Creating new thread for complete conversation...");
446    let thread_id = "thread_conversation_demo";
447    println!("   Thread ID: {thread_id}");
448
449    // Conversation turns
450    let conversation = [
451        ("user", "Hi! I'm working on a project about mathematical sequences. Can you help?"),
452        ("assistant", "Hello! I'd be delighted to help you with mathematical sequences. What specific aspect of sequences are you working on? Are you interested in arithmetic sequences, geometric sequences, Fibonacci numbers, or perhaps something else?"),
453        ("user", "I'm particularly interested in the golden ratio and how it relates to Fibonacci numbers."),
454        ("assistant", "Excellent topic! The golden ratio (φ ≈ 1.618) has a beautiful relationship with Fibonacci numbers. Let me explain and demonstrate this connection."),
455        ("user", "Could you calculate the ratio between consecutive Fibonacci numbers to show this?"),
456    ];
457
458    println!("\n [Simulated] Conversation Flow:");
459    println!("================================");
460
461    for (i, (role, message)) in conversation.iter().enumerate() {
462        println!(
463            "\n{}. {}: {}",
464            i + 1,
465            if *role == "user" { "User" } else { "Assistant" },
466            message
467        );
468
469        if *role == "user" && i < conversation.len() - 1 {
470            // Simulate processing time for assistant responses
471            print!("   [Processing");
472            for _ in 0..3 {
473                print!(".");
474                io::stdout().flush()?;
475                tokio::time::sleep(tokio::time::Duration::from_millis(400)).await;
476            }
477            println!("]");
478        }
479    }
480
481    // Demonstrate tool usage in the final response
482    println!("\n [Simulated] Final Response with Tool Integration:");
483    println!("Assistant: I'll calculate the ratios between consecutive Fibonacci numbers to demonstrate the golden ratio convergence!");
484
485    print!("\n   [Using fibonacci function and code interpreter");
486    for _ in 0..4 {
487        print!(".");
488        io::stdout().flush()?;
489        tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
490    }
491    println!("]");
492
493    println!("\n   Here are the ratios of consecutive Fibonacci numbers:");
494    let fib_ratios = [
495        (1, 1, 1.0),
496        (1, 2, 2.0),
497        (2, 3, 1.5),
498        (3, 5, 1.667),
499        (5, 8, 1.6),
500        (8, 13, 1.625),
501        (13, 21, 1.615),
502        (21, 34, 1.619),
503        (34, 55, 1.618),
504        (55, 89, 1.618),
505    ];
506
507    for (a, b, ratio) in fib_ratios {
508        println!(
509            "   F({}) / F({}) = {} / {} = {:.3}",
510            fib_ratios.iter().position(|(x, _, _)| *x == a).unwrap() + 1,
511            fib_ratios.iter().position(|(x, _, _)| *x == b).unwrap() + 2,
512            b,
513            a,
514            ratio
515        );
516    }
517
518    println!("\n    As you can see, the ratio converges to φ ≈ 1.618 (the golden ratio)!");
519    println!("   This demonstrates the beautiful mathematical relationship between");
520    println!("   the Fibonacci sequence and the golden ratio.");
521
522    println!("\n Complete Conversation Summary:");
523    println!("   • Natural conversation flow with context preservation");
524    println!("   • Assistant understanding of complex mathematical concepts");
525    println!("   • Seamless tool integration for calculations and demonstrations");
526    println!("   • Educational explanations with concrete examples");
527    println!("   • Multi-turn conversation maintaining context throughout");
528
529    Ok(())
530}
531
532/// Comprehensive error handling helper for assistants API
533fn handle_api_error(error: &Error) {
534    match error {
535        Error::Api {
536            status,
537            message,
538            error_type,
539            error_code,
540        } => {
541            eprintln!(" API Error [{status}]: {message}");
542            if let Some(error_type) = error_type {
543                eprintln!("   Type: {error_type}");
544            }
545            if let Some(error_code) = error_code {
546                eprintln!("   Code: {error_code}");
547            }
548
549            // Provide specific guidance for assistants API errors
550            match *status {
551                400 => {
552                    eprintln!(" Check your request parameters (assistant ID, thread ID, etc.)");
553                }
554                401 => eprintln!(" Check your API key: export OPENAI_API_KEY=\"your-key\""),
555                404 => eprintln!(" Assistant or thread not found - verify IDs are correct"),
556                429 => eprintln!(" Rate limited - assistants API has specific rate limits"),
557                500..=599 => eprintln!(" Server error - try again later"),
558                _ => {}
559            }
560        }
561        Error::InvalidRequest(msg) => {
562            eprintln!(" Invalid Request: {msg}");
563            eprintln!(" Check your assistant/thread/message parameters");
564        }
565        Error::Config(msg) => {
566            eprintln!(" Configuration Error: {msg}");
567            eprintln!(" Check your client configuration");
568        }
569        Error::Http(err) => {
570            eprintln!(" HTTP Error: {err}");
571            eprintln!(" Check your network connection");
572        }
573        Error::HttpMiddleware(err) => {
574            eprintln!(" HTTP Middleware Error: {err}");
575            eprintln!(" Check your network connection and middleware configuration");
576        }
577        Error::Json(err) => {
578            eprintln!(" JSON Error: {err}");
579            eprintln!(" Response parsing failed - may be a temporary issue");
580        }
581        Error::Authentication(msg) => {
582            eprintln!(" Authentication Error: {msg}");
583            eprintln!(" Check your API key and organization ID");
584        }
585        Error::RateLimit(msg) => {
586            eprintln!(" Rate Limit Error: {msg}");
587            eprintln!(" Assistants API has specific rate limits - wait before retrying");
588        }
589        Error::Builder(msg) => {
590            eprintln!(" Builder Error: {msg}");
591            eprintln!(" Check your assistant/thread builder configuration");
592        }
593        _ => {
594            eprintln!(" Unexpected Error: {error}");
595            eprintln!(" This may be a bug, please report it");
596        }
597    }
598}
599
600// Helper functions that would be used once the API is implemented
601
602/// Poll run status until completion (future implementation)
603#[allow(dead_code)]
604fn poll_run_completion(_client: &Client, _thread_id: &str, _run_id: &str) -> MockRun {
605    // This would poll the actual API in a real implementation
606    // For now, return a simulated completed run
607    MockRun {
608        id: "run_completed123".to_string(),
609        status: "completed".to_string(),
610    }
611}
612
613/// Mock run type for simulation
614#[allow(dead_code)]
615struct MockRun {
616    id: String,
617    status: String,
618}
619
620#[allow(dead_code)]
621impl MockRun {
622    fn id(&self) -> &str {
623        &self.id
624    }
625
626    fn status(&self) -> &str {
627        &self.status
628    }
629}