diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 908b7b9d..3189bd87 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -44,7 +44,7 @@ jobs:
cache-targets: "false"
- uses: mozilla-actions/sccache-action@v0.0.9
- name: Clippy
- run: cargo clippy --workspace -- -D warnings
+ run: cargo clippy --workspace --features full -- -D warnings
env:
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
@@ -67,7 +67,12 @@ jobs:
- uses: mozilla-actions/sccache-action@v0.0.9
- uses: taiki-e/install-action@nextest
- name: Run tests
- run: cargo nextest run --workspace --lib --bins
+ run: cargo nextest run --workspace --features full --lib --bins
+ env:
+ RUSTC_WRAPPER: sccache
+ SCCACHE_GHA_ENABLED: "true"
+ - name: Run doc tests
+ run: cargo test --workspace --features full --doc
env:
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
@@ -86,7 +91,7 @@ jobs:
- uses: mozilla-actions/sccache-action@v0.0.9
- uses: taiki-e/install-action@nextest
- name: Run integration tests (testcontainers)
- run: cargo nextest run --workspace --profile ci --test '*integration*'
+ run: cargo nextest run --workspace --features full --profile ci --test '*integration*'
env:
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
@@ -106,7 +111,7 @@ jobs:
- uses: taiki-e/install-action@cargo-llvm-cov
- uses: taiki-e/install-action@nextest
- name: Generate coverage
- run: cargo llvm-cov nextest --workspace --lib --bins --lcov --output-path lcov.info
+ run: cargo llvm-cov nextest --workspace --features full --lib --bins --lcov --output-path lcov.info
env:
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d06e71d..ed542846 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,34 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [Unreleased]
+### Added
+- `ProviderKind` enum for type-safe provider selection in config
+- `RuntimeConfig` struct grouping agent runtime fields
+- `AnyProvider::embed_fn()` shared embedding closure helper
+- `Config::validate()` with bounds checking for critical config values
+- `sanitize_paths()` for stripping absolute paths from error messages
+- 10-second timeout wrapper for embedding API calls
+- `full` feature flag enabling all optional features
+
+### Changed
+- `AnyChannel` moved from main.rs to zeph-channels crate
+- Default features reduced to minimal set (qdrant, self-learning, vault-age, compatible, index)
+- Skill matcher concurrency reduced from 50 to 20
+- `String::with_capacity` in context building loops
+- CI updated to use `--features full`
+
+### Breaking
+- `LlmConfig.provider` changed from `String` to `ProviderKind` enum
+- Default features reduced -- users needing a2a, candle, mcp, openai, orchestrator, router, tui must enable explicitly or use `--features full`
+- Telegram channel rejects empty `allowed_users` at startup
+- Config with extreme values now rejected by `Config::validate()`
+
+### Deprecated
+- `ToolExecutor::execute()` string-based dispatch (use `execute_tool_call()` instead)
+
+### Fixed
+- Closed #410 (clap dropped atty), #411 (rmcp updated quinn-udp), #413 (A2A body limit already present)
+
## [0.9.9] - 2026-02-17
### Added
diff --git a/Cargo.lock b/Cargo.lock
index 1988ea67..832d5039 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -137,7 +137,7 @@ dependencies = [
"proc-macro-error2",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -205,7 +205,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -216,7 +216,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -379,7 +379,7 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -622,7 +622,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -861,18 +861,18 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.5.58"
+version = "4.5.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806"
+checksum = "c5caf74d17c3aec5495110c34cc3f78644bfa89af6c8993ed4de2790e49b6499"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
-version = "4.5.58"
+version = "4.5.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2"
+checksum = "370daa45065b80218950227371916a1633217ae42b2715b2287b606dcd618e24"
dependencies = [
"anstyle",
"clap_lex",
@@ -1202,7 +1202,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
dependencies = [
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1249,7 +1249,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1293,7 +1293,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1307,7 +1307,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1320,7 +1320,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1331,7 +1331,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core 0.20.11",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1342,7 +1342,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81"
dependencies = [
"darling_core 0.21.3",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1353,7 +1353,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d"
dependencies = [
"darling_core 0.23.0",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1416,7 +1416,7 @@ dependencies = [
"darling 0.20.11",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1426,7 +1426,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1455,7 +1455,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
"unicode-xid",
]
@@ -1469,7 +1469,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustc_version",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1523,7 +1523,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1638,7 +1638,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1952,7 +1952,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -1985,21 +1985,11 @@ dependencies = [
"libc",
]
-[[package]]
-name = "futf"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843"
-dependencies = [
- "mac",
- "new_debug_unreachable",
-]
-
[[package]]
name = "futures"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d"
dependencies = [
"futures-channel",
"futures-core",
@@ -2012,9 +2002,9 @@ dependencies = [
[[package]]
name = "futures-channel"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
dependencies = [
"futures-core",
"futures-sink",
@@ -2028,9 +2018,9 @@ checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
[[package]]
name = "futures-executor"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
+checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d"
dependencies = [
"futures-core",
"futures-task",
@@ -2050,38 +2040,38 @@ dependencies = [
[[package]]
name = "futures-io"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718"
[[package]]
name = "futures-macro"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
name = "futures-sink"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
[[package]]
name = "futures-task"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
[[package]]
name = "futures-util"
-version = "0.3.31"
+version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-channel",
"futures-core",
@@ -2091,7 +2081,6 @@ dependencies = [
"futures-task",
"memchr",
"pin-project-lite",
- "pin-utils",
"slab",
]
@@ -2554,9 +2543,9 @@ dependencies = [
[[package]]
name = "html5ever"
-version = "0.36.1"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6452c4751a24e1b99c3260d505eaeee76a050573e61f30ac2c924ddc7236f01e"
+checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2"
dependencies = [
"log",
"markup5ever",
@@ -2764,7 +2753,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
- "syn 2.0.115",
+ "syn 2.0.116",
"unic-langid",
]
@@ -2778,7 +2767,7 @@ dependencies = [
"i18n-config",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -3038,7 +3027,7 @@ dependencies = [
"indoc",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -3320,12 +3309,6 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
-[[package]]
-name = "mac"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
-
[[package]]
name = "mac_address"
version = "1.1.8"
@@ -3363,9 +3346,9 @@ dependencies = [
[[package]]
name = "markup5ever"
-version = "0.36.1"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c3294c4d74d0742910f8c7b466f44dda9eb2d5742c1e430138df290a1e8451c"
+checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862"
dependencies = [
"log",
"tendril",
@@ -3374,9 +3357,9 @@ dependencies = [
[[package]]
name = "markup5ever_rcdom"
-version = "0.36.0+unofficial"
+version = "0.38.0+unofficial"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e5fc8802e8797c0dfdd2ce5c21aa0aee21abbc7b3b18559100651b3352a7b63"
+checksum = "333171ccdf66e915257740d44e38ea5b1b19ce7b45d33cc35cb6f118fbd981ff"
dependencies = [
"html5ever",
"markup5ever",
@@ -3524,7 +3507,7 @@ checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -3680,7 +3663,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -4015,7 +3998,7 @@ dependencies = [
"regex",
"regex-syntax",
"structmeta",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -4085,7 +4068,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -4169,7 +4152,7 @@ dependencies = [
"phf_shared 0.11.3",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -4182,7 +4165,7 @@ dependencies = [
"phf_shared 0.13.1",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -4220,7 +4203,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -4344,7 +4327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [
"proc-macro2",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -4366,7 +4349,7 @@ dependencies = [
"proc-macro-error-attr2",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -4422,7 +4405,7 @@ dependencies = [
"itertools 0.14.0",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -4435,7 +4418,7 @@ dependencies = [
"itertools 0.14.0",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -4868,7 +4851,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -5046,7 +5029,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_json",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -5089,7 +5072,7 @@ dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
- "syn 2.0.115",
+ "syn 2.0.116",
"walkdir",
]
@@ -5327,7 +5310,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -5338,9 +5321,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "scrape-core"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b93652c0036259a932e7ae64d8e1dc30a7f74aebfe947bf18275039ae12abf59"
+checksum = "d53cd0cb49d13b913b2f7a6da2a302ae3cb85b3550c0d7f283fec21873edf43a"
dependencies = [
"cssparser",
"html5ever",
@@ -5474,7 +5457,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -5485,7 +5468,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -5530,7 +5513,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -5582,7 +5565,7 @@ dependencies = [
"darling 0.21.3",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -5608,7 +5591,7 @@ checksum = "6f50427f258fb77356e4cd4aa0e87e2bd2c66dbcee41dc405282cae2bfc26c83"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -5852,7 +5835,7 @@ dependencies = [
"quote",
"sqlx-core",
"sqlx-macros-core",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -5873,7 +5856,7 @@ dependencies = [
"sha2",
"sqlx-core",
"sqlx-sqlite",
- "syn 2.0.115",
+ "syn 2.0.116",
"tokio",
"url",
]
@@ -6034,6 +6017,7 @@ dependencies = [
"parking_lot",
"phf_shared 0.13.1",
"precomputed-hash",
+ "serde",
]
[[package]]
@@ -6074,7 +6058,7 @@ dependencies = [
"proc-macro2",
"quote",
"structmeta-derive",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -6085,7 +6069,7 @@ checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -6106,7 +6090,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -6128,9 +6112,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.115"
+version = "2.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12"
+checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb"
dependencies = [
"proc-macro2",
"quote",
@@ -6154,7 +6138,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -6271,7 +6255,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -6289,12 +6273,11 @@ dependencies = [
[[package]]
name = "tendril"
-version = "0.4.3"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0"
+checksum = "c4790fc369d5a530f4b544b094e31388b9b3a37c0f4652ade4505945f5660d24"
dependencies = [
- "futf",
- "mac",
+ "new_debug_unreachable",
"utf-8",
]
@@ -6418,7 +6401,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -6429,7 +6412,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -6577,7 +6560,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -6641,9 +6624,9 @@ dependencies = [
[[package]]
name = "toml"
-version = "1.0.1+spec-1.1.0"
+version = "1.0.2+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbe30f93627849fa362d4a602212d41bb237dc2bd0f8ba0b2ce785012e124220"
+checksum = "d1dfefef6a142e93f346b64c160934eb13b5594b84ab378133ac6815cb2bd57f"
dependencies = [
"indexmap 2.13.0",
"serde_core",
@@ -6665,9 +6648,9 @@ dependencies = [
[[package]]
name = "toml_parser"
-version = "1.0.8+spec-1.1.0"
+version = "1.0.9+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0742ff5ff03ea7e67c8ae6c93cac239e0d9784833362da3f9a9c1da8dfefcbdc"
+checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4"
dependencies = [
"winnow 0.7.14",
]
@@ -6843,7 +6826,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -7156,9 +7139,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
[[package]]
name = "unicode-ident"
-version = "1.0.23"
+version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-normalization"
@@ -7448,7 +7431,7 @@ dependencies = [
"bumpalo",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
"wasm-bindgen-shared",
]
@@ -7746,7 +7729,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -7757,7 +7740,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -8156,7 +8139,7 @@ dependencies = [
"heck",
"indexmap 2.13.0",
"prettyplease",
- "syn 2.0.115",
+ "syn 2.0.116",
"wasm-metadata",
"wit-bindgen-core",
"wit-component",
@@ -8172,7 +8155,7 @@ dependencies = [
"prettyplease",
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
"wit-bindgen-core",
"wit-bindgen-rust",
]
@@ -8244,9 +8227,9 @@ dependencies = [
[[package]]
name = "xml5ever"
-version = "0.36.1"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f57dd51b88a4b9f99f9b55b136abb86210629d61c48117ddb87f567e51e66be7"
+checksum = "d3dc9559429edf0cd3f327cc0afd9d6b36fa8cec6d93107b7fbe64f806b5f2d9"
dependencies = [
"log",
"markup5ever",
@@ -8283,7 +8266,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
"synstructure",
]
@@ -8295,7 +8278,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
"synstructure",
]
@@ -8389,7 +8372,7 @@ dependencies = [
"thiserror 2.0.18",
"tokio",
"tokio-stream",
- "toml 1.0.1+spec-1.1.0",
+ "toml 1.0.2+spec-1.1.0",
"tracing",
"zeph-index",
"zeph-llm",
@@ -8559,7 +8542,7 @@ dependencies = [
"tempfile",
"thiserror 2.0.18",
"tokio",
- "toml 1.0.1+spec-1.1.0",
+ "toml 1.0.2+spec-1.1.0",
"tracing",
"url",
"uuid",
@@ -8605,7 +8588,7 @@ checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -8625,7 +8608,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
"synstructure",
]
@@ -8646,7 +8629,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
@@ -8680,7 +8663,7 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.115",
+ "syn 2.0.116",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 1029eb3b..6b99a0d8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -103,7 +103,8 @@ license.workspace = true
repository.workspace = true
[features]
-default = ["a2a", "candle", "compatible", "index", "mcp", "openai", "orchestrator", "qdrant", "router", "self-learning", "vault-age"]
+default = ["compatible", "openai", "qdrant", "self-learning", "vault-age"]
+full = ["a2a", "compatible", "discord", "gateway", "index", "mcp", "openai", "orchestrator", "qdrant", "router", "self-learning", "slack", "tui", "vault-age"]
a2a = ["dep:zeph-a2a", "zeph-a2a?/server"]
compatible = ["zeph-llm/compatible"]
mcp = ["dep:zeph-mcp", "zeph-core/mcp"]
diff --git a/README.md b/README.md
index 9df8f366..59bcc12c 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
[](https://www.rust-lang.org)
[](LICENSE)
-Lightweight AI agent that routes tasks across **Ollama, Claude, OpenAI, and HuggingFace** models — with semantic skill matching, vector memory, MCP tooling, and agent-to-agent communication. Ships as a single binary for Linux, macOS, and Windows.
+Lightweight AI agent that routes tasks across **Ollama, Claude, OpenAI, HuggingFace, and OpenAI-compatible endpoints** (Together AI, Groq, etc.) — with semantic skill matching, vector memory, MCP tooling, and agent-to-agent communication. Ships as a single binary for Linux, macOS, and Windows.

@@ -19,7 +19,7 @@ Lightweight AI agent that routes tasks across **Ollama, Claude, OpenAI, and Hugg
**Intelligent context management.** Two-tier context pruning: Tier 1 selectively removes old tool outputs (clearing bodies from memory after persisting to SQLite) before falling back to Tier 2 LLM-based compaction, reducing unnecessary LLM calls. A token-based protection zone preserves recent context from pruning. Parallel context preparation via `try_join!` and optimized byte-length token estimation. Cross-session memory transfers knowledge between conversations with relevance filtering. Proportional budget allocation (8% summaries, 8% semantic recall, 4% cross-session, 30% code context, 50% recent history) keeps conversations efficient. Tool outputs are truncated at 30K chars with optional LLM-based summarization for large outputs. Doom-loop detection breaks runaway tool cycles after 3 identical consecutive outputs, with configurable iteration limits (default 10). ZEPH.md project config discovery walks up the directory tree and injects project-specific context when available. Config hot-reload applies runtime-safe fields (timeouts, security, memory limits) on file change without restart.
-**Run anywhere.** Local models via Ollama or Candle (GGUF with Metal/CUDA), cloud APIs (Claude, OpenAI, GPT-compatible endpoints like Together AI and Groq), or all of them at once through the multi-model orchestrator with automatic fallback chains.
+**Run anywhere.** Local models via Ollama or Candle (GGUF with Metal/CUDA), cloud APIs (Claude, OpenAI), OpenAI-compatible endpoints (Together AI, Groq, Fireworks) via `CompatibleProvider`, or all of them at once through the multi-model orchestrator with automatic fallback chains and `RouterProvider` for prompt-based model selection.
**Production-ready security.** Shell sandboxing with path restrictions and relative path traversal detection, pattern-based permission policy per tool, destructive command confirmation, file operation sandbox with path traversal protection, tool output overflow-to-file (with LLM-accessible paths), secret redaction (AWS, OpenAI, Anthropic, Google, GitLab), audit logging, SSRF protection (including MCP client), rate limiter with TTL-based eviction, and Trivy-scanned container images with 0 HIGH/CRITICAL CVEs.
@@ -72,8 +72,12 @@ For cloud providers:
# Claude
ZEPH_LLM_PROVIDER=claude ZEPH_CLAUDE_API_KEY=sk-ant-... ./target/release/zeph
-# OpenAI (or any compatible API)
+# OpenAI
ZEPH_LLM_PROVIDER=openai ZEPH_OPENAI_API_KEY=sk-... ./target/release/zeph
+
+# OpenAI-compatible endpoint (Together AI, Groq, Fireworks, etc.)
+ZEPH_LLM_PROVIDER=compatible ZEPH_COMPATIBLE_BASE_URL=https://api.together.xyz/v1 \
+ ZEPH_COMPATIBLE_API_KEY=... ./target/release/zeph
```
For Discord or Slack bot mode (requires respective feature):
@@ -101,7 +105,7 @@ cargo build --release --features tui
| Feature | Description | Docs |
|---------|-------------|------|
| **Native Tool Use** | Structured tool calling via Claude tool_use and OpenAI function calling APIs; automatic fallback to text extraction for local models | [Tools](https://bug-ops.github.io/zeph/guide/tools.html) |
-| **Hybrid Inference** | Ollama, Claude, OpenAI, Candle (GGUF) — local, cloud, or both | [OpenAI](https://bug-ops.github.io/zeph/guide/openai.html) · [Candle](https://bug-ops.github.io/zeph/guide/candle.html) |
+| **Hybrid Inference** | Ollama, Claude, OpenAI, Candle (GGUF), Compatible (any OpenAI-compatible API) — local, cloud, or both | [OpenAI](https://bug-ops.github.io/zeph/guide/openai.html) · [Candle](https://bug-ops.github.io/zeph/guide/candle.html) |
| **Skills-First Architecture** | Embedding-based top-K matching, progressive loading, hot-reload | [Skills](https://bug-ops.github.io/zeph/guide/skills.html) |
| **Code Indexing** | AST-based chunking (tree-sitter), semantic retrieval, repo map generation, incremental indexing | [Code Indexing](https://bug-ops.github.io/zeph/guide/code-indexing.html) |
| **Context Engineering** | Two-tier context pruning (selective tool-output pruning before LLM compaction), semantic recall injection, proportional budget allocation, token-based protection zone for recent context, config hot-reload | [Context](https://bug-ops.github.io/zeph/guide/context.html) · [Configuration](https://bug-ops.github.io/zeph/getting-started/configuration.html) |
@@ -120,15 +124,15 @@ cargo build --release --features tui
## Architecture
```
-zeph (binary) — bootstrap, AnyChannel dispatch, vault resolution (anyhow for top-level errors)
+zeph (binary) — bootstrap, vault resolution (anyhow for top-level errors)
├── zeph-core — Agent split into 7 submodules (context, streaming, persistence,
│ learning, mcp, index), daemon supervisor, typed AgentError/ChannelError, config hot-reload
-├── zeph-llm — LlmProvider: Ollama, Claude, OpenAI, Candle, orchestrator,
-│ native tool_use (Claude/OpenAI), typed LlmError
+├── zeph-llm — LlmProvider: Ollama, Claude, OpenAI, Candle, Compatible, orchestrator,
+│ RouterProvider, native tool_use (Claude/OpenAI), typed LlmError
├── zeph-skills — SKILL.md parser, embedding matcher, hot-reload, self-learning, typed SkillError
├── zeph-memory — SQLite + Qdrant, semantic recall, summarization, typed MemoryError
├── zeph-index — AST-based code indexing, semantic retrieval, repo map (optional)
-├── zeph-channels — Discord, Slack, Telegram adapters with streaming
+├── zeph-channels — AnyChannel dispatch, Discord, Slack, Telegram adapters with streaming
├── zeph-tools — schemars-driven tool registry (shell, file ops, web scrape), composite dispatch
├── zeph-mcp — MCP client, multi-server lifecycle, unified tool matching
├── zeph-a2a — A2A client + server, agent discovery, JSON-RPC 2.0
@@ -137,7 +141,7 @@ zeph (binary) — bootstrap, AnyChannel dispatch, vault resolution (anyhow for t
└── zeph-tui — ratatui TUI dashboard with live agent metrics (optional)
```
-**Error handling:** Typed errors throughout all library crates -- `AgentError` (7 variants), `ChannelError` (4 variants), `LlmError`, `MemoryError`, `SkillError`. `anyhow` is used only in `main.rs` for top-level orchestration. Shared Qdrant operations consolidated via `QdrantOps` helper. `AnyProvider` dispatch deduplicated via `delegate_provider!` macro.
+**Error handling:** Typed errors throughout all library crates -- `AgentError` (7 variants), `ChannelError` (4 variants), `LlmError`, `MemoryError`, `SkillError`. `anyhow` is used only in `main.rs` for top-level orchestration. Shared Qdrant operations consolidated via `QdrantOps` helper. `AnyProvider` dispatch deduplicated via `delegate_provider!` macro. `AnyChannel` enum dispatch lives in `zeph-channels` for reuse across binaries.
**Agent decomposition:** The agent module in `zeph-core` is split into 7 submodules (`mod.rs`, `context.rs`, `streaming.rs`, `persistence.rs`, `learning.rs`, `mcp.rs`, `index.rs`) with 5 inner field-grouping structs (`MemoryState`, `SkillState`, `ContextState`, `McpState`, `IndexState`).
@@ -152,29 +156,32 @@ Deep dive: [Architecture overview](https://bug-ops.github.io/zeph/architecture/o
| Feature | Default | Description |
|---------|---------|-------------|
-| `a2a` | On | A2A protocol client and server |
-| `openai` | On | OpenAI-compatible provider |
-| `mcp` | On | MCP client for external tool servers |
-| `candle` | On | Local HuggingFace inference (GGUF) |
-| `orchestrator` | On | Multi-model routing with fallback |
-| `qdrant` | On | Qdrant vector search for skills and MCP tools (opt-out) |
+| `compatible` | On | OpenAI-compatible provider (Together AI, Groq, Fireworks, etc.) |
+| `openai` | On | OpenAI provider |
+| `qdrant` | On | Qdrant vector search for skills and MCP tools |
| `self-learning` | On | Skill evolution system |
| `vault-age` | On | Age-encrypted secret storage |
-| `index` | On | AST-based code indexing and semantic retrieval |
+| `a2a` | Off | A2A protocol client and server |
+| `candle` | Off | Local HuggingFace inference (GGUF) |
+| `index` | Off | AST-based code indexing and semantic retrieval |
+| `mcp` | Off | MCP client for external tool servers |
+| `orchestrator` | Off | Multi-model routing with fallback |
+| `router` | Off | Prompt-based model selection via RouterProvider |
| `discord` | Off | Discord bot with Gateway v10 WebSocket |
| `slack` | Off | Slack bot with Events API webhook |
| `gateway` | Off | HTTP gateway for webhook ingestion |
| `daemon` | Off | Daemon supervisor for component lifecycle |
| `scheduler` | Off | Cron-based periodic task scheduler |
+| `otel` | Off | OpenTelemetry OTLP export for Prometheus/Grafana |
| `metal` | Off | Metal GPU acceleration (macOS) |
| `tui` | Off | ratatui TUI dashboard with real-time metrics |
| `cuda` | Off | CUDA GPU acceleration (Linux) |
```bash
-cargo build --release # all defaults
+cargo build --release # default features only
+cargo build --release --features full # all non-platform features
cargo build --release --features metal # macOS Metal GPU
-cargo build --release --no-default-features # minimal binary
-cargo build --release --features index # with code indexing
+cargo build --release --no-default-features # minimal binary (Ollama + Claude only)
cargo build --release --features tui # with TUI dashboard
```
diff --git a/crates/zeph-channels/src/any.rs b/crates/zeph-channels/src/any.rs
new file mode 100644
index 00000000..c99ec04c
--- /dev/null
+++ b/crates/zeph-channels/src/any.rs
@@ -0,0 +1,77 @@
+use zeph_core::channel::{Channel, ChannelError, ChannelMessage};
+
+use crate::cli::CliChannel;
+#[cfg(feature = "discord")]
+use crate::discord::DiscordChannel;
+#[cfg(feature = "slack")]
+use crate::slack::SlackChannel;
+use crate::telegram::TelegramChannel;
+
+/// Enum dispatch for runtime channel selection.
+#[derive(Debug)]
+pub enum AnyChannel {
+ Cli(CliChannel),
+ Telegram(TelegramChannel),
+ #[cfg(feature = "discord")]
+ Discord(DiscordChannel),
+ #[cfg(feature = "slack")]
+ Slack(SlackChannel),
+}
+
+macro_rules! dispatch_channel {
+ ($self:expr, $method:ident $(, $arg:expr)*) => {
+ match $self {
+ AnyChannel::Cli(c) => c.$method($($arg),*).await,
+ AnyChannel::Telegram(c) => c.$method($($arg),*).await,
+ #[cfg(feature = "discord")]
+ AnyChannel::Discord(c) => c.$method($($arg),*).await,
+ #[cfg(feature = "slack")]
+ AnyChannel::Slack(c) => c.$method($($arg),*).await,
+ }
+ };
+}
+
+impl Channel for AnyChannel {
+ async fn recv(&mut self) -> Result