diff --git a/Cargo.lock b/Cargo.lock index 33b3d81..945837f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,21 +25,21 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alsa" -version = "0.9.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43" +checksum = "812947049edcd670a82cd5c73c3661d2e58468577ba8489de58e1a73c04cbd5d" dependencies = [ "alsa-sys", - "bitflags 2.10.0", + "bitflags", "cfg-if", "libc", ] [[package]] name = "alsa-sys" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +checksum = "ad7569085a265dd3f607ebecce7458eaab2132a84393534c95b18dcbc3f31e04" dependencies = [ "libc", "pkg-config", @@ -268,51 +268,24 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.5" +version = "0.71.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" dependencies = [ - "bitflags 2.10.0", + "bitflags", "cexpr", "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", + "itertools 0.13.0", "log", "prettyplease", "proc-macro2", "quote", "regex", - "rustc-hash 1.1.0", + "rustc-hash", "shlex", "syn", - "which", ] -[[package]] -name = "bindgen" -version = "0.72.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" -dependencies = [ - "bitflags 2.10.0", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "proc-macro2", - "quote", - "regex", - "rustc-hash 2.1.1", - "shlex", - "syn", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.10.0" @@ -334,6 +307,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + [[package]] name = "bumpalo" version = "3.19.0" @@ -578,22 +560,16 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "coreaudio-rs" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" -dependencies = [ - "bitflags 1.3.2", - "core-foundation-sys", - "coreaudio-sys", -] - -[[package]] -name = "coreaudio-sys" -version = "0.2.17" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceec7a6067e62d6f931a2baf6f3a751f4a892595bcec1461a3c94ef9949864b6" +checksum = "d15c3c3cee7c087938f7ad1c3098840b3ef1f1bdc7f6e496336c3b1e7a6f3914" dependencies = [ - "bindgen 0.72.1", + "bitflags", + "libc", + "objc2-audio-toolbox", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", ] [[package]] @@ -777,12 +753,11 @@ dependencies = [ [[package]] name = "cpal" -version = "0.15.3" +version = "0.17.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" +checksum = "d8942da362c0f0d895d7cac616263f2f9424edc5687364dfd1d25ef7eba506d7" dependencies = [ "alsa", - "core-foundation-sys", "coreaudio-rs", "dasp_sample", "jni", @@ -791,7 +766,15 @@ dependencies = [ "mach2", "ndk", "ndk-context", - "oboe", + "num-derive", + "num-traits", + "objc2", + "objc2-audio-toolbox", + "objc2-avf-audio", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -822,7 +805,7 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.10.0", + "bitflags", "crossterm_winapi", "mio", "parking_lot", @@ -1033,6 +1016,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags", + "objc2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -1391,15 +1384,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "http" version = "1.3.1" @@ -1553,7 +1537,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.62.2", + "windows-core", ] [[package]] @@ -1737,15 +1721,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -1852,17 +1827,11 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" -version = "0.2.177" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libloading" @@ -1880,7 +1849,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "bitflags 2.10.0", + "bitflags", "libc", ] @@ -1949,9 +1918,9 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "mach2" -version = "0.4.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +checksum = "6a1b95cd5421ec55b445b5ae102f5ea0e768de1f82bd3001e11f426c269c3aea" dependencies = [ "libc", ] @@ -2058,11 +2027,11 @@ dependencies = [ [[package]] name = "ndk" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.10.0", + "bitflags", "jni-sys", "log", "ndk-sys", @@ -2078,9 +2047,9 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" -version = "0.5.0+25.2.9519653" +version = "0.6.0+11769913" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" dependencies = [ "jni-sys", ] @@ -2200,35 +2169,101 @@ dependencies = [ ] [[package]] -name = "objc_id" -version = "0.1.1" +name = "objc2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" dependencies = [ - "objc", + "objc2-encode", ] [[package]] -name = "oboe" -version = "0.6.1" +name = "objc2-audio-toolbox" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" +checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08" dependencies = [ - "jni", - "ndk", - "ndk-context", - "num-derive", - "num-traits", - "oboe-sys", + "bitflags", + "libc", + "objc2", + "objc2-core-audio", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation", ] [[package]] -name = "oboe-sys" -version = "0.6.1" +name = "objc2-avf-audio" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" +checksum = "13a380031deed8e99db00065c45937da434ca987c034e13b87e4441f9e4090be" dependencies = [ - "cc", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-audio" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1eebcea8b0dbff5f7c8504f3107c68fc061a3eb44932051c8cf8a68d969c3b2" +dependencies = [ + "dispatch2", + "objc2", + "objc2-core-audio-types", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-audio-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c" +dependencies = [ + "bitflags", + "objc2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", + "block2", + "dispatch2", + "libc", + "objc2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc_id" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" +dependencies = [ + "objc", ] [[package]] @@ -2249,7 +2284,7 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 2.10.0", + "bitflags", "libc", "once_cell", "onig_sys", @@ -2271,7 +2306,7 @@ version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.10.0", + "bitflags", "cfg-if", "foreign-types", "libc", @@ -2540,7 +2575,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" dependencies = [ - "bitflags 2.10.0", + "bitflags", "getopts", "memchr", "pulldown-cmark-escape", @@ -2595,7 +2630,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.1", + "rustc-hash", "rustls", "socket2 0.6.1", "thiserror 2.0.17", @@ -2616,7 +2651,7 @@ dependencies = [ "lru-slab", "rand 0.9.2", "ring", - "rustc-hash 2.1.1", + "rustc-hash", "rustls", "rustls-pki-types", "slab", @@ -2720,7 +2755,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" dependencies = [ - "bitflags 2.10.0", + "bitflags", "cassowary", "compact_str 0.8.1", "crossterm", @@ -2741,7 +2776,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ef8dea09a92caaf73bff7adb70b76162e5937524058a7e5bff37869cbbec293" dependencies = [ - "bitflags 2.10.0", + "bitflags", "compact_str 0.9.0", "hashbrown 0.16.0", "indoc", @@ -2770,7 +2805,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags", ] [[package]] @@ -3053,9 +3088,9 @@ dependencies = [ [[package]] name = "rubato" -version = "0.15.0" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5d18b486e7d29a408ef3f825bc1327d8f87af091c987ca2f5b734625940e234" +checksum = "5258099699851cfd0082aeb645feb9c084d9a5e1f1b8d5372086b989fc5e56a1" dependencies = [ "num-complex", "num-integer", @@ -3063,12 +3098,6 @@ dependencies = [ "realfft", ] -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -3104,7 +3133,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.10.0", + "bitflags", "errno", "libc", "linux-raw-sys 0.4.15", @@ -3117,7 +3146,7 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.10.0", + "bitflags", "errno", "libc", "linux-raw-sys 0.11.0", @@ -3302,7 +3331,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.10.0", + "bitflags", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -3315,7 +3344,7 @@ version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ - "bitflags 2.10.0", + "bitflags", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -3655,7 +3684,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.10.0", + "bitflags", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -3998,7 +4027,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "bitflags 2.10.0", + "bitflags", "bytes", "http", "http-body", @@ -4015,7 +4044,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.10.0", + "bitflags", "bytes", "futures-util", "http", @@ -4431,34 +4460,22 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - [[package]] name = "whisper-rs" -version = "0.12.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c597ac8a9d5c4719fee232abc871da184ea50a4fea38d2d00348fd95072b2b0" +checksum = "71ea5d2401f30f51d08126a2d133fee4c1955136519d7ac6cf6f5ac0a91e6bc8" dependencies = [ "whisper-rs-sys", ] [[package]] name = "whisper-rs-sys" -version = "0.10.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22f00ed0995463eecc34ef89905845f6bf6fd37ea70789fed180520050da8f8" +checksum = "b5e2a6e06e7ac7b8f53c53a5f50bb0bc823ba69b63ecd887339f807a5598bbd2" dependencies = [ - "bindgen 0.69.5", + "bindgen", "cfg-if", "cmake", "fs_extra", @@ -4497,22 +4514,23 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.54.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" +checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580" dependencies = [ - "windows-core 0.54.0", - "windows-targets 0.52.6", + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", ] [[package]] -name = "windows-core" -version = "0.54.0" +name = "windows-collections" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" dependencies = [ - "windows-result 0.1.2", - "windows-targets 0.52.6", + "windows-core", ] [[package]] @@ -4528,6 +4546,17 @@ dependencies = [ "windows-strings 0.5.1", ] +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link 0.2.1", + "windows-threading", +] + [[package]] name = "windows-implement" version = "0.60.2" @@ -4562,6 +4591,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link 0.2.1", +] + [[package]] name = "windows-registry" version = "0.5.3" @@ -4573,15 +4612,6 @@ dependencies = [ "windows-strings 0.4.2", ] -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.3.4" @@ -4726,6 +4756,15 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link 0.2.1", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" diff --git a/Cargo.toml b/Cargo.toml index 4c8ee27..93176a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ members = [ ] [workspace.package] -version = "2.5.0" +version = "2.5.1" edition = "2024" rust-version = "1.86" authors = ["Sopaco"] diff --git a/cortex-mem-core/src/automation/manager.rs b/cortex-mem-core/src/automation/manager.rs index 1b36ad8..797c9f5 100644 --- a/cortex-mem-core/src/automation/manager.rs +++ b/cortex-mem-core/src/automation/manager.rs @@ -6,7 +6,7 @@ use crate::{ use std::collections::HashSet; use std::sync::Arc; use std::time::Duration; -use tokio::sync::mpsc; +use tokio::sync::{mpsc, Semaphore}; use tracing::{info, warn}; /// 自动化配置 @@ -26,6 +26,8 @@ pub struct AutomationConfig { pub auto_generate_layers_on_startup: bool, /// 每N条消息触发一次L0/L1生成(0表示禁用) pub generate_layers_every_n_messages: usize, + /// 最大并发 LLM 任务数(防止压垮 LLM API) + pub max_concurrent_llm_tasks: usize, } impl Default for AutomationConfig { @@ -33,11 +35,12 @@ impl Default for AutomationConfig { Self { auto_index: true, auto_extract: true, - index_on_message: false, // 默认不实时索引(性能考虑) - index_on_close: true, // 默认会话关闭时索引 + index_on_message: false, // 默认不实时索引(性能考虑) + index_on_close: true, // 默认会话关闭时索引 index_batch_delay: 2, auto_generate_layers_on_startup: false, // 默认关闭(避免启动时阻塞) generate_layers_every_n_messages: 0, // 默认禁用(避免频繁LLM调用) + max_concurrent_llm_tasks: 3, // 默认最多3个并发LLM任务 } } } @@ -46,8 +49,10 @@ impl Default for AutomationConfig { pub struct AutomationManager { indexer: Arc, extractor: Option>, - layer_generator: Option>, // 层级生成器 + layer_generator: Option>, config: AutomationConfig, + /// 并发限制信号量 + llm_semaphore: Arc, } impl AutomationManager { @@ -57,11 +62,13 @@ impl AutomationManager { extractor: Option>, config: AutomationConfig, ) -> Self { + let llm_semaphore = Arc::new(Semaphore::new(config.max_concurrent_llm_tasks)); Self { indexer, extractor, - layer_generator: None, // 初始为 None,需要单独设置 + layer_generator: None, config, + llm_semaphore, } } @@ -71,6 +78,11 @@ impl AutomationManager { self } + /// 获取并发限制信号量(供外部使用) + pub fn llm_semaphore(&self) -> Arc { + self.llm_semaphore.clone() + } + /// 🎯 核心方法:启动自动化任务 pub async fn start(self, mut event_rx: mpsc::UnboundedReceiver) -> Result<()> { info!("Starting AutomationManager with config: {:?}", self.config); @@ -80,7 +92,10 @@ impl AutomationManager { if let Some(ref generator) = self.layer_generator { info!("启动时检查并生成缺失的 L0/L1 文件..."); let generator_clone = generator.clone(); + let semaphore = self.llm_semaphore.clone(); tokio::spawn(async move { + // 获取信号量许可 + let _permit = semaphore.acquire().await; match generator_clone.ensure_all_layers().await { Ok(stats) => { info!( @@ -168,13 +183,16 @@ impl AutomationManager { count, session_id ); - // 异步生成L0/L1(避免阻塞) + // 异步生成L0/L1(带并发限制) let generator_clone = generator.clone(); let indexer_clone = self.indexer.clone(); let session_id_clone = session_id.clone(); let auto_index = self.config.auto_index; + let semaphore = self.llm_semaphore.clone(); tokio::spawn(async move { + // 获取信号量许可(限制并发) + let _permit = semaphore.acquire().await; let timeline_uri = format!("cortex://session/{}/timeline", session_id_clone); @@ -240,15 +258,18 @@ impl AutomationManager { session_id ); - // 🔧 异步执行所有后处理任务,避免阻塞事件循环 + // 异步执行所有后处理任务(带并发限制) let extractor = self.extractor.clone(); let generator = self.layer_generator.clone(); let indexer = self.indexer.clone(); let auto_extract = self.config.auto_extract; let auto_index = self.config.auto_index; let session_id_clone = session_id.clone(); + let semaphore = self.llm_semaphore.clone(); tokio::spawn(async move { + // 获取信号量许可(限制并发) + let _permit = semaphore.acquire().await; let start = tokio::time::Instant::now(); // 1. 自动提取记忆(如果配置了且有extractor) @@ -364,4 +385,4 @@ impl AutomationManager { } } } -} +} \ No newline at end of file diff --git a/cortex-mem-core/src/automation/sync.rs b/cortex-mem-core/src/automation/sync.rs index 2e8e203..c26d811 100644 --- a/cortex-mem-core/src/automation/sync.rs +++ b/cortex-mem-core/src/automation/sync.rs @@ -8,6 +8,7 @@ use crate::{ ContextLayer, Result, }; +use std::collections::HashSet; use std::sync::Arc; use tracing::{debug, info, warn}; @@ -185,32 +186,53 @@ impl SyncManager { } /// 同步单个目录(非递归) + /// + /// 优化:在目录级别批量处理 L0/L1,避免每个文件重复检查 fn sync_directory<'a>( &'a self, uri: &'a str, - layer: &'a str, + _layer: &'a str, ) -> std::pin::Pin> + Send + 'a>> { Box::pin(async move { let entries = self.filesystem.list(uri).await?; let mut stats = SyncStats::default(); - for entry in entries { + // 收集子目录和文件 + let mut subdirs: Vec = Vec::new(); + let mut files: Vec = Vec::new(); + + for entry in &entries { if entry.is_directory { - // 递归处理子目录 - let sub_stats = self.sync_directory(&entry.uri, layer).await?; - stats.add(&sub_stats); - } else if entry.name.ends_with(".md") { - // 处理Markdown文件 - match self.sync_file(&entry.uri, layer).await { - Ok(true) => stats.indexed_files += 1, - Ok(false) => stats.skipped_files += 1, - Err(e) => { - warn!("Failed to sync {}: {}", entry.uri, e); - stats.error_files += 1; - } + subdirs.push(entry.uri.clone()); + } else if entry.name.ends_with(".md") && !entry.name.starts_with('.') { + files.push(entry.uri.clone()); + } + } + + // 先在目录级别批量索引 L0/L1(避免重复) + if !files.is_empty() { + if let Err(e) = self.sync_directory_layers(uri).await { + debug!("Failed to sync L0/L1 for directory {}: {}", uri, e); + } + } + + // 然后处理 L2 文件 + for file_uri in files { + match self.sync_file_l2(&file_uri).await { + Ok(true) => stats.indexed_files += 1, + Ok(false) => stats.skipped_files += 1, + Err(e) => { + warn!("Failed to sync {}: {}", file_uri, e); + stats.error_files += 1; } - stats.total_files += 1; } + stats.total_files += 1; + } + + // 递归处理子目录 + for subdir in subdirs { + let sub_stats = self.sync_directory(&subdir, "L2").await?; + stats.add(&sub_stats); } Ok(stats) @@ -237,66 +259,58 @@ impl SyncManager { } } - for entry in entries { + // 收集子目录和文件 + let mut subdirs: Vec = Vec::new(); + let mut files: Vec = Vec::new(); + + for entry in &entries { if entry.is_directory { - // 递归处理子目录 - let sub_stats = self.sync_directory_recursive(&entry.uri).await?; - stats.add(&sub_stats); - } else if entry.name.ends_with(".md") { - // 处理Markdown文件 - match self.sync_file(&entry.uri, "L2").await { - Ok(true) => stats.indexed_files += 1, - Ok(false) => stats.skipped_files += 1, - Err(e) => { - warn!("Failed to sync {}: {}", entry.uri, e); - stats.error_files += 1; - } + subdirs.push(entry.uri.clone()); + } else if entry.name.ends_with(".md") && !entry.name.starts_with('.') { + files.push(entry.uri.clone()); + } + } + + // 先在目录级别批量索引 L0/L1(避免重复) + if !files.is_empty() { + if let Err(e) = self.sync_directory_layers(uri).await { + debug!("Failed to sync L0/L1 for directory {}: {}", uri, e); + } + } + + // 然后处理 L2 文件 + for file_uri in files { + match self.sync_file_l2(&file_uri).await { + Ok(true) => stats.indexed_files += 1, + Ok(false) => stats.skipped_files += 1, + Err(e) => { + warn!("Failed to sync {}: {}", file_uri, e); + stats.error_files += 1; } - stats.total_files += 1; } + stats.total_files += 1; + } + + // 递归处理子目录 + for subdir in subdirs { + let sub_stats = self.sync_directory_recursive(&subdir).await?; + stats.add(&sub_stats); } Ok(stats) }) } - /// 同步单个文件(支持分层向量索引) - async fn sync_file(&self, uri: &str, layer: &str) -> Result { - // 检查是否已经索引(检查L2层) - let l2_id = uri_to_vector_id(uri, ContextLayer::L2Detail); - if self.is_indexed(&l2_id).await? { - debug!("File already indexed: {}", uri); - return Ok(false); - } - - // 1. 读取并索引L2原始内容 - let l2_content = self.filesystem.read(uri).await?; - let l2_embedding = self.embedding.embed(&l2_content).await?; - let l2_metadata = self.parse_metadata(uri, layer)?; - - let l2_memory = Memory { - id: l2_id.clone(), - content: l2_content.clone(), - embedding: l2_embedding, - created_at: chrono::Utc::now(), - updated_at: chrono::Utc::now(), - metadata: l2_metadata, - }; - self.vector_store.insert(&l2_memory).await?; - debug!("L2 indexed: {}", uri); - - // 2. 尝试读取并索引L0 abstract (目录级别) - // 对于 timeline 文件,L0/L1 是目录级别的 - // 例如: cortex://session/abc/timeline/10_00.md 的 L0 是 cortex://session/abc/timeline/.abstract.md - // 向量 ID 应该基于目录 URI: cortex://session/abc/timeline - let (dir_uri, layer_file_uri) = Self::get_layer_info(uri, "L0"); - if let Ok(l0_content) = self.filesystem.read(&layer_file_uri).await { - // 使用目录 URI 生成向量 ID,确保同一目录下的所有文件共享同一个 L0/L1 向量 - let l0_id = uri_to_vector_id(&dir_uri, ContextLayer::L0Abstract); - if !self.is_indexed(&l0_id).await? { + /// 在目录级别批量索引 L0/L1(优化:避免每个文件重复检查) + async fn sync_directory_layers(&self, dir_uri: &str) -> Result<()> { + // 索引 L0 abstract + let l0_file_uri = format!("{}/.abstract.md", dir_uri); + let l0_id = uri_to_vector_id(dir_uri, ContextLayer::L0Abstract); + + if !self.is_indexed(&l0_id).await? { + if let Ok(l0_content) = self.filesystem.read(&l0_file_uri).await { let l0_embedding = self.embedding.embed(&l0_content).await?; - // 元数据使用目录 URI - let l0_metadata = self.parse_metadata(&dir_uri, "L0")?; + let l0_metadata = self.parse_metadata(dir_uri, "L0")?; let l0_memory = Memory { id: l0_id, @@ -307,17 +321,18 @@ impl SyncManager { metadata: l0_metadata, }; self.vector_store.insert(&l0_memory).await?; - debug!("L0 indexed for directory {}: {}", dir_uri, layer_file_uri); + debug!("L0 indexed for directory: {}", dir_uri); } } - // 3. 尝试读取并索引L1 overview (目录级别) - let (dir_uri, layer_file_uri) = Self::get_layer_info(uri, "L1"); - if let Ok(l1_content) = self.filesystem.read(&layer_file_uri).await { - let l1_id = uri_to_vector_id(&dir_uri, ContextLayer::L1Overview); - if !self.is_indexed(&l1_id).await? { + // 索引 L1 overview + let l1_file_uri = format!("{}/.overview.md", dir_uri); + let l1_id = uri_to_vector_id(dir_uri, ContextLayer::L1Overview); + + if !self.is_indexed(&l1_id).await? { + if let Ok(l1_content) = self.filesystem.read(&l1_file_uri).await { let l1_embedding = self.embedding.embed(&l1_content).await?; - let l1_metadata = self.parse_metadata(&dir_uri, "L1")?; + let l1_metadata = self.parse_metadata(dir_uri, "L1")?; let l1_memory = Memory { id: l1_id, @@ -328,43 +343,43 @@ impl SyncManager { metadata: l1_metadata, }; self.vector_store.insert(&l1_memory).await?; - debug!("L1 indexed for directory {}: {}", dir_uri, layer_file_uri); + debug!("L1 indexed for directory: {}", dir_uri); } } - Ok(true) + Ok(()) } - /// 获取分层信息 (目录 URI 和层文件 URI) - /// - /// 对于 timeline 文件: - /// - 输入: cortex://session/abc/timeline/10_00.md - /// - L0 输出: (cortex://session/abc/timeline, cortex://session/abc/timeline/.abstract.md) - /// - /// 对于 user/agent 记忆: - /// - 输入: cortex://user/preferences/language.md - /// - L0 输出: (cortex://user/preferences/language.md, cortex://user/preferences/.abstract.md) - fn get_layer_info(file_uri: &str, layer: &str) -> (String, String) { - let dir = file_uri - .rsplit_once('/') - .map(|(dir, _)| dir) - .unwrap_or(file_uri); - - let layer_file_uri = match layer { - "L0" => format!("{}/.abstract.md", dir), - "L1" => format!("{}/.overview.md", dir), - _ => file_uri.to_string(), + /// 仅同步文件的 L2 层(优化:分离 L0/L1 处理) + async fn sync_file_l2(&self, uri: &str) -> Result { + // 检查是否已经索引(检查L2层) + let l2_id = uri_to_vector_id(uri, ContextLayer::L2Detail); + if self.is_indexed(&l2_id).await? { + debug!("File already indexed (L2): {}", uri); + return Ok(false); + } + + // 读取并索引L2原始内容 + let l2_content = self.filesystem.read(uri).await?; + let l2_embedding = self.embedding.embed(&l2_content).await?; + let l2_metadata = self.parse_metadata(uri, "L2")?; + + let l2_memory = Memory { + id: l2_id, + content: l2_content, + embedding: l2_embedding, + created_at: chrono::Utc::now(), + updated_at: chrono::Utc::now(), + metadata: l2_metadata, }; - - // 目录 URI 用于向量 ID 生成 - // 对于 timeline,目录 URI 是文件所在的目录 - // 对于 user/agent,目录 URI 也是文件所在的目录 - (dir.to_string(), layer_file_uri) + self.vector_store.insert(&l2_memory).await?; + debug!("L2 indexed: {}", uri); + + Ok(true) } - /// 检查文件是否已索引 + /// 检查向量是否已索引 async fn is_indexed(&self, id: &str) -> Result { - // 尝试从向量数据库查询 match self.vector_store.get(id).await { Ok(Some(_)) => Ok(true), Ok(None) => Ok(false), @@ -376,11 +391,7 @@ impl SyncManager { } /// 解析URI获取元数据(支持layer标识) - fn parse_metadata( - &self, - uri: &str, - layer: &str, - ) -> Result { + fn parse_metadata(&self, uri: &str, layer: &str) -> Result { use serde_json::Value; // 从URI中提取信息 @@ -447,6 +458,25 @@ impl SyncManager { let layer_manager = LayerManager::new(self.filesystem.clone(), self.llm_client.clone()); layer_manager.generate_timeline_layers(timeline_uri).await } + + /// 批量同步多个目录(供外部使用) + pub async fn sync_directories(&self, dir_uris: &[String]) -> Result { + let mut total_stats = SyncStats::default(); + let mut processed_dirs: HashSet = HashSet::new(); + + for dir_uri in dir_uris { + // 跳过已处理的目录 + if processed_dirs.contains(dir_uri) { + continue; + } + processed_dirs.insert(dir_uri.clone()); + + let stats = self.sync_specific_path(dir_uri).await?; + total_stats.add(&stats); + } + + Ok(total_stats) + } } impl SyncStats { @@ -456,4 +486,4 @@ impl SyncStats { self.skipped_files += other.skipped_files; self.error_files += other.error_files; } -} +} \ No newline at end of file diff --git a/cortex-mem-core/src/memory_event_coordinator.rs b/cortex-mem-core/src/memory_event_coordinator.rs index 465b3f3..76d03dc 100644 --- a/cortex-mem-core/src/memory_event_coordinator.rs +++ b/cortex-mem-core/src/memory_event_coordinator.rs @@ -1033,24 +1033,40 @@ Return ONLY the JSON object. No additional text before or after."#, ) } - /// Parse the LLM extraction response + /// Parse the LLM extraction response with detailed error logging fn parse_extraction_response(&self, response: &str) -> ExtractedMemories { // Try to extract JSON from the response let json_str = if response.starts_with('{') { response.to_string() } else { - response + // Find JSON object in response + let found = response .find('{') - .and_then(|start| response.rfind('}').map(|end| &response[start..=end])) - .map(|s| s.to_string()) - .unwrap_or_default() + .and_then(|start| response.rfind('}').map(|end| (start, end))); + + match found { + Some((start, end)) => response[start..=end].to_string(), + None => { + warn!( + "LLM response contains no JSON object. Response preview: {}", + &response[..response.len().min(500)] + ); + return ExtractedMemories::default(); + } + } }; - if json_str.is_empty() { - return ExtractedMemories::default(); + match serde_json::from_str::(&json_str) { + Ok(memories) => memories, + Err(e) => { + warn!( + "Failed to parse LLM extraction response: {}. JSON preview: {}", + e, + &json_str[..json_str.len().min(1000)] + ); + ExtractedMemories::default() + } } - - serde_json::from_str(&json_str).unwrap_or_default() } /// Get current event statistics diff --git a/cortex-mem-mcp/src/service.rs b/cortex-mem-mcp/src/service.rs index 2684ac9..8ccecc0 100644 --- a/cortex-mem-mcp/src/service.rs +++ b/cortex-mem-mcp/src/service.rs @@ -8,7 +8,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::sync::Arc; use std::sync::atomic::{AtomicU64, Ordering}; -use std::time::Instant; +use std::time::{Instant, SystemTime, UNIX_EPOCH}; use tokio::sync::RwLock; use tracing::{debug, error, info, warn}; @@ -298,11 +298,12 @@ impl MemoryMcpService { state.message_count = 0; state.last_processed = Some(Instant::now()); - // Update global processing time - self.last_global_process.store( - Instant::now().elapsed().as_secs(), - Ordering::Relaxed, - ); + // Update global processing time (Unix timestamp in seconds) + let now_ts = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + self.last_global_process.store(now_ts, Ordering::Relaxed); // Send SessionClosed event to MemoryEventCoordinator // This triggers the full processing pipeline: diff --git a/cortex-mem-tools/src/errors.rs b/cortex-mem-tools/src/errors.rs index a4233bf..bc218d8 100644 --- a/cortex-mem-tools/src/errors.rs +++ b/cortex-mem-tools/src/errors.rs @@ -7,6 +7,10 @@ pub enum ToolsError { #[error("Invalid input: {0}")] InvalidInput(String), + /// Validation error + #[error("Validation error: {0}")] + ValidationError(String), + /// Runtime error during operation #[error("Runtime error: {0}")] Runtime(String), diff --git a/cortex-mem-tools/src/lib.rs b/cortex-mem-tools/src/lib.rs index 3f34b61..fe64824 100644 --- a/cortex-mem-tools/src/lib.rs +++ b/cortex-mem-tools/src/lib.rs @@ -9,6 +9,9 @@ pub use mcp::{ToolDefinition, get_mcp_tool_definition, get_mcp_tool_definitions} pub use operations::MemoryOperations; pub use types::*; +// 重新导出长期运行服务 API 相关类型 +pub use operations::{PendingStatus, ProcessingResult}; + pub use cortex_mem_core::automation::GenerationStats; // 重新导出 SyncStats 以便外部使用 diff --git a/cortex-mem-tools/src/operations.rs b/cortex-mem-tools/src/operations.rs index c9b6538..ec18fd8 100644 --- a/cortex-mem-tools/src/operations.rs +++ b/cortex-mem-tools/src/operations.rs @@ -14,10 +14,11 @@ use cortex_mem_core::{ layers::manager::LayerManager, llm::LLMClient, search::VectorSearchEngine, - vector_store::{QdrantVectorStore, VectorStore}, // 🔧 添加VectorStore trait + vector_store::{QdrantVectorStore, VectorStore}, }; use std::sync::Arc; use tokio::sync::RwLock; +use tracing::warn; /// High-level memory operations /// @@ -230,6 +231,7 @@ impl MemoryOperations { index_batch_delay: 1, auto_generate_layers_on_startup: false, // 启动时不生成(避免阻塞) generate_layers_every_n_messages: 5, // 每5条消息生成一次L0/L1 + max_concurrent_llm_tasks: 3, // 最多3个并发LLM任务 }; // 创建LayerGenerator(用于退出时手动生成) @@ -736,7 +738,7 @@ impl MemoryOperations { .await } else { // 降级:如果没有 coordinator,使用简单的等待 - log::warn!("⚠️ MemoryEventCoordinator 未初始化,使用简单等待"); + warn!("⚠️ MemoryEventCoordinator 未初始化,使用简单等待"); tokio::time::sleep(Duration::from_secs(max_wait_secs.min(5))).await; true } @@ -760,8 +762,117 @@ impl MemoryOperations { if let Some(ref coordinator) = self.event_coordinator { coordinator.flush_and_wait(interval).await } else { - log::warn!("⚠️ MemoryEventCoordinator 未初始化,跳过等待"); + warn!("⚠️ MemoryEventCoordinator 未初始化,跳过等待"); true } } + + // ==================== Long-Running Service APIs ==================== + // 以下 API 专为长期后台运行的服务(如 ZeroClaw)设计 + + /// 手动触发记忆处理(供外部调度使用) + /// + /// 适用于长期后台运行的服务,可以在任意时间点手动触发记忆处理, + /// 而不需要依赖 SessionClosed 事件。 + /// + /// # Arguments + /// * `scope` - 处理范围:User, Agent, Session, 或 Resources + /// * `owner_id` - 所有者 ID(如 user_id, agent_id, session_id) + /// + /// # Returns + /// 返回处理结果,包含更新的文件数和索引数 + pub async fn trigger_processing( + &self, + scope: &str, + owner_id: &str, + ) -> crate::Result { + let memory_scope = match scope.to_lowercase().as_str() { + "user" => cortex_mem_core::MemoryScope::User, + "agent" => cortex_mem_core::MemoryScope::Agent, + "session" => cortex_mem_core::MemoryScope::Session, + "resources" => cortex_mem_core::MemoryScope::Resources, + _ => { + return Err(crate::ToolsError::ValidationError(format!( + "Invalid scope: {}. Valid values: user, agent, session, resources", + scope + ))); + } + }; + + tracing::info!("Manual trigger processing for {:?}/{}", memory_scope, owner_id); + + // 强制更新层级 + if let Some(ref coordinator) = self.event_coordinator { + coordinator + .force_full_update(&memory_scope, owner_id) + .await?; + } else { + warn!("MemoryEventCoordinator 未初始化,无法触发处理"); + return Ok(ProcessingResult::default()); + } + + // 索引文件(根据 scope 和 owner_id 确定路径) + let sync_stats = match memory_scope { + cortex_mem_core::MemoryScope::Session => { + self.index_session_files(owner_id).await? + } + _ => { + // 其他 scope 使用全局索引 + self.index_all_files().await? + } + }; + + Ok(ProcessingResult { + scope: scope.to_string(), + owner_id: owner_id.to_string(), + layers_updated: sync_stats.indexed_files, + vectors_indexed: sync_stats.indexed_files, + }) + } + + /// 获取待处理队列状态 + /// + /// 返回当前的事件统计信息,用于监控和调度。 + pub async fn pending_status(&self) -> PendingStatus { + if let Some(ref coordinator) = self.event_coordinator { + let stats = coordinator.get_stats().await; + PendingStatus { + memory_created: stats.memory_created, + memory_updated: stats.memory_updated, + memory_deleted: stats.memory_deleted, + layers_updated: stats.layers_updated, + sessions_closed: stats.sessions_closed, + } + } else { + PendingStatus::default() + } + } +} + +/// 处理结果 +#[derive(Debug, Clone, Default)] +pub struct ProcessingResult { + /// 处理范围 + pub scope: String, + /// 所有者 ID + pub owner_id: String, + /// 更新的层级文件数 + pub layers_updated: usize, + /// 索引的向量数 + pub vectors_indexed: usize, +} + +/// 待处理状态(事件统计) +#[derive(Debug, Clone, Default)] +pub struct PendingStatus { + /// 创建的记忆数 + pub memory_created: u64, + /// 更新的记忆数 + pub memory_updated: u64, + /// 删除的记忆数 + pub memory_deleted: u64, + /// 更新的层级数 + pub layers_updated: u64, + /// 关闭的会话数 + pub sessions_closed: u64, } diff --git a/examples/cortex-mem-tars/Cargo.toml b/examples/cortex-mem-tars/Cargo.toml index abb6bf0..2d6d267 100644 --- a/examples/cortex-mem-tars/Cargo.toml +++ b/examples/cortex-mem-tars/Cargo.toml @@ -63,7 +63,7 @@ clipboard = "0.5" clap = { version = "4.5", features = ["derive"] } # Audio input -cpal = "0.15" -rubato = "0.15" -whisper-rs = "0.12" +cpal = "0.17" +rubato = "0.16" +whisper-rs = "0.15" libc = "0.2"