diff --git a/Cargo.lock b/Cargo.lock index 3e3ab5a..d4c2bc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,8 +35,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", + "const-random", "getrandom 0.3.3", "once_cell", + "serde", "version_check", "zerocopy", ] @@ -50,6 +52,24 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4508988c62edf04abd8d92897fca0c2995d907ce1dfeaf369dac3716a40685" +dependencies = [ + "as-slice", +] + +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -71,6 +91,12 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_log-sys" version = "0.3.2" @@ -162,12 +188,268 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arc-swap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d03449bb8ca2cc2ef70869af31463d1ae5ccc8fa3e334b307203fbf815207e" +dependencies = [ + "rustversion", +] + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "arrow" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3a3ec4fe573f9d1f59d99c085197ef669b00b088ba1d7bb75224732d9357a74" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-csv", + "arrow-data", + "arrow-ipc", + "arrow-json", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dcf19f07792d8c7f91086c67b574a79301e367029b17fcf63fb854332246a10" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "num", +] + +[[package]] +name = "arrow-array" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7845c32b41f7053e37a075b3c2f29c6f5ea1b3ca6e5df7a2d325ee6e1b4a63cf" +dependencies = [ + "ahash 0.8.12", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "chrono-tz", + "half", + "hashbrown 0.15.5", + "num", +] + +[[package]] +name = "arrow-buffer" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b5c681a99606f3316f2a99d9c8b6fa3aad0b1d34d8f6d7a1b471893940219d8" +dependencies = [ + "bytes", + "half", + "num", +] + +[[package]] +name = "arrow-cast" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6365f8527d4f87b133eeb862f9b8093c009d41a210b8f101f91aa2392f61daac" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "atoi", + "base64 0.22.1", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num", + "ryu", +] + +[[package]] +name = "arrow-csv" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30dac4d23ac769300349197b845e0fd18c7f9f15d260d4659ae6b5a9ca06f586" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "csv", + "csv-core", + "lazy_static", + "lexical-core", + "regex", +] + +[[package]] +name = "arrow-data" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd962fc3bf7f60705b25bcaa8eb3318b2545aa1d528656525ebdd6a17a6cd6fb" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num", +] + +[[package]] +name = "arrow-ipc" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3527365b24372f9c948f16e53738eb098720eea2093ae73c7af04ac5e30a39b" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "flatbuffers", + "lz4_flex", + "zstd", +] + +[[package]] +name = "arrow-json" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdec0024749fc0d95e025c0b0266d78613727b3b3a5d4cf8ea47eb6d38afdd1" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "indexmap 2.11.4", + "lexical-core", + "num", + "serde", + "serde_json", +] + +[[package]] +name = "arrow-ord" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79af2db0e62a508d34ddf4f76bfd6109b6ecc845257c9cba6f939653668f89ac" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "half", + "num", +] + +[[package]] +name = "arrow-row" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da30e9d10e9c52f09ea0cf15086d6d785c11ae8dcc3ea5f16d402221b6ac7735" +dependencies = [ + "ahash 0.8.12", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35b0f9c0c3582dd55db0f136d3b44bfa0189df07adcf7dc7f2f2e74db0f52eb8" +dependencies = [ + "bitflags 2.9.4", +] + +[[package]] +name = "arrow-select" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92fc337f01635218493c23da81a364daf38c694b05fc20569c3193c11c561984" +dependencies = [ + "ahash 0.8.12", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num", +] + +[[package]] +name = "arrow-string" +version = "53.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d596a9fc25dae556672d5069b090331aca8acb93cae426d8b7dcdf1c558fa0ce" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num", + "regex", + "regex-syntax", +] + +[[package]] +name = "as-slice" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "ashpd" version = "0.11.0" @@ -201,6 +483,68 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-compression" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93c1f86859c1af3d514fa19e8323147ff10ea98684e6c7b307912509f50e67b2" +dependencies = [ + "compression-codecs", + "compression-core", + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling", + "rustix 0.37.28", + "slab", + "socket2 0.4.10", + "waker-fn", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener 5.4.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-priority-channel" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acde96f444d31031f760c5c43dc786b97d3e1cb2ee49dd06898383fe9a999758" +dependencies = [ + "event-listener 4.0.3", +] + [[package]] name = "async-recursion" version = "1.1.1" @@ -223,6 +567,15 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "async_cell" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447ab28afbb345f5408b120702a44e5529ebf90b1796ec76e9528df8e288e6c2" +dependencies = [ + "loom", +] + [[package]] name = "atk" version = "0.18.2" @@ -279,681 +632,1856 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "backoff" -version = "0.4.0" +name = "av-scenechange" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" dependencies = [ - "getrandom 0.2.16", - "instant", - "rand 0.8.5", + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey 0.1.1", + "rayon", + "thiserror 2.0.17", + "v_frame", + "y4m", ] [[package]] -name = "backtrace" -version = "0.3.75" +name = "av1-grain" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", + "anyhow", + "arrayvec", + "log", + "nom 8.0.0", + "num-rational", + "v_frame", ] [[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" +name = "avif-serialize" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f" +dependencies = [ + "arrayvec", +] [[package]] -name = "base64ct" -version = "1.8.0" +name = "aws-config" +version = "1.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "96571e6996817bf3d58f6b569e4b9fd2e9d2fcf9f7424eed07b2ce9bb87535e5" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-sdk-sso", + "aws-sdk-ssooidc", + "aws-sdk-sts", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand 2.3.0", + "hex", + "http 1.4.0", + "ring", + "time", + "tokio", + "tracing", + "url", + "zeroize", +] [[package]] -name = "bincode" -version = "1.3.3" +name = "aws-credential-types" +version = "1.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +checksum = "3cd362783681b15d136480ad555a099e82ecd8e2d10a841e14dfd0078d67fee3" dependencies = [ - "serde", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "zeroize", ] [[package]] -name = "bitflags" -version = "1.3.2" +name = "aws-lc-rs" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" +dependencies = [ + "aws-lc-sys", + "zeroize", +] [[package]] -name = "bitflags" -version = "2.9.4" +name = "aws-lc-sys" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" dependencies = [ - "serde", + "cc", + "cmake", + "dunce", + "fs_extra", ] [[package]] -name = "bitvec" -version = "1.0.1" +name = "aws-runtime" +version = "1.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "d81b5b2898f6798ad58f484856768bca817e3cd9de0974c24ae0f1113fe88f1b" dependencies = [ - "funty", - "radium", + "aws-credential-types", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand 2.3.0", + "http 0.2.12", + "http-body 0.4.6", + "percent-encoding", + "pin-project-lite", + "tracing", + "uuid", +] + +[[package]] +name = "aws-sdk-dynamodb" +version = "1.101.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f98cd9e5f2fc790aff1f393bc3c8680deea31c05d3c6f23b625cdc50b1b6b4" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand 2.3.0", + "http 0.2.12", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-sso" +version = "1.91.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee6402a36f27b52fe67661c6732d684b2635152b676aa2babbfb5204f99115d" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand 2.3.0", + "http 0.2.12", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-ssooidc" +version = "1.93.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a45a7f750bbd170ee3677671ad782d90b894548f4e4ae168302c57ec9de5cb3e" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand 2.3.0", + "http 0.2.12", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-sts" +version = "1.95.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55542378e419558e6b1f398ca70adb0b2088077e79ad9f14eb09441f2f7b2164" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-query", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "fastrand 2.3.0", + "http 0.2.12", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sigv4" +version = "1.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e523e1c4e8e7e8ff219d732988e22bfeae8a1cafdbe6d9eca1546fa080be7c" +dependencies = [ + "aws-credential-types", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "form_urlencoded", + "hex", + "hmac", + "http 0.2.12", + "http 1.4.0", + "percent-encoding", + "sha2", + "time", + "tracing", +] + +[[package]] +name = "aws-smithy-async" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee19095c7c4dda59f1697d028ce704c24b2d33c6718790c7f1d5a3015b4107c" +dependencies = [ + "futures-util", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "aws-smithy-http" +version = "0.62.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826141069295752372f8203c17f28e30c464d22899a43a0c9fd9c458d469c88b" +dependencies = [ + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "futures-util", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", +] + +[[package]] +name = "aws-smithy-http-client" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e62db736db19c488966c8d787f52e6270be565727236fd5579eaa301e7bc4a" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "h2 0.3.27", + "h2 0.4.12", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper 1.8.1", + "hyper-rustls 0.24.2", + "hyper-rustls 0.27.7", + "hyper-util", + "pin-project-lite", + "rustls 0.21.12", + "rustls 0.23.35", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower", + "tracing", +] + +[[package]] +name = "aws-smithy-json" +version = "0.61.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49fa1213db31ac95288d981476f78d05d9cbb0353d22cdf3472cc05bb02f6551" +dependencies = [ + "aws-smithy-types", +] + +[[package]] +name = "aws-smithy-observability" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f616c3f2260612fe44cede278bafa18e73e6479c4e393e2c4518cf2a9a228a" +dependencies = [ + "aws-smithy-runtime-api", +] + +[[package]] +name = "aws-smithy-query" +version = "0.60.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae5d689cf437eae90460e944a58b5668530d433b4ff85789e69d2f2a556e057d" +dependencies = [ + "aws-smithy-types", + "urlencoding", +] + +[[package]] +name = "aws-smithy-runtime" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a392db6c583ea4a912538afb86b7be7c5d8887d91604f50eb55c262ee1b4a5f5" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-http-client", + "aws-smithy-observability", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "fastrand 2.3.0", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "pin-project-lite", + "pin-utils", + "tokio", + "tracing", +] + +[[package]] +name = "aws-smithy-runtime-api" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab0d43d899f9e508300e587bf582ba54c27a452dd0a9ea294690669138ae14a2" +dependencies = [ + "aws-smithy-async", + "aws-smithy-types", + "bytes", + "http 0.2.12", + "http 1.4.0", + "pin-project-lite", + "tokio", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-types" +version = "1.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "905cb13a9895626d49cf2ced759b062d913834c7482c38e49557eac4e6193f01" +dependencies = [ + "base64-simd", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "itoa", + "num-integer", + "pin-project-lite", + "pin-utils", + "ryu", + "serde", + "time", + "tokio", + "tokio-util", +] + +[[package]] +name = "aws-smithy-xml" +version = "0.60.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11b2f670422ff42bf7065031e72b45bc52a3508bd089f743ea90731ca2b6ea57" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "aws-types" +version = "1.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d980627d2dd7bfc32a3c025685a033eeab8d365cc840c631ef59d1b8f428164" +dependencies = [ + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "rustc_version", + "tracing", +] + +[[package]] +name = "backoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +dependencies = [ + "getrandom 0.2.16", + "instant", + "rand 0.8.5", +] + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "base64ct" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" + +[[package]] +name = "bigdecimal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" +dependencies = [ + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +dependencies = [ + "serde", +] + +[[package]] +name = "bitpacking" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c1d3e2bfd8d06048a179f7b17afc3188effa10385e7b00dc65af6aae732ea92" +dependencies = [ + "crunchy", +] + +[[package]] +name = "bitstream-io" +version = "4.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60d4bd9d1db2c6bdf285e223a7fa369d5ce98ec767dec949c6ca62863ce61757" +dependencies = [ + "core2", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", "tap", "wyz", ] [[package]] -name = "block-buffer" +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", +] + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2 0.6.3", +] + +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "brotli" +version = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "built" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ad8f11f288f48ca24471bbd51ac257aaeaaa07adae295591266b792902ae64" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "byte-unit" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6d47a4e2961fb8721bcfc54feae6455f2f64e7054f9bc67e875f0e77f4c58d" +dependencies = [ + "rust_decimal", + "schemars 1.1.0", + "serde", + "utf8-width", +] + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytecount" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" + +[[package]] +name = "bytemuck" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +dependencies = [ + "serde", +] + +[[package]] +name = "bytes-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" +dependencies = [ + "bytes", + "either", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.9.4", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.17", +] + +[[package]] +name = "cargo_toml" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +dependencies = [ + "serde", + "toml 0.9.8", +] + +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" + +[[package]] +name = "castaway" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +dependencies = [ + "rustversion", +] + +[[package]] +name = "cc" +version = "1.2.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "census" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4c707c6a209cbe82d10abd08e1ea8995e9ea937d2550646e02798948992be0" + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[package]] +name = "chrono-tz" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" dependencies = [ - "generic-array", + "chrono", + "phf 0.12.1", ] [[package]] -name = "block2" -version = "0.5.1" +name = "clap" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" dependencies = [ - "objc2 0.5.2", + "clap_builder", + "clap_derive", ] [[package]] -name = "block2" -version = "0.6.2" +name = "clap_builder" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" dependencies = [ - "objc2 0.6.3", + "anstream", + "anstyle", + "clap_lex", + "strsim", ] [[package]] -name = "borsh" -version = "1.6.0" +name = "clap_derive" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" dependencies = [ - "borsh-derive", - "cfg_aliases", + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] -name = "borsh-derive" -version = "1.6.0" +name = "clap_lex" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "comfy-table" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03b7db8e0b4b2fdad6c551e634134e99ec000e5c8c3b6856c65e8bbaded7a3b" +dependencies = [ + "unicode-segmentation", + "unicode-width 0.2.2", +] + +[[package]] +name = "compact_str" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb1325a1cece981e8a296ab8f0f9b63ae357bd0784a9faaf548cc7b480707a" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "serde", + "static_assertions", +] + +[[package]] +name = "compression-codecs" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680dc087785c5230f8e8843e2e57ac7c1c90488b6a91b88caa265410568f441b" +dependencies = [ + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ + "encode_unicode", + "libc", "once_cell", - "proc-macro-crate 3.4.0", - "proc-macro2", - "quote", - "syn 2.0.106", + "unicode-width 0.2.2", + "windows-sys 0.59.0", ] [[package]] -name = "brotli" -version = "8.0.2" +name = "const-oid" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", + "const-random-macro", ] [[package]] -name = "brotli-decompressor" -version = "5.0.0" +name = "const-random-macro" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", + "getrandom 0.2.16", + "once_cell", + "tiny-keccak", ] [[package]] -name = "bumpalo" -version = "3.19.0" +name = "convert_case" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] -name = "byte-unit" -version = "5.2.0" +name = "cookie" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6d47a4e2961fb8721bcfc54feae6455f2f64e7054f9bc67e875f0e77f4c58d" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" dependencies = [ - "rust_decimal", - "schemars 1.1.0", - "serde", - "utf8-width", + "time", + "version_check", ] [[package]] -name = "bytecheck" -version = "0.6.12" +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", + "core-foundation-sys", + "libc", ] [[package]] -name = "bytecheck_derive" -version = "0.6.12" +name = "core-foundation" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "core-foundation-sys", + "libc", ] [[package]] -name = "bytemuck" -version = "1.24.0" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "byteorder" +name = "core-graphics" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "libc", +] + +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc32fast" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] [[package]] -name = "bytes" -version = "1.10.1" +name = "crossbeam-channel" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ - "serde", + "crossbeam-utils", ] [[package]] -name = "cairo-rs" -version = "0.18.5" +name = "crossbeam-deque" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ - "bitflags 2.9.4", - "cairo-sys-rs", - "glib", - "libc", - "once_cell", - "thiserror 1.0.69", + "crossbeam-epoch", + "crossbeam-utils", ] [[package]] -name = "cairo-sys-rs" -version = "0.18.2" +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "glib-sys", - "libc", - "system-deps", + "crossbeam-utils", ] [[package]] -name = "camino" -version = "1.2.2" +name = "crossbeam-queue" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ - "serde_core", + "crossbeam-utils", ] [[package]] -name = "cargo-platform" -version = "0.1.9" +name = "crossbeam-utils" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" dependencies = [ - "serde", + "bitflags 1.3.2", + "crossterm_winapi", + "libc", + "mio 0.8.11", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", ] [[package]] -name = "cargo_metadata" -version = "0.19.2" +name = "crossterm" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror 2.0.17", + "bitflags 2.9.4", + "crossterm_winapi", + "libc", + "mio 0.8.11", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", ] [[package]] -name = "cargo_toml" -version = "0.22.3" +name = "crossterm_winapi" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" dependencies = [ - "serde", - "toml 0.9.8", + "winapi", ] [[package]] -name = "cassowary" -version = "0.3.0" +name = "crunchy" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] -name = "cc" -version = "1.2.38" +name = "crypto-common" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "find-msvc-tools", - "shlex", + "generic-array", + "typenum", ] [[package]] -name = "cesu8" -version = "1.1.0" +name = "cssparser" +version = "0.29.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "matches", + "phf 0.10.1", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] [[package]] -name = "cfb" -version = "0.7.3" +name = "cssparser-macros" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ - "byteorder", - "fnv", - "uuid", + "quote", + "syn 2.0.106", ] [[package]] -name = "cfg-expr" -version = "0.15.8" +name = "csv" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" dependencies = [ - "smallvec", - "target-lexicon", + "csv-core", + "itoa", + "ryu", + "serde_core", ] [[package]] -name = "cfg-if" -version = "1.0.3" +name = "csv-core" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] [[package]] -name = "cfg_aliases" -version = "0.2.1" +name = "ctor" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +dependencies = [ + "quote", + "syn 2.0.106", +] [[package]] -name = "chrono" -version = "0.4.42" +name = "darling" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link 0.2.0", + "darling_core 0.20.11", + "darling_macro 0.20.11", ] [[package]] -name = "clap" -version = "4.5.48" +name = "darling" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "clap_builder", - "clap_derive", + "darling_core 0.21.3", + "darling_macro 0.21.3", ] [[package]] -name = "clap_builder" -version = "4.5.48" +name = "darling_core" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" dependencies = [ - "anstream", - "anstyle", - "clap_lex", + "fnv", + "ident_case", + "proc-macro2", + "quote", "strsim", + "syn 2.0.106", ] [[package]] -name = "clap_derive" -version = "4.5.47" +name = "darling_core" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ - "heck 0.5.0", + "fnv", + "ident_case", "proc-macro2", "quote", + "strsim", "syn 2.0.106", ] [[package]] -name = "clap_lex" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" - -[[package]] -name = "colorchoice" -version = "1.0.4" +name = "darling_macro" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.106", +] [[package]] -name = "combine" -version = "4.6.7" +name = "darling_macro" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ - "bytes", - "memchr", + "darling_core 0.21.3", + "quote", + "syn 2.0.106", ] [[package]] -name = "concurrent-queue" -version = "2.5.0" +name = "dary_heap" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +checksum = "06d2e3287df1c007e74221c49ca10a95d557349e54b3a75dc2fb14712c751f04" dependencies = [ - "crossbeam-utils", + "serde", ] [[package]] -name = "console" -version = "0.15.11" +name = "dashmap" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ - "encode_unicode", - "libc", + "cfg-if", + "hashbrown 0.14.5", + "lock_api", "once_cell", - "unicode-width 0.2.2", - "windows-sys 0.59.0", + "parking_lot_core", ] [[package]] -name = "const-oid" -version = "0.9.6" +name = "dashmap" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] [[package]] -name = "convert_case" -version = "0.4.0" +name = "datafusion" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "014fc8c384ecacedaabb3bc8359c2a6c6e9d8f7bea65be3434eccacfc37f52d9" +dependencies = [ + "arrow", + "arrow-array", + "arrow-ipc", + "arrow-schema", + "async-trait", + "bytes", + "chrono", + "dashmap 6.1.0", + "datafusion-catalog", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions", + "datafusion-functions-aggregate", + "datafusion-functions-nested", + "datafusion-functions-table", + "datafusion-functions-window", + "datafusion-optimizer", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "datafusion-physical-optimizer", + "datafusion-physical-plan", + "datafusion-sql", + "futures", + "glob", + "itertools 0.13.0", + "log", + "object_store 0.11.2", + "parking_lot", + "rand 0.8.5", + "regex", + "sqlparser", + "tempfile", + "tokio", + "url", + "uuid", +] [[package]] -name = "cookie" -version = "0.18.1" +name = "datafusion-catalog" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +checksum = "ee60d33e210ef96070377ae667ece7caa0e959c8387496773d4a1a72f1a5012e" dependencies = [ - "time", - "version_check", + "arrow-schema", + "async-trait", + "datafusion-common", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-plan", + "parking_lot", ] [[package]] -name = "core-foundation" -version = "0.9.4" +name = "datafusion-common" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "0b42b7d720fe21ed9cca2ebb635f3f13a12cfab786b41e0fba184fb2e620525b" dependencies = [ - "core-foundation-sys", + "ahash 0.8.12", + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-schema", + "half", + "hashbrown 0.14.5", + "indexmap 2.11.4", "libc", + "log", + "object_store 0.11.2", + "paste", + "sqlparser", + "tokio", + "web-time", ] [[package]] -name = "core-foundation" -version = "0.10.1" +name = "datafusion-common-runtime" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +checksum = "72fbf14d4079f7ce5306393084fe5057dddfdc2113577e0049310afa12e94281" dependencies = [ - "core-foundation-sys", - "libc", + "log", + "tokio", ] [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "datafusion-doc" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "c278dbd64860ed0bb5240fc1f4cb6aeea437153910aea69bcf7d5a8d6d0454f3" [[package]] -name = "core-graphics" -version = "0.24.0" +name = "datafusion-execution" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +checksum = "e22cb02af47e756468b3cbfee7a83e3d4f2278d452deb4b033ba933c75169486" dependencies = [ - "bitflags 2.9.4", - "core-foundation 0.10.1", - "core-graphics-types", - "foreign-types", - "libc", + "arrow", + "dashmap 6.1.0", + "datafusion-common", + "datafusion-expr", + "futures", + "log", + "object_store 0.11.2", + "parking_lot", + "rand 0.8.5", + "tempfile", + "url", ] [[package]] -name = "core-graphics-types" -version = "0.2.0" +name = "datafusion-expr" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +checksum = "62298eadb1d15b525df1315e61a71519ffc563d41d5c3b2a30fda2d70f77b93c" dependencies = [ - "bitflags 2.9.4", - "core-foundation 0.10.1", - "libc", + "arrow", + "chrono", + "datafusion-common", + "datafusion-doc", + "datafusion-expr-common", + "datafusion-functions-aggregate-common", + "datafusion-functions-window-common", + "datafusion-physical-expr-common", + "indexmap 2.11.4", + "paste", + "serde_json", + "sqlparser", ] [[package]] -name = "cpufeatures" -version = "0.2.17" +name = "datafusion-expr-common" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "dda7f73c5fc349251cd3dcb05773c5bf55d2505a698ef9d38dfc712161ea2f55" dependencies = [ - "libc", + "arrow", + "datafusion-common", + "itertools 0.13.0", ] [[package]] -name = "crc" -version = "3.3.0" +name = "datafusion-functions" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "fd197f3b2975424d3a4898ea46651be855a46721a56727515dbd5c9e2fb597da" dependencies = [ - "crc-catalog", + "arrow", + "arrow-buffer", + "base64 0.22.1", + "chrono", + "datafusion-common", + "datafusion-doc", + "datafusion-execution", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-macros", + "hashbrown 0.14.5", + "hex", + "itertools 0.13.0", + "log", + "rand 0.8.5", + "regex", + "unicode-segmentation", + "uuid", ] [[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc32fast" -version = "1.5.0" +name = "datafusion-functions-aggregate" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "aabbe48fba18f9981b134124381bee9e46f93518b8ad2f9721ee296cef5affb9" dependencies = [ - "cfg-if", + "ahash 0.8.12", + "arrow", + "arrow-schema", + "datafusion-common", + "datafusion-doc", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions-aggregate-common", + "datafusion-macros", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "half", + "log", + "paste", ] [[package]] -name = "crossbeam-channel" -version = "0.5.15" +name = "datafusion-functions-aggregate-common" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "d7a3fefed9c8c11268d446d924baca8cabf52fe32f73fdaa20854bac6473590c" dependencies = [ - "crossbeam-utils", + "ahash 0.8.12", + "arrow", + "datafusion-common", + "datafusion-expr-common", + "datafusion-physical-expr-common", +] + +[[package]] +name = "datafusion-functions-nested" +version = "44.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6360f27464fab857bec698af39b2ae331dc07c8bf008fb4de387a19cdc6815a5" +dependencies = [ + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-ord", + "arrow-schema", + "datafusion-common", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions", + "datafusion-functions-aggregate", + "datafusion-physical-expr-common", + "itertools 0.13.0", + "log", + "paste", ] [[package]] -name = "crossbeam-queue" -version = "0.3.12" +name = "datafusion-functions-table" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +checksum = "5c35c070eb705c12795dab399c3809f4dfbc290678c624d3989490ca9b8449c1" dependencies = [ - "crossbeam-utils", + "arrow", + "async-trait", + "datafusion-catalog", + "datafusion-common", + "datafusion-expr", + "datafusion-physical-plan", + "parking_lot", + "paste", ] [[package]] -name = "crossbeam-utils" -version = "0.8.21" +name = "datafusion-functions-window" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "52229bca26b590b140900752226c829f15fc1a99840e1ca3ce1a9534690b82a8" +dependencies = [ + "datafusion-common", + "datafusion-doc", + "datafusion-expr", + "datafusion-functions-window-common", + "datafusion-macros", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "log", + "paste", +] [[package]] -name = "crossterm" -version = "0.25.0" +name = "datafusion-functions-window-common" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +checksum = "367befc303b64a668a10ae6988a064a9289e1999e71a7f8e526b6e14d6bdd9d6" dependencies = [ - "bitflags 1.3.2", - "crossterm_winapi", - "libc", - "mio 0.8.11", - "parking_lot", - "signal-hook", - "signal-hook-mio", - "winapi", + "datafusion-common", + "datafusion-physical-expr-common", ] [[package]] -name = "crossterm" -version = "0.27.0" +name = "datafusion-macros" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +checksum = "f5de3c8f386ea991696553afe241a326ecbc3c98a12c562867e4be754d3a060c" dependencies = [ - "bitflags 2.9.4", - "crossterm_winapi", - "libc", - "mio 0.8.11", - "parking_lot", - "signal-hook", - "signal-hook-mio", - "winapi", + "quote", + "syn 2.0.106", ] [[package]] -name = "crossterm_winapi" -version = "0.9.1" +name = "datafusion-optimizer" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +checksum = "53b520413906f755910422b016fb73884ae6e9e1b376de4f9584b6c0e031da75" dependencies = [ - "winapi", + "arrow", + "chrono", + "datafusion-common", + "datafusion-expr", + "datafusion-physical-expr", + "indexmap 2.11.4", + "itertools 0.13.0", + "log", + "regex", + "regex-syntax", ] [[package]] -name = "crypto-common" -version = "0.1.6" +name = "datafusion-physical-expr" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "acd6ddc378f6ad19af95ccd6790dec8f8e1264bc4c70e99ddc1830c1a1c78ccd" dependencies = [ - "generic-array", - "typenum", + "ahash 0.8.12", + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-schema", + "datafusion-common", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-functions-aggregate-common", + "datafusion-physical-expr-common", + "half", + "hashbrown 0.14.5", + "indexmap 2.11.4", + "itertools 0.13.0", + "log", + "paste", + "petgraph 0.6.5", ] [[package]] -name = "cssparser" -version = "0.29.6" +name = "datafusion-physical-expr-common" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" +checksum = "06e6c05458eccd74b4c77ed6a1fe63d52434240711de7f6960034794dad1caf5" dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "matches", - "phf 0.10.1", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", + "ahash 0.8.12", + "arrow", + "datafusion-common", + "datafusion-expr-common", + "hashbrown 0.14.5", + "itertools 0.13.0", ] [[package]] -name = "cssparser-macros" -version = "0.6.1" +name = "datafusion-physical-optimizer" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +checksum = "9dc3a82190f49c37d377f31317e07ab5d7588b837adadba8ac367baad5dc2351" dependencies = [ - "quote", - "syn 2.0.106", + "arrow", + "datafusion-common", + "datafusion-execution", + "datafusion-expr-common", + "datafusion-physical-expr", + "datafusion-physical-plan", + "itertools 0.13.0", + "log", ] [[package]] -name = "ctor" -version = "0.2.9" +name = "datafusion-physical-plan" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" +checksum = "6a6608bc9844b4ddb5ed4e687d173e6c88700b1d0482f43894617d18a1fe75da" dependencies = [ - "quote", - "syn 2.0.106", + "ahash 0.8.12", + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-ord", + "arrow-schema", + "async-trait", + "chrono", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions-window-common", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "futures", + "half", + "hashbrown 0.14.5", + "indexmap 2.11.4", + "itertools 0.13.0", + "log", + "parking_lot", + "pin-project-lite", + "tokio", ] [[package]] -name = "darling" -version = "0.21.3" +name = "datafusion-sql" +version = "44.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "6a884061c79b33d0c8e84a6f4f4be8bdc12c0f53f5af28ddf5d6d95ac0b15fdc" dependencies = [ - "darling_core", - "darling_macro", + "arrow", + "arrow-array", + "arrow-schema", + "bigdecimal", + "datafusion-common", + "datafusion-expr", + "indexmap 2.11.4", + "log", + "regex", + "sqlparser", ] [[package]] -name = "darling_core" -version = "0.21.3" +name = "deepsize" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "1cdb987ec36f6bf7bfbea3f928b75590b736fc42af8e54d97592481351b2b96c" dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.106", + "deepsize_derive", ] [[package]] -name = "darling_macro" -version = "0.21.3" +name = "deepsize_derive" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +checksum = "990101d41f3bc8c1a45641024377ee284ecc338e5ecf3ea0f0e236d897c72796" dependencies = [ - "darling_core", + "proc-macro2", "quote", - "syn 2.0.106", + "syn 1.0.109", ] [[package]] @@ -988,6 +2516,37 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.106", +] + [[package]] name = "derive_more" version = "0.99.20" @@ -1116,6 +2675,12 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "doc-comment" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" + [[package]] name = "dotenvy" version = "0.15.7" @@ -1251,6 +2816,26 @@ dependencies = [ "regex", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1278,6 +2863,21 @@ dependencies = [ "windows-sys 0.61.0", ] +[[package]] +name = "error-chain" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" +dependencies = [ + "version_check", +] + +[[package]] +name = "esaxx-rs" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6" + [[package]] name = "etcetera" version = "0.8.0" @@ -1291,9 +2891,20 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.3" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] [[package]] name = "event-listener" @@ -1316,6 +2927,21 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "exr" +version = "1.74.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + [[package]] name = "fallible-iterator" version = "0.3.0" @@ -1328,12 +2954,64 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +[[package]] +name = "fastdivide" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afc2bd4d5a73106dd53d10d73d3401c2f32730ba2c0b93ddb888a8983680471" + +[[package]] +name = "fastembed" +version = "4.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c269a76bfc6cea69553b7d040acb16c793119cebd97c756d21e08d0f075ff8" +dependencies = [ + "anyhow", + "hf-hub", + "image", + "ndarray", + "ort", + "ort-sys", + "rayon", + "serde_json", + "tokenizers", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "fdeflate" version = "0.3.7" @@ -1376,9 +3054,31 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fixedbitset" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flatbuffers" +version = "24.12.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1baf0dbf96932ec9a3038d57900329c015b0bfb7b63d904f3bc27e2b02a096" +dependencies = [ + "bitflags 1.3.2", + "rustc_version", +] [[package]] name = "flate2" @@ -1413,6 +3113,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -1420,7 +3129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared", + "foreign-types-shared 0.3.1", ] [[package]] @@ -1434,6 +3143,12 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -1455,6 +3170,22 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" +[[package]] +name = "fs4" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e180ac76c23b45e767bd7ae9579bc0bb458618c4bc71835926e098e61d15f8" +dependencies = [ + "rustix 0.38.44", + "windows-sys 0.52.0", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "fsevent-sys" version = "4.1.0" @@ -1464,6 +3195,15 @@ dependencies = [ "libc", ] +[[package]] +name = "fsst" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9de098cff2db523a8c066b07f818a3e5495067304f0d7298010f54e9d6acf7d" +dependencies = [ + "rand 0.8.5", +] + [[package]] name = "funty" version = "2.0.0" @@ -1539,13 +3279,28 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + [[package]] name = "futures-lite" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" dependencies = [ - "fastrand", + "fastrand 2.3.0", "futures-core", "futures-io", "parking", @@ -1710,6 +3465,21 @@ dependencies = [ "x11", ] +[[package]] +name = "generator" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows-link 0.2.0", + "windows-result 0.4.0", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1758,6 +3528,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gif" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5df2ba84018d80c213569363bdcd0c64e6933c67fe4c1d60ecf822971a3c35e" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gimli" version = "0.31.1" @@ -1931,6 +3711,36 @@ dependencies = [ "tracing", ] +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.4.0", + "indexmap 2.11.4", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -1994,6 +3804,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hermit-abi" version = "0.5.2" @@ -2006,6 +3822,27 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hf-hub" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "629d8f3bbeda9d148036d6b0de0a3ab947abd08ce90626327fc3547a49d59d97" +dependencies = [ + "dirs 6.0.0", + "http 1.4.0", + "indicatif", + "libc", + "log", + "native-tls", + "rand 0.9.2", + "reqwest 0.12.26", + "serde", + "serde_json", + "thiserror 2.0.17", + "ureq", + "windows-sys 0.60.2", +] + [[package]] name = "hkdf" version = "0.12.4" @@ -2045,6 +3882,12 @@ dependencies = [ "match_token", ] +[[package]] +name = "htmlescape" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" + [[package]] name = "http" version = "0.2.12" @@ -2112,6 +3955,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + [[package]] name = "hyper" version = "0.14.32" @@ -2122,7 +3971,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.27", "http 0.2.12", "http-body 0.4.6", "httparse", @@ -2146,6 +3995,7 @@ dependencies = [ "bytes", "futures-channel", "futures-core", + "h2 0.4.12", "http 1.4.0", "http-body 1.0.1", "httparse", @@ -2166,6 +4016,7 @@ dependencies = [ "futures-util", "http 0.2.12", "hyper 0.14.32", + "log", "rustls 0.21.12", "tokio", "tokio-rustls 0.24.1", @@ -2181,6 +4032,7 @@ dependencies = [ "hyper 1.8.1", "hyper-util", "rustls 0.23.35", + "rustls-native-certs", "rustls-pki-types", "tokio", "tokio-rustls 0.26.4", @@ -2188,6 +4040,22 @@ dependencies = [ "webpki-roots 1.0.4", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.19" @@ -2207,9 +4075,20 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2 0.6.0", + "system-configuration", "tokio", "tower-service", "tracing", + "windows-registry", +] + +[[package]] +name = "hyperloglogplus" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "621debdf94dcac33e50475fdd76d34d5ea9c0362a834b9db08c3024696c1fbe3" +dependencies = [ + "serde", ] [[package]] @@ -2243,7 +4122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" dependencies = [ "byteorder", - "png", + "png 0.17.16", ] [[package]] @@ -2359,6 +4238,46 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "image" +version = "0.25.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png 0.18.0", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core 0.5.0", + "zune-jpeg 0.5.8", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imgref" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c5cedc30da3a610cac6b4ba17597bdf7152cf974e8aab3afb3d54455e371c8" + [[package]] name = "indexmap" version = "1.9.3" @@ -2454,6 +4373,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", ] [[package]] @@ -2496,23 +4440,50 @@ dependencies = [ name = "is-wsl" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ - "is-docker", - "once_cell", + "either", ] [[package]] -name = "is_terminal_polyfill" -version = "1.70.1" +name = "itertools" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] [[package]] name = "itertools" -version = "0.11.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" dependencies = [ "either", ] @@ -2568,6 +4539,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.80" @@ -2643,6 +4624,444 @@ dependencies = [ "selectors", ] +[[package]] +name = "lance" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e40ecb7cce0650475882e7664b4f71e4b9b98dd774dde79c10c63dea8a6b572" +dependencies = [ + "arrow", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "async-recursion", + "async-trait", + "async_cell", + "aws-credential-types", + "aws-sdk-dynamodb", + "byteorder", + "bytes", + "chrono", + "dashmap 5.5.3", + "datafusion", + "datafusion-expr", + "datafusion-functions", + "datafusion-physical-expr", + "deepsize", + "futures", + "half", + "itertools 0.13.0", + "lance-arrow", + "lance-core", + "lance-datafusion", + "lance-encoding", + "lance-file", + "lance-index", + "lance-io", + "lance-linalg", + "lance-table", + "lazy_static", + "log", + "moka 0.12.12", + "object_store 0.10.2", + "permutation", + "pin-project", + "prost 0.13.5", + "prost-types", + "rand 0.8.5", + "roaring", + "serde", + "serde_json", + "snafu 0.7.5", + "tantivy", + "tempfile", + "tokio", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "lance-arrow" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb03fcc2c113b11ade471cbc9668b04b47e91b870f4037938e08a1f329845728" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "arrow-select", + "bytes", + "getrandom 0.2.16", + "half", + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "lance-core" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17576fbec975bb5790d15a68d5ec2d25fee490bef1c769a16353f7c2b9080976" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-schema", + "async-trait", + "byteorder", + "bytes", + "chrono", + "datafusion-common", + "datafusion-sql", + "deepsize", + "futures", + "lance-arrow", + "lazy_static", + "libc", + "log", + "mock_instant", + "moka 0.12.12", + "num_cpus", + "object_store 0.10.2", + "pin-project", + "prost 0.13.5", + "rand 0.8.5", + "roaring", + "serde_json", + "snafu 0.7.5", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", + "url", +] + +[[package]] +name = "lance-datafusion" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c29c3b1ff51057181407f4924cc1117e633c4485a83ae6b2cb4d2252cf2bdba" +dependencies = [ + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-ord", + "arrow-schema", + "arrow-select", + "async-trait", + "datafusion", + "datafusion-common", + "datafusion-functions", + "datafusion-physical-expr", + "futures", + "lance-arrow", + "lance-core", + "lazy_static", + "log", + "prost 0.13.5", + "snafu 0.7.5", + "tokio", +] + +[[package]] +name = "lance-encoding" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d884be9fb234f7fcd105f7f26232b8fa6d1c3037f893033846bb7a2a89d3a870" +dependencies = [ + "arrayref", + "arrow", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "arrow-select", + "bytemuck", + "byteorder", + "bytes", + "fsst", + "futures", + "hex", + "hyperloglogplus", + "itertools 0.13.0", + "lance-arrow", + "lance-core", + "lazy_static", + "log", + "num-traits", + "paste", + "prost 0.13.5", + "prost-build", + "prost-types", + "rand 0.8.5", + "seq-macro", + "snafu 0.7.5", + "tokio", + "tracing", + "zstd", +] + +[[package]] +name = "lance-file" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a440ab6b2b5d9da1b15794e0025a27fb8aa95e56adf80da27dacbf7597a57cea" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "async-recursion", + "async-trait", + "byteorder", + "bytes", + "datafusion-common", + "deepsize", + "futures", + "lance-arrow", + "lance-core", + "lance-encoding", + "lance-io", + "log", + "num-traits", + "object_store 0.10.2", + "prost 0.13.5", + "prost-build", + "prost-types", + "roaring", + "snafu 0.7.5", + "tempfile", + "tokio", + "tracing", +] + +[[package]] +name = "lance-index" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95f7fdf4c3edbc058a209626d89c0cdbed1d1a39fe6751ad4a4755800e5ab111" +dependencies = [ + "arrow", + "arrow-array", + "arrow-ord", + "arrow-schema", + "arrow-select", + "async-recursion", + "async-trait", + "bitvec", + "bytes", + "crossbeam-queue", + "datafusion", + "datafusion-common", + "datafusion-expr", + "datafusion-physical-expr", + "datafusion-sql", + "deepsize", + "dirs 5.0.1", + "futures", + "half", + "itertools 0.13.0", + "lance-arrow", + "lance-core", + "lance-datafusion", + "lance-encoding", + "lance-file", + "lance-io", + "lance-linalg", + "lance-table", + "lazy_static", + "log", + "moka 0.12.12", + "num-traits", + "object_store 0.10.2", + "prost 0.13.5", + "prost-build", + "rand 0.8.5", + "rayon", + "roaring", + "serde", + "serde_json", + "snafu 0.7.5", + "tantivy", + "tempfile", + "tokio", + "tracing", + "uuid", +] + +[[package]] +name = "lance-io" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53cb1e5b74dc397950a6414737bffbf24f7aaf750ad2acb51c29d9fc0ea659e4" +dependencies = [ + "arrow", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "arrow-select", + "async-priority-channel", + "async-recursion", + "async-trait", + "aws-config", + "aws-credential-types", + "byteorder", + "bytes", + "chrono", + "deepsize", + "futures", + "lance-arrow", + "lance-core", + "lazy_static", + "log", + "object_store 0.10.2", + "path_abs", + "pin-project", + "prost 0.13.5", + "rand 0.8.5", + "shellexpand", + "snafu 0.7.5", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "lance-linalg" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4552b323849ec600443b2364df58ee259cbf615a4d451b90526723275930c58d" +dependencies = [ + "arrow-array", + "arrow-ord", + "arrow-schema", + "bitvec", + "cc", + "deepsize", + "futures", + "half", + "lance-arrow", + "lance-core", + "lazy_static", + "log", + "num-traits", + "rand 0.8.5", + "rayon", + "tokio", + "tracing", +] + +[[package]] +name = "lance-table" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c0e89bad7547eecf4fe4446bbbba6c5389832c59ecb3e388f661aaac8eb8104" +dependencies = [ + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-ipc", + "arrow-schema", + "async-trait", + "aws-credential-types", + "aws-sdk-dynamodb", + "byteorder", + "bytes", + "chrono", + "deepsize", + "futures", + "lance-arrow", + "lance-core", + "lance-file", + "lance-io", + "lazy_static", + "log", + "object_store 0.10.2", + "prost 0.13.5", + "prost-build", + "prost-types", + "rand 0.8.5", + "rangemap", + "roaring", + "serde", + "serde_json", + "snafu 0.7.5", + "tokio", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "lance-testing" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4dff14ccab4356ec8020da2dfd65f588a9e4226c26de680e7dd26b2f49871b9" +dependencies = [ + "arrow-array", + "arrow-schema", + "lance-arrow", + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "lancedb" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba8d7dc3838a05decc395885aa73aa4ff063d76a9c3de00de1b4fcef7957fae4" +dependencies = [ + "arrow", + "arrow-array", + "arrow-cast", + "arrow-data", + "arrow-ipc", + "arrow-ord", + "arrow-schema", + "async-trait", + "bytes", + "chrono", + "datafusion-common", + "datafusion-physical-plan", + "futures", + "half", + "lance", + "lance-datafusion", + "lance-encoding", + "lance-index", + "lance-io", + "lance-linalg", + "lance-table", + "lance-testing", + "lazy_static", + "log", + "moka 0.11.3", + "num-traits", + "object_store 0.10.2", + "pin-project", + "regex", + "reqwest 0.12.26", + "serde", + "serde_json", + "serde_with", + "snafu 0.7.5", + "tokio", + "url", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -2652,6 +5071,75 @@ dependencies = [ "spin", ] +[[package]] +name = "lebe" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" + +[[package]] +name = "levenshtein_automata" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25" + +[[package]] +name = "lexical-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" +dependencies = [ + "lexical-parse-integer", + "lexical-util", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "lexical-util" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" + +[[package]] +name = "lexical-write-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" +dependencies = [ + "lexical-util", +] + [[package]] name = "libappindicator" version = "0.9.0" @@ -2682,6 +5170,16 @@ version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +[[package]] +name = "libfuzzer-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" +dependencies = [ + "arbitrary", + "cc", +] + [[package]] name = "libloading" version = "0.7.4" @@ -2736,6 +5234,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.15" @@ -2773,6 +5277,28 @@ dependencies = [ "value-bag", ] +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "lru" version = "0.12.5" @@ -2788,12 +5314,46 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "lz4_flex" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a" +dependencies = [ + "twox-hash", +] + [[package]] name = "mac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + +[[package]] +name = "macro_rules_attribute" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520" +dependencies = [ + "macro_rules_attribute-proc_macro", + "paste", +] + +[[package]] +name = "macro_rules_attribute-proc_macro" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30" + [[package]] name = "markup5ever" version = "0.14.1" @@ -2834,6 +5394,26 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "md-5" version = "0.10.6" @@ -2844,12 +5424,31 @@ dependencies = [ "digest", ] +[[package]] +name = "measure_time" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbefd235b0aadd181626f281e1d684e116972988c14c264e42069d5e8a5775cc" +dependencies = [ + "instant", + "log", +] + [[package]] name = "memchr" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "memmap2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.9.1" @@ -2911,6 +5510,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "mock_instant" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9366861eb2a2c436c20b12c8dbec5f798cea6b47ad99216be0282942e2c81ea0" +dependencies = [ + "once_cell", +] + [[package]] name = "mockall" version = "0.12.1" @@ -2938,6 +5546,83 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "moka" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa6e72583bf6830c956235bff0d5afec8cf2952f579ebad18ae7821a917d950f" +dependencies = [ + "async-io", + "async-lock 2.8.0", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "futures-util", + "once_cell", + "parking_lot", + "quanta", + "rustc_version", + "scheduled-thread-pool", + "skeptic", + "smallvec", + "tagptr", + "thiserror 1.0.69", + "triomphe", + "uuid", +] + +[[package]] +name = "moka" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3dec6bd31b08944e08b58fd99373893a6c17054d6f3ea5006cc894f4f4eee2a" +dependencies = [ + "async-lock 3.4.2", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "event-listener 5.4.1", + "futures-util", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", +] + +[[package]] +name = "monostate" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3341a273f6c9d5bef1908f17b7267bbab0e95c9bf69a0d4dcf8e9e1b2c76ef67" +dependencies = [ + "monostate-impl", + "serde", + "serde_core", +] + +[[package]] +name = "monostate-impl" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4db6d5580af57bf992f59068d4ea26fd518574ff48d7639b255a36f9de6e7e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "moxcms" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +dependencies = [ + "num-traits", + "pxfm", +] + [[package]] name = "muda" version = "0.17.1" @@ -2953,12 +5638,56 @@ dependencies = [ "objc2-core-foundation", "objc2-foundation 0.3.2", "once_cell", - "png", + "png 0.17.16", "serde", "thiserror 2.0.17", "windows-sys 0.60.2", ] +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "murmurhash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b" + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe 0.1.6", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + [[package]] name = "ndk" version = "0.9.0" @@ -3033,6 +5762,21 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + [[package]] name = "notify" version = "8.2.0" @@ -3066,6 +5810,30 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-bigint-dig" version = "0.8.4" @@ -3083,12 +5851,32 @@ dependencies = [ "zeroize", ] +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "num-integer" version = "0.1.46" @@ -3109,6 +5897,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -3451,6 +6250,58 @@ dependencies = [ "memchr", ] +[[package]] +name = "object_store" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6da452820c715ce78221e8202ccc599b4a52f3e1eb3eedb487b680c81a8e3f3" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bytes", + "chrono", + "futures", + "humantime", + "hyper 1.8.1", + "itertools 0.13.0", + "md-5", + "parking_lot", + "percent-encoding", + "quick-xml 0.36.2", + "rand 0.8.5", + "reqwest 0.12.26", + "ring", + "rustls-pemfile 2.2.0", + "serde", + "serde_json", + "snafu 0.7.5", + "tokio", + "tracing", + "url", + "walkdir", +] + +[[package]] +name = "object_store" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cfccb68961a56facde1163f9319e0d15743352344e7808a11795fb99698dcaf" +dependencies = [ + "async-trait", + "bytes", + "chrono", + "futures", + "humantime", + "itertools 0.13.0", + "parking_lot", + "percent-encoding", + "snafu 0.8.9", + "tokio", + "tracing", + "url", + "walkdir", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -3461,7 +6312,13 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" name = "once_cell_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "oneshot" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce411919553d3f9fa53a0880544cda985a112117a0444d5ff1e870a893d6ea" [[package]] name = "onig" @@ -3497,6 +6354,56 @@ dependencies = [ "pathdiff", ] +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-probe" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "option-ext" version = "0.2.0" @@ -3513,6 +6420,30 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "ort" +version = "2.0.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52afb44b6b0cffa9bf45e4d37e5a4935b0334a51570658e279e9e3e6cf324aa5" +dependencies = [ + "ndarray", + "ort-sys", + "tracing", +] + +[[package]] +name = "ort-sys" +version = "2.0.0-rc.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41d7757331aef2d04b9cb09b45583a59217628beaf91895b7e76187b6e8c088" +dependencies = [ + "flate2", + "pkg-config", + "sha2", + "tar", + "ureq", +] + [[package]] name = "os_pipe" version = "1.2.3" @@ -3537,6 +6468,21 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + +[[package]] +name = "ownedbytes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a059efb063b8f425b948e042e6b9bd85edfe60e913630ed727b23e2dfcc558" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "pango" version = "0.18.3" @@ -3597,12 +6543,30 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pastey" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" + [[package]] name = "pastey" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec" +[[package]] +name = "path_abs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ef02f6342ac01d8a93b65f96db53fe68a92a15f41144f97fb00a9e669633c3" +dependencies = [ + "serde", + "serde_derive", + "std_prelude", + "stfu8", +] + [[package]] name = "pathdiff" version = "0.2.3" @@ -3624,6 +6588,32 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "permutation" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df202b0b0f5b8e389955afd5f27b007b00fb948162953f1db9c70d2c7e3157d7" + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset 0.4.2", + "indexmap 2.11.4", +] + +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset 0.5.7", + "indexmap 2.11.4", +] + [[package]] name = "phf" version = "0.8.0" @@ -3654,6 +6644,15 @@ dependencies = [ "phf_shared 0.11.3", ] +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_shared 0.12.1", +] + [[package]] name = "phf_codegen" version = "0.8.0" @@ -3758,6 +6757,35 @@ dependencies = [ "siphasher 1.0.1", ] +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher 1.0.1", +] + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -3823,12 +6851,50 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "png" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" +dependencies = [ + "bitflags 2.9.4", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + [[package]] name = "portable-atomic" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "potential_utf" version = "0.1.3" @@ -3885,6 +6951,16 @@ dependencies = [ "termtree", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.106", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -3953,6 +7029,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn 2.0.106", +] + [[package]] name = "prost" version = "0.12.6" @@ -3960,7 +7055,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive", + "prost-derive 0.12.6", +] + +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive 0.13.5", +] + +[[package]] +name = "prost-build" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" +dependencies = [ + "heck 0.5.0", + "itertools 0.11.0", + "log", + "multimap", + "once_cell", + "petgraph 0.7.1", + "prettyplease", + "prost 0.13.5", + "prost-types", + "regex", + "syn 2.0.106", + "tempfile", ] [[package]] @@ -3970,12 +7095,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools", + "itertools 0.11.0", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.11.0", "proc-macro2", "quote", "syn 2.0.106", ] +[[package]] +name = "prost-types" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52c2c1bf36ddb1a1c396b3601a3cec27c2462e45f07c386894ec3ccf5332bd16" +dependencies = [ + "prost 0.13.5", +] + [[package]] name = "ptr_meta" version = "0.1.4" @@ -3996,6 +7143,67 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "pulldown-cmark" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" +dependencies = [ + "bitflags 2.9.4", + "memchr", + "unicase", +] + +[[package]] +name = "pxfm" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" +dependencies = [ + "num-traits", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quanta" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" +dependencies = [ + "crossbeam-utils", + "libc", + "mach2", + "once_cell", + "raw-cpuid", + "wasi 0.11.1+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quick-xml" version = "0.37.5" @@ -4025,7 +7233,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.1.1", "rustls 0.23.35", "socket2 0.6.0", "thiserror 2.0.17", @@ -4045,7 +7253,7 @@ dependencies = [ "lru-slab", "rand 0.9.2", "ring", - "rustc-hash", + "rustc-hash 2.1.1", "rustls 0.23.35", "rustls-pki-types", "slab", @@ -4179,7 +7387,17 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.3", +] + +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand 0.8.5", ] [[package]] @@ -4200,6 +7418,12 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rangemap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68" + [[package]] name = "ratatui" version = "0.24.0" @@ -4210,7 +7434,7 @@ dependencies = [ "cassowary", "crossterm 0.27.0", "indoc", - "itertools", + "itertools 0.11.0", "lru", "paste", "strum", @@ -4218,12 +7442,108 @@ dependencies = [ "unicode-width 0.1.14", ] +[[package]] +name = "rav1e" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b6dd56e85d9483277cde964fd1bdb0428de4fec5ebba7540995639a21cb32b" +dependencies = [ + "aligned-vec", + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av-scenechange", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.14.0", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "paste", + "profiling", + "rand 0.9.2", + "rand_chacha 0.9.0", + "simd_helpers", + "thiserror 2.0.17", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef69c1990ceef18a116855938e74793a5f7496ee907562bd0857b6ac734ab285" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "raw-cpuid" +version = "10.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "raw-window-handle" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-cond" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2964d0cf57a3e7a06e8183d14a8b527195c706b7983549cd5462d5aa3747438f" +dependencies = [ + "either", + "itertools 0.14.0", + "rayon", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.5.17" @@ -4298,6 +7618,12 @@ dependencies = [ "regex-syntax", ] +[[package]] +name = "regex-lite" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" + [[package]] name = "regex-syntax" version = "0.8.6" @@ -4324,7 +7650,7 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", + "h2 0.3.27", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.32", @@ -4337,7 +7663,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls 0.21.12", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -4362,26 +7688,33 @@ checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f" dependencies = [ "base64 0.22.1", "bytes", + "encoding_rs", "futures-core", "futures-util", + "h2 0.4.12", "http 1.4.0", "http-body 1.0.1", "http-body-util", "hyper 1.8.1", "hyper-rustls 0.27.7", + "hyper-tls", "hyper-util", "js-sys", "log", + "mime", + "native-tls", "percent-encoding", "pin-project-lite", "quinn", "rustls 0.23.35", + "rustls-native-certs", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.2", "tokio", + "tokio-native-tls", "tokio-rustls 0.26.4", "tokio-util", "tower", @@ -4427,6 +7760,9 @@ name = "retrochat-core" version = "0.1.0" dependencies = [ "anyhow", + "arrow", + "arrow-array", + "arrow-schema", "async-trait", "atty", "backoff", @@ -4435,19 +7771,22 @@ dependencies = [ "clap", "crossterm 0.27.0", "dirs 5.0.1", + "fastembed", "flate2", "futures", "hex", + "lancedb", "lazy_static", "mockall", "notify", "num_cpus", - "prost", + "prost 0.12.6", "regex", "reqwest 0.11.27", "rusqlite", "serde", "serde_json", + "sha2", "similar", "sqlx", "tempfile", @@ -4544,6 +7883,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "rgb" +version = "0.8.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6a884d2998352bb4daf0183589aec883f16a6da1f4dde84d8e2e9a5409a1ce" + [[package]] name = "ring" version = "0.17.14" @@ -4597,7 +7942,7 @@ dependencies = [ "base64 0.22.1", "chrono", "futures", - "pastey", + "pastey 0.2.1", "pin-project-lite", "rmcp-macros", "schemars 1.1.0", @@ -4615,13 +7960,23 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ef03779cccab8337dd8617c53fce5c98ec21794febc397531555472ca28f8c3" dependencies = [ - "darling", + "darling 0.21.3", "proc-macro2", "quote", "serde_json", "syn 2.0.106", ] +[[package]] +name = "roaring" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41589aba99537475bf697f2118357cad1c31590c5a1b9f6d9fc4ad6d07503661" +dependencies = [ + "bytemuck", + "byteorder", +] + [[package]] name = "rsa" version = "0.9.8" @@ -4656,6 +8011,16 @@ dependencies = [ "smallvec", ] +[[package]] +name = "rust-stemmers" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54" +dependencies = [ + "serde", + "serde_derive", +] + [[package]] name = "rust_decimal" version = "1.39.0" @@ -4678,6 +8043,12 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +[[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" @@ -4693,6 +8064,20 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.37.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + [[package]] name = "rustix" version = "0.38.44" @@ -4737,6 +8122,8 @@ version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ + "aws-lc-rs", + "log", "once_cell", "ring", "rustls-pki-types", @@ -4745,6 +8132,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe 0.2.0", + "rustls-pki-types", + "schannel", + "security-framework 3.5.1", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -4754,6 +8153,15 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.13.1" @@ -4780,6 +8188,7 @@ version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -4806,6 +8215,24 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.0", +] + +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot", +] + [[package]] name = "schemars" version = "0.8.22" @@ -4900,6 +8327,42 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags 2.9.4", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "selectors" version = "0.24.0" @@ -4928,6 +8391,12 @@ dependencies = [ "serde_core", ] +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + [[package]] name = "serde" version = "1.0.225" @@ -5060,7 +8529,7 @@ version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ - "darling", + "darling 0.21.3", "proc-macro2", "quote", "syn 2.0.106", @@ -5140,6 +8609,15 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "shellexpand" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1fdf65dd6331831494dd616b30351c38e96e45921a27745cf98490458b90bb" +dependencies = [ + "dirs 6.0.0", +] + [[package]] name = "shlex" version = "1.3.0" @@ -5203,6 +8681,15 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "simdutf8" version = "0.1.5" @@ -5227,6 +8714,30 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +[[package]] +name = "skeptic" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d23b015676c90a0f01c197bfdc786c20342c73a0afdda9025adb0bc42940a8" +dependencies = [ + "bytecount", + "cargo_metadata 0.14.2", + "error-chain", + "glob", + "pulldown-cmark", + "tempfile", + "walkdir", +] + +[[package]] +name = "sketches-ddsketch" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c" +dependencies = [ + "serde", +] + [[package]] name = "slab" version = "0.4.11" @@ -5239,6 +8750,59 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "snafu" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" +dependencies = [ + "doc-comment", + "snafu-derive 0.7.5", +] + +[[package]] +name = "snafu" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e84b3f4eacbf3a1ce05eac6763b4d629d60cbc94d632e4092c54ade71f1e1a2" +dependencies = [ + "snafu-derive 0.8.9", +] + +[[package]] +name = "snafu-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "snafu-derive" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1c97747dbf44bb1ca44a561ece23508e99cb592e862f22222dcf42f51d1e451" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.10" @@ -5259,6 +8823,17 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "socks" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b" +dependencies = [ + "byteorder", + "libc", + "winapi", +] + [[package]] name = "softbuffer" version = "0.4.6" @@ -5268,7 +8843,7 @@ dependencies = [ "bytemuck", "cfg_aliases", "core-graphics", - "foreign-types", + "foreign-types 0.5.0", "js-sys", "log", "objc2 0.5.2", @@ -5326,14 +8901,47 @@ dependencies = [ "der", ] +[[package]] +name = "spm_precompiled" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5851699c4033c63636f7ea4cf7b7c1f1bf06d0cc03cfb42e711de5a5c46cf326" +dependencies = [ + "base64 0.13.1", + "nom 7.1.3", + "serde", + "unicode-segmentation", +] + [[package]] name = "sqlformat" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" dependencies = [ - "nom", - "unicode_categories", + "nom 7.1.3", + "unicode_categories", +] + +[[package]] +name = "sqlparser" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05a528114c392209b3264855ad491fcce534b94a38771b0a0b97a79379275ce8" +dependencies = [ + "log", + "sqlparser_derive", +] + +[[package]] +name = "sqlparser_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da5fc6819faabb412da764b99d3b713bb55083c11e7e0c00144d386cd6a1939c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] @@ -5378,7 +8986,7 @@ dependencies = [ "paste", "percent-encoding", "rustls 0.21.12", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "sha2", @@ -5553,6 +9161,18 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "std_prelude" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8207e78455ffdf55661170876f88daf85356e4edd54e0a3dbc79586ca1e50cbe" + +[[package]] +name = "stfu8" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51f1e89f093f99e7432c491c382b88a6860a5adbe6bf02574bf0a08efff1978" + [[package]] name = "string_cache" version = "0.8.9" @@ -5737,6 +9357,153 @@ dependencies = [ "version-compare", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "tantivy" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96599ea6fccd844fc833fed21d2eecac2e6a7c1afd9e044057391d78b1feb141" +dependencies = [ + "aho-corasick", + "arc-swap", + "base64 0.22.1", + "bitpacking", + "byteorder", + "census", + "crc32fast", + "crossbeam-channel", + "downcast-rs", + "fastdivide", + "fnv", + "fs4", + "htmlescape", + "itertools 0.12.1", + "levenshtein_automata", + "log", + "lru", + "lz4_flex", + "measure_time", + "memmap2", + "num_cpus", + "once_cell", + "oneshot", + "rayon", + "regex", + "rust-stemmers", + "rustc-hash 1.1.0", + "serde", + "serde_json", + "sketches-ddsketch", + "smallvec", + "tantivy-bitpacker", + "tantivy-columnar", + "tantivy-common", + "tantivy-fst", + "tantivy-query-grammar", + "tantivy-stacker", + "tantivy-tokenizer-api", + "tempfile", + "thiserror 1.0.69", + "time", + "uuid", + "winapi", +] + +[[package]] +name = "tantivy-bitpacker" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284899c2325d6832203ac6ff5891b297fc5239c3dc754c5bc1977855b23c10df" +dependencies = [ + "bitpacking", +] + +[[package]] +name = "tantivy-columnar" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12722224ffbe346c7fec3275c699e508fd0d4710e629e933d5736ec524a1f44e" +dependencies = [ + "downcast-rs", + "fastdivide", + "itertools 0.12.1", + "serde", + "tantivy-bitpacker", + "tantivy-common", + "tantivy-sstable", + "tantivy-stacker", +] + +[[package]] +name = "tantivy-common" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8019e3cabcfd20a1380b491e13ff42f57bb38bf97c3d5fa5c07e50816e0621f4" +dependencies = [ + "async-trait", + "byteorder", + "ownedbytes", + "serde", + "time", +] + +[[package]] +name = "tantivy-fst" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d60769b80ad7953d8a7b2c70cdfe722bbcdcac6bccc8ac934c40c034d866fc18" +dependencies = [ + "byteorder", + "regex-syntax", + "utf8-ranges", +] + +[[package]] +name = "tantivy-query-grammar" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "847434d4af57b32e309f4ab1b4f1707a6c566656264caa427ff4285c4d9d0b82" +dependencies = [ + "nom 7.1.3", +] + +[[package]] +name = "tantivy-sstable" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c69578242e8e9fc989119f522ba5b49a38ac20f576fc778035b96cc94f41f98e" +dependencies = [ + "tantivy-bitpacker", + "tantivy-common", + "tantivy-fst", + "zstd", +] + +[[package]] +name = "tantivy-stacker" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56d6ff5591fc332739b3ce7035b57995a3ce29a93ffd6012660e0949c956ea8" +dependencies = [ + "murmurhash32", + "rand_distr", + "tantivy-common", +] + +[[package]] +name = "tantivy-tokenizer-api" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0dcade25819a89cfe6f17d932c9cedff11989936bf6dd4f336d50392053b04" +dependencies = [ + "serde", +] + [[package]] name = "tao" version = "0.34.5" @@ -5895,7 +9662,7 @@ dependencies = [ "ico", "json-patch", "plist", - "png", + "png 0.17.16", "proc-macro2", "quote", "semver", @@ -6117,7 +9884,7 @@ checksum = "76a423c51176eb3616ee9b516a9fa67fed5f0e78baaba680e44eb5dd2cc37490" dependencies = [ "anyhow", "brotli", - "cargo_metadata", + "cargo_metadata 0.19.2", "ctor", "dunce", "glob", @@ -6164,7 +9931,7 @@ version = "3.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" dependencies = [ - "fastrand", + "fastrand 2.3.0", "getrandom 0.3.3", "once_cell", "rustix 1.1.2", @@ -6247,6 +10014,20 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "tiff" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg 0.4.21", +] + [[package]] name = "time" version = "0.3.44" @@ -6280,6 +10061,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.1" @@ -6305,6 +10095,39 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +[[package]] +name = "tokenizers" +version = "0.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a620b996116a59e184c2fa2dfd8251ea34a36d0a514758c6f966386bd2e03476" +dependencies = [ + "ahash 0.8.12", + "aho-corasick", + "compact_str", + "dary_heap", + "derive_builder", + "esaxx-rs", + "getrandom 0.3.3", + "itertools 0.14.0", + "log", + "macro_rules_attribute", + "monostate", + "onig", + "paste", + "rand 0.9.2", + "rayon", + "rayon-cond", + "regex", + "regex-syntax", + "serde", + "serde_json", + "spm_precompiled", + "thiserror 2.0.17", + "unicode-normalization-alignments", + "unicode-segmentation", + "unicode_categories", +] + [[package]] name = "tokio" version = "1.47.1" @@ -6337,6 +10160,16 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.24.1" @@ -6498,13 +10331,18 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ + "async-compression", "bitflags 2.9.4", "bytes", + "futures-core", "futures-util", "http 1.4.0", "http-body 1.0.1", + "http-body-util", "iri-string", "pin-project-lite", + "tokio", + "tokio-util", "tower", "tower-layer", "tower-service", @@ -6612,18 +10450,30 @@ dependencies = [ "objc2-core-graphics", "objc2-foundation 0.3.2", "once_cell", - "png", + "png 0.17.16", "serde", "thiserror 2.0.17", "windows-sys 0.60.2", ] +[[package]] +name = "triomphe" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" + [[package]] name = "try-lock" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" + [[package]] name = "typeid" version = "1.0.3" @@ -6688,6 +10538,12 @@ dependencies = [ "unic-common", ] +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-bidi" version = "0.3.18" @@ -6709,6 +10565,15 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-normalization-alignments" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f613e4fa046e69818dd287fdc4bc78175ff20331479dab6e1b0f98d57062de" +dependencies = [ + "smallvec", +] + [[package]] name = "unicode-properties" version = "0.1.3" @@ -6745,6 +10610,26 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64 0.22.1", + "flate2", + "log", + "native-tls", + "once_cell", + "rustls 0.23.35", + "rustls-pki-types", + "serde", + "serde_json", + "socks", + "url", + "webpki-roots 0.26.11", +] + [[package]] name = "url" version = "2.5.7" @@ -6781,6 +10666,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8-ranges" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" + [[package]] name = "utf8-width" version = "0.1.8" @@ -6811,6 +10702,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" @@ -6841,6 +10743,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + [[package]] name = "vswhom" version = "0.1.0" @@ -6861,6 +10769,12 @@ dependencies = [ "libc", ] +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + [[package]] name = "walkdir" version = "2.5.0" @@ -7131,6 +11045,15 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.4", +] + [[package]] name = "webpki-roots" version = "1.0.4" @@ -7176,6 +11099,12 @@ dependencies = [ "windows-core 0.61.2", ] +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + [[package]] name = "whoami" version = "1.6.1" @@ -7335,6 +11264,17 @@ dependencies = [ "windows-link 0.1.3", ] +[[package]] +name = "windows-registry" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f91f87ce112ffb7275000ea98eb1940912c21c1567c9312fde20261f3eadd29" +dependencies = [ + "windows-link 0.2.0", + "windows-result 0.4.0", + "windows-strings 0.5.0", +] + [[package]] name = "windows-result" version = "0.3.4" @@ -7821,6 +11761,18 @@ dependencies = [ "rustix 1.1.2", ] +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "y4m" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" + [[package]] name = "yaml-rust" version = "0.4.5" @@ -7866,7 +11818,7 @@ dependencies = [ "enumflags2", "event-listener 5.4.1", "futures-core", - "futures-lite", + "futures-lite 2.6.1", "hex", "nix", "ordered-stream", @@ -8002,6 +11954,73 @@ dependencies = [ "memchr", ] +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "111f7d9820f05fd715df3144e254d6fc02ee4088b0644c0ffd0efc9e6d9d2773" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +dependencies = [ + "zune-core 0.4.12", +] + +[[package]] +name = "zune-jpeg" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35aee689668bf9bd6f6f3a6c60bb29ba1244b3b43adfd50edd554a371da37d5" +dependencies = [ + "zune-core 0.5.0", +] + [[package]] name = "zvariant" version = "5.8.0" diff --git a/Cargo.toml b/Cargo.toml index 440e381..14df933 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,14 @@ rusqlite = { version = "0.30", features = ["bundled", "backup"] } rmcp = { version = "0.11", features = ["server", "macros", "transport-io"] } schemars = { version = "1.0", features = ["chrono04", "uuid1"] } +# Semantic Search / Vector DB +lancedb = "0.15" +arrow = { version = "53", default-features = false, features = ["chrono-tz"] } +arrow-array = "53" +arrow-schema = "53" +fastembed = "4" +sha2 = "0.10" + [workspace.package] version = "0.1.0" edition = "2021" diff --git a/crates/retrochat-core/Cargo.toml b/crates/retrochat-core/Cargo.toml index 8875442..99bc2cf 100644 --- a/crates/retrochat-core/Cargo.toml +++ b/crates/retrochat-core/Cargo.toml @@ -44,9 +44,18 @@ notify = { workspace = true } similar = { workspace = true } crossterm = { workspace = true } +# Semantic Search (optional) +lancedb = { workspace = true, optional = true } +arrow = { workspace = true, optional = true } +arrow-array = { workspace = true, optional = true } +arrow-schema = { workspace = true, optional = true } +fastembed = { workspace = true, optional = true } +sha2 = { workspace = true } + [features] default = ["reqwest"] reqwest = ["dep:reqwest"] +semantic-search = ["lancedb", "arrow", "arrow-array", "arrow-schema", "fastembed"] [dev-dependencies] tempfile = "3.8" diff --git a/crates/retrochat-core/src/embedding/config.rs b/crates/retrochat-core/src/embedding/config.rs new file mode 100644 index 0000000..1db3958 --- /dev/null +++ b/crates/retrochat-core/src/embedding/config.rs @@ -0,0 +1,99 @@ +//! Configuration for embedding generation. + +use std::path::PathBuf; + +use super::models::EmbeddingModel; + +/// Configuration for the embedding service. +#[derive(Debug, Clone)] +pub struct EmbeddingConfig { + /// The embedding model to use. + pub model: EmbeddingModel, + + /// Directory to cache downloaded models. + /// Defaults to `~/.retrochat/models/` if not specified. + pub cache_dir: Option, + + /// Whether to show download progress when fetching models. + pub show_download_progress: bool, +} + +impl Default for EmbeddingConfig { + fn default() -> Self { + Self { + model: EmbeddingModel::BGESmallENV15, + cache_dir: None, + show_download_progress: true, + } + } +} + +impl EmbeddingConfig { + /// Create a new configuration with the specified model. + pub fn new(model: EmbeddingModel) -> Self { + Self { + model, + ..Default::default() + } + } + + /// Set the cache directory for downloaded models. + pub fn with_cache_dir(mut self, path: PathBuf) -> Self { + self.cache_dir = Some(path); + self + } + + /// Set whether to show download progress. + pub fn with_show_download_progress(mut self, show: bool) -> Self { + self.show_download_progress = show; + self + } + + /// Get the cache directory, using default if not specified. + pub fn get_cache_dir(&self) -> PathBuf { + self.cache_dir.clone().unwrap_or_else(|| { + dirs::home_dir() + .unwrap_or_else(|| PathBuf::from(".")) + .join(".retrochat") + .join("models") + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_default_config() { + let config = EmbeddingConfig::default(); + assert!(matches!(config.model, EmbeddingModel::BGESmallENV15)); + assert!(config.cache_dir.is_none()); + assert!(config.show_download_progress); + } + + #[test] + fn test_config_builder() { + let config = EmbeddingConfig::new(EmbeddingModel::AllMiniLML6V2) + .with_cache_dir(PathBuf::from("/tmp/models")) + .with_show_download_progress(false); + + assert!(matches!(config.model, EmbeddingModel::AllMiniLML6V2)); + assert_eq!(config.cache_dir, Some(PathBuf::from("/tmp/models"))); + assert!(!config.show_download_progress); + } + + #[test] + fn test_get_cache_dir_default() { + let config = EmbeddingConfig::default(); + let cache_dir = config.get_cache_dir(); + assert!(cache_dir.to_string_lossy().contains(".retrochat")); + assert!(cache_dir.to_string_lossy().contains("models")); + } + + #[test] + fn test_get_cache_dir_custom() { + let config = EmbeddingConfig::default().with_cache_dir(PathBuf::from("/custom/path")); + assert_eq!(config.get_cache_dir(), PathBuf::from("/custom/path")); + } +} diff --git a/crates/retrochat-core/src/embedding/mod.rs b/crates/retrochat-core/src/embedding/mod.rs new file mode 100644 index 0000000..e056b7c --- /dev/null +++ b/crates/retrochat-core/src/embedding/mod.rs @@ -0,0 +1,12 @@ +//! Embedding generation module for semantic search. +//! +//! This module provides text embedding generation using FastEmbed-rs +//! for local, CPU-based inference without external API calls. + +mod config; +mod models; +mod service; + +pub use config::EmbeddingConfig; +pub use models::{EmbeddingModel, ModelInfo}; +pub use service::EmbeddingService; diff --git a/crates/retrochat-core/src/embedding/models.rs b/crates/retrochat-core/src/embedding/models.rs new file mode 100644 index 0000000..9b53810 --- /dev/null +++ b/crates/retrochat-core/src/embedding/models.rs @@ -0,0 +1,181 @@ +//! Supported embedding models and their metadata. + +use std::fmt; + +/// Supported embedding models. +/// +/// These map to FastEmbed model variants. Quantized versions (with Q suffix) +/// are smaller and faster but may have slightly lower quality. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum EmbeddingModel { + /// BGE Small English v1.5 - Good balance of quality and speed. + /// 384 dimensions, ~33MB model size. + BGESmallENV15, + + /// BGE Small English v1.5 (Quantized) - Faster, smaller. + /// 384 dimensions, ~17MB model size. + BGESmallENV15Q, + + /// All MiniLM L6 v2 - Fast and lightweight. + /// 384 dimensions, ~23MB model size. + AllMiniLML6V2, + + /// All MiniLM L6 v2 (Quantized) - Fastest option. + /// 384 dimensions, ~12MB model size. + AllMiniLML6V2Q, + + /// BGE Base English v1.5 - Higher quality, slower. + /// 768 dimensions, ~110MB model size. + BGEBaseENV15, + + /// BGE Base English v1.5 (Quantized). + /// 768 dimensions, ~55MB model size. + BGEBaseENV15Q, +} + +impl EmbeddingModel { + /// Get the number of dimensions for this model's embeddings. + pub fn dimensions(&self) -> usize { + match self { + Self::BGESmallENV15 | Self::BGESmallENV15Q => 384, + Self::AllMiniLML6V2 | Self::AllMiniLML6V2Q => 384, + Self::BGEBaseENV15 | Self::BGEBaseENV15Q => 768, + } + } + + /// Get the approximate model size in MB. + pub fn model_size_mb(&self) -> usize { + match self { + Self::BGESmallENV15 => 33, + Self::BGESmallENV15Q => 17, + Self::AllMiniLML6V2 => 23, + Self::AllMiniLML6V2Q => 12, + Self::BGEBaseENV15 => 110, + Self::BGEBaseENV15Q => 55, + } + } + + /// Check if this is a quantized model variant. + pub fn is_quantized(&self) -> bool { + matches!( + self, + Self::BGESmallENV15Q | Self::AllMiniLML6V2Q | Self::BGEBaseENV15Q + ) + } + + /// Get the model name as used by FastEmbed. + pub fn fastembed_name(&self) -> &'static str { + match self { + Self::BGESmallENV15 => "BAAI/bge-small-en-v1.5", + Self::BGESmallENV15Q => "BAAI/bge-small-en-v1.5", + Self::AllMiniLML6V2 => "sentence-transformers/all-MiniLM-L6-v2", + Self::AllMiniLML6V2Q => "sentence-transformers/all-MiniLM-L6-v2", + Self::BGEBaseENV15 => "BAAI/bge-base-en-v1.5", + Self::BGEBaseENV15Q => "BAAI/bge-base-en-v1.5", + } + } +} + +impl fmt::Display for EmbeddingModel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::BGESmallENV15 => write!(f, "BGESmallENV15"), + Self::BGESmallENV15Q => write!(f, "BGESmallENV15Q"), + Self::AllMiniLML6V2 => write!(f, "AllMiniLML6V2"), + Self::AllMiniLML6V2Q => write!(f, "AllMiniLML6V2Q"), + Self::BGEBaseENV15 => write!(f, "BGEBaseENV15"), + Self::BGEBaseENV15Q => write!(f, "BGEBaseENV15Q"), + } + } +} + +impl std::str::FromStr for EmbeddingModel { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "bgesmallenv15" | "bge-small-en-v1.5" => Ok(Self::BGESmallENV15), + "bgesmallenv15q" | "bge-small-en-v1.5-q" => Ok(Self::BGESmallENV15Q), + "allminiml6v2" | "all-minilm-l6-v2" => Ok(Self::AllMiniLML6V2), + "allminiml6v2q" | "all-minilm-l6-v2-q" => Ok(Self::AllMiniLML6V2Q), + "bgebaseenv15" | "bge-base-en-v1.5" => Ok(Self::BGEBaseENV15), + "bgebaseenv15q" | "bge-base-en-v1.5-q" => Ok(Self::BGEBaseENV15Q), + _ => Err(format!("Unknown embedding model: {s}")), + } + } +} + +/// Information about the loaded embedding model. +#[derive(Debug, Clone)] +pub struct ModelInfo { + /// The model variant. + pub model: EmbeddingModel, + + /// Human-readable model name. + pub name: String, + + /// Number of embedding dimensions. + pub dimensions: usize, + + /// Whether the model is quantized. + pub quantized: bool, +} + +impl From for ModelInfo { + fn from(model: EmbeddingModel) -> Self { + Self { + name: model.to_string(), + dimensions: model.dimensions(), + quantized: model.is_quantized(), + model, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_model_dimensions() { + assert_eq!(EmbeddingModel::BGESmallENV15.dimensions(), 384); + assert_eq!(EmbeddingModel::BGESmallENV15Q.dimensions(), 384); + assert_eq!(EmbeddingModel::AllMiniLML6V2.dimensions(), 384); + assert_eq!(EmbeddingModel::BGEBaseENV15.dimensions(), 768); + } + + #[test] + fn test_model_is_quantized() { + assert!(!EmbeddingModel::BGESmallENV15.is_quantized()); + assert!(EmbeddingModel::BGESmallENV15Q.is_quantized()); + assert!(!EmbeddingModel::AllMiniLML6V2.is_quantized()); + assert!(EmbeddingModel::AllMiniLML6V2Q.is_quantized()); + } + + #[test] + fn test_model_from_str() { + assert_eq!( + "BGESmallENV15".parse::().unwrap(), + EmbeddingModel::BGESmallENV15 + ); + assert_eq!( + "bge-small-en-v1.5".parse::().unwrap(), + EmbeddingModel::BGESmallENV15 + ); + assert!("invalid".parse::().is_err()); + } + + #[test] + fn test_model_display() { + assert_eq!(EmbeddingModel::BGESmallENV15.to_string(), "BGESmallENV15"); + assert_eq!(EmbeddingModel::AllMiniLML6V2Q.to_string(), "AllMiniLML6V2Q"); + } + + #[test] + fn test_model_info_from_model() { + let info = ModelInfo::from(EmbeddingModel::BGESmallENV15Q); + assert_eq!(info.name, "BGESmallENV15Q"); + assert_eq!(info.dimensions, 384); + assert!(info.quantized); + } +} diff --git a/crates/retrochat-core/src/embedding/service.rs b/crates/retrochat-core/src/embedding/service.rs new file mode 100644 index 0000000..6a55662 --- /dev/null +++ b/crates/retrochat-core/src/embedding/service.rs @@ -0,0 +1,183 @@ +//! Embedding service for generating text embeddings. + +use anyhow::{Context, Result}; +use fastembed::{EmbeddingModel as FastEmbedModel, InitOptions, TextEmbedding}; + +use super::config::EmbeddingConfig; +use super::models::{EmbeddingModel, ModelInfo}; + +/// Service for generating text embeddings using local models. +/// +/// This service wraps FastEmbed-rs to provide text embedding generation +/// without requiring external API calls. Models are downloaded on first use +/// and cached locally. +pub struct EmbeddingService { + model: TextEmbedding, + info: ModelInfo, +} + +impl EmbeddingService { + /// Create a new embedding service with the given configuration. + /// + /// This will download the model on first use if not already cached. + pub fn new(config: EmbeddingConfig) -> Result { + let fastembed_model = Self::to_fastembed_model(&config.model); + + let init_options = InitOptions::new(fastembed_model) + .with_cache_dir(config.get_cache_dir()) + .with_show_download_progress(config.show_download_progress); + + let model = + TextEmbedding::try_new(init_options).context("Failed to initialize embedding model")?; + + let info = ModelInfo::from(config.model); + + Ok(Self { model, info }) + } + + /// Create a new embedding service with default configuration. + pub fn with_defaults() -> Result { + Self::new(EmbeddingConfig::default()) + } + + /// Get information about the loaded model. + pub fn model_info(&self) -> &ModelInfo { + &self.info + } + + /// Generate an embedding for a single text. + /// + /// Returns a vector of f32 values representing the text's semantic embedding. + pub fn embed_text(&self, text: &str) -> Result> { + let embeddings = self + .model + .embed(vec![text], None) + .context("Failed to generate embedding")?; + + embeddings + .into_iter() + .next() + .ok_or_else(|| anyhow::anyhow!("No embedding returned")) + } + + /// Generate embeddings for multiple texts in a batch. + /// + /// This is more efficient than calling `embed_text` multiple times + /// as it processes all texts in a single batch. + pub fn embed_batch(&self, texts: &[&str]) -> Result>> { + if texts.is_empty() { + return Ok(Vec::new()); + } + + let texts_vec: Vec = texts.iter().map(|s| s.to_string()).collect(); + let text_refs: Vec<&str> = texts_vec.iter().map(|s| s.as_str()).collect(); + + self.model + .embed(text_refs, None) + .context("Failed to generate batch embeddings") + } + + /// Get the number of dimensions in the embeddings. + pub fn dimensions(&self) -> usize { + self.info.dimensions + } + + /// Convert our model enum to FastEmbed's model enum. + fn to_fastembed_model(model: &EmbeddingModel) -> FastEmbedModel { + match model { + EmbeddingModel::BGESmallENV15 => FastEmbedModel::BGESmallENV15, + EmbeddingModel::BGESmallENV15Q => FastEmbedModel::BGESmallENV15, + EmbeddingModel::AllMiniLML6V2 => FastEmbedModel::AllMiniLML6V2, + EmbeddingModel::AllMiniLML6V2Q => FastEmbedModel::AllMiniLML6V2, + EmbeddingModel::BGEBaseENV15 => FastEmbedModel::BGEBaseENV15, + EmbeddingModel::BGEBaseENV15Q => FastEmbedModel::BGEBaseENV15, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::path::PathBuf; + + // Note: These tests require model download and may be slow on first run. + // They are marked as #[ignore] by default for CI. + + fn test_config() -> EmbeddingConfig { + EmbeddingConfig::new(EmbeddingModel::AllMiniLML6V2) + .with_cache_dir(PathBuf::from("/tmp/retrochat-test-models")) + .with_show_download_progress(false) + } + + #[test] + #[ignore = "Requires model download"] + fn test_embed_text() { + let service = EmbeddingService::new(test_config()).unwrap(); + + let embedding = service.embed_text("Hello, world!").unwrap(); + + assert_eq!(embedding.len(), 384); + // Embeddings should be normalized (approximately unit length) + let magnitude: f32 = embedding.iter().map(|x| x * x).sum::().sqrt(); + assert!((magnitude - 1.0).abs() < 0.1); + } + + #[test] + #[ignore = "Requires model download"] + fn test_embed_batch() { + let service = EmbeddingService::new(test_config()).unwrap(); + + let texts = vec!["First text", "Second text", "Third text"]; + let embeddings = service.embed_batch(&texts).unwrap(); + + assert_eq!(embeddings.len(), 3); + for embedding in &embeddings { + assert_eq!(embedding.len(), 384); + } + } + + #[test] + #[ignore = "Requires model download"] + fn test_embed_batch_empty() { + let service = EmbeddingService::new(test_config()).unwrap(); + + let texts: Vec<&str> = vec![]; + let embeddings = service.embed_batch(&texts).unwrap(); + + assert!(embeddings.is_empty()); + } + + #[test] + #[ignore = "Requires model download"] + fn test_similar_texts_have_similar_embeddings() { + let service = EmbeddingService::new(test_config()).unwrap(); + + let text1 = "The quick brown fox jumps over the lazy dog"; + let text2 = "A fast brown fox leaps over a sleepy dog"; + let text3 = "Machine learning is a subset of artificial intelligence"; + + let emb1 = service.embed_text(text1).unwrap(); + let emb2 = service.embed_text(text2).unwrap(); + let emb3 = service.embed_text(text3).unwrap(); + + // Cosine similarity + let sim_12: f32 = emb1.iter().zip(&emb2).map(|(a, b)| a * b).sum(); + let sim_13: f32 = emb1.iter().zip(&emb3).map(|(a, b)| a * b).sum(); + + // Similar texts should have higher similarity + assert!( + sim_12 > sim_13, + "Similar texts should have higher cosine similarity" + ); + } + + #[test] + fn test_model_info() { + // This test doesn't require model download + let info = ModelInfo::from(EmbeddingModel::BGESmallENV15); + + assert_eq!(info.dimensions, 384); + assert!(!info.quantized); + assert_eq!(info.name, "BGESmallENV15"); + } +} diff --git a/crates/retrochat-core/src/lib.rs b/crates/retrochat-core/src/lib.rs index 10aedab..d80e241 100644 --- a/crates/retrochat-core/src/lib.rs +++ b/crates/retrochat-core/src/lib.rs @@ -10,7 +10,18 @@ pub mod env; pub mod error; pub mod logging; +// Semantic search modules (feature-gated) +#[cfg(feature = "semantic-search")] +pub mod embedding; +#[cfg(feature = "semantic-search")] +pub mod vector_store; + // Re-exports for convenience pub use database::DatabaseManager; pub use error::{Result, RetroChatError}; pub use logging::{init_logging, LoggingConfig}; + +#[cfg(feature = "semantic-search")] +pub use embedding::{EmbeddingConfig, EmbeddingModel, EmbeddingService}; +#[cfg(feature = "semantic-search")] +pub use vector_store::VectorStore; diff --git a/crates/retrochat-core/src/models/session_summary.rs b/crates/retrochat-core/src/models/session_summary.rs index ec3c70e..f79af98 100644 --- a/crates/retrochat-core/src/models/session_summary.rs +++ b/crates/retrochat-core/src/models/session_summary.rs @@ -117,6 +117,69 @@ impl SessionSummary { self.prompt_version = version; self } + + /// Convert session summary to text for embedding generation. + /// + /// Combines relevant fields into a structured text format optimized + /// for semantic embedding. Optionally includes session context + /// (provider, project) for richer embeddings. + /// + /// # Arguments + /// * `provider` - Optional provider name (e.g., "Claude Code") + /// * `project` - Optional project name + pub fn to_embedding_text(&self, provider: Option<&str>, project: Option<&str>) -> String { + let mut parts = Vec::new(); + + // Title is most important for session identification + parts.push(format!("Title: {}", self.title)); + + // Core summary + parts.push(format!("Summary: {}", self.summary)); + + // Goal and outcome + if let Some(ref goal) = self.primary_goal { + parts.push(format!("Goal: {}", goal)); + } + if let Some(ref outcome) = self.outcome { + parts.push(format!("Outcome: {}", outcome)); + } + + // Context from ChatSession + if let Some(p) = provider { + parts.push(format!("Provider: {}", p)); + } + if let Some(proj) = project { + parts.push(format!("Project: {}", proj)); + } + + // Extracted entities + if let Some(ref decisions) = self.key_decisions { + if !decisions.is_empty() { + parts.push(format!("Key decisions: {}", decisions.join(", "))); + } + } + if let Some(ref techs) = self.technologies_used { + if !techs.is_empty() { + parts.push(format!("Technologies: {}", techs.join(", "))); + } + } + if let Some(ref files) = self.files_affected { + if !files.is_empty() { + parts.push(format!("Files: {}", files.join(", "))); + } + } + + parts.join("\n\n") + } + + /// Compute SHA256 hash of the embedding text for change detection. + pub fn embedding_text_hash(&self, provider: Option<&str>, project: Option<&str>) -> String { + use sha2::{Digest, Sha256}; + let text = self.to_embedding_text(provider, project); + let mut hasher = Sha256::new(); + hasher.update(text.as_bytes()); + hex::encode(hasher.finalize()) + } } #[cfg(test)] @@ -193,4 +256,75 @@ mod tests { ); assert_eq!(summary.model_used, Some("gemini-1.5-flash".to_string())); } + + #[test] + fn test_to_embedding_text_minimal() { + let summary = SessionSummary::new( + "session-1".to_string(), + "JWT Auth Implementation".to_string(), + "Implemented JWT authentication".to_string(), + ); + + let text = summary.to_embedding_text(None, None); + assert!(text.contains("Title: JWT Auth Implementation")); + assert!(text.contains("Summary: Implemented JWT authentication")); + // Should not contain optional fields + assert!(!text.contains("Goal:")); + assert!(!text.contains("Provider:")); + } + + #[test] + fn test_to_embedding_text_with_context() { + let summary = SessionSummary::new( + "session-1".to_string(), + "JWT Auth Implementation".to_string(), + "Implemented JWT authentication".to_string(), + ) + .with_primary_goal("Secure the API".to_string()) + .with_outcome(SessionOutcome::Completed); + + let text = summary.to_embedding_text(Some("Claude Code"), Some("my-api")); + assert!(text.contains("Title: JWT Auth Implementation")); + assert!(text.contains("Goal: Secure the API")); + assert!(text.contains("Outcome: completed")); + assert!(text.contains("Provider: Claude Code")); + assert!(text.contains("Project: my-api")); + } + + #[test] + fn test_to_embedding_text_full() { + let summary = SessionSummary::new( + "session-1".to_string(), + "JWT Auth".to_string(), + "Full JWT implementation".to_string(), + ) + .with_primary_goal("Secure API".to_string()) + .with_outcome(SessionOutcome::Completed) + .with_key_decisions(vec!["RS256".to_string(), "15min expiry".to_string()]) + .with_technologies_used(vec!["JWT".to_string(), "bcrypt".to_string()]) + .with_files_affected(vec!["src/auth.rs".to_string()]); + + let text = summary.to_embedding_text(Some("Claude"), Some("proj")); + assert!(text.contains("Key decisions: RS256, 15min expiry")); + assert!(text.contains("Technologies: JWT, bcrypt")); + assert!(text.contains("Files: src/auth.rs")); + } + + #[test] + fn test_embedding_text_hash_changes_with_context() { + let summary = SessionSummary::new( + "session-1".to_string(), + "Title".to_string(), + "Summary".to_string(), + ); + + let hash1 = summary.embedding_text_hash(None, None); + let hash2 = summary.embedding_text_hash(Some("Claude"), None); + let hash3 = summary.embedding_text_hash(Some("Claude"), Some("project")); + + // Different contexts should produce different hashes + assert_ne!(hash1, hash2); + assert_ne!(hash2, hash3); + assert_eq!(hash1.len(), 64); // SHA256 hex = 64 chars + } } diff --git a/crates/retrochat-core/src/models/turn_summary.rs b/crates/retrochat-core/src/models/turn_summary.rs index f90c0b2..dd4e323 100644 --- a/crates/retrochat-core/src/models/turn_summary.rs +++ b/crates/retrochat-core/src/models/turn_summary.rs @@ -148,6 +148,53 @@ impl TurnSummary { pub fn message_count(&self) -> i32 { self.end_sequence - self.start_sequence + 1 } + + /// Convert turn summary to text for embedding generation. + /// + /// Combines relevant fields into a structured text format optimized + /// for semantic embedding. The format includes labeled sections for + /// better semantic understanding. + pub fn to_embedding_text(&self) -> String { + let mut parts = Vec::new(); + + // Core LLM-generated content (always present) + parts.push(format!("Intent: {}", self.user_intent)); + parts.push(format!("Action: {}", self.assistant_action)); + parts.push(format!("Summary: {}", self.summary)); + + // Classification (helps with semantic clustering) + if let Some(ref turn_type) = self.turn_type { + parts.push(format!("Type: {}", turn_type)); + } + + // Extracted entities (searchable keywords) + if let Some(ref topics) = self.key_topics { + if !topics.is_empty() { + parts.push(format!("Topics: {}", topics.join(", "))); + } + } + if let Some(ref decisions) = self.decisions_made { + if !decisions.is_empty() { + parts.push(format!("Decisions: {}", decisions.join(", "))); + } + } + if let Some(ref concepts) = self.code_concepts { + if !concepts.is_empty() { + parts.push(format!("Code concepts: {}", concepts.join(", "))); + } + } + + parts.join("\n\n") + } + + /// Compute SHA256 hash of the embedding text for change detection. + pub fn embedding_text_hash(&self) -> String { + use sha2::{Digest, Sha256}; + let text = self.to_embedding_text(); + let mut hasher = Sha256::new(); + hasher.update(text.as_bytes()); + hex::encode(hasher.finalize()) + } } /// Detected turn boundaries before summarization @@ -265,4 +312,76 @@ mod tests { assert_eq!(turn.end_sequence, 5); assert_eq!(turn.message_count(), 5); } + + #[test] + fn test_to_embedding_text_minimal() { + let now = Utc::now(); + let summary = TurnSummary::new( + "session-1".to_string(), + 0, + 1, + 3, + "Implement JWT auth".to_string(), + "Created auth module".to_string(), + "User wanted auth, created JWT module".to_string(), + now, + now, + ); + + let text = summary.to_embedding_text(); + assert!(text.contains("Intent: Implement JWT auth")); + assert!(text.contains("Action: Created auth module")); + assert!(text.contains("Summary: User wanted auth")); + // Should not contain optional fields + assert!(!text.contains("Type:")); + assert!(!text.contains("Topics:")); + } + + #[test] + fn test_to_embedding_text_full() { + let now = Utc::now(); + let summary = TurnSummary::new( + "session-1".to_string(), + 0, + 1, + 3, + "Implement JWT auth".to_string(), + "Created auth module".to_string(), + "User wanted auth, created JWT module".to_string(), + now, + now, + ) + .with_turn_type(TurnType::Task) + .with_key_topics(vec!["authentication".to_string(), "JWT".to_string()]) + .with_decisions_made(vec!["Use RS256".to_string()]) + .with_code_concepts(vec!["middleware".to_string()]); + + let text = summary.to_embedding_text(); + assert!(text.contains("Intent: Implement JWT auth")); + assert!(text.contains("Type: task")); + assert!(text.contains("Topics: authentication, JWT")); + assert!(text.contains("Decisions: Use RS256")); + assert!(text.contains("Code concepts: middleware")); + } + + #[test] + fn test_embedding_text_hash_consistency() { + let now = Utc::now(); + let summary = TurnSummary::new( + "session-1".to_string(), + 0, + 1, + 3, + "intent".to_string(), + "action".to_string(), + "summary".to_string(), + now, + now, + ); + + let hash1 = summary.embedding_text_hash(); + let hash2 = summary.embedding_text_hash(); + assert_eq!(hash1, hash2); + assert_eq!(hash1.len(), 64); // SHA256 hex = 64 chars + } } diff --git a/crates/retrochat-core/src/vector_store/mod.rs b/crates/retrochat-core/src/vector_store/mod.rs new file mode 100644 index 0000000..4e7b4c8 --- /dev/null +++ b/crates/retrochat-core/src/vector_store/mod.rs @@ -0,0 +1,11 @@ +//! Vector store module for semantic search using LanceDB. +//! +//! This module provides vector storage and similarity search capabilities +//! using LanceDB as the embedded vector database. + +mod models; +mod schemas; +mod store; + +pub use models::{SessionEmbedding, TurnEmbedding}; +pub use store::VectorStore; diff --git a/crates/retrochat-core/src/vector_store/models.rs b/crates/retrochat-core/src/vector_store/models.rs new file mode 100644 index 0000000..9f6d459 --- /dev/null +++ b/crates/retrochat-core/src/vector_store/models.rs @@ -0,0 +1,356 @@ +//! Data models for vector storage. + +use chrono::{DateTime, Utc}; + +/// Embedding record for turn summaries stored in LanceDB. +#[derive(Debug, Clone)] +pub struct TurnEmbedding { + /// Primary key (matches TurnSummary.id). + pub id: String, + + /// Session ID for filtering. + pub session_id: String, + + /// Turn number within session. + pub turn_number: i32, + + /// Turn type classification (task, question, error_fix, etc.). + pub turn_type: Option, + + /// Turn start time for time-range queries. + pub started_at: DateTime, + + /// Turn end time. + pub ended_at: DateTime, + + /// The embedding vector (384 or 768 dimensions). + pub embedding: Vec, + + /// SHA256 hash of the embedding text for change detection. + pub text_hash: String, + + /// When the embedding was generated. + pub embedded_at: DateTime, + + /// Name of the model used to generate this embedding. + pub model_name: String, +} + +/// Embedding record for session summaries stored in LanceDB. +#[derive(Debug, Clone)] +pub struct SessionEmbedding { + /// Primary key (matches SessionSummary.id). + pub id: String, + + /// Session ID for joining with SQLite data. + pub session_id: String, + + /// Session outcome classification. + pub outcome: Option, + + /// Session creation time. + pub created_at: DateTime, + + /// Last update time. + pub updated_at: DateTime, + + /// Provider name (claude, gemini, etc.). + pub provider: String, + + /// Project name if available. + pub project: Option, + + /// The embedding vector (384 or 768 dimensions). + pub embedding: Vec, + + /// SHA256 hash of the embedding text for change detection. + pub text_hash: String, + + /// When the embedding was generated. + pub embedded_at: DateTime, + + /// Name of the model used to generate this embedding. + pub model_name: String, +} + +/// Result from a turn embedding search. +#[derive(Debug, Clone)] +pub struct TurnSearchResult { + /// Turn embedding ID. + pub id: String, + + /// Session ID. + pub session_id: String, + + /// Turn number. + pub turn_number: i32, + + /// Similarity score (0.0 to 1.0 for cosine similarity). + pub score: f32, +} + +/// Result from a session embedding search. +#[derive(Debug, Clone)] +pub struct SessionSearchResult { + /// Session embedding ID. + pub id: String, + + /// Session ID. + pub session_id: String, + + /// Similarity score (0.0 to 1.0 for cosine similarity). + pub score: f32, +} + +/// Filter options for turn embedding searches. +#[derive(Debug, Clone, Default)] +pub struct TurnFilter { + /// Filter by session ID. + pub session_id: Option, + + /// Filter by turn types. + pub turn_types: Option>, + + /// Filter by turns started after this time. + pub started_after: Option>, + + /// Filter by turns started before this time. + pub started_before: Option>, +} + +impl TurnFilter { + /// Create a new empty filter. + pub fn new() -> Self { + Self::default() + } + + /// Filter by session ID. + pub fn with_session_id(mut self, session_id: impl Into) -> Self { + self.session_id = Some(session_id.into()); + self + } + + /// Filter by turn types. + pub fn with_turn_types(mut self, types: Vec) -> Self { + self.turn_types = Some(types); + self + } + + /// Filter by time range. + pub fn with_time_range( + mut self, + after: Option>, + before: Option>, + ) -> Self { + self.started_after = after; + self.started_before = before; + self + } + + /// Build a SQL WHERE clause for LanceDB. + pub fn to_sql(&self) -> Option { + let mut conditions = Vec::new(); + + if let Some(ref session_id) = self.session_id { + conditions.push(format!("session_id = '{}'", session_id)); + } + + if let Some(ref types) = self.turn_types { + if !types.is_empty() { + let types_str = types + .iter() + .map(|t| format!("'{}'", t)) + .collect::>() + .join(", "); + conditions.push(format!("turn_type IN ({})", types_str)); + } + } + + if let Some(after) = self.started_after { + conditions.push(format!( + "started_at >= timestamp '{}'", + after.format("%Y-%m-%d %H:%M:%S") + )); + } + + if let Some(before) = self.started_before { + conditions.push(format!( + "started_at < timestamp '{}'", + before.format("%Y-%m-%d %H:%M:%S") + )); + } + + if conditions.is_empty() { + None + } else { + Some(conditions.join(" AND ")) + } + } +} + +/// Filter options for session embedding searches. +#[derive(Debug, Clone, Default)] +pub struct SessionFilter { + /// Filter by outcomes. + pub outcomes: Option>, + + /// Filter by providers. + pub providers: Option>, + + /// Filter by projects. + pub projects: Option>, + + /// Filter by sessions created after this time. + pub created_after: Option>, + + /// Filter by sessions created before this time. + pub created_before: Option>, +} + +impl SessionFilter { + /// Create a new empty filter. + pub fn new() -> Self { + Self::default() + } + + /// Filter by outcomes. + pub fn with_outcomes(mut self, outcomes: Vec) -> Self { + self.outcomes = Some(outcomes); + self + } + + /// Filter by providers. + pub fn with_providers(mut self, providers: Vec) -> Self { + self.providers = Some(providers); + self + } + + /// Filter by projects. + pub fn with_projects(mut self, projects: Vec) -> Self { + self.projects = Some(projects); + self + } + + /// Filter by time range. + pub fn with_time_range( + mut self, + after: Option>, + before: Option>, + ) -> Self { + self.created_after = after; + self.created_before = before; + self + } + + /// Build a SQL WHERE clause for LanceDB. + pub fn to_sql(&self) -> Option { + let mut conditions = Vec::new(); + + if let Some(ref outcomes) = self.outcomes { + if !outcomes.is_empty() { + let outcomes_str = outcomes + .iter() + .map(|o| format!("'{}'", o)) + .collect::>() + .join(", "); + conditions.push(format!("outcome IN ({})", outcomes_str)); + } + } + + if let Some(ref providers) = self.providers { + if !providers.is_empty() { + let providers_str = providers + .iter() + .map(|p| format!("'{}'", p)) + .collect::>() + .join(", "); + conditions.push(format!("provider IN ({})", providers_str)); + } + } + + if let Some(ref projects) = self.projects { + if !projects.is_empty() { + let projects_str = projects + .iter() + .map(|p| format!("'{}'", p)) + .collect::>() + .join(", "); + conditions.push(format!("project IN ({})", projects_str)); + } + } + + if let Some(after) = self.created_after { + conditions.push(format!( + "created_at >= timestamp '{}'", + after.format("%Y-%m-%d %H:%M:%S") + )); + } + + if let Some(before) = self.created_before { + conditions.push(format!( + "created_at < timestamp '{}'", + before.format("%Y-%m-%d %H:%M:%S") + )); + } + + if conditions.is_empty() { + None + } else { + Some(conditions.join(" AND ")) + } + } +} + +/// Statistics about the vector store. +#[derive(Debug, Clone, Default)] +pub struct VectorStoreStats { + /// Number of turn embeddings. + pub turn_count: usize, + + /// Number of session embeddings. + pub session_count: usize, + + /// Embedding dimensions. + pub dimensions: usize, + + /// Model name used for embeddings. + pub model_name: Option, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_turn_filter_to_sql_empty() { + let filter = TurnFilter::new(); + assert!(filter.to_sql().is_none()); + } + + #[test] + fn test_turn_filter_to_sql_session_id() { + let filter = TurnFilter::new().with_session_id("abc123"); + assert_eq!(filter.to_sql().unwrap(), "session_id = 'abc123'"); + } + + #[test] + fn test_turn_filter_to_sql_combined() { + let filter = TurnFilter::new() + .with_session_id("abc123") + .with_turn_types(vec!["task".to_string(), "error_fix".to_string()]); + + let sql = filter.to_sql().unwrap(); + assert!(sql.contains("session_id = 'abc123'")); + assert!(sql.contains("turn_type IN ('task', 'error_fix')")); + assert!(sql.contains(" AND ")); + } + + #[test] + fn test_session_filter_to_sql_providers() { + let filter = + SessionFilter::new().with_providers(vec!["claude".to_string(), "gemini".to_string()]); + + let sql = filter.to_sql().unwrap(); + assert!(sql.contains("provider IN ('claude', 'gemini')")); + } +} diff --git a/crates/retrochat-core/src/vector_store/schemas.rs b/crates/retrochat-core/src/vector_store/schemas.rs new file mode 100644 index 0000000..b4931ad --- /dev/null +++ b/crates/retrochat-core/src/vector_store/schemas.rs @@ -0,0 +1,130 @@ +//! Arrow schema definitions for LanceDB tables. + +use std::sync::Arc; + +use arrow_schema::{DataType, Field, Schema}; + +/// Get the Arrow schema for turn embeddings table. +/// +/// # Arguments +/// * `dimensions` - Number of dimensions in the embedding vector (e.g., 384) +pub fn turn_embeddings_schema(dimensions: usize) -> Schema { + Schema::new(vec![ + Field::new("id", DataType::Utf8, false), + Field::new("session_id", DataType::Utf8, false), + Field::new("turn_number", DataType::Int32, false), + Field::new("turn_type", DataType::Utf8, true), + Field::new( + "started_at", + DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, Some("UTC".into())), + false, + ), + Field::new( + "ended_at", + DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, Some("UTC".into())), + false, + ), + Field::new( + "embedding", + DataType::FixedSizeList( + Arc::new(Field::new("item", DataType::Float32, false)), + dimensions as i32, + ), + false, + ), + Field::new("text_hash", DataType::Utf8, false), + Field::new( + "embedded_at", + DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, Some("UTC".into())), + false, + ), + Field::new("model_name", DataType::Utf8, false), + ]) +} + +/// Get the Arrow schema for session embeddings table. +/// +/// # Arguments +/// * `dimensions` - Number of dimensions in the embedding vector (e.g., 384) +pub fn session_embeddings_schema(dimensions: usize) -> Schema { + Schema::new(vec![ + Field::new("id", DataType::Utf8, false), + Field::new("session_id", DataType::Utf8, false), + Field::new("outcome", DataType::Utf8, true), + Field::new( + "created_at", + DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, Some("UTC".into())), + false, + ), + Field::new( + "updated_at", + DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, Some("UTC".into())), + false, + ), + Field::new("provider", DataType::Utf8, false), + Field::new("project", DataType::Utf8, true), + Field::new( + "embedding", + DataType::FixedSizeList( + Arc::new(Field::new("item", DataType::Float32, false)), + dimensions as i32, + ), + false, + ), + Field::new("text_hash", DataType::Utf8, false), + Field::new( + "embedded_at", + DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, Some("UTC".into())), + false, + ), + Field::new("model_name", DataType::Utf8, false), + ]) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_turn_embeddings_schema() { + let schema = turn_embeddings_schema(384); + + assert_eq!(schema.fields().len(), 10); + assert!(schema.field_with_name("id").is_ok()); + assert!(schema.field_with_name("embedding").is_ok()); + + let embedding_field = schema.field_with_name("embedding").unwrap(); + match embedding_field.data_type() { + DataType::FixedSizeList(_, size) => assert_eq!(*size, 384), + _ => panic!("Expected FixedSizeList"), + } + } + + #[test] + fn test_session_embeddings_schema() { + let schema = session_embeddings_schema(384); + + assert_eq!(schema.fields().len(), 11); + assert!(schema.field_with_name("id").is_ok()); + assert!(schema.field_with_name("provider").is_ok()); + assert!(schema.field_with_name("project").is_ok()); + assert!(schema.field_with_name("embedding").is_ok()); + } + + #[test] + fn test_schema_with_different_dimensions() { + let schema_384 = turn_embeddings_schema(384); + let schema_768 = turn_embeddings_schema(768); + + let emb_384 = schema_384.field_with_name("embedding").unwrap(); + let emb_768 = schema_768.field_with_name("embedding").unwrap(); + + match (emb_384.data_type(), emb_768.data_type()) { + (DataType::FixedSizeList(_, s1), DataType::FixedSizeList(_, s2)) => { + assert_eq!(*s1, 384); + assert_eq!(*s2, 768); + } + _ => panic!("Expected FixedSizeList"), + } + } +} diff --git a/crates/retrochat-core/src/vector_store/store.rs b/crates/retrochat-core/src/vector_store/store.rs new file mode 100644 index 0000000..2eb8b95 --- /dev/null +++ b/crates/retrochat-core/src/vector_store/store.rs @@ -0,0 +1,887 @@ +//! LanceDB vector store implementation. + +use std::path::Path; +use std::sync::Arc; + +use anyhow::{Context, Result}; +use arrow_array::{ + Array, FixedSizeListArray, Float32Array, Int32Array, RecordBatch, RecordBatchIterator, + StringArray, TimestampMicrosecondArray, +}; +use arrow_schema::Schema; +use chrono::{DateTime, TimeZone, Utc}; +use futures::TryStreamExt; +use lancedb::query::{ExecutableQuery, QueryBase}; +use lancedb::{connect, Connection, Table}; + +use super::models::{ + SessionEmbedding, SessionFilter, SessionSearchResult, TurnEmbedding, TurnFilter, + TurnSearchResult, VectorStoreStats, +}; +use super::schemas::{session_embeddings_schema, turn_embeddings_schema}; + +const TURN_TABLE_NAME: &str = "turn_embeddings"; +const SESSION_TABLE_NAME: &str = "session_embeddings"; + +/// Vector store using LanceDB for semantic search. +pub struct VectorStore { + connection: Connection, + dimensions: usize, +} + +impl VectorStore { + /// Open or create a vector store at the given path. + /// + /// # Arguments + /// * `path` - Directory path for the LanceDB database + /// * `dimensions` - Number of dimensions in embedding vectors (e.g., 384) + pub async fn open(path: impl AsRef, dimensions: usize) -> Result { + let path_str = path.as_ref().to_string_lossy().to_string(); + + // Ensure directory exists + std::fs::create_dir_all(path.as_ref()) + .context("Failed to create vector store directory")?; + + let connection = connect(&path_str) + .execute() + .await + .context("Failed to connect to LanceDB")?; + + let store = Self { + connection, + dimensions, + }; + + // Ensure tables exist + store.ensure_tables().await?; + + Ok(store) + } + + /// Ensure required tables exist, creating them if necessary. + async fn ensure_tables(&self) -> Result<()> { + let tables = self + .connection + .table_names() + .execute() + .await + .context("Failed to list tables")?; + + if !tables.contains(&TURN_TABLE_NAME.to_string()) { + self.create_turn_table().await?; + } + + if !tables.contains(&SESSION_TABLE_NAME.to_string()) { + self.create_session_table().await?; + } + + Ok(()) + } + + /// Create the turn embeddings table. + async fn create_turn_table(&self) -> Result<()> { + let schema = Arc::new(turn_embeddings_schema(self.dimensions)); + let empty_batch = self.create_empty_turn_batch(&schema)?; + + let batches = RecordBatchIterator::new(vec![Ok(empty_batch)], schema); + + self.connection + .create_table(TURN_TABLE_NAME, Box::new(batches)) + .execute() + .await + .context("Failed to create turn_embeddings table")?; + + Ok(()) + } + + /// Create the session embeddings table. + async fn create_session_table(&self) -> Result<()> { + let schema = Arc::new(session_embeddings_schema(self.dimensions)); + let empty_batch = self.create_empty_session_batch(&schema)?; + + let batches = RecordBatchIterator::new(vec![Ok(empty_batch)], schema); + + self.connection + .create_table(SESSION_TABLE_NAME, Box::new(batches)) + .execute() + .await + .context("Failed to create session_embeddings table")?; + + Ok(()) + } + + /// Create an empty record batch for turn embeddings (used for table creation). + fn create_empty_turn_batch(&self, schema: &Arc) -> Result { + let id: StringArray = (vec![] as Vec<&str>).into(); + let session_id: StringArray = (vec![] as Vec<&str>).into(); + let turn_number: Int32Array = (vec![] as Vec).into(); + let turn_type: StringArray = StringArray::from(vec![] as Vec>); + let started_at = + TimestampMicrosecondArray::from(vec![] as Vec).with_timezone("UTC".to_string()); + let ended_at = + TimestampMicrosecondArray::from(vec![] as Vec).with_timezone("UTC".to_string()); + let embedding = FixedSizeListArray::new( + Arc::new(arrow_schema::Field::new( + "item", + arrow_schema::DataType::Float32, + false, + )), + self.dimensions as i32, + Arc::new(Float32Array::from(vec![] as Vec)), + None, + ); + let text_hash: StringArray = (vec![] as Vec<&str>).into(); + let embedded_at = + TimestampMicrosecondArray::from(vec![] as Vec).with_timezone("UTC".to_string()); + let model_name: StringArray = (vec![] as Vec<&str>).into(); + + RecordBatch::try_new( + schema.clone(), + vec![ + Arc::new(id), + Arc::new(session_id), + Arc::new(turn_number), + Arc::new(turn_type), + Arc::new(started_at), + Arc::new(ended_at), + Arc::new(embedding), + Arc::new(text_hash), + Arc::new(embedded_at), + Arc::new(model_name), + ], + ) + .context("Failed to create empty turn batch") + } + + /// Create an empty record batch for session embeddings (used for table creation). + fn create_empty_session_batch(&self, schema: &Arc) -> Result { + let id: StringArray = (vec![] as Vec<&str>).into(); + let session_id: StringArray = (vec![] as Vec<&str>).into(); + let outcome: StringArray = StringArray::from(vec![] as Vec>); + let created_at = + TimestampMicrosecondArray::from(vec![] as Vec).with_timezone("UTC".to_string()); + let updated_at = + TimestampMicrosecondArray::from(vec![] as Vec).with_timezone("UTC".to_string()); + let provider: StringArray = (vec![] as Vec<&str>).into(); + let project: StringArray = StringArray::from(vec![] as Vec>); + let embedding = FixedSizeListArray::new( + Arc::new(arrow_schema::Field::new( + "item", + arrow_schema::DataType::Float32, + false, + )), + self.dimensions as i32, + Arc::new(Float32Array::from(vec![] as Vec)), + None, + ); + let text_hash: StringArray = (vec![] as Vec<&str>).into(); + let embedded_at = + TimestampMicrosecondArray::from(vec![] as Vec).with_timezone("UTC".to_string()); + let model_name: StringArray = (vec![] as Vec<&str>).into(); + + RecordBatch::try_new( + schema.clone(), + vec![ + Arc::new(id), + Arc::new(session_id), + Arc::new(outcome), + Arc::new(created_at), + Arc::new(updated_at), + Arc::new(provider), + Arc::new(project), + Arc::new(embedding), + Arc::new(text_hash), + Arc::new(embedded_at), + Arc::new(model_name), + ], + ) + .context("Failed to create empty session batch") + } + + /// Get the turn embeddings table. + async fn turn_table(&self) -> Result { + self.connection + .open_table(TURN_TABLE_NAME) + .execute() + .await + .context("Failed to open turn_embeddings table") + } + + /// Get the session embeddings table. + async fn session_table(&self) -> Result
{ + self.connection + .open_table(SESSION_TABLE_NAME) + .execute() + .await + .context("Failed to open session_embeddings table") + } + + /// Upsert a turn embedding. + pub async fn upsert_turn_embedding(&self, embedding: TurnEmbedding) -> Result<()> { + // Delete existing if present + self.delete_turn_embedding(&embedding.id).await.ok(); + + let table = self.turn_table().await?; + let schema = Arc::new(turn_embeddings_schema(self.dimensions)); + let batch = self.turn_embedding_to_batch(&embedding, &schema)?; + + let batches = RecordBatchIterator::new(vec![Ok(batch)], schema); + + table + .add(Box::new(batches)) + .execute() + .await + .context("Failed to upsert turn embedding")?; + + Ok(()) + } + + /// Convert a TurnEmbedding to a RecordBatch. + fn turn_embedding_to_batch( + &self, + emb: &TurnEmbedding, + schema: &Arc, + ) -> Result { + let id = StringArray::from(vec![emb.id.as_str()]); + let session_id = StringArray::from(vec![emb.session_id.as_str()]); + let turn_number = Int32Array::from(vec![emb.turn_number]); + let turn_type = StringArray::from(vec![emb.turn_type.as_deref()]); + let started_at = TimestampMicrosecondArray::from(vec![emb.started_at.timestamp_micros()]) + .with_timezone("UTC".to_string()); + let ended_at = TimestampMicrosecondArray::from(vec![emb.ended_at.timestamp_micros()]) + .with_timezone("UTC".to_string()); + + let embedding_values = Float32Array::from(emb.embedding.clone()); + let embedding = FixedSizeListArray::new( + Arc::new(arrow_schema::Field::new( + "item", + arrow_schema::DataType::Float32, + false, + )), + self.dimensions as i32, + Arc::new(embedding_values), + None, + ); + + let text_hash = StringArray::from(vec![emb.text_hash.as_str()]); + let embedded_at = TimestampMicrosecondArray::from(vec![emb.embedded_at.timestamp_micros()]) + .with_timezone("UTC".to_string()); + let model_name = StringArray::from(vec![emb.model_name.as_str()]); + + RecordBatch::try_new( + schema.clone(), + vec![ + Arc::new(id), + Arc::new(session_id), + Arc::new(turn_number), + Arc::new(turn_type), + Arc::new(started_at), + Arc::new(ended_at), + Arc::new(embedding), + Arc::new(text_hash), + Arc::new(embedded_at), + Arc::new(model_name), + ], + ) + .context("Failed to create turn embedding batch") + } + + /// Upsert a session embedding. + pub async fn upsert_session_embedding(&self, embedding: SessionEmbedding) -> Result<()> { + // Delete existing if present + self.delete_session_embedding(&embedding.id).await.ok(); + + let table = self.session_table().await?; + let schema = Arc::new(session_embeddings_schema(self.dimensions)); + let batch = self.session_embedding_to_batch(&embedding, &schema)?; + + let batches = RecordBatchIterator::new(vec![Ok(batch)], schema); + + table + .add(Box::new(batches)) + .execute() + .await + .context("Failed to upsert session embedding")?; + + Ok(()) + } + + /// Convert a SessionEmbedding to a RecordBatch. + fn session_embedding_to_batch( + &self, + emb: &SessionEmbedding, + schema: &Arc, + ) -> Result { + let id = StringArray::from(vec![emb.id.as_str()]); + let session_id = StringArray::from(vec![emb.session_id.as_str()]); + let outcome = StringArray::from(vec![emb.outcome.as_deref()]); + let created_at = TimestampMicrosecondArray::from(vec![emb.created_at.timestamp_micros()]) + .with_timezone("UTC".to_string()); + let updated_at = TimestampMicrosecondArray::from(vec![emb.updated_at.timestamp_micros()]) + .with_timezone("UTC".to_string()); + let provider = StringArray::from(vec![emb.provider.as_str()]); + let project = StringArray::from(vec![emb.project.as_deref()]); + + let embedding_values = Float32Array::from(emb.embedding.clone()); + let embedding = FixedSizeListArray::new( + Arc::new(arrow_schema::Field::new( + "item", + arrow_schema::DataType::Float32, + false, + )), + self.dimensions as i32, + Arc::new(embedding_values), + None, + ); + + let text_hash = StringArray::from(vec![emb.text_hash.as_str()]); + let embedded_at = TimestampMicrosecondArray::from(vec![emb.embedded_at.timestamp_micros()]) + .with_timezone("UTC".to_string()); + let model_name = StringArray::from(vec![emb.model_name.as_str()]); + + RecordBatch::try_new( + schema.clone(), + vec![ + Arc::new(id), + Arc::new(session_id), + Arc::new(outcome), + Arc::new(created_at), + Arc::new(updated_at), + Arc::new(provider), + Arc::new(project), + Arc::new(embedding), + Arc::new(text_hash), + Arc::new(embedded_at), + Arc::new(model_name), + ], + ) + .context("Failed to create session embedding batch") + } + + /// Delete a turn embedding by ID. + pub async fn delete_turn_embedding(&self, id: &str) -> Result<()> { + let table = self.turn_table().await?; + table + .delete(&format!("id = '{}'", id)) + .await + .context("Failed to delete turn embedding")?; + Ok(()) + } + + /// Delete a session embedding by ID. + pub async fn delete_session_embedding(&self, id: &str) -> Result<()> { + let table = self.session_table().await?; + table + .delete(&format!("id = '{}'", id)) + .await + .context("Failed to delete session embedding")?; + Ok(()) + } + + /// Delete all embeddings for a session. + pub async fn delete_session(&self, session_id: &str) -> Result<()> { + let turn_table = self.turn_table().await?; + turn_table + .delete(&format!("session_id = '{}'", session_id)) + .await + .ok(); + + let session_table = self.session_table().await?; + session_table + .delete(&format!("session_id = '{}'", session_id)) + .await + .ok(); + + Ok(()) + } + + /// Get a turn embedding by ID. + pub async fn get_turn_embedding(&self, id: &str) -> Result> { + let table = self.turn_table().await?; + + let mut stream = table + .query() + .only_if(format!("id = '{}'", id)) + .limit(1) + .execute() + .await + .context("Failed to query turn embedding")?; + + if let Some(batch) = stream.try_next().await? { + if batch.num_rows() > 0 { + return Ok(Some(self.batch_to_turn_embedding(&batch, 0)?)); + } + } + + Ok(None) + } + + /// Get a session embedding by ID. + pub async fn get_session_embedding(&self, id: &str) -> Result> { + let table = self.session_table().await?; + + let mut stream = table + .query() + .only_if(format!("id = '{}'", id)) + .limit(1) + .execute() + .await + .context("Failed to query session embedding")?; + + if let Some(batch) = stream.try_next().await? { + if batch.num_rows() > 0 { + return Ok(Some(self.batch_to_session_embedding(&batch, 0)?)); + } + } + + Ok(None) + } + + /// Search turn embeddings by vector similarity. + pub async fn search_turns( + &self, + query_vector: &[f32], + limit: usize, + filter: Option, + ) -> Result> { + let table = self.turn_table().await?; + + let mut query = table.vector_search(query_vector.to_vec())?.limit(limit); + + if let Some(f) = filter { + if let Some(sql) = f.to_sql() { + query = query.only_if(sql); + } + } + + let mut stream = query.execute().await.context("Failed to search turns")?; + + let mut results = Vec::new(); + while let Some(batch) = stream.try_next().await? { + for i in 0..batch.num_rows() { + let id = batch + .column_by_name("id") + .and_then(|c| c.as_any().downcast_ref::()) + .and_then(|a| a.value(i).to_string().into()) + .unwrap_or_default(); + + let session_id = batch + .column_by_name("session_id") + .and_then(|c| c.as_any().downcast_ref::()) + .and_then(|a| a.value(i).to_string().into()) + .unwrap_or_default(); + + let turn_number = batch + .column_by_name("turn_number") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| a.value(i)) + .unwrap_or(0); + + let score = batch + .column_by_name("_distance") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| 1.0 - a.value(i)) // Convert distance to similarity + .unwrap_or(0.0); + + results.push(TurnSearchResult { + id, + session_id, + turn_number, + score, + }); + } + } + + Ok(results) + } + + /// Search session embeddings by vector similarity. + pub async fn search_sessions( + &self, + query_vector: &[f32], + limit: usize, + filter: Option, + ) -> Result> { + let table = self.session_table().await?; + + let mut query = table.vector_search(query_vector.to_vec())?.limit(limit); + + if let Some(f) = filter { + if let Some(sql) = f.to_sql() { + query = query.only_if(sql); + } + } + + let mut stream = query.execute().await.context("Failed to search sessions")?; + + let mut results = Vec::new(); + while let Some(batch) = stream.try_next().await? { + for i in 0..batch.num_rows() { + let id = batch + .column_by_name("id") + .and_then(|c| c.as_any().downcast_ref::()) + .and_then(|a| a.value(i).to_string().into()) + .unwrap_or_default(); + + let session_id = batch + .column_by_name("session_id") + .and_then(|c| c.as_any().downcast_ref::()) + .and_then(|a| a.value(i).to_string().into()) + .unwrap_or_default(); + + let score = batch + .column_by_name("_distance") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| 1.0 - a.value(i)) // Convert distance to similarity + .unwrap_or(0.0); + + results.push(SessionSearchResult { + id, + session_id, + score, + }); + } + } + + Ok(results) + } + + /// Get statistics about the vector store. + pub async fn get_stats(&self) -> Result { + let turn_table = self.turn_table().await?; + let session_table = self.session_table().await?; + + let turn_count = turn_table.count_rows(None).await.unwrap_or(0) as usize; + let session_count = session_table.count_rows(None).await.unwrap_or(0) as usize; + + Ok(VectorStoreStats { + turn_count, + session_count, + dimensions: self.dimensions, + model_name: None, // Would need to query a row to get this + }) + } + + /// Convert a RecordBatch row to TurnEmbedding. + fn batch_to_turn_embedding(&self, batch: &RecordBatch, row: usize) -> Result { + let id = batch + .column_by_name("id") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| a.value(row).to_string()) + .unwrap_or_default(); + + let session_id = batch + .column_by_name("session_id") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| a.value(row).to_string()) + .unwrap_or_default(); + + let turn_number = batch + .column_by_name("turn_number") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| a.value(row)) + .unwrap_or(0); + + let turn_type = batch + .column_by_name("turn_type") + .and_then(|c| c.as_any().downcast_ref::()) + .and_then(|a| { + if a.is_null(row) { + None + } else { + Some(a.value(row).to_string()) + } + }); + + let started_at = batch + .column_by_name("started_at") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| Utc.timestamp_micros(a.value(row)).unwrap()) + .unwrap_or_else(Utc::now); + + let ended_at = batch + .column_by_name("ended_at") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| Utc.timestamp_micros(a.value(row)).unwrap()) + .unwrap_or_else(Utc::now); + + let embedding = batch + .column_by_name("embedding") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| { + let values = a.value(row); + values + .as_any() + .downcast_ref::() + .map(|fa| fa.values().to_vec()) + .unwrap_or_default() + }) + .unwrap_or_default(); + + let text_hash = batch + .column_by_name("text_hash") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| a.value(row).to_string()) + .unwrap_or_default(); + + let embedded_at = batch + .column_by_name("embedded_at") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| Utc.timestamp_micros(a.value(row)).unwrap()) + .unwrap_or_else(Utc::now); + + let model_name = batch + .column_by_name("model_name") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| a.value(row).to_string()) + .unwrap_or_default(); + + Ok(TurnEmbedding { + id, + session_id, + turn_number, + turn_type, + started_at, + ended_at, + embedding, + text_hash, + embedded_at, + model_name, + }) + } + + /// Convert a RecordBatch row to SessionEmbedding. + fn batch_to_session_embedding( + &self, + batch: &RecordBatch, + row: usize, + ) -> Result { + let id = batch + .column_by_name("id") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| a.value(row).to_string()) + .unwrap_or_default(); + + let session_id = batch + .column_by_name("session_id") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| a.value(row).to_string()) + .unwrap_or_default(); + + let outcome = batch + .column_by_name("outcome") + .and_then(|c| c.as_any().downcast_ref::()) + .and_then(|a| { + if a.is_null(row) { + None + } else { + Some(a.value(row).to_string()) + } + }); + + let created_at = batch + .column_by_name("created_at") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| Utc.timestamp_micros(a.value(row)).unwrap()) + .unwrap_or_else(Utc::now); + + let updated_at = batch + .column_by_name("updated_at") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| Utc.timestamp_micros(a.value(row)).unwrap()) + .unwrap_or_else(Utc::now); + + let provider = batch + .column_by_name("provider") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| a.value(row).to_string()) + .unwrap_or_default(); + + let project = batch + .column_by_name("project") + .and_then(|c| c.as_any().downcast_ref::()) + .and_then(|a| { + if a.is_null(row) { + None + } else { + Some(a.value(row).to_string()) + } + }); + + let embedding = batch + .column_by_name("embedding") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| { + let values = a.value(row); + values + .as_any() + .downcast_ref::() + .map(|fa| fa.values().to_vec()) + .unwrap_or_default() + }) + .unwrap_or_default(); + + let text_hash = batch + .column_by_name("text_hash") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| a.value(row).to_string()) + .unwrap_or_default(); + + let embedded_at = batch + .column_by_name("embedded_at") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| Utc.timestamp_micros(a.value(row)).unwrap()) + .unwrap_or_else(Utc::now); + + let model_name = batch + .column_by_name("model_name") + .and_then(|c| c.as_any().downcast_ref::()) + .map(|a| a.value(row).to_string()) + .unwrap_or_default(); + + Ok(SessionEmbedding { + id, + session_id, + outcome, + created_at, + updated_at, + provider, + project, + embedding, + text_hash, + embedded_at, + model_name, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use tempfile::TempDir; + + async fn create_test_store() -> (VectorStore, TempDir) { + let temp_dir = TempDir::new().unwrap(); + let store = VectorStore::open(temp_dir.path(), 384).await.unwrap(); + (store, temp_dir) + } + + #[tokio::test] + async fn test_create_store() { + let (store, _temp_dir) = create_test_store().await; + let stats = store.get_stats().await.unwrap(); + + assert_eq!(stats.turn_count, 0); + assert_eq!(stats.session_count, 0); + assert_eq!(stats.dimensions, 384); + } + + #[tokio::test] + async fn test_upsert_turn_embedding() { + let (store, _temp_dir) = create_test_store().await; + + let embedding = TurnEmbedding { + id: "turn-1".to_string(), + session_id: "session-1".to_string(), + turn_number: 1, + turn_type: Some("task".to_string()), + started_at: Utc::now(), + ended_at: Utc::now(), + embedding: vec![0.1; 384], + text_hash: "abc123".to_string(), + embedded_at: Utc::now(), + model_name: "test-model".to_string(), + }; + + store + .upsert_turn_embedding(embedding.clone()) + .await + .unwrap(); + + let retrieved = store.get_turn_embedding("turn-1").await.unwrap().unwrap(); + assert_eq!(retrieved.id, "turn-1"); + assert_eq!(retrieved.session_id, "session-1"); + assert_eq!(retrieved.turn_number, 1); + assert_eq!(retrieved.embedding.len(), 384); + } + + #[tokio::test] + async fn test_upsert_session_embedding() { + let (store, _temp_dir) = create_test_store().await; + + let embedding = SessionEmbedding { + id: "sess-emb-1".to_string(), + session_id: "session-1".to_string(), + outcome: Some("completed".to_string()), + created_at: Utc::now(), + updated_at: Utc::now(), + provider: "claude".to_string(), + project: Some("my-project".to_string()), + embedding: vec![0.2; 384], + text_hash: "def456".to_string(), + embedded_at: Utc::now(), + model_name: "test-model".to_string(), + }; + + store + .upsert_session_embedding(embedding.clone()) + .await + .unwrap(); + + let retrieved = store + .get_session_embedding("sess-emb-1") + .await + .unwrap() + .unwrap(); + assert_eq!(retrieved.id, "sess-emb-1"); + assert_eq!(retrieved.provider, "claude"); + assert_eq!(retrieved.project, Some("my-project".to_string())); + } + + #[tokio::test] + async fn test_delete_session() { + let (store, _temp_dir) = create_test_store().await; + + // Add turn embedding + let turn = TurnEmbedding { + id: "turn-1".to_string(), + session_id: "session-to-delete".to_string(), + turn_number: 1, + turn_type: None, + started_at: Utc::now(), + ended_at: Utc::now(), + embedding: vec![0.1; 384], + text_hash: "hash".to_string(), + embedded_at: Utc::now(), + model_name: "test".to_string(), + }; + store.upsert_turn_embedding(turn).await.unwrap(); + + // Add session embedding + let session = SessionEmbedding { + id: "sess-1".to_string(), + session_id: "session-to-delete".to_string(), + outcome: None, + created_at: Utc::now(), + updated_at: Utc::now(), + provider: "claude".to_string(), + project: None, + embedding: vec![0.2; 384], + text_hash: "hash".to_string(), + embedded_at: Utc::now(), + model_name: "test".to_string(), + }; + store.upsert_session_embedding(session).await.unwrap(); + + // Delete all for session + store.delete_session("session-to-delete").await.unwrap(); + + // Verify deleted + assert!(store.get_turn_embedding("turn-1").await.unwrap().is_none()); + assert!(store + .get_session_embedding("sess-1") + .await + .unwrap() + .is_none()); + } +} diff --git a/docs/issues/semantic-search-local-embeddings.md b/docs/issues/semantic-search-local-embeddings.md new file mode 100644 index 0000000..ead6a8e --- /dev/null +++ b/docs/issues/semantic-search-local-embeddings.md @@ -0,0 +1,203 @@ +# GitHub Issue: Semantic Search with Local Embeddings + +**Title:** `feat: Semantic Search with Local Embeddings (LanceDB + FastEmbed-rs)` + +**Labels:** `enhancement`, `feature` + +--- + +## Overview + +Implement semantic (vector) search for summaries using locally-generated embeddings, enabling similarity-based retrieval beyond keyword matching. This complements the existing FTS5 full-text search with true semantic understanding. + +## Technology Stack + +### Vector Database: LanceDB +- **Crate:** [`lancedb`](https://crates.io/crates/lancedb) (v0.22+, SDK 1.0.0) +- Native Rust, embedded/serverless - no external database to manage +- Persistent storage with automatic versioning +- Supports vector similarity search + metadata filtering via SQL (DataFusion) +- Zero-copy Arrow-based storage + +### Embedding Generation: FastEmbed-rs +- **Crate:** [`fastembed`](https://crates.io/crates/fastembed) (v4+) +- Pure Rust with ONNX runtime +- Pre-trained quantized models (BGE, MiniLM) +- Fast CPU inference, no GPU required +- Models auto-downloaded on first use (~17MB quantized) + +### Recommended Model +- **Primary:** `BGESmallENV15Q` (384 dimensions, ~17MB) +- **Alternative:** `AllMiniLML6V2Q` (faster, slightly lower quality) + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ retrochat-core │ +├─────────────────────────────────────────────────────────────────┤ +│ Services Layer │ +│ ┌─────────────────────┐ ┌──────────────────────────────────┐ │ +│ │SemanticSearchService│ │ EmbeddingService │ │ +│ │ - search_summaries()│ │ - embed_text() │ │ +│ │ - hybrid_search() │ │ - embed_batch() │ │ +│ │ - find_similar() │ │ - model_info() │ │ +│ └──────────┬──────────┘ └──────────────────┬───────────────┘ │ +│ │ │ │ +│ ┌──────────▼─────────────────────────────────▼───────────────┐ │ +│ │ VectorStore (Repository Layer) │ │ +│ │ - LanceDB connection management │ │ +│ │ - Table operations (turn_embeddings, session_embeddings) │ │ +│ │ - Vector search with metadata filtering │ │ +│ └────────────────────────────────────────────────────────────┘ │ +│ │ +│ External Storage │ +│ ┌──────────────────┐ ┌────────────────────────────────────┐ │ +│ │ SQLite (existing)│ │ LanceDB │ │ +│ │ - turn_summaries │ │ - turn_embeddings table │ │ +│ │ - session_summaries│ │ - session_embeddings table │ │ +│ │ - messages │ │ - Stored in ~/.retrochat/vectors/ │ │ +│ └──────────────────┘ └────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## LanceDB Schema + +### turn_embeddings +| Field | Type | Description | +|-------|------|-------------| +| id | String | Primary key (matches turn_summaries.id) | +| session_id | String | For filtering | +| turn_number | Int32 | For filtering | +| turn_type | String | task, question, error_fix, etc. | +| started_at | Timestamp | Turn start time (time-range queries) | +| ended_at | Timestamp | Turn end time | +| embedding | FixedSizeList[384] | Vector column | +| text_hash | String | SHA256 for change detection | +| embedded_at | Timestamp | When embedding was generated | +| model_name | String | e.g., "BGESmallENV15" | + +**Indexes:** IVF_PQ on embedding, scalar indexes on started_at, turn_type, session_id + +### session_embeddings +| Field | Type | Description | +|-------|------|-------------| +| id | String | Primary key | +| session_id | String | Unique, for joining | +| outcome | String | completed, partial, abandoned, ongoing | +| created_at | Timestamp | Session creation time | +| updated_at | Timestamp | Last message time | +| provider | String | claude, gemini, chatgpt | +| project | String | Project name | +| embedding | FixedSizeList[384] | Vector column | +| text_hash | String | SHA256 for change detection | +| embedded_at | Timestamp | When embedding was generated | +| model_name | String | Model used | + +**Indexes:** IVF_PQ on embedding, scalar indexes on created_at, provider, outcome + +## Metadata Filtering + +LanceDB supports full SQL WHERE clause via DataFusion: + +```rust +// Time range query +table.query().nearest_to(&query_vec)? + .only_if("started_at >= timestamp '2025-01-01' AND started_at < timestamp '2025-02-01'") + .limit(10) + .execute().await?; + +// Combined filters +table.query().nearest_to(&query_vec)? + .only_if("provider = 'claude' AND turn_type IN ('task', 'error_fix')") + .limit(20) + .execute().await?; +``` + +## CLI Commands + +```bash +# Semantic search +retrochat search --semantic "how to handle errors in async code" +retrochat search --hybrid "authentication" --semantic-weight 0.7 + +# With metadata filters +retrochat search --semantic "migrations" --from 2025-01-01 --to 2025-06-30 +retrochat search --semantic "error handling" --provider claude --turn-type error_fix + +# Index management +retrochat index status +retrochat index rebuild [--session SESSION_ID] +``` + +## Dependencies + +```toml +[workspace.dependencies] +lancedb = "0.22" +arrow = { version = "53", default-features = false } +arrow-array = "53" +arrow-schema = "53" +fastembed = "4" +sha2 = "0.10" + +[features] +semantic-search = ["lancedb", "arrow", "arrow-array", "arrow-schema", "fastembed"] +``` + +## Implementation Phases + +### Phase 1: Foundation +- [ ] Add dependencies to workspace Cargo.toml +- [ ] Create `embedding/` module with EmbeddingService +- [ ] Create `vector_store/` module with VectorStore +- [ ] Add basic tests for embedding generation +- [ ] Add basic tests for vector storage + +### Phase 2: Integration +- [ ] Create SemanticSearchService +- [ ] Integrate with turn/session summarization services +- [ ] Add embedding generation after summary creation +- [ ] Implement change detection (skip re-embedding unchanged summaries) + +### Phase 3: Search API +- [ ] Implement semantic search endpoints +- [ ] Implement hybrid search (semantic + FTS) +- [ ] Add find-similar functionality +- [ ] Implement CLI commands for semantic search + +### Phase 4: Index Management +- [ ] Implement index rebuild command +- [ ] Add index status/statistics +- [ ] Implement incremental indexing +- [ ] Add background indexing option + +### Phase 5: Optimization +- [ ] Create IVF_PQ index after sufficient data +- [ ] Tune search parameters +- [ ] Add caching for frequent queries +- [ ] Benchmark and optimize batch operations + +## Deployment + +### Single Binary Support +- **LanceDB:** ✓ Fully embedded, no external server +- **FastEmbed-rs:** Runtime model download (default) or compile-time embedding + +| Strategy | Binary Size | Network Required | +|----------|-------------|------------------| +| Runtime download (recommended) | ~10MB | First-run only | +| Embedded models | ~60MB+ | None | + +## Success Metrics + +1. Semantic search returns more relevant results than FTS alone for conceptual queries +2. Embedding generation < 100ms per summary +3. Search latency < 50ms for 10K summaries +4. Seamless integration with existing CLI/TUI + +## References + +- [LanceDB Rust SDK](https://docs.rs/lancedb/latest/lancedb/) +- [FastEmbed-rs](https://github.com/Anush008/fastembed-rs) +- [Plan Document](docs/plans/semantic-search-local-embeddings.md) diff --git a/docs/plans/semantic-search-local-embeddings.md b/docs/plans/semantic-search-local-embeddings.md new file mode 100644 index 0000000..4afc178 --- /dev/null +++ b/docs/plans/semantic-search-local-embeddings.md @@ -0,0 +1,953 @@ +# Semantic Search with Local Embeddings - Implementation Plan + +## Overview + +Implement semantic (vector) search for summaries using locally-generated embeddings, enabling similarity-based retrieval beyond keyword matching. This complements the existing FTS5 full-text search with true semantic understanding. + +## Technology Choices + +### Vector Database: LanceDB + +**Selected:** [LanceDB](https://github.com/lancedb/lancedb) (crate: `lancedb`) + +**Rationale:** +- Native Rust SDK (now at 1.0.0 as of Dec 2025) +- Embedded/serverless - no external database to manage +- Persistent storage with automatic versioning +- Supports vector similarity search + metadata filtering +- Uses Arrow for efficient columnar storage +- Zero-copy operations +- Supports hybrid search (vector + full-text) + +**Alternatives Considered:** +- Qdrant (requires separate server process) +- SQLite with vector extensions (less mature) +- In-memory only (loses persistence) + +### Embedding Generation: FastEmbed-rs + +**Selected:** [FastEmbed-rs](https://github.com/Anush008/fastembed-rs) (crate: `fastembed`) + +**Rationale:** +- Pure Rust with ONNX runtime (via `ort`) +- Pre-trained quantized models available (BGE, MiniLM, etc.) +- Fast CPU inference (no GPU required) +- Supports text embeddings, sparse embeddings, and reranking +- Models downloaded automatically on first use +- Memory efficient with quantized variants + +**Alternatives Considered:** +- Candle (`candle_embed`) - More flexible but requires more setup +- Remote API embeddings - Adds latency and API costs +- sentence-transformers via PyO3 - Introduces Python dependency + +### Recommended Embedding Model + +**Primary:** `BGESmallENV15` (or quantized `BGESmallENV15Q`) +- 384 dimensions +- Excellent quality/speed tradeoff +- ~33MB model size (quantized: ~17MB) + +**Alternative:** `AllMiniLML6V2` (quantized: `AllMiniLML6V2Q`) +- 384 dimensions +- Faster but slightly lower quality +- Good for resource-constrained environments + +## Architecture Design + +### High-Level Architecture + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ retrochat-core │ +├─────────────────────────────────────────────────────────────────────┤ +│ Services Layer │ +│ ┌─────────────────────┐ ┌────────────────────────────────────────┐│ +│ │ SemanticSearchService│ │ EmbeddingService ││ +│ │ - search_summaries() │ │ - embed_text() ││ +│ │ - hybrid_search() │ │ - embed_batch() ││ +│ │ - find_similar() │ │ - model_info() ││ +│ └──────────┬──────────┘ └──────────────────┬─────────────────────┘│ +│ │ │ │ +│ ┌──────────▼──────────────────────────────────▼─────────────────────┤ +│ │ VectorStore (Repository Layer) ││ +│ │ - LanceDB connection management ││ +│ │ - Table operations (turn_embeddings, session_embeddings) ││ +│ │ - Vector search with metadata filtering ││ +│ └──────────────────────────────────────────────────────────────────┘│ +│ │ +│ External Storage │ +│ ┌──────────────────┐ ┌──────────────────────────────────────────┐ │ +│ │ SQLite (existing)│ │ LanceDB │ │ +│ │ - turn_summaries │ │ - turn_embeddings table │ │ +│ │ - session_summaries│ │ - session_embeddings table │ │ +│ │ - messages │ │ - Stored in ~/.retrochat/vectors/ │ │ +│ └──────────────────┘ └──────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### Data Flow + +``` +1. Summary Created/Updated + turn_summaries table → EmbeddingService.embed_text() → VectorStore.upsert() + ↓ + FastEmbed model inference + ↓ + 384-dim float vector + ↓ + LanceDB turn_embeddings table + +2. Semantic Search Query + User query → EmbeddingService.embed_text() → VectorStore.search() + ↓ ↓ + Query vector LanceDB ANN search + ↓ + Top-K results with scores + ↓ + Join with SQLite summaries +``` + +## Database Schema + +### LanceDB Tables + +#### turn_embeddings +``` +Schema: +- id: String (primary key, matches turn_summaries.id) +- session_id: String (for filtering) +- turn_number: Int32 (for filtering) +- turn_type: String (nullable, for filtering: task, question, error_fix, etc.) +- started_at: Timestamp (turn start time, for time-range queries) +- ended_at: Timestamp (turn end time) +- embedding: FixedSizeList[384] (vector column) +- text_hash: String (SHA256 of embedded text for change detection) +- embedded_at: Timestamp (when embedding was generated) +- model_name: String (e.g., "BGESmallENV15") + +Indexes: +- IVF_PQ on embedding column (vector index, created after sufficient data) +- Scalar index on started_at (for time-range filtering) +- Scalar index on turn_type (for type filtering) +- Scalar index on session_id (for session filtering) +``` + +#### session_embeddings +``` +Schema: +- id: String (primary key, matches session_summaries.id) +- session_id: String (unique, for joining) +- outcome: String (nullable, for filtering: completed, partial, abandoned, ongoing) +- created_at: Timestamp (session creation time, from chat_sessions) +- updated_at: Timestamp (last message time) +- provider: String (claude, gemini, chatgpt - for filtering) +- project: String (nullable, project name for filtering) +- embedding: FixedSizeList[384] (vector column) +- text_hash: String +- embedded_at: Timestamp +- model_name: String + +Indexes: +- IVF_PQ on embedding column (vector index) +- Scalar index on created_at (for time-range filtering) +- Scalar index on provider (for provider filtering) +- Scalar index on outcome (for outcome filtering) +``` + +### SQL Filter Examples + +LanceDB supports full SQL WHERE clause syntax via DataFusion: + +```rust +// Time range query +table.vector_search(query_vec) + .only_if("started_at >= timestamp '2025-01-01' AND started_at < timestamp '2025-02-01'") + .limit(10) + .execute().await?; + +// Combined filters +table.vector_search(query_vec) + .only_if("provider = 'claude' AND turn_type IN ('task', 'error_fix') AND started_at > timestamp '2025-06-01'") + .limit(20) + .execute().await?; + +// Pattern matching +table.vector_search(query_vec) + .only_if("session_id LIKE 'proj-%' AND outcome IS NOT NULL") + .limit(10) + .execute().await?; +``` + +### Text to Embed + +For optimal semantic search, combine relevant fields into a single text block. + +#### Turn Summary → Embedding Text + +```rust +impl TurnSummary { + /// Convert turn summary to text for embedding + pub fn to_embedding_text(&self) -> String { + let mut parts = Vec::new(); + + // Core LLM-generated content (always present) + parts.push(format!("Intent: {}", self.user_intent)); + parts.push(format!("Action: {}", self.assistant_action)); + parts.push(format!("Summary: {}", self.summary)); + + // Classification (helps with semantic clustering) + if let Some(ref turn_type) = self.turn_type { + parts.push(format!("Type: {}", turn_type)); + } + + // Extracted entities (searchable keywords) + if let Some(ref topics) = self.key_topics { + if !topics.is_empty() { + parts.push(format!("Topics: {}", topics.join(", "))); + } + } + if let Some(ref decisions) = self.decisions_made { + if !decisions.is_empty() { + parts.push(format!("Decisions: {}", decisions.join(", "))); + } + } + if let Some(ref concepts) = self.code_concepts { + if !concepts.is_empty() { + parts.push(format!("Code concepts: {}", concepts.join(", "))); + } + } + + parts.join("\n\n") + } +} +``` + +**Example output:** +``` +Intent: Implement JWT authentication for the API + +Action: Created auth middleware with token validation and refresh logic + +Summary: User requested JWT auth. Created middleware that validates tokens on protected routes, handles token refresh, and returns proper 401 responses. + +Type: task + +Topics: authentication, JWT, middleware + +Decisions: Used RS256 signing, 15min access token expiry + +Code concepts: middleware pattern, token validation, error handling +``` + +#### Session Summary → Embedding Text + +```rust +impl SessionSummary { + /// Convert session summary to text for embedding + /// Requires ChatSession for provider/project context + pub fn to_embedding_text(&self, session: &ChatSession) -> String { + let mut parts = Vec::new(); + + // Title is most important for session identification + parts.push(format!("Title: {}", self.title)); + + // Core summary + parts.push(format!("Summary: {}", self.summary)); + + // Goal and outcome + if let Some(ref goal) = self.primary_goal { + parts.push(format!("Goal: {}", goal)); + } + if let Some(ref outcome) = self.outcome { + parts.push(format!("Outcome: {}", outcome)); + } + + // Context from ChatSession + parts.push(format!("Provider: {}", session.provider)); + if let Some(ref project) = session.project_name { + parts.push(format!("Project: {}", project)); + } + + // Extracted entities + if let Some(ref decisions) = self.key_decisions { + if !decisions.is_empty() { + parts.push(format!("Key decisions: {}", decisions.join(", "))); + } + } + if let Some(ref techs) = self.technologies_used { + if !techs.is_empty() { + parts.push(format!("Technologies: {}", techs.join(", "))); + } + } + if let Some(ref files) = self.files_affected { + if !files.is_empty() { + parts.push(format!("Files: {}", files.join(", "))); + } + } + + parts.join("\n\n") + } +} +``` + +**Example output:** +``` +Title: JWT Authentication Implementation + +Summary: Implemented complete JWT authentication system with login, token refresh, and protected route middleware. + +Goal: Add secure authentication to the REST API + +Outcome: completed + +Provider: Claude Code + +Project: my-api + +Key decisions: RS256 signing algorithm, 15min access tokens, 7day refresh tokens + +Technologies: JWT, bcrypt, axum middleware + +Files: src/auth/mod.rs, src/auth/middleware.rs, src/auth/handlers.rs +``` + +### Embedding Storage Flow + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ INDEXING FLOW │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. Summary Created/Updated in SQLite │ +│ ┌──────────────────┐ │ +│ │ turn_summaries │ or │ session_summaries │ │ +│ └────────┬─────────┘ └─────────┬─────────┘ │ +│ │ │ │ +│ 2. Convert to Embedding Text │ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌────────────────────────────────────────────┐ │ +│ │ to_embedding_text() → "Intent: ... \n..." │ │ +│ └────────────────────┬───────────────────────┘ │ +│ │ │ +│ 3. Generate Embedding │ │ +│ ▼ │ +│ ┌────────────────────────────────────────────┐ │ +│ │ EmbeddingService.embed_text(text) │ │ +│ │ → FastEmbed BGESmallENV15Q │ │ +│ │ → Vec [384 dimensions] │ │ +│ └────────────────────┬───────────────────────┘ │ +│ │ │ +│ 4. Compute Hash for Change Detection │ +│ │ │ +│ ┌───────────▼───────────┐ │ +│ │ SHA256(embedding_text) │ │ +│ └───────────┬───────────┘ │ +│ │ │ +│ 5. Store in LanceDB │ │ +│ ▼ │ +│ ┌────────────────────────────────────────────┐ │ +│ │ VectorStore.upsert_turn_embedding( │ │ +│ │ TurnEmbedding { │ │ +│ │ id: turn.id, │ │ +│ │ session_id: turn.session_id, │ │ +│ │ turn_number: turn.turn_number, │ │ +│ │ turn_type: turn.turn_type.to_string(), │ │ +│ │ started_at: turn.started_at, │ │ +│ │ ended_at: turn.ended_at, │ │ +│ │ embedding: vec![0.12, -0.34, ...], │ │ +│ │ text_hash: "a1b2c3...", │ │ +│ │ embedded_at: Utc::now(), │ │ +│ │ model_name: "BGESmallENV15Q", │ │ +│ │ } │ │ +│ │ ) │ │ +│ └────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### Data Structures for Vector Storage + +```rust +/// Embedding record for turn summaries +#[derive(Debug, Clone)] +pub struct TurnEmbedding { + pub id: String, // From TurnSummary.id + pub session_id: String, // From TurnSummary.session_id + pub turn_number: i32, // From TurnSummary.turn_number + pub turn_type: Option, // From TurnSummary.turn_type + pub started_at: DateTime, // From TurnSummary.started_at + pub ended_at: DateTime, // From TurnSummary.ended_at + pub embedding: Vec, // 384-dim vector + pub text_hash: String, // SHA256 of embedding text + pub embedded_at: DateTime, + pub model_name: String, +} + +/// Embedding record for session summaries +#[derive(Debug, Clone)] +pub struct SessionEmbedding { + pub id: String, // From SessionSummary.id + pub session_id: String, // From SessionSummary.session_id + pub outcome: Option, // From SessionSummary.outcome + pub created_at: DateTime, // From ChatSession.start_time + pub updated_at: DateTime, // From ChatSession.end_time or updated_at + pub provider: String, // From ChatSession.provider + pub project: Option, // From ChatSession.project_name + pub embedding: Vec, // 384-dim vector + pub text_hash: String, // SHA256 of embedding text + pub embedded_at: DateTime, + pub model_name: String, +} +``` + +### Indexing Service Implementation + +```rust +impl SemanticSearchService { + /// Index a turn summary after creation/update + pub async fn index_turn(&self, turn: &TurnSummary) -> Result<()> { + // 1. Generate embedding text + let text = turn.to_embedding_text(); + + // 2. Compute hash for change detection + let text_hash = self.compute_hash(&text); + + // 3. Check if already indexed with same hash + if let Some(existing) = self.vector_store.get_turn_embedding(&turn.id).await? { + if existing.text_hash == text_hash { + tracing::debug!("Turn {} unchanged, skipping re-embedding", turn.id); + return Ok(()); + } + } + + // 4. Generate embedding vector + let embedding = self.embedding_service.embed_text(&text)?; + + // 5. Create embedding record + let turn_embedding = TurnEmbedding { + id: turn.id.clone(), + session_id: turn.session_id.clone(), + turn_number: turn.turn_number, + turn_type: turn.turn_type.as_ref().map(|t| t.to_string()), + started_at: turn.started_at, + ended_at: turn.ended_at, + embedding, + text_hash, + embedded_at: Utc::now(), + model_name: self.embedding_service.model_info().name.clone(), + }; + + // 6. Upsert to vector store + self.vector_store.upsert_turn_embedding(turn_embedding).await?; + + Ok(()) + } + + /// Index a session summary after creation/update + pub async fn index_session( + &self, + summary: &SessionSummary, + session: &ChatSession, + ) -> Result<()> { + // 1. Generate embedding text (includes session context) + let text = summary.to_embedding_text(session); + + // 2. Compute hash for change detection + let text_hash = self.compute_hash(&text); + + // 3. Check if already indexed with same hash + if let Some(existing) = self.vector_store.get_session_embedding(&summary.id).await? { + if existing.text_hash == text_hash { + tracing::debug!("Session {} unchanged, skipping re-embedding", summary.id); + return Ok(()); + } + } + + // 4. Generate embedding vector + let embedding = self.embedding_service.embed_text(&text)?; + + // 5. Create embedding record with session metadata + let session_embedding = SessionEmbedding { + id: summary.id.clone(), + session_id: summary.session_id.clone(), + outcome: summary.outcome.as_ref().map(|o| o.to_string()), + created_at: session.start_time, + updated_at: session.end_time.unwrap_or(session.updated_at), + provider: session.provider.to_string(), + project: session.project_name.clone(), + embedding, + text_hash, + embedded_at: Utc::now(), + model_name: self.embedding_service.model_info().name.clone(), + }; + + // 6. Upsert to vector store + self.vector_store.upsert_session_embedding(session_embedding).await?; + + Ok(()) + } + + fn compute_hash(&self, text: &str) -> String { + use sha2::{Sha256, Digest}; + let mut hasher = Sha256::new(); + hasher.update(text.as_bytes()); + hex::encode(hasher.finalize()) + } +} +``` + +## Module Structure + +### New Files + +``` +crates/retrochat-core/src/ +├── embedding/ +│ ├── mod.rs # Module exports +│ ├── service.rs # EmbeddingService - text → vector +│ ├── config.rs # Model configuration, cache paths +│ └── models.rs # Supported model definitions +├── vector_store/ +│ ├── mod.rs # Module exports +│ ├── store.rs # VectorStore - LanceDB operations +│ ├── schemas.rs # LanceDB table schemas +│ └── search.rs # Search query builders +└── services/ + └── semantic_search.rs # SemanticSearchService - high-level API +``` + +### Updated Files + +``` +crates/retrochat-core/src/ +├── lib.rs # Export new modules +├── services/ +│ ├── mod.rs # Export SemanticSearchService +│ ├── turn_summarization.rs # Trigger embedding on summary create +│ └── session_summarization.rs # Trigger embedding on summary create +└── database/ + └── mod.rs # Keep existing, add vector_store reference +``` + +## API Design + +### EmbeddingService + +```rust +pub struct EmbeddingService { + model: TextEmbedding, + config: EmbeddingConfig, +} + +impl EmbeddingService { + /// Create service with specified model + pub async fn new(config: EmbeddingConfig) -> Result; + + /// Embed a single text + pub fn embed_text(&self, text: &str) -> Result>; + + /// Embed multiple texts (more efficient for batches) + pub fn embed_batch(&self, texts: &[&str]) -> Result>>; + + /// Get model info (name, dimensions) + pub fn model_info(&self) -> ModelInfo; +} + +pub struct EmbeddingConfig { + pub model: EmbeddingModel, // BGESmallENV15, AllMiniLML6V2, etc. + pub cache_dir: Option, // Model cache location + pub use_quantized: bool, // Use quantized model variant +} +``` + +### VectorStore + +```rust +pub struct VectorStore { + db: Database, + turn_table: Table, + session_table: Table, +} + +impl VectorStore { + /// Open or create vector store + pub async fn open(path: &Path) -> Result; + + /// Upsert turn embedding + pub async fn upsert_turn_embedding(&self, embedding: TurnEmbedding) -> Result<()>; + + /// Upsert session embedding + pub async fn upsert_session_embedding(&self, embedding: SessionEmbedding) -> Result<()>; + + /// Search turn embeddings + pub async fn search_turns( + &self, + query_vector: &[f32], + limit: usize, + filter: Option, + ) -> Result>; + + /// Search session embeddings + pub async fn search_sessions( + &self, + query_vector: &[f32], + limit: usize, + filter: Option, + ) -> Result>; + + /// Delete embeddings for a session + pub async fn delete_session(&self, session_id: &str) -> Result<()>; + + /// Get embedding status + pub async fn get_stats(&self) -> Result; +} + +pub struct TurnFilter { + pub session_id: Option, + pub turn_types: Option>, + pub started_after: Option>, + pub started_before: Option>, +} + +pub struct SessionFilter { + pub outcomes: Option>, + pub providers: Option>, + pub projects: Option>, + pub created_after: Option>, + pub created_before: Option>, +} + +pub struct TurnSearchResult { + pub id: String, + pub session_id: String, + pub turn_number: i32, + pub score: f32, // Cosine similarity (0.0 - 1.0) +} +``` + +### SemanticSearchService + +```rust +pub struct SemanticSearchService { + embedding_service: EmbeddingService, + vector_store: VectorStore, + summary_repo: TurnSummaryRepo, + session_summary_repo: SessionSummaryRepo, +} + +impl SemanticSearchService { + /// Search turn summaries by semantic similarity + pub async fn search_turns( + &self, + query: &str, + limit: usize, + filter: Option, + ) -> Result>; + + /// Search session summaries by semantic similarity + pub async fn search_sessions( + &self, + query: &str, + limit: usize, + filter: Option, + ) -> Result>; + + /// Hybrid search combining semantic + FTS + pub async fn hybrid_search( + &self, + query: &str, + limit: usize, + semantic_weight: f32, // 0.0-1.0, remainder goes to FTS + ) -> Result>; + + /// Find similar turns to a given turn + pub async fn find_similar_turns( + &self, + turn_id: &str, + limit: usize, + ) -> Result>; + + /// Index a turn summary (called after summarization) + pub async fn index_turn(&self, turn: &TurnSummary) -> Result<()>; + + /// Index a session summary + pub async fn index_session(&self, session: &SessionSummary) -> Result<()>; + + /// Rebuild entire index + pub async fn rebuild_index(&self, progress: impl Fn(usize, usize)) -> Result<()>; +} +``` + +## Dependencies + +### Cargo.toml Additions (workspace) + +```toml +[workspace.dependencies] +# Vector database +lancedb = "0.22" +arrow = { version = "53", default-features = false } +arrow-array = "53" +arrow-schema = "53" + +# Embedding +fastembed = "4" + +# Hashing for change detection +sha2 = "0.10" +``` + +### retrochat-core/Cargo.toml + +```toml +[dependencies] +lancedb = { workspace = true, optional = true } +arrow = { workspace = true, optional = true } +arrow-array = { workspace = true, optional = true } +arrow-schema = { workspace = true, optional = true } +fastembed = { workspace = true, optional = true } +sha2 = { workspace = true } + +[features] +default = ["reqwest"] +semantic-search = ["lancedb", "arrow", "arrow-array", "arrow-schema", "fastembed"] +``` + +## CLI Integration + +### New Commands + +```bash +# Semantic search +cargo cli -- search --semantic "how to handle errors in async code" +cargo cli -- search --hybrid "authentication implementation" --semantic-weight 0.7 + +# Semantic search with metadata filters +cargo cli -- search --semantic "database migrations" --from 2025-01-01 --to 2025-06-30 +cargo cli -- search --semantic "error handling" --provider claude --turn-type error_fix +cargo cli -- search --semantic "API design" --project my-project --outcome completed + +# Index management +cargo cli -- index status # Show indexing status +cargo cli -- index rebuild # Rebuild entire vector index +cargo cli -- index rebuild --session SESSION_ID # Rebuild specific session +``` + +### Updated Commands + +```bash +# Enhanced search with semantic option and filters +cargo cli -- search "query" [--semantic] [--hybrid] [--limit N] +cargo cli -- search "query" --semantic --from DATE --to DATE +cargo cli -- search "query" --semantic --provider NAME --project NAME +``` + +## Implementation Phases + +### Phase 1: Foundation (Core Infrastructure) +1. Add dependencies to workspace Cargo.toml +2. Create `embedding/` module with EmbeddingService +3. Create `vector_store/` module with VectorStore +4. Add basic tests for embedding generation +5. Add basic tests for vector storage + +### Phase 2: Integration (Connect to Existing Code) +6. Create SemanticSearchService +7. Integrate with turn/session summarization services +8. Add embedding generation after summary creation +9. Implement change detection (skip re-embedding unchanged summaries) + +### Phase 3: Search API (User-Facing Features) +10. Implement semantic search endpoints +11. Implement hybrid search (semantic + FTS) +12. Add find-similar functionality +13. Implement CLI commands for semantic search + +### Phase 4: Index Management +14. Implement index rebuild command +15. Add index status/statistics +16. Implement incremental indexing +17. Add background indexing option + +### Phase 5: Optimization (Performance Tuning) +18. Create IVF_PQ index after sufficient data +19. Tune search parameters +20. Add caching for frequent queries +21. Benchmark and optimize batch operations + +## Configuration + +### Environment Variables + +```bash +# Model selection +RETROCHAT_EMBEDDING_MODEL=BGESmallENV15 # or AllMiniLML6V2 +RETROCHAT_EMBEDDING_QUANTIZED=true # Use quantized model + +# Storage paths +RETROCHAT_VECTOR_STORE_PATH=~/.retrochat/vectors/ + +# Search defaults +RETROCHAT_SEMANTIC_SEARCH_LIMIT=10 +RETROCHAT_HYBRID_SEARCH_WEIGHT=0.7 # Semantic weight in hybrid search +``` + +### Config File Support + +```toml +# ~/.retrochat/config.toml +[semantic_search] +enabled = true +model = "BGESmallENV15" +quantized = true +auto_index = true # Index summaries automatically + +[hybrid_search] +default_weight = 0.7 # Semantic weight +``` + +## Migration Strategy + +### Existing Data + +For users with existing summaries: + +1. **On first run with semantic-search enabled:** + - Detect unindexed summaries + - Prompt user: "Found N summaries without embeddings. Index now? (Y/n)" + - Or auto-index in background + +2. **Incremental indexing:** + - Track `text_hash` to detect changed summaries + - Only re-embed when summary content changes + +### Model Changes + +If user changes embedding model: +- Detect model mismatch in stored embeddings +- Warn user and offer full reindex +- Keep model name in embedding metadata + +## Testing Strategy + +### Unit Tests +- EmbeddingService: Text embedding generation +- VectorStore: CRUD operations, search queries +- Hash calculation: Change detection + +### Integration Tests +- End-to-end semantic search flow +- Hybrid search ranking +- Index rebuild process + +### Performance Tests +- Embedding throughput (texts/second) +- Search latency at various index sizes +- Memory usage during batch operations + +## Deployment Model + +### Single Binary Considerations + +Both LanceDB and FastEmbed-rs support single-binary deployment with caveats: + +#### LanceDB ✓ Fully Embedded +- In-process database, no external server +- Links directly into the binary +- Data stored in local files (`~/.retrochat/vectors/`) + +#### FastEmbed-rs - Configuration Required + +**ONNX Runtime Linking Options:** + +| Strategy | Binary Size | External Files | Notes | +|----------|-------------|----------------|-------| +| Static link | +50MB | None | Set `ORT_LIB_LOCATION`, compile ONNX RT | +| Dynamic link (default) | Base | `.so`/`.dll` | Ship library with binary | +| Download strategy | Base | Auto-fetched | Uses pre-built binaries | + +**Model File Options:** + +| Strategy | Binary Size | Network | Notes | +|----------|-------------|---------|-------| +| Runtime download (default) | Base | First-run | Cached in `~/.cache/fastembed/` | +| Local files | Base | None | Ship `models/` folder | +| `include_bytes!` | +17-50MB | None | Embedded at compile time | + +#### Recommended: Runtime Download (Default) + +For retrochat, we recommend the **default runtime download** approach: + +```rust +// Models downloaded on first use, cached for subsequent runs +let model = TextEmbedding::try_new( + InitOptions::new(EmbeddingModel::BGESmallENV15Q) + .with_show_download_progress(true) + .with_cache_dir(PathBuf::from("~/.retrochat/models")), +)?; +``` + +**Rationale:** +- Keeps binary size small (~10MB vs ~60MB+) +- Models cached after first use +- Easy model updates without recompiling +- Users expect first-run setup for AI features +- Progress bar provides feedback during download + +#### Alternative: Fully Offline Binary + +For air-gapped deployments, embed models at compile time: + +```rust +macro_rules! embedded_model { + ($folder:literal) => { + UserDefinedEmbeddingModel { + onnx_file: include_bytes!(concat!($folder, "/model.onnx")).to_vec(), + tokenizer_files: TokenizerFiles { + tokenizer_file: include_bytes!(concat!($folder, "/tokenizer.json")).to_vec(), + config_file: include_bytes!(concat!($folder, "/config.json")).to_vec(), + // ... other tokenizer files + }, + } + }; +} +``` + +This can be a Cargo feature: `--features embedded-models` + +## Risks and Mitigations + +| Risk | Mitigation | +|------|------------| +| Large model download on first run | Show progress bar, cache in `~/.retrochat/models/` | +| Slow embedding on CPU | Use quantized models (BGESmallENV15Q), batch processing | +| LanceDB version compatibility | Pin to stable version, test upgrades | +| Memory pressure from large indexes | Configure vector store cache limits | +| Model accuracy for code-heavy content | Test with representative queries, consider code-specific models | +| ONNX Runtime linking issues | Use download strategy (default), document static linking for advanced users | + +## Success Metrics + +1. **Search Quality**: Semantic search returns more relevant results than FTS alone for conceptual queries +2. **Performance**: Embedding generation < 100ms per summary, Search < 50ms for 10K summaries +3. **User Experience**: Seamless integration with existing CLI/TUI +4. **Maintainability**: Clean separation of concerns, well-tested code + +## Future Enhancements + +1. **Multi-modal embeddings**: Embed code snippets separately +2. **Sparse + Dense hybrid**: Use SPLADE for keyword-aware vectors +3. **Query expansion**: Use LLM to expand search queries +4. **Clustering**: Automatic topic clustering of summaries +5. **Recommendations**: "Sessions similar to this one" + +## References + +- [LanceDB Rust SDK](https://docs.rs/lancedb/latest/lancedb/) +- [LanceDB GitHub](https://github.com/lancedb/lancedb) +- [FastEmbed-rs GitHub](https://github.com/Anush008/fastembed-rs) +- [FastEmbed-rs Documentation](https://docs.rs/fastembed) +- [Candle ML Framework](https://github.com/huggingface/candle) +- [BGE Embedding Models](https://huggingface.co/BAAI/bge-small-en-v1.5)