Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,24 @@ jobs:
- "--no-default-features --features store"
- "--no-default-features --features config"
- "--no-default-features --features client-async"
- "--no-default-features --features cache"
- "--no-default-features --features discovery-async"
- "--no-default-features --features graph"
- "--no-default-features --features graph-async"
- "--no-default-features --features graph-pool"
- "--no-default-features --features graph-cjk"
- "--no-default-features --features graph-pg"
- "--no-default-features --features mcp"
- "--no-default-features --features mcp-http"
- "--no-default-features --features tokens"
- "--no-default-features --features safety"
- "--no-default-features --features telemetry"
- "--no-default-features --features search"
- "--no-default-features --features federation"
- "--no-default-features --features embedding"
- "--no-default-features --features embedding-openai"
- "--no-default-features --features vector-index"
- "--no-default-features --features install"
- "--no-default-features --features qdrant"
- "--no-default-features --features elastic"
- "--no-default-features --features full"
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

| Command | Description |
|---------|-------------|
| `cargo test --all-features` | Run all tests (483 passed, 12 ignored) |
| `cargo test --all-features` | Run all tests (599 passed, 13 ignored) |
| `cargo clippy --all-features -- -D warnings` | Lint |
| `cargo fmt --all -- --check` | Format check |
| `cargo bench` | Run criterion benchmarks |
Expand Down
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.13.0] - 2026-07-03

### Added

- **llm**: `LLMRequest::tools` and `LLMRequest::response_format` are now **forwarded to the provider APIs**. OpenAI receives `tools` (`type: "function"`) and `response_format` (`json_object` / `json_schema`); Anthropic receives `tools` (with `input_schema`) and, for `ResponseFormat::JsonSchema`, `output_config.format`. Previously both fields were accepted by the builder but silently dropped.
- **llm**: `LLMResponse::tool_calls: Vec<ToolCall>` — tool calls the model requested are parsed back from OpenAI `tool_calls` and Anthropic `tool_use` content blocks. `LLMResponse` now also captures `finish_reason` (OpenAI `finish_reason` / Anthropic `stop_reason`), `id`, and `created` from the provider response.
- **mcp**: protocol-version negotiation — `initialize` echoes the client's requested `protocolVersion` when supported (`2025-06-18`, `2025-03-26`, `2024-11-05`), otherwise proposes the server's latest (`2025-06-18`). Exposed via `McpServer::negotiate_protocol_version` and the `SUPPORTED_PROTOCOL_VERSIONS` / `LATEST_PROTOCOL_VERSION` constants.
- **mcp**: `ping` method (returns `{}`), **prompts** support (`prompts/list`, `prompts/get`, `McpServer::register_prompt` / `set_prompt_handler`, `PromptDescription` / `PromptArgument`), and `resources/templates/list`. The `prompts` capability is advertised in `initialize` when prompts are registered. Both stdio and HTTP/SSE transports support all new methods.
- **error**: `KernelError::Embedding` and `KernelError::Discovery` variants (with `KernelError::embedding` / `KernelError::discovery` constructors).

### Changed

- **error** (**breaking**): the `embedding` and `discovery` subsystems now return `crate::error::Result` (`KernelError`) instead of `anyhow::Result` — the `EmbeddingProvider` / `VectorIndex` / `AsyncVectorIndex` traits, all provider and index constructors (`FastembedProvider`, `OpenAIEmbeddingClient`, `Qwen3Provider`, `NomicMoeProvider`, `LazyFastembedProvider`, `TurbovecIndex`, `QdrantVectorIndex`, `ElasticsearchVectorIndex`), `DiscoverySource`, `chunk_batch`, the `discovery::fetch*` functions, and `provider::sync::*`. `anyhow` no longer appears in the library's public surface. Downstream code that matched on `anyhow::Error` must switch to `KernelError`.
- **mcp** (**breaking**): `McpServer::initialize_response` now takes the client's requested protocol version (`initialize_response(Option<&str>)`).
- **mcp**: `ToolDescription` and `ResourceDescription` now serialize with the correct MCP wire-format field names — `inputSchema` (was `input_schema`) and `mimeType` (was `mime_type`).
- **mcp**: JSON-RPC request `id`s are preserved verbatim (string **or** number) in responses, per JSON-RPC 2.0 — previously only integer ids round-tripped.
- **mcp**: `tools/call` reports **tool-execution failures in-band** as a result with `isError: true` (so the model can react), and reserves the JSON-RPC error path (`-32602`) for an unknown tool — matching the MCP spec.

