1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
//! # Seedframe - Core API Documentation
//!
//! Seedframe is a clean, macro-driven Rust library for building LLM applications.
//!
//! ## Features
//!
//! - **Declarative API** through straight forward proc-macros
//! - **Modular Architecture** with clearly defined components:
//! - **Loaders**: Data ingestion from various sources (files, APIs, etc.)
//! - **Vector Stores**: Embedding storage and retrieval (In-memory, Redis, etc.)
//! - **Embedders**: Text embedding providers
//! - **LLM Clients**: Unified interface for different LLM providers
//! - **Tools**: Function calling abstractions with state management and automatic documentation
//! - **Extractors**: Structured output generation from LLM responses
//!
//! ## Examples
//!
//! The seedframe repo contains a [number of examples](https://github.com/Shifta-Robel/SeedFrame/tree/main/core/examples) that show how to put all the pieces together.
//!
//! ### Building a simple RAG
//!
//! ```rust,ignore
//! use seedframe::prelude::*;
//! use seedframe::providers::{completions::OpenAI, embeddings::OpenAIEmbedding};
//! use seedframe::vector_store::InMemoryVectorStore;
//!
//! // Declare file loader that doesnt check for updates, loading files that match the glob pattern
//! #[loader(kind = "FileOnceLoader", path = "/tmp/data/**/*.txt")]
//! pub struct MyLoader;
//!
//! #[vector_store(store = "InMemoryVectorStore")]
//! pub struct MyVectorStore;
//!
//! #[embedder(provider = "OpenAIEmbedding")]
//! struct MyEmbedder {
//! #[vector_store]
//! my_vector_store: MyVectorStore,
//! #[loader]
//! my_loader: MyLoader,
//! }
//!
//! #[client(provider = "OpenAI")]
//! struct MyClient {
//! #[embedder]
//! my_embedder: MyEmbedder,
//! }
//!
//! #[tokio::main]
//! async fn main() {
//! let mut client = MyClient::build(
//! "You are a helpful assistant".to_string()
//! ).await;
//!
//! tokio::time::sleep(Duration::from_secs(5)).await;
//! let response = client.prompt("Explain quantum computing").send().await.unwrap();
//! }
//! ```
//!
//! ### Tool calls and Extractors
//!
//! ```rust,ignore
//! use seedframe::{providers::completions::OpenAI, prelude::*};
//!
//! #[client(provider = "OpenAI", tools("analyze"))]
//! struct ToolClient;
//!
//! /// Perform sentiment analysis on text
//! /// # Arguments
//! /// * `text`: Input text to analyze
//! /// * `language`: Language of the text (ISO 639-1)
//! #[tool]
//! fn analyze(text: String, language: String) -> String {
//! todo!("implementation");
//! }
//!
//! #[derive(Extractor)]
//! struct PersonData {
//! /// Age in years
//! age: u8,
//! /// Email address
//! email: String
//! }
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//! let mut client = ToolClient::build("You're a data analyst".to_string())
//! .await
//! .with_state(AppState::new())?;
//!
//! // Tool call
//! client.prompt("Analyze this: 'I love Rust!' (en)")
//! .append_tool_response(true) // append result of tool execution to the message history
//! // more prompt modifiers if you want
//! .send()
//! .await?;
//!
//! // Structured extraction
//! let person = client.prompt("John is 30, email john@example.com")
//! .extract::<PersonData>()
//! .await?;
//! }
//! ```
//!
//! ### Sharing state with tools
//!
//! You can pass state to tools by adding arguments of type `State<_>` to them, the only catch is that there can only be one type of State\<T\> attached to the client.
//!
//! ```rust,ignore
//! use seedframe::{providers::completions::OpenAI, prelude::*};
//!
//! #[client(provider = "OpenAI", tools("greet"))]
//! struct ToolClient;
//!
//! /// Greets a user
//! /// # Arguments
//! /// * `name`: name of the user
//! #[tool]
//! fn greet(name: String, State(count): State<u32>) -> String {
//! for _ in range 0..count { println("Hello {name}!!")};
//! }
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//! let mut client = ToolClient::build("You're a helpful assistant".to_string())
//! .await
//! .with_state(3u32)?
//! .with_state(7u32)? // this is an error since there's already a State of type u32 attached
//! .with_state("some other state".to_string())?;
//!
//! // Tool call
//! client.prompt("Say hi to jack for me".to_string())
//! .send()
//! .await?;
//! }
//! ```
//!
//! #### Sharing mutable state with tools
//!
//! To share mutable state you can use types with interior mutablity, eg `Mutex`s
//!
//! ```rust,ignore
//! /// Greets a user
//! /// # Arguments
//! /// * `name`: name of the user
//! #[tool]
//! fn greet(name: String, State(count): State<u32>) -> String {
//! let mut count = count.lock().unwrap();
//! println!("{name}! This is my {count}th time saying hello");
//! *count += 1;
//! }
//!
//! struct AppState {
//! count: std::sync::Mutex<u32>
//! }
//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//! let mut client = ToolClient::build("You're a helpful assistant".to_string())
//! .await
//! .with_state(AppState { count: std::sync::Mutex::new(0u32) })?;
//!
//! // Tool call
//! client.prompt("Say hi to jack for me".to_string())
//! .send()
//! .await?;
//!
//! // Tool call
//! client.prompt("Say hi to jack for me".to_string())
//! .send()
//! .await?;
//! }
//! ```
//!
//! ## Feature flags
//!
//! seedframe uses a set of [feature flags] to reduce the amount of compiled and
//! optional dependencies.
//!
//! The following optional features are available:
//!
//! Name | Description | Default?
//! ---|---|---
//! `pdf` | enables file loaders to parse PDFs | No
/// Language model completion and conversation management
///
/// Contains:
/// - Client for managing LLM interactions
/// - Message history tracking
/// - Response extraction
/// Document processing and representation utilities
///
/// Provides core types for handling text documents in embedding and retrieval workflows.
/// Text embeddings support
/// Error types for all library operations
/// Resource loading utilities
/// Convenience prelude exports
///
/// Re-exports commonly used types:
/// - macros from `seedframe_macros`
/// - `completion::State`
/// Builtin completion and embedding model providers
/// Function calling and tool execution support
/// Vector storage and retrieval