openrouter-rust 0.1.0

A modular, type-safe Rust client for the OpenRouter API
Documentation
use mockito::Server;
use openrouter_rust::{
    OpenRouterClient,
    embeddings::{EmbeddingBuilder, EmbeddingRequest, EmbeddingInput, EmbeddingEncodingFormat},
};
use serde_json::json;

#[tokio::test]
async fn test_create_embedding_single() {
    let mut server = Server::new_async().await;
    
    let mock_response = json!({
        "object": "list",
        "data": [
            {
                "object": "embedding",
                "embedding": [0.1, 0.2, 0.3, 0.4, 0.5],
                "index": 0
            }
        ],
        "model": "text-embedding-ada-002",
        "usage": {
            "prompt_tokens": 8,
            "total_tokens": 8,
            "cost": 0.00001
        }
    });

    let _m = server.mock("POST", "/embeddings")
        .match_header("authorization", "Bearer test-key")
        .with_status(200)
        .with_header("content-type", "application/json")
        .with_body(mock_response.to_string())
        .create_async()
        .await;

    let client = OpenRouterClient::builder()
        .api_key("test-key")
        .base_url(&server.url())
        .build()
        .unwrap();

    let request = EmbeddingBuilder::new("text-embedding-ada-002", "Hello world")
        .build();

    let response = client.create_embedding(request).await.unwrap();

    assert_eq!(response.object, "list");
    assert_eq!(response.model, "text-embedding-ada-002");
    assert_eq!(response.data.len(), 1);
    assert_eq!(response.usage.total_tokens, 8.0);
}

#[tokio::test]
async fn test_create_embedding_batch() {
    let mut server = Server::new_async().await;
    
    let mock_response = json!({
        "object": "list",
        "data": [
            {
                "object": "embedding",
                "embedding": [0.1, 0.2, 0.3],
                "index": 0
            },
            {
                "object": "embedding",
                "embedding": [0.4, 0.5, 0.6],
                "index": 1
            }
        ],
        "model": "text-embedding-ada-002",
        "usage": {
            "prompt_tokens": 16,
            "total_tokens": 16
        }
    });

    let _m = server.mock("POST", "/embeddings")
        .with_status(200)
        .with_header("content-type", "application/json")
        .with_body(mock_response.to_string())
        .create_async()
        .await;

    let client = OpenRouterClient::builder()
        .api_key("test-key")
        .base_url(&server.url())
        .build()
        .unwrap();

    let request = EmbeddingBuilder::new_with_array(
        "text-embedding-ada-002",
        vec!["First text".to_string(), "Second text".to_string()]
    ).build();

    let response = client.create_embedding(request).await.unwrap();

    assert_eq!(response.data.len(), 2);
    assert_eq!(response.data[0].index, 0.0);
    assert_eq!(response.data[1].index, 1.0);
}

#[tokio::test]
async fn test_list_embedding_models() {
    let mut server = Server::new_async().await;
    
    let mock_response = json!({
        "data": [
            {
                "id": "text-embedding-ada-002",
                "canonical_slug": "openai/text-embedding-ada-002",
                "name": "Embedding Ada 002",
                "created": 1677649963.0,
                "description": "OpenAI's embedding model",
                "pricing": {},
                "architecture": {
                    "input_modalities": ["text"],
                    "output_modalities": ["embeddings"]
                },
                "top_provider": {"is_moderated": false},
                "per_request_limits": {"prompt_tokens": 8191, "completion_tokens": 0},
                "supported_parameters": ["temperature"],
                "default_parameters": {}
            }
        ]
    });

    let _m = server.mock("GET", "/embeddings/models")
        .match_header("authorization", "Bearer test-key")
        .with_status(200)
        .with_header("content-type", "application/json")
        .with_body(mock_response.to_string())
        .create_async()
        .await;

    let client = OpenRouterClient::builder()
        .api_key("test-key")
        .base_url(&server.url())
        .build()
        .unwrap();

    let response = client.list_embedding_models().await.unwrap();

    assert_eq!(response.data.len(), 1);
    assert_eq!(response.data[0].id, "text-embedding-ada-002");
    assert_eq!(response.data[0].name, "Embedding Ada 002");
}

#[tokio::test]
async fn test_embedding_with_dimensions() {
    let mut server = Server::new_async().await;
    
    let _m = server.mock("POST", "/embeddings")
        .match_body(mockito::Matcher::Json(json!({
            "input": "test",
            "model": "text-embedding-3-small",
            "dimensions": 256
        })))
        .with_status(200)
        .with_header("content-type", "application/json")
        .with_body(json!({
            "object": "list",
            "data": [{"object": "embedding", "embedding": [0.1; 256], "index": 0}],
            "model": "text-embedding-3-small",
            "usage": {"prompt_tokens": 1, "total_tokens": 1}
        }).to_string())
        .create_async()
        .await;

    let client = OpenRouterClient::builder()
        .api_key("test-key")
        .base_url(&server.url())
        .build()
        .unwrap();

    let request = EmbeddingBuilder::new("text-embedding-3-small", "test")
        .dimensions(256)
        .build();

    let response = client.create_embedding(request).await.unwrap();
    assert_eq!(response.model, "text-embedding-3-small");
}