### Fixed

- **embedding**: `LazyFastembedProvider::embed_batch` no longer panics with an index-out-of-bounds when the inner provider returns fewer vectors than inputs (a truncated/malformed response); it now returns a `KernelError::Embedding`.
- **llm**: `CacheClient::complete` offloads the synchronous `KvStore` read/write to `tokio::task::spawn_blocking`, so a slow or remote store (or a single-threaded runtime) no longer blocks the async reactor on the completion hot path.

### CI

- Isolated per-feature build/test matrix entries added for `cache`, `discovery-async`, `graph-async`, `graph-pool`, `graph-cjk`, `mcp`, `mcp-http`, `tokens`, `safety`, `telemetry`, `search`, `federation`, `embedding`, `embedding-openai`, `vector-index`, and `install`, so a missing `#[cfg]` gate is caught even when a sibling feature isn't co-enabled.

## [0.12.0] - 2026-07-02

### Changed
Expand All @@ -27,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- **graph**: new optional `graph-pg-tls` feature adding TLS support to `PgGraph` connections, closing #48. `PgGraph::connect_native_tls(url)` is a one-call convenience constructor using `native-tls` with the system trust store (full certificate chain and hostname verification, not weakened) — covers the common case of a Postgres server requiring `sslmode=require`+ (e.g. RDS with `rds.force_ssl`). `PgGraph::connect_tls` / `connect_config_tls` are generic over any `postgres::tls::MakeTlsConnect` implementor for custom CAs, client certificates, or a caller-vendored connector. Existing `connect` / `connect_config` (`NoTls`) are unchanged — fully backward compatible, no new mandatory deps for `graph-pg` consumers.


## [0.10.0] - 2026-06-29

