diff --git a/.loki-project.json b/.loki-project.json new file mode 100644 index 0000000..165f4c7 --- /dev/null +++ b/.loki-project.json @@ -0,0 +1 @@ +{"type":"rust","build":"cargo build","test":"cargo test","check":"cargo check","_detected_by":"heuristic","_cached_at":"2026-04-13T13:36:33-06:00"} diff --git a/Cargo.lock b/Cargo.lock index 62acbb4..2f9f5c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,9 +65,9 @@ dependencies = [ [[package]] name = "anndists" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8238f99889a837cd6641360f9f3ead18f70b07bf6ce1f04a319bc6bd8a2f48f1" +checksum = "9a8396b473aa0bceed68fb32462505387ea39fa47c7029417e0a49f10592b036" dependencies = [ "anyhow", "cfg-if", @@ -165,9 +165,9 @@ dependencies = [ [[package]] name = "arc-swap" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07d1f37ff60921c83bdfc7407723bdefe89b44b98a9b772f225c8f9d67141a6" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" dependencies = [ "rustversion", ] @@ -183,7 +183,7 @@ dependencies = [ "convert_case 0.8.0", "dirs", "either", - "indexmap 2.13.0", + "indexmap 2.14.0", "natord", "nom 8.0.0", "num_cpus", @@ -310,11 +310,11 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.16.2" +version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" +checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" dependencies = [ - "aws-lc-sys", + "aws-lc-sys 0.40.0", "zeroize", ] @@ -331,6 +331,18 @@ dependencies = [ "fs_extra", ] +[[package]] +name = "aws-lc-sys" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "aws-runtime" version = "1.6.0" @@ -534,11 +546,11 @@ dependencies = [ "hyper 0.14.32", "hyper 1.9.0", "hyper-rustls 0.24.2", - "hyper-rustls 0.27.7", + "hyper-rustls 0.27.9", "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.37", + "rustls 0.23.39", "rustls-native-certs", "rustls-pki-types", "tokio", @@ -668,9 +680,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ "axum-core", "bytes", @@ -869,9 +881,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" -version = "2.11.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" dependencies = [ "serde_core", ] @@ -987,9 +999,9 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "cc" -version = "1.2.58" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ "find-msvc-tools", "jobserver", @@ -1037,7 +1049,7 @@ checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" dependencies = [ "cfg-if", "cpufeatures 0.3.0", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -1091,9 +1103,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" dependencies = [ "clap_builder", "clap_derive", @@ -1114,9 +1126,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.6.0" +version = "4.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c9f1dde76b736e3681f28cec9d5a61299cbaae0fce80a68e43724ad56031eb" +checksum = "3ff7a1dccbdd8b078c2bdebff47e404615151534d5043da397ec50286816f9cb" dependencies = [ "clap", "clap_lex", @@ -1136,9 +1148,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.0" +version = "4.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" dependencies = [ "heck", "proc-macro2", @@ -1351,23 +1363,6 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" -[[package]] -name = "crossterm" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" -dependencies = [ - "bitflags", - "crossterm_winapi", - "filedescriptor", - "mio", - "parking_lot", - "rustix 0.38.44", - "signal-hook", - "signal-hook-mio", - "winapi", -] - [[package]] name = "crossterm" version = "0.29.0" @@ -1378,9 +1373,10 @@ dependencies = [ "crossterm_winapi", "derive_more 2.1.1", "document-features", + "filedescriptor", "mio", "parking_lot", - "rustix 1.1.4", + "rustix", "serde", "signal-hook", "signal-hook-mio", @@ -1811,9 +1807,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.3.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "fd-lock" @@ -1822,7 +1818,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "rustix 1.1.4", + "rustix", "windows-sys 0.59.0", ] @@ -2038,7 +2034,7 @@ dependencies = [ "once_cell", "prost", "prost-types", - "reqwest", + "reqwest 0.12.28", "secret-vault-value", "serde", "serde_json", @@ -2082,7 +2078,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ - "rustix 1.1.4", + "rustix", "windows-link", ] @@ -2122,7 +2118,7 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", - "rand_core 0.10.0", + "rand_core 0.10.1", "wasip2", "wasip3", ] @@ -2149,7 +2145,7 @@ dependencies = [ "argon2", "async-trait", "aws-config", - "aws-lc-sys", + "aws-lc-sys 0.39.1", "aws-sdk-secretsmanager", "azure_core", "azure_identity", @@ -2162,7 +2158,7 @@ dependencies = [ "clap_complete", "confy", "crc32c", - "crossterm 0.29.0", + "crossterm", "dialoguer", "dirs", "futures", @@ -2199,7 +2195,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.13.0", + "indexmap 2.14.0", "slab", "tokio", "tokio-util", @@ -2218,7 +2214,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.4.0", - "indexmap 2.13.0", + "indexmap 2.14.0", "slab", "tokio", "tokio-util", @@ -2244,9 +2240,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] name = "heck" @@ -2288,14 +2284,14 @@ dependencies = [ "cpu-time", "env_logger", "hashbrown 0.15.5", - "indexmap 2.13.0", + "indexmap 2.14.0", "lazy_static", "log", "mmap-rs", "num-traits", "num_cpus", "parking_lot", - "rand 0.9.2", + "rand 0.9.4", "rayon", "serde", ] @@ -2499,16 +2495,15 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.7" +version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ "http 1.4.0", "hyper 1.9.0", "hyper-util", - "rustls 0.23.37", + "rustls 0.23.39", "rustls-native-certs", - "rustls-pki-types", "tokio", "tokio-rustls 0.26.4", "tower-service", @@ -2719,12 +2714,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.16.1", + "hashbrown 0.17.0", "serde", "serde_core", ] @@ -2754,7 +2749,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6654738b8024300cf062d04a1c13c10c8e2cea598ec1c47dc9b6641159429756" dependencies = [ "bitflags", - "crossterm 0.29.0", + "crossterm", "dyn-clone", "fuzzy-matcher", "unicode-segmentation", @@ -2848,9 +2843,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jiff" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d" dependencies = [ "jiff-static", "log", @@ -2861,9 +2856,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.23" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7" dependencies = [ "proc-macro2", "quote", @@ -2882,9 +2877,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.94" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ "cfg-if", "futures-util", @@ -2944,9 +2939,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.184" +version = "0.2.185" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" [[package]] name = "libloading" @@ -2960,19 +2955,13 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" dependencies = [ "libc", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -3032,7 +3021,7 @@ dependencies = [ "log-mdc", "mock_instant", "parking_lot", - "rand 0.9.2", + "rand 0.9.4", "serde", "serde-value", "serde_json", @@ -3065,8 +3054,7 @@ dependencies = [ "clap_complete", "clap_complete_nushell", "colored", - "crossterm 0.28.1", - "crossterm 0.29.0", + "crossterm", "dirs", "duct", "dunce", @@ -3081,7 +3069,7 @@ dependencies = [ "http-body-util", "hyper 1.9.0", "hyper-util", - "indexmap 2.13.0", + "indexmap 2.14.0", "indoc", "inquire", "is-terminal", @@ -3095,10 +3083,10 @@ dependencies = [ "parking_lot", "path-absolutize", "pretty_assertions", - "rand 0.10.0", + "rand 0.10.1", "rayon", "reedline", - "reqwest", + "reqwest 0.12.28", "reqwest-eventsource", "rmcp", "rust-embed", @@ -3106,6 +3094,7 @@ dependencies = [ "serde", "serde_json", "serde_yaml", + "serial_test", "sha2", "shell-words", "strum_macros 0.27.2", @@ -3671,9 +3660,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "open" -version = "5.3.3" +version = "5.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb73a7fa3799b198970490a51174027ba0d4ec504b03cd08caf513d40024bc" +checksum = "9f3bab717c29a857abf75fcef718d441ec7cb2725f937343c734740a985d37fd" dependencies = [ "is-wsl", "libc", @@ -3682,9 +3671,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.76" +version = "0.10.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" +checksum = "f38c4372413cdaaf3cc79dd92d29d7d9f5ab09b51b10dded508fb90bb70b9222" dependencies = [ "bitflags", "cfg-if", @@ -3714,18 +3703,18 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-src" -version = "300.5.5+3.5.5" +version = "300.6.0+3.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1787d533e03597a7934fd0a765f0d28e94ecc5fb7789f8053b1e699a56f709" +checksum = "a8e8cbfd3a4a8c8f089147fd7aaa33cf8c7450c4d09f8f80698a0cf093abeff4" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.112" +version = "0.9.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" +checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6" dependencies = [ "cc", "libc", @@ -3822,9 +3811,9 @@ dependencies = [ [[package]] name = "pastey" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec" +checksum = "c5a797f0e07bdf071d15742978fc3128ec6c22891c31a3a931513263904c982a" [[package]] name = "path-absolutize" @@ -3874,7 +3863,7 @@ checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", "hashbrown 0.15.5", - "indexmap 2.13.0", + "indexmap 2.14.0", ] [[package]] @@ -3904,7 +3893,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", - "rand 0.8.5", + "rand 0.8.6", ] [[package]] @@ -3963,9 +3952,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plist" @@ -3974,7 +3963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" dependencies = [ "base64", - "indexmap 2.13.0", + "indexmap 2.14.0", "quick-xml 0.38.4", "serde", "time", @@ -3999,9 +3988,9 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "portable-atomic-util" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ "portable-atomic", ] @@ -4094,7 +4083,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e842efad9119158434d193c6682e2ebee4b44d6ad801d7b349623b3f57cdf55" dependencies = [ "futures", - "indexmap 2.13.0", + "indexmap 2.14.0", "nix 0.31.2", "tokio", "tracing", @@ -4163,7 +4152,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.37", + "rustls 0.23.39", "socket2 0.6.3", "thiserror 2.0.18", "tokio", @@ -4180,10 +4169,10 @@ dependencies = [ "bytes", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand 0.9.4", "ring", "rustc-hash", - "rustls 0.23.37", + "rustls 0.23.39", "rustls-pki-types", "slab", "thiserror 2.0.18", @@ -4229,18 +4218,18 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "rand_core 0.6.4", ] [[package]] name = "rand" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" dependencies = [ "rand_chacha", "rand_core 0.9.5", @@ -4248,13 +4237,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ "chacha20 0.10.0", "getrandom 0.4.2", - "rand_core 0.10.0", + "rand_core 0.10.1", ] [[package]] @@ -4287,15 +4276,15 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "rayon" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", @@ -4338,7 +4327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe9e7c532bfc2759bc8a28902c04e8b993fc13ebd085ee4292eb1b230fa9beef" dependencies = [ "chrono", - "crossterm 0.29.0", + "crossterm", "fd-lock", "itertools 0.13.0", "nu-ansi-term", @@ -4421,7 +4410,7 @@ dependencies = [ "http-body 1.0.1", "http-body-util", "hyper 1.9.0", - "hyper-rustls 0.27.7", + "hyper-rustls 0.27.9", "hyper-tls", "hyper-util", "js-sys", @@ -4431,7 +4420,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.37", + "rustls 0.23.39", "rustls-native-certs", "rustls-pki-types", "serde", @@ -4448,11 +4437,49 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", + "wasm-streams 0.4.2", "web-sys", "webpki-roots", ] +[[package]] +name = "reqwest" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.9.0", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.5.0", + "web-sys", +] + [[package]] name = "reqwest-eventsource" version = "0.6.0" @@ -4465,7 +4492,7 @@ dependencies = [ "mime", "nom 7.1.3", "pin-project-lite", - "reqwest", + "reqwest 0.12.28", "thiserror 1.0.69", ] @@ -4494,21 +4521,24 @@ dependencies = [ [[package]] name = "rmcp" -version = "0.16.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4c9c94680f75470ee8083a0667988b5d7b5beb70b9f998a8e51de7c682ce60" +checksum = "67d69668de0b0ccd9cc435f700f3b39a7861863cf37a15e1f304ea78688a4826" dependencies = [ "async-trait", "base64", "chrono", "futures", + "http 1.4.0", "pastey", "pin-project-lite", "process-wrap", + "reqwest 0.13.2", "rmcp-macros", "schemars 1.2.1", "serde", "serde_json", + "sse-stream", "thiserror 2.0.18", "tokio", "tokio-stream", @@ -4518,9 +4548,9 @@ dependencies = [ [[package]] name = "rmcp-macros" -version = "0.16.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90c23c8f26cae4da838fbc3eadfaecf2d549d97c04b558e7bd90526a9c28b42a" +checksum = "48fdc01c81097b0aed18633e676e269fefa3a78ec1df56b4fe597c1241b92025" dependencies = [ "darling 0.23.0", "proc-macro2", @@ -4548,12 +4578,12 @@ dependencies = [ [[package]] name = "rtoolbox" -version = "0.0.3" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f" +checksum = "50a0e551c1e27e1731aba276dbeaeac73f53c7cd34d1bda485d02bd1e0f36844" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4621,19 +4651,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - [[package]] name = "rustix" version = "1.1.4" @@ -4643,7 +4660,7 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.12.1", + "linux-raw-sys", "windows-sys 0.61.2", ] @@ -4661,16 +4678,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.37" +version = "0.23.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" +checksum = "7c2c118cb077cca2822033836dfb1b975355dfb784b5e8da48f7b6c5db74e60e" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.10", + "rustls-webpki 0.103.13", "subtle", "zeroize", ] @@ -4709,9 +4726,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.10" +version = "0.103.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" dependencies = [ "aws-lc-rs", "ring", @@ -4740,6 +4757,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scc" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" +dependencies = [ + "sdd", +] + [[package]] name = "schannel" version = "0.1.29" @@ -4808,7 +4834,7 @@ dependencies = [ "cssparser", "ego-tree", "html5ever 0.29.1", - "indexmap 2.13.0", + "indexmap 2.14.0", "precomputed-hash", "selectors", "tendril", @@ -4824,6 +4850,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sdd" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" + [[package]] name = "secrecy" version = "0.10.3" @@ -4888,9 +4920,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" @@ -4949,7 +4981,7 @@ version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.0", "itoa", "memchr", "serde", @@ -4988,7 +5020,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.13.0", + "indexmap 2.14.0", "schemars 0.9.0", "schemars 1.2.1", "serde_core", @@ -5015,13 +5047,39 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.13.0", + "indexmap 2.14.0", "itoa", "ryu", "serde", "unsafe-libyaml", ] +[[package]] +name = "serial_test" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "911bd979bf1070a3f3aa7b691a3b3e9968f339ceeec89e08c280a8a22207a32f" +dependencies = [ + "futures-executor", + "futures-util", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a7d91949b85b0d2fb687445e448b40d322b6b3e4af6b44a29b21d9a5f33e6d9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "servo_arc" version = "0.4.3" @@ -5193,6 +5251,19 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "sse-stream" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c5e6deb40826033bd7b11c7ef25ef71193fabd71f680f40dd16538a2704d2f4" +dependencies = [ + "bytes", + "futures-util", + "http-body 1.0.1", + "http-body-util", + "pin-project-lite", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -5388,7 +5459,7 @@ dependencies = [ "fastrand", "getrandom 0.4.2", "once_cell", - "rustix 1.1.4", + "rustix", "windows-sys 0.61.2", ] @@ -5435,7 +5506,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" dependencies = [ - "rustix 1.1.4", + "rustix", "windows-sys 0.61.2", ] @@ -5577,9 +5648,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.50.0" +version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ "bytes", "libc", @@ -5607,9 +5678,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.6.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -5642,7 +5713,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.37", + "rustls 0.23.39", "tokio", ] @@ -5748,7 +5819,7 @@ checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", - "indexmap 2.13.0", + "indexmap 2.14.0", "pin-project-lite", "slab", "sync_wrapper", @@ -5923,9 +5994,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" [[package]] name = "typespec" @@ -5953,8 +6024,8 @@ dependencies = [ "futures", "getrandom 0.3.4", "pin-project", - "rand 0.9.2", - "reqwest", + "rand 0.9.4", + "reqwest 0.12.28", "serde", "serde_json", "time", @@ -6089,9 +6160,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.0" +version = "1.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" dependencies = [ "getrandom 0.4.2", "js-sys", @@ -6188,11 +6259,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.2+wasi-0.2.9" +version = "1.0.3+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.57.1", ] [[package]] @@ -6201,14 +6272,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.51.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ "cfg-if", "once_cell", @@ -6219,9 +6290,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.67" +version = "0.4.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03623de6905b7206edd0a75f69f747f134b7f0a2323392d664448bf2d3c5d87e" +checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" dependencies = [ "js-sys", "wasm-bindgen", @@ -6229,9 +6300,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6239,9 +6310,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ "bumpalo", "proc-macro2", @@ -6252,9 +6323,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.117" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" dependencies = [ "unicode-ident", ] @@ -6276,7 +6347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ "anyhow", - "indexmap 2.13.0", + "indexmap 2.14.0", "wasm-encoder", "wasmparser", ] @@ -6294,6 +6365,19 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wasmparser" version = "0.244.0" @@ -6302,7 +6386,7 @@ checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ "bitflags", "hashbrown 0.15.5", - "indexmap 2.13.0", + "indexmap 2.14.0", "semver", ] @@ -6314,7 +6398,7 @@ checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" dependencies = [ "cc", "downcast-rs", - "rustix 1.1.4", + "rustix", "smallvec", "wayland-sys", ] @@ -6326,7 +6410,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" dependencies = [ "bitflags", - "rustix 1.1.4", + "rustix", "wayland-backend", "wayland-scanner", ] @@ -6378,9 +6462,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.94" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd70027e39b12f0849461e08ffc50b9cd7688d942c1c8e3c7b22273236b4dd0a" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" dependencies = [ "js-sys", "wasm-bindgen", @@ -6398,9 +6482,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" dependencies = [ "rustls-pki-types", ] @@ -6801,6 +6885,12 @@ dependencies = [ "wit-bindgen-rust-macro", ] +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "wit-bindgen-core" version = "0.51.0" @@ -6820,7 +6910,7 @@ checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ "anyhow", "heck", - "indexmap 2.13.0", + "indexmap 2.14.0", "prettyplease", "syn", "wasm-metadata", @@ -6851,7 +6941,7 @@ checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ "anyhow", "bitflags", - "indexmap 2.13.0", + "indexmap 2.14.0", "log", "serde", "serde_derive", @@ -6870,7 +6960,7 @@ checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" dependencies = [ "anyhow", "id-arena", - "indexmap 2.13.0", + "indexmap 2.14.0", "log", "semver", "serde", @@ -6889,7 +6979,7 @@ dependencies = [ "libc", "log", "os_pipe", - "rustix 1.1.4", + "rustix", "thiserror 2.0.18", "tree_magic_mini", "wayland-backend", @@ -6900,9 +6990,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "x11rb" @@ -6911,7 +7001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" dependencies = [ "gethostname", - "rustix 1.1.4", + "rustix", "x11rb-protocol", ] diff --git a/Cargo.toml b/Cargo.toml index 5d15c52..146010b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,7 +89,12 @@ duct = "1.0.0" argc = "1.23.0" strum_macros = "0.27.2" indoc = "2.0.6" -rmcp = { version = "0.16.0", features = ["client", "transport-child-process"] } +rmcp = { version = "1.5.0", features = [ + "client", + "transport-child-process", + "transport-streamable-http-client-reqwest", + "reqwest-native-tls", +] } num_cpus = "1.17.0" tree-sitter = "0.26.8" tree-sitter-language = "0.1" @@ -120,7 +125,7 @@ default-features = false features = ["parsing", "regex-onig", "plist-load"] [target.'cfg(target_os = "macos")'.dependencies] -crossterm = { version = "0.28.1", features = ["use-dev-tty"] } +crossterm = { version = "0.29.0", features = ["use-dev-tty"] } [target.'cfg(target_os = "linux")'.dependencies] arboard = { version = "3.3.0", default-features = false, features = [ @@ -132,6 +137,7 @@ arboard = { version = "3.3.0", default-features = false } [dev-dependencies] pretty_assertions = "1.4.0" +serial_test = "3" [[bin]] name = "loki" diff --git a/README.md b/README.md index c3d9cf5..461af13 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # Loki: All-in-one, batteries-included LLM CLI Tool ![Test](https://github.com/Dark-Alex-17/loki/actions/workflows/ci.yaml/badge.svg) -![LOC](https://tokei.rs/b1/github/Dark-Alex-17/loki?category=code) [![crates.io link](https://img.shields.io/crates/v/loki-ai.svg)](https://crates.io/crates/loki-ai) ![Release](https://img.shields.io/github/v/release/Dark-Alex-17/loki?color=%23c694ff) ![Crate.io downloads](https://img.shields.io/crates/d/loki-ai?label=Crate%20downloads) @@ -13,36 +12,36 @@ Agents, and More. It is designed to include a number of useful agents, roles, macros, and more so users can get up and running with Loki in as little time as possible. -![Agent example](./docs/images/agents/sql.gif) +![Agent example](https://raw.githubusercontent.com/wiki/Dark-Alex-17/loki/images/agents/sql.gif) -Coming from [AIChat](https://github.com/sigoden/aichat)? Follow the [migration guide](./docs/AICHAT-MIGRATION.md) to get started. +Coming from [AIChat](https://github.com/sigoden/aichat)? Follow the [migration guide](https://github.com/Dark-Alex-17/loki/wiki/AIChat-Migration) to get started. ## Quick Links -* [AIChat Migration Guide](./docs/AICHAT-MIGRATION.md): Coming from AIChat? Follow the migration guide to get started. +* [AIChat Migration Guide](https://github.com/Dark-Alex-17/loki/wiki/AIChat-Migration): Coming from AIChat? Follow the migration guide to get started. * [Installation](#install): Install Loki * [Getting Started](#getting-started): Get started with Loki by doing first-run setup steps. -* [REPL](./docs/REPL.md): Interactive Read-Eval-Print Loop for conversational interactions with LLMs and Loki. - * [Custom REPL Prompt](./docs/REPL-PROMPT.md): Customize the REPL prompt to provide useful contextual information. -* [Vault](./docs/VAULT.md): Securely store and manage sensitive information such as API keys and credentials. -* [Shell Integrations](./docs/SHELL-INTEGRATIONS.md): Seamlessly integrate Loki with your shell environment for enhanced command-line assistance. -* [Function Calling](./docs/function-calling/TOOLS.md#Tools): Leverage function calling capabilities to extend Loki's functionality with custom tools - * [Creating Custom Tools](./docs/function-calling/CUSTOM-TOOLS.md): You can create your own custom tools to enhance Loki's capabilities. - * [Create Custom Python Tools](./docs/function-calling/CUSTOM-TOOLS.md#custom-python-based-tools) - * [Create Custom TypeScript Tools](./docs/function-calling/CUSTOM-TOOLS.md#custom-typescript-based-tools) - * [Create Custom Bash Tools](./docs/function-calling/CUSTOM-BASH-TOOLS.md) - * [Bash Prompt Utilities](./docs/function-calling/BASH-PROMPT-HELPERS.md) -* [First-Class MCP Server Support](./docs/function-calling/MCP-SERVERS.md): Easily connect and interact with MCP servers for advanced functionality. -* [Macros](./docs/MACROS.md): Automate repetitive tasks and workflows with Loki "scripts" (macros). -* [RAG](./docs/RAG.md): Retrieval-Augmented Generation for enhanced information retrieval and generation. -* [Sessions](/docs/SESSIONS.md): Manage and persist conversational contexts and settings across multiple interactions. -* [Roles](./docs/ROLES.md): Customize model behavior for specific tasks or domains. -* [Agents](/docs/AGENTS.md): Leverage AI agents to perform complex tasks and workflows, including sub-agent spawning, teammate messaging, and user interaction tools. - * [Todo System](./docs/TODO-SYSTEM.md): Built-in task tracking for improved agent reliability with smaller models. -* [Environment Variables](./docs/ENVIRONMENT-VARIABLES.md): Override and customize your Loki configuration at runtime with environment variables. -* [Client Configurations](./docs/clients/CLIENTS.md): Configuration instructions for various LLM providers. - * [Authentication (API Key & OAuth)](./docs/clients/CLIENTS.md#authentication): Authenticate with API keys or OAuth for subscription-based access. - * [Patching API Requests](./docs/clients/PATCHES.md): Learn how to patch API requests for advanced customization. -* [Custom Themes](./docs/THEMES.md): Change the look and feel of Loki to your preferences with custom themes. +* [REPL](https://github.com/Dark-Alex-17/loki/wiki/REPL): Interactive Read-Eval-Print Loop for conversational interactions with LLMs and Loki. + * [Custom REPL Prompt](https://github.com/Dark-Alex-17/loki/wiki/REPL-Prompt): Customize the REPL prompt to provide useful contextual information. +* [Vault](https://github.com/Dark-Alex-17/loki/wiki/Vault): Securely store and manage sensitive information such as API keys and credentials. +* [Shell Integrations](https://github.com/Dark-Alex-17/loki/wiki/Shell-Integrations): Seamlessly integrate Loki with your shell environment for enhanced command-line assistance. +* [Function Calling](https://github.com/Dark-Alex-17/loki/wiki/Tools): Leverage function calling capabilities to extend Loki's functionality with custom tools + * [Creating Custom Tools](https://github.com/Dark-Alex-17/loki/wiki/Custom-Tools): You can create your own custom tools to enhance Loki's capabilities. + * [Create Custom Python Tools](https://github.com/Dark-Alex-17/loki/wiki/Custom-Tools#custom-python-based-tools) + * [Create Custom TypeScript Tools](https://github.com/Dark-Alex-17/loki/wiki/Custom-Tools#custom-typescript-based-tools) + * [Create Custom Bash Tools](https://github.com/Dark-Alex-17/loki/wiki/Custom-Bash-Tools) + * [Bash Prompt Utilities](https://github.com/Dark-Alex-17/loki/wiki/Bash-Prompt-Helpers) +* [First-Class MCP Server Support](https://github.com/Dark-Alex-17/loki/wiki/MCP-Servers): Easily connect and interact with MCP servers for advanced functionality. +* [Macros](https://github.com/Dark-Alex-17/loki/wiki/Macros): Automate repetitive tasks and workflows with Loki "scripts" (macros). +* [RAG](https://github.com/Dark-Alex-17/loki/wiki/RAG): Retrieval-Augmented Generation for enhanced information retrieval and generation. +* [Sessions](https://github.com/Dark-Alex-17/loki/wiki/Sessions): Manage and persist conversational contexts and settings across multiple interactions. +* [Roles](https://github.com/Dark-Alex-17/loki/wiki/Roles): Customize model behavior for specific tasks or domains. +* [Agents](https://github.com/Dark-Alex-17/loki/wiki/Agents): Leverage AI agents to perform complex tasks and workflows, including sub-agent spawning, teammate messaging, and user interaction tools. + * [Todo System](https://github.com/Dark-Alex-17/loki/wiki/TODO-System): Built-in task tracking for improved agent reliability with smaller models. +* [Environment Variables](https://github.com/Dark-Alex-17/loki/wiki/Environment-Variables): Override and customize your Loki configuration at runtime with environment variables. +* [Client Configurations](https://github.com/Dark-Alex-17/loki/wiki/Clients): Configuration instructions for various LLM providers. + * [Authentication (API Key & OAuth)](https://github.com/Dark-Alex-17/loki/wiki/Clients#authentication): Authenticate with API keys or OAuth for subscription-based access. + * [Patching API Requests](https://github.com/Dark-Alex-17/loki/wiki/Patches): Learn how to patch API requests for advanced customization. +* [Custom Themes](https://github.com/Dark-Alex-17/loki/wiki/Themes): Change the look and feel of Loki to your preferences with custom themes. * [History](#history): A history of how Loki came to be. ## Prerequisites @@ -154,7 +153,7 @@ loki --list-secrets ### Authentication Each client in your configuration needs authentication (with a few exceptions; e.g. ollama). Most clients use an API key -(set via `api_key` in the config or through the [vault](./docs/VAULT.md)). For providers that support OAuth (e.g. Claude Pro/Max +(set via `api_key` in the config or through the [vault](https://github.com/Dark-Alex-17/loki/wiki/Vault)). For providers that support OAuth (e.g. Claude Pro/Max subscribers, Google Gemini), you can authenticate with your existing subscription instead: ```yaml @@ -170,7 +169,7 @@ loki --authenticate my-claude-oauth # Or via the REPL: .authenticate ``` -For full details, see the [authentication documentation](./docs/clients/CLIENTS.md#authentication). +For full details, see the [authentication documentation](https://github.com/Dark-Alex-17/loki/wiki/Clients#authentication). ### Tab-Completions You can also enable tab completions to make using Loki easier. To do so, add the following to your shell profile: @@ -247,7 +246,7 @@ shown below: | Setting | Description | |-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `repl_prelude` | This setting lets you specify a default `session` or `role` to use when starting Loki in [REPL](./docs/REPL.md) mode.
Values can be | +| `repl_prelude` | This setting lets you specify a default `session` or `role` to use when starting Loki in [REPL](https://github.com/Dark-Alex-17/loki/wiki/REPL) mode.
Values can be | | `cmd_prelude` | This setting lets you specify a default `session` or `role` to use when running one-off queries in Loki via the CLI.
Values can be | | `agent_session` | This setting is used to specify a default session that all agents should start into, unless otherwise specified in the agent configuration. (e.g. `temp`, `default`) | diff --git a/assets/functions/mcp.json b/assets/functions/mcp.json index d3794f6..0ae8f79 100644 --- a/assets/functions/mcp.json +++ b/assets/functions/mcp.json @@ -1,6 +1,7 @@ { "mcpServers": { "github": { + "type": "stdio", "command": "docker", "args": [ "run", @@ -15,14 +16,17 @@ } }, "atlassian": { + "type": "stdio", "command": "npx", "args": ["-y", "mcp-remote@0.1.13", "https://mcp.atlassian.com/v1/mcp"] }, "docker": { + "type": "stdio", "command": "uvx", "args": ["mcp-server-docker"] }, "ddg-search": { + "type": "stdio", "command": "uvx", "args": ["duckduckgo-mcp-server"] } diff --git a/assets/functions/tools/query_jira_issues.sh b/assets/functions/tools/query_jira_issues.sh deleted file mode 100755 index 4160be0..0000000 --- a/assets/functions/tools/query_jira_issues.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash -set -e - -# @meta require-tools jira -# @describe Query for jira issues using a Jira Query Language (JQL) query -# @option --jql-query! The Jira Query Language query to execute -# @env LLM_OUTPUT=/dev/stdout The output path - -main() { - jira issue ls -q "$argc_jql_query" --plain >> "$LLM_OUTPUT" -} \ No newline at end of file diff --git a/docs/AGENTS.md b/docs/AGENTS.md deleted file mode 100644 index e9782d8..0000000 --- a/docs/AGENTS.md +++ /dev/null @@ -1,775 +0,0 @@ -# Agents - -Agents in Loki follow the same style as OpenAI's GPTs. They consist of 3 parts: - -* [Role](./ROLES.md) - Tell the LLM how to behave -* [RAG](./RAG.md) - Pre-built knowledge bases specifically for the agent -* [Function Calling](./function-calling/TOOLS.md#tools) ([#2](./function-calling/MCP-SERVERS.md)) - Extends the functionality of the LLM through custom functions it can call - -![Agent example](./images/agents/sql.gif) - -Agent configuration files are stored in the `agents` subdirectory of your Loki configuration directory. The location of -this directory varies between systems so you can use the following command to locate yours: - -```shell -loki --info | grep 'agents_dir' | awk '{print $2}' -``` - -If you're looking for more example agents, refer to the [built-in agents](../assets/agents). - -## Quick Links - -- [Directory Structure](#directory-structure) -- [Metadata](#1-metadata) -- [2. Define the Instructions](#2-define-the-instructions) - - [Static Instructions](#static-instructions) - - [Special Variables](#special-variables) - - [User-Defined Variables](#user-defined-variables) - - [Dynamic Instructions](#dynamic-instructions) - - [Variables](#variables) -- [3. Initializing RAG](#3-initializing-rag) -- [4. Building Tools for Agents](#4-building-tools-for-agents) - - [Limitations](#limitations) - - [.env File Support](#env-file-support) - - [Python-Based Agent Tools](#python-based-agent-tools) - - [Bash-Based Agent Tools](#bash-based-agent-tools) - - [TypeScript-Based Agent Tools](#typescript-based-agent-tools) -- [5. Conversation Starters](#5-conversation-starters) -- [6. Todo System & Auto-Continuation](#6-todo-system--auto-continuation) -- [7. Sub-Agent Spawning System](#7-sub-agent-spawning-system) - - [Configuration](#spawning-configuration) - - [Spawning & Collecting Agents](#spawning--collecting-agents) - - [Task Queue with Dependencies](#task-queue-with-dependencies) - - [Active Task Dispatch](#active-task-dispatch) - - [Output Summarization](#output-summarization) - - [Teammate Messaging](#teammate-messaging) - - [Runaway Safeguards](#runaway-safeguards) -- [8. User Interaction Tools](#8-user-interaction-tools) - - [Available Tools](#user-interaction-available-tools) - - [Escalation (Sub-Agent to User)](#escalation-sub-agent-to-user) -- [9. Auto-Injected Prompts](#9-auto-injected-prompts) -- [Built-In Agents](#built-in-agents) - - ---- - -## Directory Structure -Agent configurations often have the following directory structure: - -``` -/agents - └── my-agent - ├── config.yaml - ├── tools.sh - or - ├── tools.py - or - ├── tools.ts -``` - -This means that agent configurations often are only two files: the agent configuration file (`config.yaml`), and the -tool definitions (`agents/my-agent/tools.sh`, `tools.py`, or `tools.ts`). - -To see a full example configuration file, refer to the [example agent config file](../config.agent.example.yaml). - -The best way to understand how an agent is built is to go step by step in the following manner: - ---- - -## 1. Metadata -Agent configurations have the following settings available to customize each agent: - -```yaml -# Model Configuration -model: openai:gpt-4o # Specify the LLM to use -temperature: null # Set default temperature parameter, range (0, 1) -top_p: null # Set default top-p parameter, with a range of (0, 1) or (0, 2), depending on the model -# Agent Metadata Configuration -agent_session: null # Set a session to use when starting the agent. (e.g. temp, default); defaults to globally set agent_session -# Agent Configuration -name: # Name of the agent, used in the UI and logs -description: # Description of the agent, used in the UI -version: 1 # Version of the agent -# Function Calling Configuration -mcp_servers: # Optional list of MCP servers that the agent utilizes - - github # Corresponds to the name of an MCP server in the `/functions/mcp.json` file -global_tools: # Optional list of additional global tools to enable for the agent; i.e. not tools specific to the agent - - web_search - - fs - - python -# Todo System & Auto-Continuation (see "Todo System & Auto-Continuation" section below) -auto_continue: false # Enable automatic continuation when incomplete todos remain -max_auto_continues: 10 # Maximum continuation attempts before stopping -inject_todo_instructions: true # Inject todo tool instructions into system prompt -continuation_prompt: null # Custom prompt for continuations (optional) -# Sub-Agent Spawning (see "Sub-Agent Spawning System" section below) -can_spawn_agents: false # Enable spawning child agents -max_concurrent_agents: 4 # Max simultaneous child agents -max_agent_depth: 3 # Max nesting depth (prevents runaway) -inject_spawn_instructions: true # Inject spawning instructions into system prompt -summarization_model: null # Model for summarizing sub-agent output (e.g. 'openai:gpt-4o-mini') -summarization_threshold: 4000 # Char count above which sub-agent output is summarized -escalation_timeout: 300 # Seconds sub-agents wait for escalated user input (default: 5 min) -``` - -As mentioned previously: Agents utilize function calling to extend a model's capabilities. However, agents operate in -isolated environment, so in order for an agent to use a tool or MCP server that you have defined globally, you must -explicitly state which tools and/or MCP servers the agent uses. Otherwise, it is assumed that the agent doesn't use any -tools outside its own custom defined tools. - -And if you don't define a `agents/my-agent/tools.sh`, `agents/my-agent/tools.py`, or `agents/my-agent/tools.ts`, then the agent is really just a -`role`. - -You'll notice there are no settings for agent-specific tooling. This is because they are handled separately and -automatically. See the [Building Tools for Agents](#4-building-tools-for-agents) section below for more information. - -To see a full example configuration file, refer to the [example agent config file](../config.agent.example.yaml). - -## 2. Define the Instructions -At their heart, agents function similarly to roles in that they tell the model how to behave. Agent configuration files -have the following settings for the instruction definitions: - -```yaml -dynamic_instructions: # Whether to use dynamically generated instructions for the agent; if false, static instructions are used. False by default. -instructions: # Static instructions for the LLM; These are ignored if dynamic instructions are used -variables: # An array of optional variables that the agent expects and uses -``` - -### Static Instructions -By default, Loki agents use statically defined instructions. Think of them as being identical to the instructions for a -[role](./ROLES.md#instructions), because they virtually are. - -**Example:** -```yaml -instructions: | - You are an AI agent designed to demonstrate agentic capabilities -``` - -Just like roles, agents support variable interpolation at runtime. There's two types of variables that can be -interpolated into the instructions at runtime: special variables (like roles have), and user-defined variables. Just -like roles, variables are interpolated into your instructions anywhere Loki sees the `{{variable}}` syntax. - -#### Special Variables -The following special variables are provided by Loki at runtime and can be injected into your agent's instructions: - -| Name | Description | Example | -|-----------------|---------------------------------------------------------------------|----------------------------| -| `__os__` | Operating system name | `linux` | -| `__os_family__` | Operating system family | `unix` | -| `__arch__` | System architecture | `x86_64` | -| `__shell__` | The current user's default shell | `bash` | -| `__locale__` | The current user's preferred language and region settings | `en-US` | -| `__now__` | Current timestamp in ISO 8601 format | `2025-11-07T10:15:44.268Z` | -| `__cwd__` | The current working directory | `/tmp` | -| `__tools__` | A list of the enabled tools (global + mcp servers + agent-specific) | | - -#### User-Defined Variables -Agents also support user-defined variables that can be interpolated into the instructions, and are made available to any -agent-specific tools you define (see [Building Tools for Agents](#4-building-tools-for-agents) for more details on how to -create agent-specific tooling). - -The `variables` setting in an agent's config has the following fields: - -| Field | Required | Description | -|---------------|----------|----------------------------------------------------------------------------------------------------| -| `name` | * | The name of the variable | -| `description` | * | The description of the field | -| `default` | | A default value for the field. If left undefined, the user will be prompted for a value at runtime | - -These variables can be referenced in both the agent's instructions, and in the tool definitions via `LLM_AGENT_VAR_`. - -**Example:** -```yaml -instructions: | - You are an agent who answers questions about a user's system. - - - {{__tools__}} - - - - os: {{__os__}} - os_family: {{__os_family__}} - arch: {{__arch__}} - shell: {{__shell__}} - locale: {{__locale__}} - now: {{__now__}} - cwd: {{__cwd__}} - - - - username: {{username}} - -variables: - - name: username # Accessible from the tool definitions via the `LLM_AGENT_VAR_USERNAME` environment variable - description: Your user name -``` - -### Dynamic Instructions -Sometimes you may find it useful to dynamically generate instructions on startup. Whether that be via a call to Loki -itself to generate them, or by some other means. Loki supports this type of behavior using a special function defined -in your `agents/my-agent/tools.py`, `agents/my-agent/tools.sh`, or `agents/my-agent/tools.ts`. - -**Example: Instructions for a JSON-reader agent that specializes on each JSON input it receives** -`agents/json-reader/tools.py`: -```python -import json -from pathlib import Path -from genson import SchemaBuilder - -def _instructions(): - """Generates instructions for the agent dynamically""" - value = input("Enter a JSON file path OR paste raw JSON: ").strip() - if not value: - raise SystemExit("A file path or JSON string is required.") - - p = Path(value) - if p.exists() and p.is_file(): - json_file_path = str(p.resolve()) - json_text = p.read_text(encoding="utf-8") - else: - try: - json.loads(value) - except json.JSONDecodeError as e: - raise SystemExit(f"Input is neither a file nor valid JSON.\n{e}") - json_file_path = "" - json_text = value - - try: - data = json.loads(json_text) - except json.JSONDecodeError as e: - raise SystemExit(f"Provided content is not valid JSON.\n{e}") - - builder = SchemaBuilder() - builder.add_object(data) - json_schema = builder.to_schema() - return f""" - You are an AI agent that can view and filter JSON data with jq. - - ## Context - json_file_path: {json_file_path} - json_schema: {json.dumps(json_schema, indent=2)} - """ -``` - -or - -`agents/json-reader/tools.sh`: -```bash -#!/usr/bin/env bash -set -e - -# @meta require-tools jq,genson -# @env LLM_OUTPUT=/dev/stdout The output path - -# @cmd Generates instructions for the agent dynamically -_instructions() { - read -r -p "Enter a JSON file path OR paste raw JSON: " value - - if [[ -z "${value}" ]]; then - echo "A file path or JSON string is required" >&2 - exit 1 - fi - json_file_path="" - inline_temp="" - cleanup() { - [[ -n "${inline_temp:-}" && -f "${inline_temp}" ]] && rm -f "${inline_temp}" - } - trap cleanup EXIT - - if [[ -f "${value}" ]]; then - json_file_path="$(realpath "${value}")" - if ! jq empty "${json_file_path}" >/dev/null 2>&1; then - echo "Error: File does not contain valid JSON: ${json_file_path}" >&2 - exit 1 - fi - else - inline_temp="$(mktemp)" - printf "%s" "${value}" > "${inline_temp}" - if ! jq empty "${inline_temp}" >/dev/null 2>&1; then - echo "Error: Input is neither a file nor valid JSON." >&2 - exit 1 - fi - json_file_path="" - fi - - source_file="${json_file_path}" - if [[ "${json_file_path}" == "" ]]; then - source_file="${inline_temp}" - fi - - json_schema="$(genson < "${source_file}" | jq -c '.')" - cat <> "$LLM_OUTPUT" -You are an AI agent that can view and filter JSON data with jq. - -## Context -json_file_path: ${json_file_path} -json_schema: ${json_schema} -EOF -} -``` - -For more information on how to create custom tools for your agent and the structure of the `agent/my-agent/tools.sh`, -`agent/my-agent/tools.py`, or `agent/my-agent/tools.ts` files, refer to the [Building Tools for Agents](#4-building-tools-for-agents) section below. - -#### Variables -All the same variable interpolations supported by static instructions is also supported by dynamic instructions. For -more information on what variables are available and how to use them, refer to the [Special Variables](#special-variables) -and [User-Defined Variables](#user-defined-variables) sections above. - -## 3. Initializing RAG -Each agent you create also has a dedicated knowledge base that adds additional context to your queries and helps the LLM -answer queries effectively. The documents to load into RAG are defined in the `documents` array of your agent -configuration file: - -```yaml -documents: - - https://www.ohdsi.org/data-standardization/ - - https://github.com/OHDSI/Vocabulary-v5.0/wiki/** - - OMOPCDM_ddl.sql # Relative path to agent (i.e. file lives at '/agents/my-agent/OMOPCDM_ddl.sql') -``` - -These documents use the same syntax as those you'd define when constructing RAG normally. To see all the available types -of documents that Loki supports and how to use custom document loaders, refer to the [RAG documentation](./RAG.md#supported-document-sources). - -Anytime your agent starts up, it will automatically be using the RAG you've defined here. - -## 4. Building Tools for Agents -Building tools for agents is virtually identical to building custom tools, with one slight difference: instead of -defining a single function that gets executed at runtime (e.g. `main` for bash tools and `run` for Python tools), agent -tools define a number of *subcommands*. - -### Limitations -You can only utilize one of: a bash-based `/agents/my-agent/tools.sh`, a Python-based -`/agents/my-agent/tools.py`, or a TypeScript-based `/agents/my-agent/tools.ts`. -However, if it's easier to achieve a task in one language vs the other, -you're free to define other scripts in your agent's configuration directory and reference them from the main -tools file. **Any scripts *not* named `tools.{py,sh,ts}` will not be picked up by Loki's compiler**, meaning they -can be used like any other set of scripts. - -It's important to keep in mind the following: - -* **Do not give agents the same name as an executable**. Loki compiles the tools for each agent into a binary that it - temporarily places on your path during execution. If you have a binary with the same name as your agent, then your - shell may execute the existing binary instead of your agent's tools -* **`LLM_ROOT_DIR` points to the agent's configuration directory**. This is where agents differ slightly from normal - tools: The `LLM_ROOT_DIR` environment variable does *not* point to the `functions/tools` directory like it does in - global tools. Instead, it points to the agent's configuration directory, making it easier to source scripts and other - miscellaneous files - -### .env File Support -When Loki loads an agent, it will also search the agent's configuration directory for a `.env` file. If found, all -environment variables defined in the file will be made available to the agent's tools. - -### Python-Based Agent Tools -Python-based tools are defined exactly the same as they are for custom tool definitions. The only difference is that -instead of a single `run` function, you define as many as you like with whatever arguments you like. - -**Example:** -`agents/my-agent/tools.py` -```python -import urllib.request - -def get_ip_info(): - """ - Get your IP information - """ - with urllib.request.urlopen("https://httpbin.org/ip") as response: - data = response.read() - return data.decode('utf-8') - -def get_ip_address_from_aws(): - """ - Find your public IP address using AWS - """ - with urllib.request.urlopen("https://checkip.amazonaws.com") as response: - data = response.read() - return data.decode('utf-8') -``` - -Loki automatically compiles these as separate functions for the LLM to call. No extra work is needed. Just make sure you -follow all the same steps to define each function as you would when creating custom Python tools. - -For more information on how to build tools in Python, refer to the [custom Python tools documentation](./function-calling/CUSTOM-TOOLS.md#custom-python-based-tools) - -### Bash-Based Agent Tools -Bash-based agent tools are virtually identical to custom bash tools, with only one difference. Instead of defining a -single entrypoint via the `main` function, you actually define as many subcommands as you like. - -**Example:** -`agents/my-agent/tools.sh` -```bash -#!/usr/bin/env bash - -# @env LLM_OUTPUT=/dev/stdout The output path -# @describe Discover network information about your computer and its place in the internet - -# Use the `@cmd` annotation to define subcommands for your script. -# @cmd Get your IP information -get_ip_info() { - curl -fsSL https://httpbin.org/ip >> "$LLM_OUTPUT" -} - -# @cmd Find your public IP address using AWS -get_ip_address_from_aws() { - curl -fsSL https://checkip.amazonaws.com >> "$LLM_OUTPUT" -} -``` -To compile the script so it's executable and testable: -```bash -$ loki --build-tools -``` - -Then you can execute your script (assuming your current working directory is `agents/my-agent`): -```bash -$ ./tools.sh get_ip_info -$ ./tools.sh get_ip_address_from_aws -``` - -All other special annotations (`@env`, `@arg`, `@option` `@flags`) apply to subcommands as well, so be sure to follow -the same syntax ad formatting as is used to create custom bash tools globally. - -For more information on how to write, [build and test](function-calling/CUSTOM-BASH-TOOLS.md#execute-and-test-your-bash-tools) tools in bash, refer to the -[custom bash tools documentation](function-calling/CUSTOM-BASH-TOOLS.md). - -### TypeScript-Based Agent Tools -TypeScript-based agent tools work exactly the same as TypeScript global tools. Instead of a single `run` function, -you define as many exported functions as you like. Non-exported functions are private helpers and are invisible to the -LLM. - -**Example:** -`agents/my-agent/tools.ts` -```typescript -/** - * Get your IP information - */ -export async function get_ip_info(): Promise { - const resp = await fetch("https://httpbin.org/ip"); - return await resp.text(); -} - -/** - * Find your public IP address using AWS - */ -export async function get_ip_address_from_aws(): Promise { - const resp = await fetch("https://checkip.amazonaws.com"); - return await resp.text(); -} - -// Non-exported helper — invisible to the LLM -function formatResponse(data: string): string { - return data.trim(); -} -``` - -Loki automatically compiles each exported function as a separate tool for the LLM to call. Just make sure you -follow the same JSDoc and parameter conventions as you would when creating custom TypeScript tools. - -TypeScript agent tools also support dynamic instructions via an exported `_instructions()` function: - -```typescript -import { readFileSync } from "fs"; - -/** - * Generates instructions for the agent dynamically - */ -export function _instructions(): string { - const schema = readFileSync("schema.json", "utf-8"); - return `You are an AI agent that works with the following schema:\n${schema}`; -} -``` - -For more information on how to build tools in TypeScript, refer to the [custom TypeScript tools documentation](function-calling/CUSTOM-TOOLS.md#custom-typescript-based-tools). - -## 5. Conversation Starters -It's often helpful to also have some conversation starters so users know what kinds of things the agent is capable of -doing. These are available in the REPL via the `.starter` command and are selectable. - -They are defined using the `conversation_starters` setting in your agent's configuration file: - -**Example:** -`agents/my-agent/config.yaml`: -```yaml -conversation_starters: - - What is my username? - - What is my current shell? - - What is my ip? - - How much disk space is left on my PC?? - - How to create an agent? -``` - -![Example Conversation Starters](./images/agents/conversation-starters.gif) - -## 6. Todo System & Auto-Continuation - -Loki includes a built-in task tracking system designed to improve the reliability of agents, especially when using -smaller language models. The Todo System helps models: - -- Break complex tasks into manageable steps -- Track progress through multi-step workflows -- Automatically continue work until all tasks are complete - -### Quick Configuration - -```yaml -# agents/my-agent/config.yaml -auto_continue: true # Enable auto-continuation -max_auto_continues: 10 # Max continuation attempts -inject_todo_instructions: true # Include the default todo instructions into prompt -``` - -### How It Works - -1. When `inject_todo_instructions` is enabled, agents receive instructions on using five built-in tools: - - `todo__init`: Initialize a todo list with a goal - - `todo__add`: Add a task to the list - - `todo__done`: Mark a task complete - - `todo__list`: View current todo state - - `todo__clear`: Clear the entire todo list and reset the goal - - These instructions are a reasonable default that detail how to use Loki's To-Do System. If you wish, - you can disable the injection of the default instructions and specify your own instructions for how - to use the To-Do System into your main `instructions` for the agent. - -2. When `auto_continue` is enabled and the model stops with incomplete tasks, Loki automatically sends a - continuation prompt with the current todo state, nudging the model to continue working. - -3. This continues until all tasks are done or `max_auto_continues` is reached. - -### When to Use - -- Multistep tasks where the model might lose track -- Smaller models that need more structure -- Workflows requiring guaranteed completion of all steps - -For complete documentation including all configuration options, tool details, and best practices, see the -[Todo System Guide](./TODO-SYSTEM.md). - -## 7. Sub-Agent Spawning System - -Loki agents can spawn and manage child agents that run **in parallel** as background tasks inside the same process. -This enables orchestrator-style agents that delegate specialized work to other agents, similar to how tools like -Claude Code or OpenCode handle complex multi-step tasks. - -For a working example of an orchestrator agent that uses sub-agent spawning, see the built-in -[sisyphus](../assets/agents/sisyphus) agent. For an example of the teammate messaging pattern with parallel sub-agents, -see the [code-reviewer](../assets/agents/code-reviewer) agent. - -### Spawning Configuration - -| Setting | Type | Default | Description | -|-----------------------------|---------|---------------|--------------------------------------------------------------------------------| -| `can_spawn_agents` | boolean | `false` | Enable this agent to spawn child agents | -| `max_concurrent_agents` | integer | `4` | Maximum number of child agents that can run simultaneously | -| `max_agent_depth` | integer | `3` | Maximum nesting depth for sub-agents (prevents runaway spawning chains) | -| `inject_spawn_instructions` | boolean | `true` | Inject the default spawning instructions into the agent's system prompt | -| `summarization_model` | string | current model | Model to use for summarizing long sub-agent output (e.g. `openai:gpt-4o-mini`) | -| `summarization_threshold` | integer | `4000` | Character count above which sub-agent output is summarized before returning | -| `escalation_timeout` | integer | `300` | Seconds a sub-agent waits for an escalated user interaction response | - -**Example configuration:** -```yaml -# agents/my-orchestrator/config.yaml -can_spawn_agents: true -max_concurrent_agents: 6 -max_agent_depth: 2 -inject_spawn_instructions: true -summarization_model: openai:gpt-4o-mini -summarization_threshold: 3000 -escalation_timeout: 600 -``` - -### Spawning & Collecting Agents - -When `can_spawn_agents` is enabled, the agent receives tools for spawning and managing child agents: - -| Tool | Description | -|------------------|-------------------------------------------------------------------------| -| `agent__spawn` | Spawn a child agent in the background. Returns an agent ID immediately. | -| `agent__check` | Non-blocking check: is the agent done? Returns `PENDING` or the result. | -| `agent__collect` | Blocking wait: wait for an agent to finish, return its output. | -| `agent__list` | List all spawned agents and their status. | -| `agent__cancel` | Cancel a running agent by ID. | - -The core pattern is **Spawn -> Continue -> Collect**: - -``` -# 1. Spawn agents in parallel (returns IDs immediately) -agent__spawn --agent explore --prompt "Find auth middleware patterns in src/" -agent__spawn --agent explore --prompt "Find error handling patterns in src/" - -# 2. Continue your own work while they run - -# 3. Check if done (non-blocking) -agent__check --id agent_explore_a1b2c3d4 - -# 4. Collect results when ready (blocking) -agent__collect --id agent_explore_a1b2c3d4 -agent__collect --id agent_explore_e5f6g7h8 -``` - -Any agent defined in your `/agents/` directory can be spawned as a child. Child agents: -- Run in a fully isolated environment (separate session, config, and tools) -- Have their output suppressed from the terminal (no spinner, no tool call logging) -- Return their accumulated output to the parent when collected - -### Task Queue with Dependencies - -For complex workflows where tasks have ordering requirements, the spawning system includes a dependency-aware -task queue: - -| Tool | Description | -|------------------------|-----------------------------------------------------------------------------| -| `agent__task_create` | Create a task with optional dependencies and auto-dispatch agent. | -| `agent__task_list` | List all tasks with their status, dependencies, and assignments. | -| `agent__task_complete` | Mark a task done. Returns newly unblocked tasks and auto-dispatches agents. | -| `agent__task_fail` | Mark a task as failed. Dependents remain blocked. | - -``` -# Create tasks with dependency ordering -agent__task_create --subject "Explore existing patterns" -agent__task_create --subject "Implement feature" --blocked_by ["task_1"] -agent__task_create --subject "Write tests" --blocked_by ["task_2"] - -# Mark tasks complete to unblock dependents -agent__task_complete --task_id task_1 -``` - -### Active Task Dispatch - -Tasks can optionally specify an agent to auto-spawn when the task becomes runnable: - -``` -agent__task_create \ - --subject "Implement the auth module" \ - --blocked_by ["task_1"] \ - --agent coder \ - --prompt "Implement auth module based on patterns found in task_1" -``` - -When `task_1` completes and the dependent task becomes unblocked, an agent is automatically spawned with the -specified prompt. No manual intervention needed. This enables fully automated multi-step pipelines. - -### Output Summarization - -When a child agent produces long output, it can be automatically summarized before returning to the parent. -This keeps parent context windows manageable. - -- If the output exceeds `summarization_threshold` characters (default: 4000), it is sent through an LLM - summarization pass -- The `summarization_model` setting lets you use a cheaper/faster model for summarization (e.g. `gpt-4o-mini`) -- If `summarization_model` is not set, the parent's current model is used -- The summarization preserves all actionable information: code snippets, file paths, error messages, and - concrete recommendations - -### Teammate Messaging - -All agents (including children) automatically receive tools for **direct sibling-to-sibling messaging**: - -| Tool | Description | -|-----------------------|-----------------------------------------------------| -| `agent__send_message` | Send a text message to another agent's inbox by ID. | -| `agent__check_inbox` | Drain all pending messages from your inbox. | - -This enables coordination patterns where child agents share cross-cutting findings: - -``` -# Agent A discovers something relevant to Agent B -agent__send_message --id agent_reviewer_b1c2d3e4 --message "Found a security issue in auth.rs line 42" - -# Agent B checks inbox before finalizing -agent__check_inbox -``` - -Messages are routed through the parent's supervisor. A parent can message its children, and children can message -their siblings. For a working example of the teammate pattern, see the built-in -[code-reviewer](../assets/agents/code-reviewer) agent, which spawns file-specific reviewers that share -cross-cutting findings with each other. - -### Runaway Safeguards - -The spawning system includes built-in safeguards to prevent runaway agent chains: - -- **`max_concurrent_agents`:** Caps how many agents can run at once (default: 4). Spawn attempts beyond this - limit return an error asking the agent to wait or cancel existing agents. -- **`max_agent_depth`:** Caps nesting depth (default: 3). A child agent spawning its own child increments the - depth counter. Attempts beyond the limit are rejected. -- **`can_spawn_agents`:** Only agents with this flag set to `true` can spawn children. By default, spawning is - disabled. This means child agents cannot spawn their own children unless you explicitly create them with - `can_spawn_agents: true` in their config. - -## 8. User Interaction Tools - -Loki includes built-in tools for agents (and the REPL) to interactively prompt the user for input. These tools -are **always available**. No configuration needed. They are automatically injected into every agent and into -REPL mode when function calling is enabled. - -### User Interaction Available Tools - -| Tool | Description | Returns | -|------------------|-----------------------------------------|----------------------------------| -| `user__ask` | Present a single-select list of options | The selected option string | -| `user__confirm` | Ask a yes/no question | `"yes"` or `"no"` | -| `user__input` | Request free-form text input | The text entered by the user | -| `user__checkbox` | Present a multi-select checkbox list | Array of selected option strings | - -**Parameters:** - -- `user__ask`: `--question "..." --options ["Option A", "Option B", "Option C"]` -- `user__confirm`: `--question "..."` -- `user__input`: `--question "..."` -- `user__checkbox`: `--question "..." --options ["Option A", "Option B", "Option C"]` - -At the top level (depth 0), these tools render interactive terminal prompts directly using arrow-key navigation, -checkboxes, and text input fields. - -### Escalation (Sub-Agent to User) - -When a **child agent** (depth > 0) calls a `user__*` tool, it cannot prompt the terminal directly. Instead, -the request is **automatically escalated** to the root agent: - -1. The child agent calls `user__ask(...)` and **blocks**, waiting for a reply -2. The root agent sees a `pending_escalations` notification in its next tool results -3. The root agent either answers from context or prompts the user itself, then calls - `agent__reply_escalation` to unblock the child -4. The child receives the reply and continues - -The escalation timeout is configurable via `escalation_timeout` in the agent's `config.yaml` (default: 300 -seconds / 5 minutes). If the timeout expires, the child receives a fallback message asking it to use its -best judgment. - -| Tool | Description | -|---------------------------|--------------------------------------------------------------------------| -| `agent__reply_escalation` | Reply to a pending child escalation, unblocking the waiting child agent. | - -This tool is automatically available to any agent with `can_spawn_agents: true`. - -## 9. Auto-Injected Prompts - -Loki automatically appends usage instructions to your agent's system prompt for each enabled built-in system. -These instructions are injected into both **static and dynamic instructions** after your own instructions, -ensuring agents always know how to use their available tools. - -| System | Injected When | Toggle | -|--------------------|----------------------------------------------------------------|-----------------------------| -| Todo tools | `auto_continue: true` AND `inject_todo_instructions: true` | `inject_todo_instructions` | -| Spawning tools | `can_spawn_agents: true` AND `inject_spawn_instructions: true` | `inject_spawn_instructions` | -| Teammate messaging | Always (all agents) | None (always injected) | -| User interaction | Always (all agents) | None (always injected) | - -If you prefer to write your own instructions for a system, set the corresponding `inject_*` flag to `false` -and include your custom instructions in the agent's `instructions` field. The built-in tools will still be -available; only the auto-injected prompt text is suppressed. - -## Built-In Agents -Loki comes packaged with some useful built-in agents: - -* `coder`: An agent to assist you with all your coding tasks -* `code-reviewer`: A [CodeRabbit](https://coderabbit.ai)-style code reviewer that spawns per-file reviewers using the teammate messaging pattern -* `demo`: An example agent to use for reference when learning to create your own agents -* `explore`: An agent designed to help you explore and understand your codebase -* `file-reviewer`: An agent designed to perform code-review on a single file (used by the `code-reviewer` agent) -* `jira-helper`: An agent that assists you with all your Jira-related tasks -* `oracle`: An agent for high-level architecture, design decisions, and complex debugging -* `sisyphus`: A powerhouse orchestrator agent for writing complex code and acting as a natural language interface for your codebase (similar to ClaudeCode, Gemini CLI, Codex, or OpenCode). Uses sub-agent spawning to delegate to `explore`, `coder`, and `oracle`. -* `sql`: A universal SQL agent that enables you to talk to any relational database in natural language diff --git a/docs/AICHAT-MIGRATION.md b/docs/AICHAT-MIGRATION.md deleted file mode 100644 index f48050f..0000000 --- a/docs/AICHAT-MIGRATION.md +++ /dev/null @@ -1,211 +0,0 @@ -# AIChat to Loki Migration Guide -Loki originally started as a fork of AIChat but has since evolved into its own separate project with separate goals. - -As a result, there's some changes you'll need to make to your AIChat configuration to be able to use Loki. - -Be sure you've run `loki` at least once so that the Loki configuration directory and subdirectories exist and is -populated with the built-in defaults. - -## Global Configuration File -You should be able to copy/paste your AIChat configuration file into your Loki configuration directory. Since the -location of the Loki configuration directory varies between systems, you can use the following command to locate your -config directory: - -```shell -loki --info | grep 'config_dir' | awk '{print $2}' -``` - -Then, you'll need to make the following changes: - -* `function_calling` -> `function_calling_support` -* `use_tools` -> `enabled_tools` -* `agent_prelude` -> `agent_session` -* `compress_threshold` -> `compression_threshold` -* `summarize_prompt` -> `summarization_prompt` -* `summary_prompt` -> `summary_context_prompt` - -## Roles -Locate your `roles` directory using the following command: - -```shell -loki --info | grep 'roles_dir' | awk '{print $2}' -``` - -Update any roles that have `use_tools` to `enabled_tools`. - -## Sessions -Locate your `sessions` directory using the following command: - -```shell -loki --info | grep 'sessions_dir' | awk '{print $2}' -``` - -Update the following settings: -* `use_tools` -> `enabled_tools` -* `compress_threshold` -> `compression_threshold` -* `summarize_prompt` -> `summarization_prompt` -* `summary_prompt` -> `summary_context_prompt` - ---- - -# LLM Functions Changes -Probably the most significant difference between AIChat and Loki is how tools are handled. So if you cloned the -[llm-functions](https://github.com/sigoden/llm-functions) repo, you'll need to make the following changes. - -**Note: JavaScript functions are not supported in Loki.** - -The following guide assumes you're using the `llm-functions` repository as your base for custom functions, and thus -follows that directory structure. - -## Agents -Agents are now all handled in one place: the `agents` directory (`/agents`): - -```shell -loki --info | grep 'agents_dir' | awk '{print $2}' -``` - -And instead of separate `index.yaml` and `config.yaml` files, they're now both in a single `config.yaml` file. - -So now for all of your agents, copy all the contents of those directories to the corresponding directory in the Loki -`agents` directory. Then make the following changes: - -* Copy the contents of your `/functions/agents` directory into `/agents//tools.txt` -* No `/agents//index.yaml` - -## Functions -Loki consolidates much of the `llm-functions` repo functionality into one binary. So this means - -* There's no need to have `argc` installed anymore -* No separate repository to manage -* No `tools.txt` -* No `functions.json` -* No `functions/mcp` directory at all -* No `functions/scripts` - -Here's how to migrate your functions over to Loki from the `llm-functions` repository. - -* Copy your AIChat `/functions` directory into your Loki config directory -* Delete the following files and directories from your `/functions` directory: - * `scripts/` - * `agents.txt` - * `functions.json` - * `Argcfile.sh` - * `README.md` (irrelevant now) - * `LICENSE` (irrelevant now) - * `utils/guard_operation.sh` - * `utils/guard_path.sh` - * `utils/patch.awk` -* Everything in `tools.txt` now lives in the global config file under the `visible_tools` setting: - ```text - get_current_weather.sh - execute_command.sh - web_search.sh - #execute_py_code.py - query_jira_issues.sh - ``` - becomes the following in your `/config.yaml` - ```yaml - visible_tools: - - get_current_weather.sh - - execute_command.sh - - web_search.sh - # - web_search.sh - - query_jira_issues.sh - ``` -* If you've defined a `functions/mcp.json` file, you can leave it alone. -* Similarly to agents, if you have any bash `tools.sh` that depend on the utility scripts in the `llm-functions` - repository, they've been replaced by built-in utility scripts. So use the following to replace any matching lines in - your `tools.sh` files: - ```bash - ################## - ## Scripts file ## - ################## - ROOT_DIR="${LLM_ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}" - # replace with - source "$LLM_PROMPT_UTILS_FILE" - - ####################### - ## guard_path script ## - ####################### - "$ROOT_DIR/utils/guard_path.sh" - # replace with - guard_path - - ############################ - ## guard_operation script ## - ############################ - "$ROOT_DIR/utils/guard_operation.sh" - # replace with - guard_operation - - ###################### - ## patch.awk script ## - ###################### - awk -f "$ROOT_DIR/utils/patch.awk" - # replace with - patch_file - ``` - -Refer to the [custom bash tools docs](./function-calling/CUSTOM-BASH-TOOLS.md) to learn how to compile and test bash -tools in Loki without needing to use `argc`. diff --git a/docs/ENVIRONMENT-VARIABLES.md b/docs/ENVIRONMENT-VARIABLES.md deleted file mode 100644 index a9a0a3f..0000000 --- a/docs/ENVIRONMENT-VARIABLES.md +++ /dev/null @@ -1,113 +0,0 @@ -# Environment Variables - -Loki is designed to be highly dynamic and customizable. As a result, Loki utilizes a number of environment variables -that can be used to modify its behavior at runtime without needing to modify the existing configuration files. - -Loki also supports defining environment variables via a `.env` file in the Loki configuration directory. This directory -varies between systems, so you can find the location of your configuration directory using the following command: - -```shell -loki --info | grep 'config_dir' | awk '{print $2}' -``` - -## Quick Links - -- [Global Configuration Related Variables](#global-configuration-related-variables) -- [Client Related Variables](#client-related-variables) -- [Files and Directory Related Variables](#files-and-directory-related-variables) -- [Agent Related Variables](#agent-related-variables) -- [Logging Related Variables](#logging-related-variables) -- [Miscellaneous Variables](#miscellaneous-variables) - - ---- - -## Global Configuration Related Variables -All configuration items in the global config file have environment variables that can be overridden at runtime. To see -all configuration options and more thorough descriptions, refer to the [example config file](../config.example.yaml). - -Below are the most commonly used configuration settings and their corresponding environment variables: - -| Setting | Environment Variable | -|----------------------------|---------------------------------| -| `model` | `LOKI_MODEL` | -| `temperature` | `LOKI_TEMPERATURE` | -| `top_p` | `LOKI_TOP_P` | -| `stream` | `LOKI_STREAM` | -| `save` | `LOKI_SAVE` | -| `editor` | `LOKI_EDITOR` | -| `wrap` | `LOKI_WRAP` | -| `wrap_code` | `LOKI_WRAP_CODE` | -| `save_session` | `LOKI_SAVE_SESSION` | -| `compression_threshold` | `LOKI_COMPRESSION_THRESHOLD` | -| `function_calling_support` | `LOKI_FUNCTION_CALLING_SUPPORT` | -| `enabled_tools` | `LOKI_ENABLED_TOOLS` | -| `mcp_server_support` | `LOKI_MCP_SERVER_SUPPORT` | -| `enabled_mcp_servers` | `LOKI_ENABLED_MCP_SERVERS` | -| `rag_embedding_model` | `LOKI_RAG_EMBEDDING_MODEL` | -| `rag_reranker_model` | `LOKI_RAG_RERANKER_MODEL` | -| `rag_top_k` | `LOKI_RAG_TOP_K` | -| `rag_chunk_size` | `LOKI_RAG_CHUNK_SIZE` | -| `rag_chunk_overlap` | `LOKI_RAG_CHUNK_OVERLAP` | -| `highlight` | `LOKI_HIGHLIGHT` | -| `theme` | `LOKI_THEME` | -| `serve_addr` | `LOKI_SERVE_ADDR` | -| `user_agent` | `LOKI_USER_AGENT` | -| `save_shell_history` | `LOKI_SAVE_SHELL_HISTORY` | -| `sync_models_url` | `LOKI_SYNC_MODELS_URL` | - - -## Client Related Variables -The following environment variables are available for clients in Loki: - -| Environment Variable | Description | -|----------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `{client}_API_KEY` | For clients that require an API key, you can define the keys either through environment variables or
using the [vault](./VAULT.md). The variables are named after the client to which they apply;
e.g. `OPENAI_API_KEY`, `GEMINI_API_KEY`, etc. | -| `LOKI_PLATFORM` | Combine with `{client}_API_KEY` to run Loki without a configuration file.
This variable is ignored if a configuration file exists. | -| `LOKI_PATCH_{client}_CHAT_COMPLETIONS` | Patch chat completion requests to models on the corresponding client; Can modify the URL, body,
or headers. | -| `LOKI_SHELL` | Specify the shell that Loki should be using when executing commands | - -## Files and Directory Related Variables -You can also customize the files and directories that Loki loads its configuration files from: - -| Environment Variable | Description | Default Value | -|----------------------|------------------------------------------------------------------------|---------------------------------| -| `LOKI_CONFIG_DIR` | Customize the location of the Loki configuration directory. | `/loki` | -| `LOKI_ENV_FILE` | Customize the location of the `.env` file to load at startup. | `/.env` | -| `LOKI_CONFIG_FILE` | Customize the location of the global `config.yaml` configuration file. | `/config.yaml` | -| `LOKI_ROLES_DIR` | Customize the location of the `roles` directory. | `/roles` | -| `LOKI_SESSIONS_DIR` | Customize the location of the `sessions` directory. | `/sessions` | -| `LOKI_RAGS_DIR` | Customize the location of the `rags` directory. | `/rags` | -| `LOKI_FUNCTIONS_DIR` | Customize the location of the `functions` directory. | `/functions` | - -## Agent Related Variables -You can also customize the location of full agent configurations using the following environment variables: - -| Environment Variable | Description | -|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------| -| `_CONFIG_FILE` | Customize the location of the agent's configuration file; e.g. `SQL_CONFIG_FILE` | -| `_MODEL` | Customize the `model` used for the agent; e.g `SQL_MODEL` | -| `_TEMPERATURE` | Customize the `temperature` used for the agent; e.g. `SQL_TEMPERATURE` | -| `_TOP_P` | Customize the `top_p` used for the agent; e.g. `SQL_TOP_P` | -| `_GLOBAL_TOOLS` | Customize the `global_tools` that are enabled for the agent (a JSON string array); e.g. `SQL_GLOBAL_TOOLS` | -| `_MCP_SERVERS` | Customize the `mcp_servers` that are enabled for the agent (a JSON string array); e.g. `SQL_MCP_SERVERS` | -| `_AGENT_SESSION` | Customize the `agent_session` used with the agent; e.g. `SQL_SESSION` | -| `_INSTRUCTIONS` | Customize the `instructions` for the agent; e.g. `SQL_INSTRUCTIONS` | -| `_VARIABLES` | Customize the `variables` used for the agent (in JSON format of `[{"key1": "value1", "key2": "value2"}]`);
e.g. `SQL_VARIABLES` | - -## Logging Related Variables -The following variables can be used to change the log level of Loki or the location of the log file: - -| Environment Variable | Description | Default Value | -|----------------------|---------------------------------------------|----------------------------------| -| `LOKI_LOG_LEVEL` | Customize the log level of Loki | `INFO` | -| `LOKI_LOG_FILE` | Customize the location of the Loki log file | `/loki/loki.log` | - -**Pro-Tip:** You can always tail the Loki logs using the `--tail-logs` flag. If you need to disable color output, you -can also pass the `--disable-log-colors` flag as well. - -## Miscellaneous Variables -| Environment Variable | Description | Default Value | -|----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| -| `AUTO_CONFIRM` | Bypass all `guard_*` checks in the bash prompt helpers; useful for agent composition and routing | | -| `LLM_TOOL_DATA_FILE` | Set automatically by Loki on Windows. Points to a temporary file containing the JSON tool call data.
Tool scripts (`run-tool.sh`, `run-agent.sh`, etc.) read from this file instead of command-line args
to avoid JSON escaping issues when data passes through `cmd.exe` → bash. **Not intended to be set by users.** | | \ No newline at end of file diff --git a/docs/MACROS.md b/docs/MACROS.md deleted file mode 100644 index a90aafe..0000000 --- a/docs/MACROS.md +++ /dev/null @@ -1,103 +0,0 @@ -# Macros -Macros are essentially Loki "scripts"; that is, a predefined sequence of REPL commands that automate repetitive tasks or -workflows. Macros run in isolated environments, ensuring that the macros don't inherit any pre-existing role, session, -RAG, or agent state, and they will not affect your current context. - -This isolation ensures that your workspace remains clean and unaffected by macro operations. - -![Macro Example](./images/macros/macros-example.gif) - -For more information on Loki's REPL, refer to the [REPL](./REPL.md) documentation. - -## Quick Links - -- [Macro Definition](#macro-definition) - - [Step Definitions](#step-definitions) - - [Macro Variables](#macro-variables) -- [Built-In Macros](#built-in-macros) - - ---- - -## Macro Definition -Macros are defined as YAML files in the `macros` subdirectory of your Loki configuration directory. The Loki configuration -directory can vary between systems, so to find the location of your macros config directory, you can use the following -command: - -```shell -loki --info | grep 'macros_dir' | awk '{print $2}' -``` - -Macro definitions are broken into two parts: the `steps` of the macro, and an optional `variables` section that lets -users pass in variables to alter the behavior of the macro at runtime. - -### Step Definitions -The step definitions for a macro are straightforward: They are simply the exact commands you would otherwise type in the -REPL. - -**Example: Macro to generate a git commit message** -`macros/generate-commit-message.yaml` -```yaml -steps: - - .file `git diff` -- generate git commit message -``` -Usage: -```shell -$ loki --macro generate-commit-message ->> .file `git diff` -- generate a git commit message -Add documentation on macros -``` - -For a full example configuration, refer to the [example macro configuration file](../config.macro.example.yaml) in the root of this project. - -### Macro Variables -Sometimes it's useful to be able to modify the behavior of a macro at runtime. This is achieved with the `variables` -array of the macro definition. - -To pass variables to a macro, since they are just Loki scripts, the syntax is the same as it is for any other scripting -language: You just pass them alongside your invocation. - -**Example:** -```shell -$ loki --macro example-variable-macro first_argument second_argument -``` - -Each variable in the `variables` array has the following properties: -* `name` (Required): the name of the variable, which can be referenced in the actual steps of the macro using the - `{{name}}` syntax. -* `default` (Optional): A default value for the variable if no value is specified. If no default value is defined, and - no value is provided for the variable at runtime, Loki will error out. -* `rest` (Optional, Boolean): When set to `true`, this variable will collect all remaining arguments passed to the - macro. This behavior is only applicable when the variable is the last variable in the list. By default, this is - `false`. - -The `variables` array is order-dependent; that is to say that all arguments passed to the macro are positional. So be -careful about the ordering if that is important to your macro's invocation. - -**Example: Simple variable example to invoke an agent** -`macros/invoke-agent.yaml` -```yaml -variables: - - name: agent # No default value means this must be defined at runtime - - name: args - rest: true # All remaining arguments to the macro are collected into this variable - default: What can you do? # This is used if no value is passed at runtime -steps: - - .agent {{agent}} - - '{{args}}' -``` -Usage: -```shell -$ loki --macro invoke-agent sql -# or -$ loki --macro invoke-agent sql What tables are available? -``` - -For a full example configuration, refer to the [example macro configuration file](../config.macro.example.yaml) in the root of this project. - -## Built-In Macros -Loki comes packaged with some useful built-in macros. These are also good examples if you're looking for more examples -on how to make your own macros, so be sure to check out the [built-in macro definitions](../assets/macros) if you're -looking for more examples. - -* `generate-commit-message` - Generate a Git commit message based on the staged changes in the current directory diff --git a/docs/RAG.md b/docs/RAG.md deleted file mode 100644 index ea3fe9e..0000000 --- a/docs/RAG.md +++ /dev/null @@ -1,307 +0,0 @@ -# RAG -Retrieval Augmented Generation (RAG) is a method of minimizing LLM hallucinations and extending the model's context -without consuming a significant portion of the context length. It uses documents and other additional resources that you -provide to give the model more context for all of your prompts. - -Loki has a built-in vector database and full-text search engine to support RAG knowledge bases for your queries. - -The generated knowledge bases are stored in the `rag` subdirectory of your Loki configuration directory. The location of -this directory varies by system, so you can use the following command to find your RAG directory: - -```shell -loki --info | grep 'rags_dir' | awk '{print $2}' -``` - -## Quick Links - -- [Usage](#usage) - - [Persistent RAG](#persistent-rag) - - [Ephemeral RAG](#ephemeral-rag) -- [How It Works](#how-it-works) - - [1. Build](#1-build) - - [2. Lookup](#2-lookup) - - [2a. Reranking (Optional)](#2a-reranking-optional) - - [3. Prompt](#3-prompt) -- [Supported Document Sources](#supported-document-sources) -- [Document Loaders](#document-loaders) - - [Document Loader Usage](#document-loader-usage) -- [Advanced Customizations](#advanced-customizations) - - [Embedding Model](#embedding-model) - - [Reranker](#reranker) - - [Chunk Size](#chunk-size) - - [Trade-Offs](#chunk-size-trade-offs) - - [Chunk Overlap](#chunk-overlap) - - [Top K](#top-k) - - [Trade-Offs](#top-k-trade-offs) - - [RAG Template](#rag-template) - - ---- - -## Usage -There's two ways to use RAG in Loki: A persistent RAG that can be loaded on-demand for queries, and an ephemeral one for -adding RAG to a single specific query. - -### Persistent RAG -In the REPL, persistent RAG is initialized via the `.rag` command: - -![Persistent RAG example](./images/rag/persistent-rag.gif) - -The generated RAG is then saved to the `rag` subdirectory of the Loki configuration, and can then be loaded whenever you -want that knowledge base via either `.rag ` or `loki --rag `. - -### Ephemeral RAG -Short-lived RAG that is only used for a single session or query is loaded using `.file`/`--file`. - -You can use it to either execute a prompt from a file, or for temporary RAG. The difference is the usage of the `--` -separator. If you only specify a filename and no `--` separator, Loki will know to read the file contents and pass them -as a query to the model. Otherwise, the `--` separator is read to indicate that this is the end of the list of documents -to load into the ephemeral RAG, and what follows is the query to pass to the model. - -```shell -.file prompt.md # Read the file as a prompt -.file %% -- translate the last reply to italian -.file `git diff` -- generate a commit message -``` - -![Ephemeral RAG Example](./images/rag/ephemeral-rag.gif) - -Once the session ends, this RAG will no longer be accessible and is only visible to the current session. - -#### The `%%` Document Type -In addition to the usual documents that can be specified for persistent RAG, ephemeral RAG has a special `%%` value. -This value references the content of the last reply. So you can use it like this: - -```shell -.file %% -- translate the last reply to italian -``` - -The `--` indicates that this is the end of your documents and the beginning of your prompt. - -#### The `cmd` Document Type -Loki also lets you use command outputs for ephemeral RAG input. Simply enclose the command in backticks: - -```shell -.file `git diff` -- generate a commit message -``` - -The `--` indicates that this is the end of your documents and the beginning of your prompt. - -## How It Works -#### 1. Build -When you define RAG, Loki will first "build" the RAG. This means that Loki will consume the documents you specified and -generate [embeddings](https://huggingface.co/spaces/hesamation/primer-llm-embedding) for that text. This essentially just means that Loki translates the document into a language -the LLM can understand. - -These embeddings are then stored in an in-memory vector database. - -#### 2. Lookup -Loki sits between you and the model. So when you submit a prompt to the model, before Loki ever sends it, it will first -convert your prompt into embeddings (LLM language), and look for relevant snippets of text in the vector database. - -Loki then passes the top `n`-snippets of text that it finds in the vector database as additional context to the model -before your prompt. - -#### 2a. Reranking (Optional) -The lookup for relevant snippets of texts uses embeddings to find text that is semantically similar to your prompt, and -returns the top `n`-results. This often works fairly well, however these top results aren't always the most relevant for -answering the specific query. - -Reranking improves these initial results (say, the top 20-100 text snippets) and re-scores them using a more -sophisticated model. The reranker model will rank documents by their actual usefulness for answering the query to ensure -the most relevant context is passed to the model alongside your query. - -This reranking model can be customized for each RAG you build in Loki. See the [Custom Reranker](#reranker) section -below for more details on how to customize this. - -#### 3. Prompt -Finally, the text snippets that were looked up in RAG are passed to the model as additional context to your prompt, -giving the model query-specific context to answer your question. - -## Supported Document Sources -Loki supports a number of document sources that can be used for RAG: - -| Source | Example | Comments | -|--------------------------|-----------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------| -| Files | `/tmp/dir1/file1;/tmp/dir1/file2` | | -| Directory | `/tmp/dir` | Picks up all files in a directory and all its subdirectories | -| Directory (extensions} | `/tmp/dir2/**/*.{md,txt}` | Finds all files in all subdirectories with the specified extensions | -| Recursive Filename | `/tmp/*/LOKI.md` | The following files will be picked up:
  • `/tmp/dir1/LOKI.md`
  • `/tmp/dir2/subdir1/LOKI.md`
  • `/tmp/dir2/subdir2/LOKI.md`
| -| URL | `https://www.ohdsi.org/data-standardization/` | Downloads and loads the specified webpage into the
knowledge base | -| Recursive URL (Websites) | `https://github.com/OHDSI/Vocabulary-v5.0/wiki/**` | Crawls all pages under the given URL and loads them
into the knowledge base | -| Document Loader (custom) | `jina:https://cloud.google.com/bigquery/docs/reference/standard-sql/` | Use a custom document loader to parse the given document | - -## Document Loaders -Loki only has built-in support for loading text files. But that functionality can be extended to read all kinds of files -into your knowledge bases. These custom loaders are used by both RAG and for documents specified using the -`.file`/`--file` flags. - -In the global configuration file, you can specify loaders for specific document types using the `document_loaders` -setting. Each loader is defined by specifying a name and then a command that Loki will execute to load the document. - -The following variables are interpolated at runtime by Loki and can be used as placeholders in your command definitions: -* `$1` (Required) - The input file -* `$2` (Optional) - The output file. If omitted, `stdout` is used as the output destination - -**Note:** It is your responsibility to ensure that any tools used to parse documents into text that Loki can read are -installed on your system and are available on your `$PATH`. Loki does not have any built-in way of installing -dependencies for document loaders for you. - -The following are some example loaders: -```yaml -document_loaders: - pdf: 'pdftotext $1 -' # Use pdftotext to convert a PDF file to text - # (see https://poppler.freedesktop.org for details on how to install pdftotext) - docx: 'pandoc --to plain $1' # Use pandoc to convert a .docx file to text - # (see https://pandoc.org for details on how to install pandoc) - jina: 'curl -fsSL https://r.jina.ai/$1 -H "Authorization: Bearer {{JINA_API_KEY}}' # Use Jina to translate a website into text; - # Requires a Jina API key to be added to the Loki vault - git: > # Use yek to load a git repository into the knowledgebase (https://github.com/bodo-run/yek) - sh -c "yek $1 --json | jq 'map({ path: .filename, contents: .content })'" -``` - -### Document Loader Usage -Once you have your loaders defined, you can specify when Loki should use them by prefixing any RAG file/directory/URI -with the name of the loader. - -**Example: Load a git repo into RAG** -![Git Repo Loader Example](./images/rag/git-loader.png) - -**Example: Use pdf loader for ephemeral RAG** -```shell -$ loki --file pdf:some-file.pdf -``` - -## Advanced Customizations -For those familiar with RAG, Loki exposes a handful of advanced global settings that can be used to tweak your default -RAG configurations. - -### Embedding Model -When Loki queries your RAG knowledge bases, it needs to first convert your query into embeddings. By default, Loki uses -the same embedding model that was used to create the knowledge base in the first place. - -This can be customized to any other embedding model available in your configured clients by setting the -`rag_embedding_model` setting in your global Loki configuration file: - -```yaml -rag_embedding_model: null # Specifies the embedding model used for context retrieval -``` - -### Reranker -By default, Loki uses [Reciprocal Rank Fusion (RRF)](https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion) to merge vector and keyword search results. - -You can change the default reranker model to any other reranking model in your configured clients. To change the default -reranker model, simply change the value of the `rag_reranker_model` setting in your global configuration file: - -```yaml -rag_reranker_model: null # By default, -``` - -### Chunk Size -In the context of RAG, the chunk size is the maximum length of each text chunk (measured in characters) that is created -when splitting documents. In Loki, this defaults to `2000` characters. - -You can specify a different global default by setting the `rag_chunk_size` property in your global configuration file: - -```yaml -rag_chunk_size: null # Defines the size of chunks for document processing in characters -``` - -#### Chunk Size Trade-Offs -Keep in mind the following trade-offs when changing the chunk size: - -* **Smaller chunks (e.g. 256 characters):** More precise retrieval, better semantic focus, but may lack context or split - important information -* **Larger chunks (e.g. 1024 characters):** More context preserved, fewer chunks to manage, but less precise matching - and more noise in retrieved document - -### Chunk Overlap -Chunk overlap in RAG is the number of characters that overlap between consecutive chunks to maintain continuity. - ---- - -**Example:** If the following sentence is cut off at the end of one chunk - -`I was doing fine until someone brought up` - -You'll ideally want that full sentence to be picked up at the beginning of the next chunk to make sure the full meaning -is captured. So in this example, if your chunk overlap is 42 characters, then the start of the next chunk would look -like this: - -`I was doing fine until someone brought up the game. ` - ---- - -Often, this value is 10%-20% of the chunk size. - -By default, in Loki, this value is 5% the chunk size. You can override this and specify the default chunk overlap (in -characters) that Loki should use as a global default by setting the `rag_chunk_overlap` property in the global Loki -configuration file: - -```yaml -rag_chunk_overlap: null # Defines the overlap between chunks -``` - -### Top K -In RAG, `top_k` represents the top `k`-chunks to return from the vector database query. Think of it like if you search -something on Google and only care about the top 10 results, that's what you'll use for your context. - -In Loki, the default value for this is `5`. You can customize this global default by setting the `rag_top_k` property in -your global configuration file: - -```yaml -rag_top_k: 5 # Specifies the number of documents to retrieve for answering queries -``` - -#### Top K Trade-Offs -When customizing this value, keep in mind the following trade-offs so you get the best performance: - -* **Lower top_k (e.g. 3):** Faster, more focused context, lower cost, but risks missing relevant information -* **Higher top_k (e.g. 10):** More comprehensive coverage, but more noise, higher latency, increased token costs, and - potential context window constraints - -### RAG Template -When you use RAG in Loki, after Loki performs the lookup for relevant chunks of text to add as context to your query, it -will add the retrieved text chunks as context to your query before sending it to the model. The format of this context -is determined by the `rag_template` setting in your global Loki configuration file. - -This template utilizes three placeholders: -* `__INPUT__`: The user's actual query -* `__CONTEXT__`: The context retrieved from RAG -* `__SOURCES__`: A numbered list of the source file paths or URLs that the retrieved context came from - -These placeholders are replaced with the corresponding values into the template and make up what's actually passed to -the model at query-time. The `__SOURCES__` placeholder enables the model to cite which documents its answer is based on, -which is especially useful when building knowledge-base assistants that need to provide verifiable references. - -The default template that Loki uses is the following: - -```text -Answer the query based on the context while respecting the rules. (user query, some textual context and rules, all inside xml tags) - - -__CONTEXT__ - - - -__SOURCES__ - - - -- If you don't know, just say so. -- If you are not sure, ask for clarification. -- Answer in the same language as the user query. -- If the context appears unreadable or of poor quality, tell the user then answer as best as you can. -- If the answer is not in the context but you think you know the answer, explain that to the user then answer with your own knowledge. -- Answer directly and without using xml tags. -- When using information from the context, cite the relevant source from the section. - - - -__INPUT__ - -``` - -You can customize this template by specifying the `rag_template` setting in your global Loki configuration file. Your -template *must* include both the `__INPUT__` and `__CONTEXT__` placeholders in order for it to be valid. The -`__SOURCES__` placeholder is optional. If it is omitted, source references will not be included in the prompt. diff --git a/docs/REPL-PROMPT.md b/docs/REPL-PROMPT.md deleted file mode 100644 index 01acbb9..0000000 --- a/docs/REPL-PROMPT.md +++ /dev/null @@ -1,117 +0,0 @@ -# Customize REPL Prompt - -The prompt you see when you start the Loki REPL can be customized to your liking. This is achieved via the `left_prompt` -and `right_prompt` settings in the global Loki configuration file: - -```yaml -left_prompt: '{color.red}{model}){color.green}{?session {?agent {agent}>}{session}{?role /}}{!session {?agent {agent}>}}{role}{?rag @{rag}}{color.cyan}{?session )}{!session >}{color.reset} ' -right_prompt: '{color.purple}{?session {?consume_tokens {consume_tokens}({consume_percent}%)}{!consume_tokens {consume_tokens}}}{color.reset}' -``` - -The location of the global configuration file differs between systems, so you can use the following command to find your -global configuration file's location: - -```shell -loki --info | grep 'config_file' | awk '{print $2}' -``` - -## Quick Links - -- [Syntax](#syntax) -- [Variables](#variables) - - -## Syntax -The syntax for the prompts consists of plain text and templates contained in `{...}`. The plain text is -printed exactly as given. - -The syntax for the templates `{...}` is as follows: - -* `{variable}` - Replaced with the value of `variable` -* `{?variable