| Crates.io | octolib |
| lib.rs | octolib |
| version | 0.5.1 |
| created_at | 2025-11-22 09:57:15.272744+00 |
| updated_at | 2026-01-22 14:39:11.173858+00 |
| description | Self-sufficient AI provider library with multi-provider support, embedding models, model validation, and cost tracking |
| homepage | https://octolib.muvon.io |
| repository | https://github.com/muvon/octolib |
| max_upload_size | |
| id | 1945133 |
| size | 627,880 |
© 2025 Muvon Un Limited (Hong Kong) | Website | Product Page
Octolib is a comprehensive, self-sufficient AI provider library that provides a unified, type-safe interface for interacting with multiple AI services. It offers intelligent model selection, robust error handling, and advanced features like cross-provider tool calling and vision support.
provider:model format parsing with case-insensitive model support# Add to Cargo.toml
octolib = { git = "https://github.com/muvon/octolib" }
use octolib::{ProviderFactory, ChatCompletionParams, Message};
async fn example() -> anyhow::Result<()> {
// Parse model and get provider
let (provider, model) = ProviderFactory::get_provider_for_model("openai:gpt-4o")?;
// Create messages
let messages = vec![
Message::user("Hello, how are you?"),
];
// Create completion parameters
let params = ChatCompletionParams::new(&messages, &model, 0.7, 1.0, 50, 1000);
// Get completion (requires OPENAI_API_KEY environment variable)
let response = provider.chat_completion(params).await?;
println!("Response: {}", response.content);
Ok(())
}
Get structured JSON responses with schema validation:
use octolib::{ProviderFactory, ChatCompletionParams, Message, StructuredOutputRequest};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct PersonInfo {
name: String,
age: u32,
skills: Vec<String>,
}
async fn structured_example() -> anyhow::Result<()> {
let (provider, model) = ProviderFactory::get_provider_for_model("openai:gpt-4o")?;
// Check if provider supports structured output
if !provider.supports_structured_output(&model) {
return Err(anyhow::anyhow!("Provider does not support structured output"));
}
let messages = vec![
Message::user("Tell me about a software engineer in JSON format"),
];
// Request structured JSON output
let structured_request = StructuredOutputRequest::json();
let params = ChatCompletionParams::new(&messages, &model, 0.7, 1.0, 50, 1000)
.with_structured_output(structured_request);
let response = provider.chat_completion(params).await?;
if let Some(structured) = response.structured_output {
let person: PersonInfo = serde_json::from_value(structured)?;
println!("Person: {:?}", person);
}
Ok(())
}
Use AI models to call functions with automatic parameter extraction:
use octolib::{ProviderFactory, ChatCompletionParams, Message, FunctionDefinition, ToolCall};
use serde_json::json;
async fn tool_calling_example() -> anyhow::Result<()> {
let (provider, model) = ProviderFactory::get_provider_for_model("openai:gpt-4o")?;
// Define available tools/functions
let tools = vec![
FunctionDefinition {
name: "get_weather".to_string(),
description: "Get the current weather for a location".to_string(),
parameters: json!({
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
},
"required": ["location"]
}),
cache_control: None,
},
FunctionDefinition {
name: "calculate".to_string(),
description: "Perform a mathematical calculation".to_string(),
parameters: json!({
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Mathematical expression to evaluate"
}
},
"required": ["expression"]
}),
cache_control: None,
},
];
let mut messages = vec![
Message::user("What's the weather in Tokyo and calculate 15 * 23?"),
];
// Initial request with tools
let params = ChatCompletionParams::new(&messages, &model, 0.7, 1.0, 50, 1000)
.with_tools(tools.clone());
let response = provider.chat_completion(params).await?;
// Check if model wants to call tools
if let Some(tool_calls) = response.tool_calls {
println!("Model requested {} tool calls", tool_calls.len());
// Add assistant's response with tool calls to conversation
let mut assistant_msg = Message::assistant(&response.content);
assistant_msg.tool_calls = Some(serde_json::to_value(&tool_calls)?);
messages.push(assistant_msg);
// Execute each tool call and add results
for tool_call in tool_calls {
println!("Calling tool: {} with args: {}", tool_call.name, tool_call.arguments);
// Execute the tool (your implementation)
let result = match tool_call.name.as_str() {
"get_weather" => {
let location = tool_call.arguments["location"].as_str().unwrap_or("Unknown");
json!({
"location": location,
"temperature": 22,
"unit": "celsius",
"condition": "sunny"
})
}
"calculate" => {
let expr = tool_call.arguments["expression"].as_str().unwrap_or("0");
// Simple calculation (in real app, use proper eval)
json!({
"expression": expr,
"result": 345 // 15 * 23
})
}
_ => json!({"error": "Unknown tool"}),
};
// Add tool result to conversation
messages.push(Message::tool(
&serde_json::to_string(&result)?,
&tool_call.id,
&tool_call.name,
));
}
// Get final response with tool results
let params = ChatCompletionParams::new(&messages, &model, 0.7, 1.0, 50, 1000)
.with_tools(tools);
let final_response = provider.chat_completion(params).await?;
println!("Final response: {}", final_response.content);
} else {
println!("Direct response: {}", response.content);
}
Ok(())
}
Tool Calling Features:
ToolCall and GenericToolCall formats across all providersto_generic_tool_calls() methodGenerate embeddings using multiple providers:
use octolib::embedding::{generate_embeddings, generate_embeddings_batch, InputType};
async fn embedding_example() -> anyhow::Result<()> {
// Single embedding generation
let embedding = generate_embeddings(
"Hello, world!",
"voyage", // provider
"voyage-3.5-lite" // model
).await?;
println!("Embedding dimension: {}", embedding.len());
// Batch embedding generation
let texts = vec![
"First document".to_string(),
"Second document".to_string(),
];
let embeddings = generate_embeddings_batch(
texts,
"jina", // provider
"jina-embeddings-v4", // model
InputType::Document, // input type for better embeddings
16, // batch size
100_000, // max tokens per batch
).await?;
println!("Generated {} embeddings", embeddings.len());
Ok(())
}
// Supported embedding providers:
// - Jina: jina-embeddings-v4, jina-clip-v2, etc.
// - Voyage: voyage-3.5, voyage-code-2, etc.
// - Google: gemini-embedding-001, text-embedding-005
// - OpenAI: text-embedding-3-small, text-embedding-3-large
// - FastEmbed: Local models (feature-gated)
// - HuggingFace: sentence-transformers models
Octolib supports OAuth authentication for ChatGPT subscriptions and Anthropic:
OpenAI OAuth (ChatGPT Plus/Pro/Team/Enterprise):
export OPENAI_OAUTH_ACCESS_TOKEN="your_oauth_token"
export OPENAI_OAUTH_ACCOUNT_ID="your_account_id"
Anthropic OAuth:
export ANTHROPIC_OAUTH_TOKEN="your_bearer_token"
The library automatically detects OAuth credentials and prefers them over API keys. See examples/openai_oauth.rs and examples/anthropic_oauth.rs for full usage examples.
| Provider | Structured Output | Vision | Tool Calls | Caching |
|---|---|---|---|---|
| OpenAI | ✅ JSON + Schema | ✅ Yes | ✅ Yes | ✅ Yes |
| OpenRouter | ✅ JSON + Schema | ✅ Yes | ✅ Yes | ✅ Yes |
| DeepSeek | ✅ JSON Mode | ❌ No | ❌ No | ✅ Yes |
| Anthropic | ❌ No | ✅ Yes | ✅ Yes | ✅ Yes |
| MiniMax | ✅ JSON Mode | ❌ No | ✅ Yes | ✅ Yes |
| Z.ai | ✅ JSON Mode | ❌ No | ✅ Yes | ✅ Yes |
| Google Vertex | ❌ No | ✅ Yes | ✅ Yes | ❌ No |
| Amazon Bedrock | ❌ No | ✅ Yes | ✅ Yes | ❌ No |
| Cloudflare | ❌ No | ❌ No | ❌ No | ❌ No |
provider.supports_structured_output(&model) to check capabilityOctolib provides first-class support for models that produce thinking/reasoning content. Thinking is stored separately from the main response content, similar to how tool_calls are separate from content.
use octolib::{ProviderFactory, ChatCompletionParams, Message, ThinkingBlock};
async fn thinking_example() -> anyhow::Result<()> {
// MiniMax and OpenAI o-series models support thinking
let (provider, model) = ProviderFactory::get_provider_for_model("minimax:MiniMax-M2")?;
let messages = vec![
Message::user("Solve this complex math problem step by step"),
];
let params = ChatCompletionParams::new(&messages, &model, 0.7, 1.0, 50, 1000);
let response = provider.chat_completion(params).await?;
// Access thinking content (separate from response.content)
if let Some(ref thinking) = response.thinking {
println!("=== MODEL THINKING ({}) ===", thinking.tokens);
println!("{}", thinking.content);
println!("==========================");
}
// Final response (clean, no thinking prefix)
println!("Response: {}", response.content);
// Token usage breakdown
if let Some(usage) = &response.exchange.usage {
println!("Prompt tokens: {}", usage.prompt_tokens);
println!("Output tokens: {}", usage.output_tokens);
println!("Reasoning tokens: {}", usage.reasoning_tokens);
}
Ok(())
}
| Provider | Thinking Format | Notes |
|---|---|---|
| MiniMax | Content blocks ({"type": "thinking"}) |
Full thinking block extraction |
| OpenAI o-series | reasoning_content field |
o1, o3, o4 models |
| OpenRouter | reasoning_details |
Gemini and other providers |
Thinking tokens are tracked separately in TokenUsage.reasoning_tokens:
if let Some(usage) = &response.exchange.usage {
println!("Total tokens: {}", usage.total_tokens);
println!(" - Prompt: {}", usage.prompt_tokens);
println!(" - Output: {}", usage.output_tokens);
println!(" - Reasoning: {}", usage.reasoning_tokens);
}
📖 Quick Navigation
| Provider | Status | Capabilities |
|---|---|---|
| OpenAI | ✅ Full Support | Chat, Vision, Tools, Structured Output, Caching |
| Anthropic | ✅ Full Support | Claude Models, Vision, Tools, Caching |
| OpenRouter | ✅ Full Support | Multi-Provider Proxy, Vision, Caching, Structured Output |
| DeepSeek | ✅ Full Support | Open-Source AI Models, Structured Output, Caching |
| MiniMax | ✅ Full Support | Anthropic-Compatible API, Tools, Caching, Thinking, Structured Output |
| Z.ai | ✅ Full Support | GLM Models, Caching, Structured Output |
| Google Vertex AI | ✅ Supported | Enterprise AI Integration |
| Amazon Bedrock | ✅ Supported | Cloud AI Services |
| Cloudflare Workers AI | ✅ Supported | Edge AI Compute |
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Built with ❤️ by the Muvon team in Hong Kong