{"id":43854189,"url":"https://github.com/hiddenpath/ai-lib-rust","last_synced_at":"2026-03-08T08:04:20.746Z","repository":{"id":332978986,"uuid":"1125829546","full_name":"hiddenpath/ai-lib-rust","owner":"hiddenpath","description":null,"archived":false,"fork":false,"pushed_at":"2026-02-15T06:54:32.000Z","size":608,"stargazers_count":4,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-15T12:57:51.621Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hiddenpath.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-31T12:55:08.000Z","updated_at":"2026-02-15T06:54:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hiddenpath/ai-lib-rust","commit_stats":null,"previous_names":["hiddenpath/ai-lib-rust"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/hiddenpath/ai-lib-rust","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hiddenpath%2Fai-lib-rust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hiddenpath%2Fai-lib-rust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hiddenpath%2Fai-lib-rust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hiddenpath%2Fai-lib-rust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hiddenpath","download_url":"https://codeload.github.com/hiddenpath/ai-lib-rust/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hiddenpath%2Fai-lib-rust/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29671513,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T00:11:43.526Z","status":"online","status_checked_at":"2026-02-21T02:00:07.432Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-06T08:13:44.196Z","updated_at":"2026-02-21T02:02:21.631Z","avatar_url":"https://github.com/hiddenpath.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ai-lib-rust\n\n**Protocol Runtime for AI-Protocol** - A high-performance Rust reference implementation.\n\n`ai-lib-rust` is the Rust runtime implementation for the [AI-Protocol](https://github.com/hiddenpath/ai-protocol) specification. It embodies the core design principle: **一切逻辑皆算子，一切配置皆协议** (All logic is operators, all configuration is protocol).\n\n## 🎯 Design Philosophy\n\nUnlike traditional adapter libraries that hardcode provider-specific logic, `ai-lib-rust` is a **protocol-driven runtime** that executes AI-Protocol specifications. This means:\n\n- **Zero hardcoded provider logic**: All behavior is driven by protocol manifests (source YAML or dist JSON)\n- **Operator-based architecture**: Processing is done through composable operators (Decoder → Selector → Accumulator → FanOut → EventMapper)\n- **Hot-reloadable**: Protocol configurations can be updated without restarting the application\n- **Unified interface**: Developers interact with a single, consistent API regardless of the underlying provider\n\n## 🏗️ Architecture\n\nThe library is organized into three layers:\n\n### 1. Protocol Specification Layer (`protocol/`)\n- **Loader**: Loads protocol files from local filesystem, embedded assets, or remote URLs\n- **Validator**: Validates protocols against JSON Schema\n- **Schema**: Protocol structure definitions\n\n### 2. Pipeline Interpreter Layer (`pipeline/`)\n- **Decoder**: Parses raw bytes into protocol frames (SSE, JSON Lines, etc.)\n- **Selector**: Filters frames using JSONPath expressions\n- **Accumulator**: Accumulates stateful data (e.g., tool call arguments)\n- **FanOut**: Handles multi-candidate scenarios\n- **EventMapper**: Converts protocol frames to unified events\n\n### 3. User Interface Layer (`client/`, `types/`)\n- **Client**: Unified client interface\n- **Types**: Standard type system based on AI-Protocol `standard_schema`\n\n## 🔄 V2 Protocol Alignment\n\nStarting with v0.7.0, `ai-lib-rust` aligns with the **AI-Protocol V2** specification. V0.8.0 adds full V2 runtime support including V2 manifest parsing, provider drivers, MCP, Computer Use, and extended multimodal.\n\n### Standard Error Codes (V2)\n\nAll provider errors are classified into 13 standard error codes with unified retry/fallback semantics:\n\n| Code | Name | Retryable | Fallbackable |\n|------|------|-----------|--------------|\n| E1001 | `invalid_request` | No | No |\n| E1002 | `authentication` | No | Yes |\n| E1003 | `permission_denied` | No | No |\n| E1004 | `not_found` | No | No |\n| E1005 | `request_too_large` | No | No |\n| E2001 | `rate_limited` | Yes | Yes |\n| E2002 | `quota_exhausted` | No | Yes |\n| E3001 | `server_error` | Yes | Yes |\n| E3002 | `overloaded` | Yes | Yes |\n| E3003 | `timeout` | Yes | Yes |\n| E4001 | `conflict` | Yes | No |\n| E4002 | `cancelled` | No | No |\n| E9999 | `unknown` | No | No |\n\nClassification follows a priority pipeline: provider-specific error code → HTTP status override → standard HTTP mapping → `E9999`.\n\n### Compliance Tests\n\nCross-runtime behavioral consistency is verified by a shared YAML-based test suite from the `ai-protocol` repository:\n\n```bash\n# Run compliance tests\ncargo test --test compliance\n\n# With explicit compliance directory\nCOMPLIANCE_DIR=../ai-protocol/tests/compliance cargo test --test compliance\n```\n\nFor details, see [CROSS_RUNTIME.md](https://github.com/hiddenpath/ai-protocol/blob/main/docs/CROSS_RUNTIME.md).\n\n### Testing with ai-protocol-mock\n\nFor integration and MCP tests without real API calls, use [ai-protocol-mock](https://github.com/hiddenpath/ai-protocol-mock):\n\n```bash\n# Start mock server (from ai-protocol-mock repo)\ndocker-compose up -d\n\n# Run tests with mock\nMOCK_HTTP_URL=http://localhost:4010 MOCK_MCP_URL=http://localhost:4010/mcp cargo test -- --ignored --nocapture\n\n# Run specific mock integration tests\nMOCK_HTTP_URL=http://localhost:4010 cargo test test_sse_streaming_via_mock test_error_classification_via_mock -- --ignored --nocapture\n```\n\nOr in code: `AiClientBuilder::new().base_url_override(\"http://localhost:4010\").build(...)`\n\n## 🧩 Feature flags \u0026 re-exports\n\n`ai-lib-rust` keeps the runtime core small, and exposes optional capabilities behind feature flags. This aligns with the V2 \"lean core, progressive complexity\" design principle.\n\nFor a deeper overview, see [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).\n\n- **Always available re-exports (crate root)**:\n  - `AiClient`, `AiClientBuilder`, `CancelHandle`, `CallStats`, `ChatBatchRequest`, `ClientMetrics`, `EndpointExt`\n  - `Message`, `MessageRole`, `StreamingEvent`, `ToolCall`\n  - `Result\u003cT\u003e`, `Error`, `ErrorContext`\n  - `FeedbackEvent`, `FeedbackSink` (core feedback types)\n- **Capability features (V2 aligned)**:\n  - **`embeddings`**: embedding generation (`EmbeddingClient`)\n  - **`batch`**: batch API processing (`BatchExecutor`)\n  - **`guardrails`**: input/output validation\n  - **`tokens`**: token counting and cost estimation\n  - **`telemetry`**: advanced observability sinks (`InMemoryFeedbackSink`, `ConsoleFeedbackSink`, etc.)\n  - **`mcp`**: MCP (Model Context Protocol) tool bridge — namespace-based tool conversion and filtering\n  - **`computer_use`**: Computer Use abstraction — safety policies, domain allowlists, action validation\n  - **`multimodal`**: Extended multimodal support — vision, audio, video modality validation and format checks\n  - **`reasoning`**: Extended reasoning / chain-of-thought support\n- **Infrastructure features**:\n  - **`routing_mvp`**: pure logic model management helpers (`CustomModelManager`, `ModelArray`, etc.)\n  - **`interceptors`**: application-layer call hooks (`InterceptorPipeline`, `Interceptor`, `RequestContext`)\n- **Meta-feature**:\n  - **`full`**: enables all capability and infrastructure features\n\nEnable with:\n\n```toml\n[dependencies]\n# Lean core (default)\nai-lib-rust = \"0.8.0\"\n\n# With specific capabilities\nai-lib-rust = { version = \"0.8.0\", features = [\"embeddings\", \"telemetry\"] }\n\n# Everything enabled\nai-lib-rust = { version = \"0.8.0\", features = [\"full\"] }\n```\n\n## 🗺️ Capability map (layered tools)\n\nThis is a structured view of what the crate provides, grouped by layers.\n\n### 1) Protocol layer (`src/protocol/`)\n- **`ProtocolLoader`**: load provider manifests from local paths / env paths / GitHub raw URLs\n- **`ProtocolValidator`**: JSON Schema validation (supports offline via embedded schema)\n- **`ProtocolManifest`**: typed representation of provider manifests\n- **`UnifiedRequest`**: provider-agnostic request payload used by the runtime\n\n### 2) Transport layer (`src/transport/`)\n- **`HttpTransport`**: reqwest-based transport with proxy/timeout defaults and env knobs\n- **API key resolution**: keyring → `\u003cPROVIDER_ID\u003e_API_KEY` env\n\n### 3) Pipeline layer (`src/pipeline/`)\n- **Operator pipeline**: decoder → selector → accumulator → fanout → event mapper\n- **Streaming normalization**: maps provider frames to `StreamingEvent`\n\n### 4) Client layer (`src/client/`)\n- **`AiClient`**: runtime entry point; model-driven (`\"provider/model\"`)\n- **Chat builder**: `client.chat().messages(...).stream().execute_stream()`\n- **Batch**: `chat_batch`, `chat_batch_smart`\n- **Observability**: `call_model_with_stats` returns `CallStats`\n- **Cancellation**: `execute_stream_with_cancel()` → `CancelHandle`\n- **Services**: `EndpointExt` for calling `services` declared in protocol manifests\n\n### 5) Resilience layer (`src/resilience/` + `client/policy`)\n- **Policy engine**: capability validation + retry/fallback decisions\n- **Rate limiter**: token-bucket + adaptive header-driven mode\n- **Circuit breaker**: minimal breaker with env or builder defaults\n- **Backpressure**: max in-flight permit gating\n\n### 6) Types layer (`src/types/`)\n- **Messages**: `Message`, `MessageRole`, `MessageContent`, `ContentBlock`\n- **Tools**: `ToolDefinition`, `FunctionDefinition`, `ToolCall`\n- **Events**: `StreamingEvent`\n\n### 7) Telemetry layer (`src/telemetry/`)\n- **`FeedbackSink`** / **`FeedbackEvent`**: opt-in feedback reporting\n- **Extended feedback types**: `RatingFeedback`, `ThumbsFeedback`, `TextFeedback`, `CorrectionFeedback`, `RegenerateFeedback`, `StopFeedback`\n- **Multiple sinks**: `InMemoryFeedbackSink`, `ConsoleFeedbackSink`, `CompositeFeedbackSink`\n- **Global sink management**: `get_feedback_sink()`, `set_feedback_sink()`, `report_feedback()`\n\n### 8) Embedding layer (`src/embeddings/`) - NEW in v0.6.5\n- **`EmbeddingClient`** / **`EmbeddingClientBuilder`**: Generate embeddings from text\n- **Types**: `Embedding`, `EmbeddingRequest`, `EmbeddingResponse`, `EmbeddingUsage`\n- **Vector operations**: `cosine_similarity`, `dot_product`, `euclidean_distance`, `manhattan_distance`\n- **Utilities**: `normalize_vector`, `average_vectors`, `weighted_average_vectors`, `find_most_similar`\n\n### 9) Cache layer (`src/cache/`) - NEW in v0.6.5\n- **`CacheBackend`** trait with `MemoryCache` and `NullCache` implementations\n- **`CacheManager`**: TTL-based caching with statistics\n- **`CacheKey`** / **`CacheKeyGenerator`**: Deterministic cache key generation\n\n### 10) Token layer (`src/tokens/`) - NEW in v0.6.5\n- **`TokenCounter`** trait: `CharacterEstimator`, `AnthropicEstimator`, `CachingCounter`\n- **`ModelPricing`**: Pre-configured pricing for GPT-4o, Claude models\n- **`CostEstimate`**: Calculate request costs\n\n### 11) Batch layer (`src/batch/`) - NEW in v0.6.5\n- **`BatchCollector`** / **`BatchConfig`**: Accumulate requests for batch processing\n- **`BatchExecutor`**: Execute batches with configurable strategies\n- **`BatchResult`**: Structured batch execution results\n\n### 12) Plugin layer (`src/plugins/`) - NEW in v0.6.5\n- **`Plugin`** trait with lifecycle hooks\n- **`PluginRegistry`**: Centralized plugin management\n- **Hook system**: `HookType`, `Hook`, `HookManager`\n- **Middleware**: `Middleware`, `MiddlewareChain` for request/response transformation\n\n### 13) Utils (`src/utils/`)\n- JSONPath mapping helpers, tool-call assembler, and small runtime utilities\n\n### 14) Optional helpers (feature-gated)\n- **`routing_mvp`** (`src/routing/`): model selection + endpoint array load balancing (pure logic)\n- **`interceptors`** (`src/interceptors/`): hooks around calls for logging/metrics/audit\n\n## 🚀 Quick Start\n\n### Sharing the client across tasks\n\n`AiClient` does not implement `Clone` (by design, for API key and provider ToS compliance).\nUse `Arc\u003cAiClient\u003e` to share across async tasks:\n\n```rust\nuse ai_lib_rust::{AiClient, Message};\nuse std::sync::Arc;\n\n#[tokio::main]\nasync fn main() -\u003e ai_lib_rust::Result\u003c()\u003e {\n    let client = Arc::new(AiClient::new(\"openai/gpt-4o\").await?);\n    // Pass Arc::clone(\u0026client) to spawned tasks\n    let handle = tokio::spawn({\n        let c = Arc::clone(\u0026client);\n        async move { c.chat().messages(vec![Message::user(\"Hi\")]).execute().await }\n    });\n    let _ = handle.await?;\n    Ok(())\n}\n```\n\n### Basic Usage\n\n```rust\nuse ai_lib_rust::{AiClient, Message};\nuse ai_lib_rust::types::events::StreamingEvent;\nuse futures::StreamExt;\n\n#[tokio::main]\nasync fn main() -\u003e ai_lib_rust::Result\u003c()\u003e {\n    // Create client directly using provider/model string\n    // This is fully protocol-driven and supports any provider defined in ai-protocol manifests\n    let client = AiClient::new(\"anthropic/claude-3-5-sonnet\").await?;\n\n    let messages = vec![Message::user(\"Hello!\")];\n\n    // Streaming (unified events)\n    let mut stream = client\n        .chat()\n        .messages(messages)\n        .temperature(0.7)\n        .stream()\n        .execute_stream()\n        .await?;\n\n    while let Some(event) = stream.next().await {\n        match event? {\n            StreamingEvent::PartialContentDelta { content, .. } =\u003e print!(\"{content}\"),\n            StreamingEvent::StreamEnd { .. } =\u003e break,\n            _ =\u003e {}\n        }\n    }\n\n    Ok(())\n}\n```\n\n### Multimodal (Image / Audio)\n\nMultimodal inputs are represented as `MessageContent::Blocks(Vec\u003cContentBlock\u003e)`.\n\n```rust\nuse ai_lib_rust::{Message, MessageRole};\nuse ai_lib_rust::types::message::{MessageContent, ContentBlock};\n\nfn multimodal_message(image_path: \u0026str) -\u003e ai_lib_rust::Result\u003cMessage\u003e {\n    let blocks = vec![\n        ContentBlock::text(\"Describe this image briefly.\"),\n        ContentBlock::image_from_file(image_path)?,\n    ];\n    Ok(Message::with_content(\n        MessageRole::User,\n        MessageContent::blocks(blocks),\n    ))\n}\n```\n\n### Useful environment variables\n\n- `AI_PROTOCOL_DIR` / `AI_PROTOCOL_PATH`: path to your local `ai-protocol` repo root (containing `v1/`)\n- `AI_LIB_ATTEMPT_TIMEOUT_MS`: per-attempt timeout guard used by the unified policy engine\n- `AI_LIB_BATCH_CONCURRENCY`: override concurrency limit for batch operations\n\n### Custom Protocol\n\n```rust\nuse ai_lib_rust::protocol::ProtocolLoader;\n\nlet loader = ProtocolLoader::new()\n    .with_base_path(\"./ai-protocol\")\n    .with_hot_reload(true);\n\nlet manifest = loader.load_provider(\"openai\").await?;\n```\n\n## 📦 Installation\n\nAdd to your `Cargo.toml`:\n\n```toml\n[dependencies]\nai-lib-rust = \"0.8.0\"\ntokio = { version = \"1.0\", features = [\"full\"] }\nfutures = \"0.3\"\n```\n\n## 🔧 Configuration\n\nThe library automatically looks for protocol manifests in the following locations (in order):\n\n1. Custom path set via `ProtocolLoader::with_base_path()`\n2. `AI_PROTOCOL_DIR` / `AI_PROTOCOL_PATH` (local path or GitHub raw URL)\n3. Common dev paths: `ai-protocol/`, `../ai-protocol/`, `../../ai-protocol/`\n4. Last resort: GitHub raw `hiddenpath/ai-protocol` (main)\n\nFor each base path, provider manifests are resolved in a backward-compatible order:\n`dist/v1/providers/\u003cid\u003e.json` → `v1/providers/\u003cid\u003e.yaml`.\n\nProtocol manifests should follow the AI-Protocol v1.5 specification structure. The runtime validates manifests against the official JSON Schema from the AI-Protocol repository.\n\n## 🔐 Provider Requirements (API Keys)\n\nMost providers require an API key. The runtime reads keys from (in order):\n\n1. **OS Keyring** (optional, convenience feature)\n   - **Windows**: Uses Windows Credential Manager\n   - **macOS**: Uses Keychain\n   - **Linux**: Uses Secret Service API\n   - Service: `ai-protocol`, Username: provider id\n   - **Note**: Keyring is optional and may not work in containers/WSL. Falls back to environment variables automatically.\n\n2. **Environment Variable** (recommended for production)\n   - Format: `\u003cPROVIDER_ID\u003e_API_KEY` (e.g. `DEEPSEEK_API_KEY`, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`)\n   - **Recommended for**: CI/CD, containers, WSL, production deployments\n\n**Example**:\n```bash\n# Set API key via environment variable (recommended)\nexport DEEPSEEK_API_KEY=\"sk-...\"\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"\n\n# Or use keyring (optional, for local development)\n# Windows: Stored in Credential Manager\n# macOS: Stored in Keychain\n```\n\nProvider-specific details vary, but `ai-lib-rust` normalizes them behind a unified client API.\n\n## 🌐 Proxy / Timeout / Backpressure (Production knobs)\n\n- **Proxy**: set `AI_PROXY_URL` (e.g. `http://user:pass@host:port`)\n- **HTTP timeout**: set `AI_HTTP_TIMEOUT_SECS` (fallback: `AI_TIMEOUT_SECS`)\n- **In-flight limit**: set `AI_LIB_MAX_INFLIGHT` or use `AiClientBuilder::max_inflight(n)`\n- **Rate limiting** (optional): set either\n  - `AI_LIB_RPS` (requests per second), or\n  - `AI_LIB_RPM` (requests per minute)\n- **Circuit breaker** (optional): enable via `AiClientBuilder::circuit_breaker_default()` or env\n  - `AI_LIB_BREAKER_FAILURE_THRESHOLD` (default 5)\n  - `AI_LIB_BREAKER_COOLDOWN_SECS` (default 30)\n\n## 📊 Observability: CallStats\n\nIf you need per-call stats (latency, retries, request ids, endpoint), use:\n\n```rust\nlet (resp, stats) = client.call_model_with_stats(unified_req).await?;\nprintln!(\"client_request_id={}\", stats.client_request_id);\n```\n\n## 🛑 Cancellable Streaming\n\n```rust\nlet (mut stream, cancel) = client.chat().messages(messages).stream().execute_stream_with_cancel().await?;\n// cancel.cancel(); // emits StreamEnd{finish_reason:\"cancelled\"}, drops the underlying network stream, and releases inflight permit\n```\n\n## 🧾 Optional Feedback (Choice Selection)\n\nTelemetry is **opt-in**. You can inject a `FeedbackSink` and report feedback explicitly:\n\n```rust\nuse ai_lib_rust::telemetry::{FeedbackEvent, ChoiceSelectionFeedback};\n\nclient.report_feedback(FeedbackEvent::ChoiceSelection(ChoiceSelectionFeedback {\n    request_id: stats.client_request_id.clone(),\n    chosen_index: 0,\n    rejected_indices: None,\n    latency_to_select_ms: None,\n    ui_context: None,\n    candidate_hashes: None,\n})).await?;\n```\n\n## 🎨 Key Features\n\n### Protocol-Driven Architecture\n\nNo `match provider` statements. All logic is derived from protocol configuration:\n\n```rust\n// The pipeline is built dynamically from protocol manifest\nlet pipeline = Pipeline::from_manifest(\u0026manifest)?;\n\n// Operators are configured via manifests (YAML/JSON), not hardcoded\n// Adding a new provider requires zero code changes\n```\n\n### Multi-Candidate Support\n\nAutomatically handles multi-candidate scenarios through the `FanOut` operator:\n\n```yaml\nstreaming:\n  candidate:\n    candidate_id_path: \"$.choices[*].index\"\n    fan_out: true\n```\n\n### Tool Accumulation\n\nStateful accumulation of tool call arguments:\n\n```yaml\nstreaming:\n  accumulator:\n    stateful_tool_parsing: true\n    key_path: \"$.delta.partial_json\"\n    flush_on: \"$.type == 'content_block_stop'\"\n```\n\n### Hot Reload\n\nProtocol configurations can be updated at runtime:\n\n```rust\nlet loader = ProtocolLoader::new().with_hot_reload(true);\n// Protocol changes are automatically picked up\n```\n\n## 📚 Examples\n\nSee the `examples/` directory:\n\n- `basic_usage.rs`: Simple non-streaming chat completion\n- `deepseek_chat_stream.rs`: Streaming chat example\n- `deepseek_tool_call_stream.rs`: Tool calling with streaming\n- `custom_protocol.rs`: Loading custom protocol configurations\n- `list_models.rs`: Listing available models from provider\n- `service_discovery.rs`: Service discovery and custom service calls\n- `test_protocol_loading.rs`: Protocol loading sanity check\n\n## 🧪 Testing\n\n```bash\n# Run all tests\ncargo test\n\n# Run compliance tests (cross-runtime consistency)\ncargo test --test compliance\n\n# Run with all features enabled\ncargo test --features full\n```\n\n## 📦 Batch (Chat)\n\nFor batch execution (order-preserving), use:\n\n```rust\nuse ai_lib_rust::{AiClient, ChatBatchRequest, Message};\n\nlet client = AiClient::new(\"deepseek/deepseek-chat\").await?;\n\nlet reqs = vec![\n    ChatBatchRequest::new(vec![Message::user(\"Hello\")]),\n    ChatBatchRequest::new(vec![Message::user(\"Explain SSE in one sentence\")])\n        .temperature(0.2),\n];\n\nlet results = client.chat_batch(reqs, Some(5)).await;\n```\n\n### Smart batch tuning\n\nIf you prefer a conservative default heuristic, use:\n\n```rust\nlet results = client.chat_batch_smart(reqs).await;\n```\n\nOverride concurrency with:\n- `AI_LIB_BATCH_CONCURRENCY`\n\n## 🤝 Contributing\n\nContributions are welcome! Please ensure that:\n\n1. All protocol configurations follow the AI-Protocol specification (v1.5 / V2)\n2. New operators are properly documented\n3. Tests are included for new features\n4. Compliance tests pass for cross-runtime behaviors (`cargo test --test compliance`)\n5. Code follows Rust best practices and passes `cargo clippy`\n\n## 📄 License\n\nThis project is licensed under either of:\n\n- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))\n- MIT License ([LICENSE-MIT](LICENSE-MIT))\n\nat your option.\n\n## 🔗 Related Projects\n\n- [AI-Protocol](https://github.com/hiddenpath/ai-protocol): Protocol specification (v1.5 / V2)\n- [ai-lib-python](https://github.com/hiddenpath/ai-lib-python): Python runtime implementation\n\n---\n\n**ai-lib-rust** - Where protocol meets performance. 🚀\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhiddenpath%2Fai-lib-rust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhiddenpath%2Fai-lib-rust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhiddenpath%2Fai-lib-rust/lists"}