### Added
Expand Down
6 changes: 4 additions & 2 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ representative at an online or offline event.
## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
[INSERT CONTACT METHOD].
reported to the project maintainers via GitHub — open a private report through
the repository's **Security** tab ("Report a vulnerability") or contact a
maintainer of the [`epicsagas/llm-kernel`](https://github.com/epicsagas/llm-kernel)
repository directly.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
Expand Down
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "llm-kernel"
version = "0.12.0"
version = "0.13.0"
edition = "2024"
description = "Foundation library for Rust AI-native apps — provider catalog, LLM client, MCP server, search, telemetry, and safety"
license = "Apache-2.0"
Expand Down Expand Up @@ -152,9 +152,12 @@ safety = ["dep:regex"]
eval = ["dep:clap", "tokens", "safety", "embedding", "search"]
eval-full = ["eval", "graph"]

# Everything except Windows-only execution backends.
# embedding-fastembed-directml is intentionally excluded: it pulls in the ort
# RC dependency which is not appropriate for cross-platform builds.
# Everything except Windows-only execution backends and dev-only CLI tooling.
# Intentionally excluded:
# - embedding-fastembed-directml: pulls in the ort RC dependency, Windows-only.
# - embedding-fastembed-dynamic-linking: opt-in dynamic ONNX linking (see #50).
# - eval / eval-full: developer CLI tooling (the `llm-kernel-eval` binary),
# not part of the library surface. Enable explicitly to run the eval suite.
full = ["provider", "discovery", "discovery-async", "client-async", "cache", "secrets", "store", "config", "graph", "graph-async", "graph-pool", "graph-cjk", "graph-pg", "graph-pg-tls", "mcp", "mcp-http", "tokens", "install", "search", "embedding", "embedding-openai", "embedding-fastembed", "embedding-fastembed-qwen3", "embedding-fastembed-nomic-moe", "vector-index", "qdrant", "elastic", "federation", "telemetry", "safety", "catalog-sync"]

[dependencies]
Expand Down
38 changes: 28 additions & 10 deletions PROGRESS.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
# Progress

> Auto-generated status snapshot. Last updated: 2026-06-15
> Auto-generated status snapshot. Last updated: 2026-07-03

## Current Version: v0.9.0
## Current Version: v0.13.0

| Metric | Value |
|--------|-------|
| Version | `0.9.0` |
| Version | `0.13.0` |
| Edition | Rust 2024, MSRV 1.92 |
| Lines of code | ~18,100 |
| Total tests | 511 (499 passed, 12 ignored, 0 failed) |
| Lines of code | ~23,000 |
| Total tests | `--all-features`: 599 passed, 13 ignored, 0 failed |
| Backend features | `graph-pg` (PostgreSQL), `qdrant` (vector search), `elastic` (Elasticsearch vector search) |
| Open PRs | 1 |
| Open branches | 1 |
| Last commit | `feat: v0.9.0 search integrations` |
| Last commit | `chore: bump v0.13.0` |

---

## Recent Releases

### v0.13.0 (2026-07-03)

- **error**: unified `embedding` + `discovery` public APIs onto `KernelError` (new `Embedding` / `Discovery` variants) — no more `anyhow::Result` in the library's public surface (**breaking**)
- **llm**: `LLMRequest::tools` and `response_format` are now forwarded to OpenAI and Anthropic; tool calls are parsed back into `LLMResponse::tool_calls`
- **mcp**: protocol version negotiation (2025-06-18), `ping`, prompts (`prompts/list` / `prompts/get`), string/number JSON-RPC ids, `tools/call` in-band `isError`, and camelCase wire format (`inputSchema` / `mimeType`)
- **embedding**: fixed a `LazyFastembedProvider::embed_batch` panic on a truncated provider response; `CacheClient` now offloads blocking store I/O via `spawn_blocking`
- **ci**: isolated per-feature build/test matrix entries (`mcp`, `tokens`, `safety`, `search`, `cache`, …)

### v0.12.0 (2026-07-02)

- **embedding** (breaking): `ModelState::Failed(String)` → `Failed { message, panicked }`; dropped default `ort-load-dynamic` so `embedding-fastembed` statically links ONNX Runtime, made the model-load path panic-safe via `catch_unwind`, and added `LazyFastembedProvider::reset()` + opt-in `embedding-fastembed-dynamic-linking` (#50)

### v0.11.0 (2026-07-01)

- **graph** (`graph-pg-tls`): TLS support for `PgGraph` connections — `connect_native_tls` / `connect_tls` / `connect_config_tls` (#48)

### v0.10.0 (2026-06-29)

- **graph**: pure-Rust CSR graph algorithms (`algo/`) — weighted PageRank, connected components, label propagation, Dijkstra, Jaccard/Adamic-Adar similarity; `smart_recall`'s graph boost now ranks by true PageRank centrality (SQLite + PostgreSQL share one impl)

### v0.9.0 (2026-06-15)

- **embedding** (`elastic`): `ElasticsearchVectorIndex` — `AsyncVectorIndex` over Elasticsearch 8.x (dense_vector cosine, bulk upsert/delete, knn `_search`, `_count`). 공식 `elasticsearch` 크레이트가 alpha-only라 **직접 구현한 reqwest 클라이언트** 사용 (v1.0.0 semver lock 안전)
Expand Down Expand Up @@ -151,8 +169,8 @@ safety → secret masking, error classification, prompt-injection detectio

| Check | Status |
|-------|--------|
| All tests pass | ✅ 489/489 (477 passed, 12 ignored) |
| All tests pass | ✅ 593 passed, 13 ignored, 0 failed (`--all-features`) |
| Clippy clean | ✅ (verified before each release) |
| CI passing | ✅ Linux + macOS dual runner |
| Crate structure | ✅ Monolithic (subcrate removed) |
| Roadmap on track | ✅ v0.7.0 complete, v0.8.0 ready to start |
| Roadmap on track | ✅ v0.13.0 complete, v1.0.0 next |
10 changes: 5 additions & 5 deletions QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ Add to your `Cargo.toml`. The `provider` feature is enabled by default.

```toml
[dependencies]
llm-kernel = "0.6.0"
llm-kernel = "0.13.0"
```

For the async LLM client:

```toml
[dependencies]
llm-kernel = { version = "0.6.0", features = ["client-async"] }
llm-kernel = { version = "0.13.0", features = ["client-async"] }
```

To enable everything:

```toml
[dependencies]
llm-kernel = { version = "0.6.0", features = ["full"] }
llm-kernel = { version = "0.13.0", features = ["full"] }
```

## 2. Browse the provider catalog
Expand Down Expand Up @@ -82,7 +82,7 @@ println!("{}", response.content);

```toml
[dependencies]
llm-kernel = { version = "0.6.0", features = ["graph"] }
llm-kernel = { version = "0.13.0", features = ["graph"] }
```

```rust
Expand Down Expand Up @@ -117,7 +117,7 @@ for scored in &results {

```toml
[dependencies]
llm-kernel = { version = "0.6.0", features = ["embedding-fastembed"] }
llm-kernel = { version = "0.13.0", features = ["embedding-fastembed"] }
```

```rust
Expand Down
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ llm-kernel provides the foundational layer for building LLM-powered tools, agent
- **Model discovery** — dynamic model discovery from models.dev, Ollama, OpenAI-compatible endpoints
- **Credential vault** — dotenv-style API key management with atomic writes
- **Config loader** — TOML config with auto-create from template
- **Knowledge graph** — `GraphBackend` trait (SQLite impl), FTS5 search, smart recall, BFS traversal, CJK search, schema migrations, async wrappers
- **MCP server** — JSON-RPC 2.0 server framework with stdio and HTTP/SSE transports, async handlers, Bearer auth
- **Knowledge graph** — `GraphBackend` trait (SQLite impl), FTS5 search, smart recall, BFS traversal, CJK search, schema migrations, async wrappers, pure-Rust graph algorithms (PageRank, community detection, shortest path, similarity)
- **MCP server** — JSON-RPC 2.0 server framework (protocol 2025-06-18) with stdio and HTTP/SSE transports, tools, resources, prompts, `ping`, async handlers, Bearer auth
- **Key-value store** — `KvStore` trait powering LLM response caching and other byte-oriented stores
- **Embedding** — provider trait + cosine similarity, local ONNX (44 models), Qwen3 candle, Nomic V2 MoE candle, OpenAI remote, compressed vector indexing ([full model list →](EMBEDDING_MODELS.md))
- **Search** — Reciprocal Rank Fusion for hybrid search result merging
Expand All @@ -46,12 +46,12 @@ Each module is gated behind a feature flag so you only pay for what you use.
| `secrets` | SecretVault credential management | |
| `store` | SQLite init helpers (WAL, FTS5, schema versioning) + `KvStore` | |
| `config` | TOML config loader | |
| `graph` | Knowledge graph — `GraphBackend` trait, SQLite impl, FTS5, smart recall, BFS, migrations | |
| `graph` | Knowledge graph — `GraphBackend` trait, SQLite impl, FTS5, smart recall, BFS, migrations, graph algorithms (PageRank, community, shortest-path, similarity) | |
| `graph-async` | Async graph wrappers (requires tokio) | |
| `graph-pool` | Multi-connection async graph pool (`AsyncPoolGraph`, WAL concurrency) | |
| `graph-cjk` | CJK-aware graph search via Rust-side segmentation (no schema change) | |
| `graph-pg` | PostgreSQL `GraphBackend` (`PgGraph`) + SQLite↔PostgreSQL migration CLI | |
| `mcp` | MCP server — JSON-RPC 2.0, stdio transport, async handlers, Bearer auth | |
| `mcp` | MCP server — JSON-RPC 2.0 (protocol 2025-06-18), stdio transport, tools/resources/prompts, `ping`, async handlers, Bearer auth | |
| `mcp-http` | MCP remote transport — HTTP/SSE (axum + tokio) | |
| `cache` | LLM response cache — `CacheClient` over `KvStore` | |
| `tokens` | Token estimation, budgeting, and sentence-aware document chunking | |
Expand Down Expand Up @@ -80,28 +80,28 @@ Add to your `Cargo.toml`:

```toml
[dependencies]
llm-kernel = "0.9.1"
llm-kernel = "0.13.0"
```

The `provider` feature is enabled by default. For the async client:

```toml
[dependencies]
llm-kernel = { version = "0.9.1", features = ["client-async"] }
llm-kernel = { version = "0.13.0", features = ["client-async"] }
```

For the knowledge graph with async wrappers:

```toml
[dependencies]
llm-kernel = { version = "0.9.1", features = ["graph", "graph-async"] }
llm-kernel = { version = "0.13.0", features = ["graph", "graph-async"] }
```

For local embedding (ONNX, no API key):

```toml
[dependencies]
llm-kernel = { version = "0.9.1", features = ["embedding-fastembed"] }
llm-kernel = { version = "0.13.0", features = ["embedding-fastembed"] }
```

## Usage
Expand Down Expand Up @@ -337,11 +337,11 @@ println!("{} nodes, {} edges", stats.total_nodes, stats.total_edges);
### MCP server

```rust
use llm_kernel::mcp::{McpServer, Tool, JsonRpcRequest};
use llm_kernel::mcp::{McpServer, ToolDescription};
use serde_json::json;

let mut server = McpServer::new("my-server", "1.0.0");
server.register_tool(Tool {
server.register_tool(ToolDescription {
name: "greet".into(),
description: "Say hello".into(),
input_schema: json!({
Expand Down Expand Up @@ -571,9 +571,9 @@ llm-kernel is a **lightweight foundation layer** — compose it with rig or lang
- **`EmbeddingProvider` trait** — unified interface for `FastembedProvider` (ONNX), `Qwen3Provider` (candle), `NomicMoeProvider` (candle), `OpenAIEmbeddingClient` (remote)
- **`VectorIndex` trait** — unified interface for compressed vector indexes; `TurbovecIndex` (TurboQuant) implements 2-bit/4-bit quantized ANN search with SIMD kernels
- **`ProviderIndex`** — zero-copy access to embedded catalog, queryable by provider or model
- **`McpServer`** — JSON-RPC 2.0 server with stdio transport, Bearer auth, tool registration
- **`McpServer`** — JSON-RPC 2.0 server (protocol 2025-06-18) with stdio transport, Bearer auth, tools/resources/prompts registration, `ping`
- **`SecretVault`** — `HashMap<String, String>` with dotenv load/save and symlink guards
- **`graph`** — SQLite knowledge graph with FTS5 search, composite scoring recall, BFS traversal, importance decay
- **`graph`** — SQLite knowledge graph with FTS5 search, composite scoring recall, BFS traversal, importance decay, and pure-Rust CSR graph algorithms (PageRank, connected components, label propagation, Dijkstra, Jaccard/Adamic-Adar similarity)
- **`TelemetryEvent`** — enum-gated variants for structured observability (no PII)
- **`safety`** — secret masking, error classification, bidi/ANSI/null sanitization, prompt-injection detection
- **`SearchProvider`** — unified sync interface for ranking backends; `KeywordIndex` reference impl plus RRF / weighted-sum / CombMNZ fusion
Expand Down
Loading
Loading