diff --git a/sgl-model-gateway/Cargo.lock b/sgl-model-gateway/Cargo.lock new file mode 100644 index 000000000000..06be0a317cd8 --- /dev/null +++ b/sgl-model-gateway/Cargo.lock @@ -0,0 +1,9146 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.2.17", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "serde", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +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 = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "ambient-authority" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arc-swap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" +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.119", +] + +[[package]] +name = "array-init" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[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 = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-compression" +version = "0.4.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb61aea1a7def73ee7c350a184f0e70b32c182344e2e75bf70c9b621b83417fd" +dependencies = [ + "compression-codecs", + "compression-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "auto_ops" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7460f7dd8e100147b82a63afca1a20eb6c231ee36b90ba7272e14951cb58af59" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "av-scenechange" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f321d77c20e19b92c39e7471cf986812cbb46659d2af674adc4331ef3f18394" +dependencies = [ + "aligned", + "anyhow", + "arg_enum_proc_macro", + "arrayvec", + "log", + "num-rational", + "num-traits", + "pastey 0.1.1", + "rayon", + "thiserror 2.0.21", + "v_frame", + "y4m", +] + +[[package]] +name = "av1-grain" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom 8.0.0", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7178fe5f7d460b13895ebb9dcb28a3a6216d2df2574a0806cb51b555d297f38" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "aws-lc-rs" +version = "1.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bff6c3b54fad79a2e60b8102caf565819711497c1f5f092f49508e2f5c31b27" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", + "pkg-config", +] + +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core 0.4.5", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "itoa", + "matchit 0.7.3", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower 0.5.3", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core 0.5.6", + "axum-macros", + "base64 0.22.1", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit 0.8.4", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower 0.5.3", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "axum-server" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1df331683d982a0b9492b38127151e6453639cd34926eb9c07d4cd8c6d22bfc" +dependencies = [ + "arc-swap", + "bytes", + "either", + "fs-err", + "http", + "http-body", + "hyper", + "hyper-util", + "pin-project-lite", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "backoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +dependencies = [ + "futures-core", + "getrandom 0.2.17", + "instant", + "pin-project-lite", + "rand 0.8.8", + "tokio", +] + +[[package]] +name = "backon" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" +dependencies = [ + "fastrand", + "gloo-timers", + "tokio", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[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.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "bitstream-io" +version = "4.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7eff00be299a18769011411c9def0d827e8f2d7bf0c3dbf53633147a8867fd1f" +dependencies = [ + "no_std_io2", +] + +[[package]] +name = "blake3" +version = "1.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" +dependencies = [ + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq 0.4.2", + "cpufeatures 0.3.1", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bstr" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" +dependencies = [ + "memchr", + "regex-automata", + "serde_core", +] + +[[package]] +name = "built" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0e531d93d39c34eef561e929e8a7f86d77a5af08aac4f6d6e39976c51858e9" + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a1f896587b6f2c069c73d2f0913e2d590c3990285cd2f0b6aa02b786b4c679c" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[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.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "cap-fs-ext" +version = "3.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476f0d0003a760918ed4b1e039a59e11769030416f79c8222551d22785f7f70d" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes", + "windows-sys 0.59.0", +] + +[[package]] +name = "cap-net-ext" +version = "3.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "150941cefd3df4de2fea24604ba4949371576f62e527410298333f7d431a1bc6" +dependencies = [ + "cap-primitives", + "cap-std", + "rustix 1.1.5", + "smallvec", +] + +[[package]] +name = "cap-primitives" +version = "3.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e0bf07d379916947be6c4a07f43684153d710a2896c31f9e97781362895596c" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes", + "ipnet", + "maybe-owned", + "rustix 1.1.5", + "rustix-linux-procfs", + "windows-sys 0.59.0", + "winx", +] + +[[package]] +name = "cap-rand" +version = "3.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ec6a5b75f54547c579a6b117c6fdd5f04f4ab7598de747b9f440a53592b3a4a" +dependencies = [ + "ambient-authority", + "rand 0.8.8", +] + +[[package]] +name = "cap-std" +version = "3.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a59e59fa26472d29680ece6a9f8ee8b0551a719a33df2f5240bde065ecbddfd7" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes", + "rustix 1.1.5", +] + +[[package]] +name = "cap-time-ext" +version = "3.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b54c289326c70f1c697ebf0a31842a480932e5942b5fac92fcc46e87286b48e2" +dependencies = [ + "ambient-authority", + "cap-primitives", + "iana-time-zone", + "once_cell", + "rustix 1.1.5", + "winx", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[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.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f360145194ee8e21db5ee7f3fcd4fe52210864c75c985dae33218202c8bbe040" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link 0.2.1", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.7", + "inout", +] + +[[package]] +name = "clap" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim 0.11.1", +] + +[[package]] +name = "clap_derive" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "clap_lex" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.21", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "combine" +version = "4.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e" +dependencies = [ + "bytes", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "compact_str" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dfdd1c2274d9aa354115b09dc9a901d6c5576818cdf70d14cae2bdb47df00ab" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "serde", + "static_assertions", +] + +[[package]] +name = "compression-codecs" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef16c47ba2797aa6a909cc37d39911f3a6743811fe7408ac0b0cc0276b656e9" +dependencies = [ + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e8ccc4ea9f6acc32d102c0f6d471d11d913ad15f20c04de743374861fa1d414" + +[[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.16.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96a4956774c13c126a8b5af4daa79384f4d826534c95a02d76afb39e2ab64e3" +dependencies = [ + "encode_unicode", + "libc", + "unicode-width", + "windows-sys 0.61.2", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "cookie" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a373e3602691c3cdea496d2f0ee5935151e6168fe87739483c463db1b2f2f87" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b2c103cf610ec6cae3da84a766285b42fd16aad564758459e6ecf128c75206" +dependencies = [ + "cookie", + "document-features", + "idna", + "indexmap 2.14.2", + "log", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core_detect" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" + +[[package]] +name = "cpp_demangle" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-assembler-x64" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c088d3406f0c0252efa7445adfd2d05736bfb5218838f64eaf79d567077aed14" +dependencies = [ + "cranelift-assembler-x64-meta", +] + +[[package]] +name = "cranelift-assembler-x64-meta" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c03f887a763abb9c1dc08f722aa82b69067fda623b6f0273050f45f8b1a6776" +dependencies = [ + "cranelift-srcgen", +] + +[[package]] +name = "cranelift-bforest" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206887a11a43f507fee320a218dc365980bfc42ec2696792079a9f8c9369e90" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-bitset" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac0790c83cfdab95709c5d0105fd888221e3af9049a7d7ec376ec901ab4e4dba" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-codegen" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a98aed2d262eda69310e84bae8e053ee4f17dbdd3347b8d9156aa618ba2de0a" +dependencies = [ + "bumpalo", + "cranelift-assembler-x64", + "cranelift-bforest", + "cranelift-bitset", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.15.5", + "log", + "pulley-interpreter", + "regalloc2", + "rustc-hash 2.1.3", + "serde", + "smallvec", + "target-lexicon", + "wasmtime-internal-math", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6906852826988563e9b0a9232ad951f53a47aa41ffd02f8ac852d3f41aae836a" +dependencies = [ + "cranelift-assembler-x64-meta", + "cranelift-codegen-shared", + "cranelift-srcgen", + "heck", + "pulley-interpreter", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a50105aab667b5cc845f2be37c78475d7cc127cd8ec0a31f7b2b71d526099a7" + +[[package]] +name = "cranelift-control" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6adcc7aa7c0bc1727176a6f2d99c28a9e79a541ccd5ca911a0cb352da8befa36" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "981b56af777f9a34ea6dcce93255125776d391410c2a68b75bed5941b714fa15" +dependencies = [ + "cranelift-bitset", + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-frontend" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea982589684dfb71afecb9fc09555c3a266300a1162a60d7fa39d41a5705b1c" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0422686b22ed6a1f33cc40e3c43eb84b67155788568d1a5cac8439d3dca1783" + +[[package]] +name = "cranelift-native" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f697bbbe135c655ea1deb7af0bae4a5c4fae2c88fdfc0fa57b34ae58c91040" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-srcgen" +version = "0.125.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718efe674f3df645462677e22a3128e890d88ba55821bb091083d257707be76c" + +[[package]] +name = "crc32fast" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crdts" +version = "7.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387808c885b79055facbd4b2e806a683fe1bc37abc7dfa5fea1974ad2d4137b0" +dependencies = [ + "num", + "quickcheck", + "serde", + "tiny-keccak", +] + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + +[[package]] +name = "darling" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed17f5901b6630b993ca003def43f2f8ef4014fc13b047b57aad617ff32bc2ec" +dependencies = [ + "darling_core 0.24.1", + "darling_macro 0.24.1", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.119", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.119", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.119", +] + +[[package]] +name = "darling_core" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6837e2cf7485aaae18f86181d2f0e9a7ed297a025e220aeabf63fdebd3a2ddff" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 3.0.6", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785" +dependencies = [ + "darling_core 0.24.1", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "dary_heap" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1e3a325bc115f096c8b77bbf027a7c2592230e70be2d985be950d3d5e60ebe" +dependencies = [ + "serde", +] + +[[package]] +name = "dashmap" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-connector" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2efb0047943a818c9839a1a898cb6442144d7e623b63d657c8b7005b713ef4d" +dependencies = [ + "async-trait", + "chrono", + "dashmap", + "deadpool 0.12.3", + "deadpool-postgres", + "deadpool-redis", + "futures", + "oracle", + "parking_lot", + "rand 0.9.5", + "redis", + "serde", + "serde_json", + "thiserror 2.0.21", + "tokio", + "tokio-postgres", + "tracing", + "ulid", + "url", +] + +[[package]] +name = "data-encoding" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" + +[[package]] +name = "deadpool" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" +dependencies = [ + "deadpool-runtime 0.1.4", + "lazy_static", + "num_cpus", + "tokio", +] + +[[package]] +name = "deadpool" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e98a7e119cd347f4201e1159b19831029e203e2d8b790547708e8157b4acf1e" +dependencies = [ + "deadpool-runtime 0.3.1", + "tokio", +] + +[[package]] +name = "deadpool-postgres" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65a536565624b97fc19f758cd01b15d12908d3344425066efc8162236fbd3749" +dependencies = [ + "async-trait", + "deadpool 0.13.1", + "getrandom 0.4.3", + "tokio", + "tokio-postgres", + "tracing", +] + +[[package]] +name = "deadpool-redis" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfae6799b68a735270e4344ee3e834365f707c72da09c9a8bb89b45cc3351395" +dependencies = [ + "deadpool 0.12.3", + "redis", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" +dependencies = [ + "tokio", +] + +[[package]] +name = "deadpool-runtime" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2657f61fb1dd8bf37a8d51093cc7cee4e77125b22f7753f49b289f831bec2bae" +dependencies = [ + "tokio", +] + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.21", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid 0.9.6", + "pem-rfc7468 0.7.0", + "zeroize", +] + +[[package]] +name = "der" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a878c850e9e421b20262e9b41f9c860e4785fa07541c266b62ff9d1ef998a80a" +dependencies = [ + "pem-rfc7468 1.0.0", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] + +[[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.119", +] + +[[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.119", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl 2.1.1", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "unicode-xid", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.119", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.7", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid 0.10.2", + "crypto-common 0.2.2", + "ctutils", +] + +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users 0.5.3", + "windows-sys 0.59.0", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users 0.4.6", + "winapi", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "encoding_rs" +version = "0.8.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679" +dependencies = [ + "cfg-if", + "core_detect", + "multiversion_no_op", + "rustversion", + "scopeguard", + "simdutf8", +] + +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "env_filter" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" +dependencies = [ + "env_filter", + "log", +] + +[[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.119", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "esaxx-rs" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6" +dependencies = [ + "cc", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "exr" +version = "1.74.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711fe42c9964295e01ee3fba3f9fe0e1d24b98886950d68efe81b1c76e21adf3" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide 0.8.9", + "num-complex", + "pulp", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fancy-regex" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "fax" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a" + +[[package]] +name = "fd-lock" +version = "4.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" +dependencies = [ + "cfg-if", + "rustix 1.1.5", + "windows-sys 0.59.0", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" +dependencies = [ + "crc32fast", + "miniz_oxide 0.9.1", + "zlib-rs", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs-err" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91aa448ca50d7e79433bdf3ee8d99215430d2ec02ade5aefab2a073a1822e8a" +dependencies = [ + "autocfg", + "tokio", +] + +[[package]] +name = "fs-set-times" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" +dependencies = [ + "io-lifetimes", + "rustix 1.1.5", + "windows-sys 0.59.0", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "fxprof-processed-profile" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25234f20a3ec0a962a61770cfe39ecf03cb529a6e474ad8cff025ed497eda557" +dependencies = [ + "bitflags 2.13.2", + "debugid", + "rustc-hash 2.1.3", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getopts" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", +] + +[[package]] +name = "gif" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8cfcc411d9adbbaba82fb72661cc1bcca13e8bba98b364e62b2dba8f960159" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +dependencies = [ + "fallible-iterator 0.3.0", + "indexmap 2.14.2", + "stable_deref_trait", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "h2" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.14.2", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", + "serde", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hdrhistogram" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d1053f4708f0af3cf9fc5bffc7e68a914a3c45becb231c80068c9c3f78bea" +dependencies = [ + "byteorder", + "num-traits", +] + +[[package]] +name = "headers" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2700e3fe555c3310aa7286cac6167449f2c87e0eb58769c9208a1c58a1d106" +dependencies = [ + "base64 0.22.1", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hf-hub" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef3982638978efa195ff11b305f51f1f22f4f0a6cabee7af79b383ebee6a213" +dependencies = [ + "dirs", + "futures", + "http", + "indicatif", + "libc", + "log", + "native-tls", + "num_cpus", + "rand 0.9.5", + "reqwest", + "serde", + "serde_json", + "thiserror 2.0.21", + "tokio", + "ureq", + "windows-sys 0.61.2", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "hostname" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd" +dependencies = [ + "cfg-if", + "libc", + "windows-link 0.2.1", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + +[[package]] +name = "hyper" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-http-proxy" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd1d471ea2f65ba45eddb1d6ab7d58ac2671d2d4ac14da5c6516ae1d97e1327a" +dependencies = [ + "bytes", + "futures-util", + "headers", + "http", + "hyper", + "hyper-rustls", + "hyper-util", + "pin-project-lite", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53" +dependencies = [ + "http", + "hyper", + "hyper-util", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[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", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff" +dependencies = [ + "base64 0.23.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.5", + "system-configuration", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp", + "moxcms", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e44b0a4eaa4c82f441d50a963f2d5f05a787240aeee097597033e72accfd22f" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "indicatif" +version = "0.18.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9433806cd6b4ec1aba79c021c7e4c58fb4c3b9977c085062e611ac929998fb0c" +dependencies = [ + "console", + "portable-atomic", + "unicode-width", + "unit-prefix", + "web-time", +] + +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[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.119", +] + +[[package]] +name = "io-extras" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2285ddfe3054097ef4b2fe909ef8c3bcd1ea52a8f0d274416caebeef39f04a65" +dependencies = [ + "io-lifetimes", + "windows-sys 0.59.0", +] + +[[package]] +name = "io-lifetimes" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983" + +[[package]] +name = "ipnet" +version = "2.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" + +[[package]] +name = "is-macro" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8267aa6001e25494f3015f9663bbd88a18240c74483afa5f0934a1b3e4c388e9" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[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.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "ittapi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b996fe614c41395cdaedf3cf408a9534851090959d90d54a535f675550b64b1" +dependencies = [ + "anyhow", + "ittapi-sys", + "log", +] + +[[package]] +name = "ittapi-sys" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f5385394064fa2c886205dba02598013ce83d3e92d33dbdc0c52fe0e7bf4fc" +dependencies = [ + "cc", +] + +[[package]] +name = "jiff" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1baf72f08796de0260609515130699b890ac25f30e610ad894bc5856cafdb" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-link 0.2.1", +] + +[[package]] +name = "jiff-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e52fe76043ccecc9005d2305ebaadf7d7fc0cc89ca6baa10a94d6bc68c7128c" +dependencies = [ + "defmt", + "log", +] + +[[package]] +name = "jiff-static" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378268a1116ad67ae6228701118ac9f491d78fda38a40a1f1a9e1348de6f7212" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror 2.0.21", +] + +[[package]] +name = "jsonpath-rust" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c00ae348f9f8fd2d09f82a98ca381c60df9e0820d8d79fce43e649b4dc3128b" +dependencies = [ + "pest", + "pest_derive", + "regex", + "serde_json", + "thiserror 2.0.21", +] + +[[package]] +name = "jsonptr" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64 0.22.1", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "k8s-openapi" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa60a41b57ae1a0a071af77dbcf89fc9819cfe66edaf2beeb204c34459dcf0b2" +dependencies = [ + "base64 0.22.1", + "chrono", + "serde", + "serde_json", +] + +[[package]] +name = "kube" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "778f98664beaf4c3c11372721e14310d1ae00f5e2d9aabcf8906c881aa4e9f51" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", + "kube-derive", + "kube-runtime", +] + +[[package]] +name = "kube-client" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cb276b85b6e94ded00ac8ea2c68fcf4697ea0553cb25fddc35d4a0ab718db8d" +dependencies = [ + "base64 0.22.1", + "bytes", + "chrono", + "either", + "futures", + "home", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-http-proxy", + "hyper-rustls", + "hyper-timeout", + "hyper-util", + "jsonpath-rust", + "k8s-openapi", + "kube-core", + "pem", + "rustls", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror 2.0.21", + "tokio", + "tokio-util", + "tower 0.5.3", + "tower-http", + "tracing", +] + +[[package]] +name = "kube-core" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c56ff45deb0031f2a476017eed60c06872251f271b8387ad8020b8fef60960" +dependencies = [ + "chrono", + "derive_more 2.1.1", + "form_urlencoded", + "http", + "json-patch", + "k8s-openapi", + "schemars 0.8.22", + "serde", + "serde-value", + "serde_json", + "thiserror 2.0.21", +] + +[[package]] +name = "kube-derive" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "079fc8c1c397538628309cfdee20696ebdcc26745f9fb17f89b78782205bd995" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.119", +] + +[[package]] +name = "kube-runtime" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f1326e946fadf6248febdf8a1c001809c3899ccf48cb9768cbc536b741040dc" +dependencies = [ + "ahash", + "async-broadcast", + "async-stream", + "backon", + "educe", + "futures", + "hashbrown 0.15.5", + "hostname", + "json-patch", + "k8s-openapi", + "kube-client", + "parking_lot", + "pin-project", + "serde", + "serde_json", + "thiserror 2.0.21", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "kv-index" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46271559cf2ea33e1a226af6cbe8e01148432b4c76663a482389d1aec1ff923" +dependencies = [ + "bincode", + "blake3", + "dashmap", + "once_cell", + "parking_lot", + "rustc-hash 2.1.3", + "serde", + "tracing", + "xxhash-rust", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "leb128" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83bff1d572d6b9aeef67ddfc8448e4a3737909cb28e81f97c791b9018703e52" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "lebe" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" +dependencies = [ + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "llm-tokenizer" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4992c0d29fdf0e964a5a1446c4b61b74ce7148b064b18feabfb375f7717e5d96" +dependencies = [ + "aho-corasick", + "anyhow", + "base64 0.22.1", + "blake3", + "dashmap", + "futures", + "hf-hub", + "minijinja", + "minijinja-contrib", + "rayon", + "rustc-hash 1.1.0", + "serde", + "serde_json", + "thiserror 2.0.21", + "tiktoken-rs", + "tokenizers", + "tokio", + "tracing", + "uuid", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[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.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "lru-slab" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f" + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3ae8f6d608c795738406608304d30a2dfbdc8e58e44f7ba43236da5208ded3c" +dependencies = [ + "macro_rules_attribute-proc_macro", + "pastey 0.2.3", +] + +[[package]] +name = "macro_rules_attribute-proc_macro" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc04a4c58212d57930a24bf47d3fa87485264a3a054e9c10e042eb373573ad3c" + +[[package]] +name = "malachite" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fbdf9cb251732db30a7200ebb6ae5d22fe8e11397364416617d2c2cf0c51cb5" +dependencies = [ + "malachite-base", + "malachite-nz", + "malachite-q", +] + +[[package]] +name = "malachite-base" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea0ed76adf7defc1a92240b5c36d5368cfe9251640dcce5bd2d0b7c1fd87aeb" +dependencies = [ + "hashbrown 0.14.5", + "itertools 0.11.0", + "libm", + "ryu", +] + +[[package]] +name = "malachite-bigint" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d149aaa2965d70381709d9df4c7ee1fc0de1c614a4efc2ee356f5e43d68749f8" +dependencies = [ + "derive_more 1.0.0", + "malachite", + "num-integer", + "num-traits", + "paste", +] + +[[package]] +name = "malachite-nz" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34a79feebb2bc9aa7762047c8e5495269a367da6b5a90a99882a0aeeac1841f7" +dependencies = [ + "itertools 0.11.0", + "libm", + "malachite-base", +] + +[[package]] +name = "malachite-q" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f235d5747b1256b47620f5640c2a17a88c7569eebdf27cd9cb130e1a619191" +dependencies = [ + "itertools 0.11.0", + "malachite-base", + "malachite-nz", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + +[[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.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest 0.11.3", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memfd" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57804b2c9b69967f1536a56f86297e367a33b19e98852ed624b84551cdbc0d90" +dependencies = [ + "rustix 1.1.5", +] + +[[package]] +name = "memo-map" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c8c750f1a07ea702bbd212bd999fceece9b3d1508b17023b3e174583124b" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metrics" +version = "0.24.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89550ee9f79e88fef3119de263694973a8adb26c21d75322164fb8c493039fe2" +dependencies = [ + "portable-atomic", + "rapidhash", +] + +[[package]] +name = "metrics-exporter-prometheus" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b166dea96003ee2531cf14833efedced545751d800f03535801d833313f8c15" +dependencies = [ + "base64 0.22.1", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "indexmap 2.14.2", + "ipnet", + "metrics", + "metrics-util", + "quanta", + "thiserror 2.0.21", + "tokio", + "tracing", +] + +[[package]] +name = "metrics-util" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96f8722f8562635f92f8ed992f26df0532266eb03d5202607c20c0d7e9745e13" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "hashbrown 0.16.1", + "metrics", + "quanta", + "rand 0.9.5", + "rand_xoshiro", + "rapidhash", + "sketches-ddsketch", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minijinja" +version = "2.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86886cf6dbf4e614b19c9a1eec9775f021869d7eadde0fc73921a81b90c9b4c9" +dependencies = [ + "memo-map", + "serde", + "serde_json", +] + +[[package]] +name = "minijinja-contrib" +version = "2.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd3e5f077bc2379f0f7d911e7cfdd921114ed99fc884533dca502944cb355b11" +dependencies = [ + "minijinja", + "serde", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[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.119", +] + +[[package]] +name = "moxcms" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "multiversion_no_op" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" + +[[package]] +name = "native-tls" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.13.2", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "no_std_io2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418abd1b6d34fbf6cae440dc874771b0525a604428704c76e48b29a5e67b8003" +dependencies = [ + "memchr", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "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 = "npyz" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f0e759e014e630f90af745101b614f761306ddc541681e546649068e25ec1b9" +dependencies = [ + "byteorder", + "num-bigint", + "py_literal", + "zip", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.59.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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.8", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "bytemuck", + "num-traits", + "serde", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[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.119", +] + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "num-integer", + "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", + "serde", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "oauth2" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" +dependencies = [ + "base64 0.22.1", + "chrono", + "getrandom 0.2.17", + "http", + "rand 0.8.8", + "reqwest", + "serde", + "serde_json", + "serde_path_to_error", + "sha2 0.10.9", + "thiserror 1.0.69", + "url", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "objc2-system-configuration" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396" +dependencies = [ + "objc2-core-foundation", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "crc32fast", + "hashbrown 0.15.5", + "indexmap 2.14.2", + "memchr", +] + +[[package]] +name = "odpic-sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "920b5474a5128a9f0232df5a0ffc50aaa5b077b29b8b06ab0131985ac82793ed" +dependencies = [ + "cc", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "onig" +version = "6.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc3cbf698f9438986c11a880c90a6d04b9de27575afd28bbf45b154b6c709e2" +dependencies = [ + "bitflags 2.13.2", + "libc", + "once_cell", + "onig_sys", +] + +[[package]] +name = "onig_sys" +version = "69.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e68317604e77e53b85896388e1a803c1d21b74c899ec9e5e1112db90735edd7" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "openai-harmony" +version = "0.0.4" +source = "git+https://github.com/openai/harmony?tag=v0.0.4#72079ca4971f326dddcd5ff62bfb7e2fff37a07a" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bstr", + "clap", + "fancy-regex", + "futures", + "image", + "regex", + "reqwest", + "rustc-hash 1.1.0", + "serde", + "serde_json", + "serde_with", + "sha1", + "sha2 0.10.9", + "thiserror 2.0.21", +] + +[[package]] +name = "openai-protocol" +version = "1.0.0" +dependencies = [ + "axum 0.8.9", + "chrono", + "rand 0.9.5", + "serde", + "serde_json", + "tokio", + "tracing", + "validator", +] + +[[package]] +name = "openmetrics-parser" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e40a68c62e09c5dfec2f6472af3bd5e8ddf506fcf14c78ece23794ffbb874eca" +dependencies = [ + "auto_ops", + "pest", + "pest_derive", +] + +[[package]] +name = "openssl" +version = "0.10.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" +dependencies = [ + "bitflags 2.13.2", + "cfg-if", + "foreign-types", + "libc", + "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.119", +] + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-src" +version = "300.6.1+3.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46eb8fb9fb3b61ce1c0f8a026c4c1a0714d3a9e138e7fbde78753ce2babc3846" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "opentelemetry" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab70038c28ed37b97d8ed414b6429d343a8bbf44c9f79ec854f3a643029ba6d7" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76" +dependencies = [ + "async-trait", + "futures-core", + "http", + "opentelemetry", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost 0.13.5", + "thiserror 1.0.69", + "tokio", + "tonic 0.12.3", + "tracing", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e05acbfada5ec79023c85368af14abd0b307c015e9064d249b2a950ef459a6" +dependencies = [ + "hex", + "opentelemetry", + "opentelemetry_sdk", + "prost 0.13.5", + "serde", + "tonic 0.12.3", +] + +[[package]] +name = "opentelemetry_sdk" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231e9d6ceef9b0b2546ddf52335785ce41252bc7474ee8ba05bfad277be13ab8" +dependencies = [ + "async-trait", + "futures-channel", + "futures-executor", + "futures-util", + "glob", + "opentelemetry", + "percent-encoding", + "rand 0.8.8", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "oracle" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db40fe6e4df881b683691ade5ef1f7b1afd52aefa115581f7b92855524d7ec0" +dependencies = [ + "cc", + "chrono", + "odpic-sys", + "once_cell", + "oracle_procmacro", + "paste", + "rustversion", +] + +[[package]] +name = "oracle_procmacro" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad247f3421d57de56a0d0408d3249d4b1048a522be2013656d92f022c3d8af27" +dependencies = [ + "darling 0.13.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "paste" +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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", + "password-hash", + "sha2 0.10.9", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pem-rfc7468" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pest" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d3aca230fad2e6f6317ca0a72724338c4960cb97168a85cdee66df4a9a21a8" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284b60557f2c4a2e72ad3f2d34d42685a2fa4a6a61d0d2a10c0ae2a5e916c2cf" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d9d1f08a115309ee99268cf85e5228e0e56aa9caf8841ec12866b6be07c3109" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pest_meta" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed93ba1a9ffcca32130a5188701c81c0c49cf00d4b7c5007d5148951d743adcb" +dependencies = [ + "pest", +] + +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap 2.14.2", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared 0.11.3", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_shared 0.13.1", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand 0.8.8", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der 0.7.10", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.10", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.13.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide 0.8.9", +] + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10ab3eb7f3becc3a1cbc4f2c6f20267996cfc1a6467a873763411b136a122715" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "portpicker" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be97d76faf1bfab666e1375477b23fde79eccf0276e9b63b92a39d676a889ba9" +dependencies = [ + "rand 0.8.8", +] + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[package]] +name = "postgres-protocol" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08808e3c483c46e999108051c78334f473d5adb59d78bb80a1268c7e6aa6c514" +dependencies = [ + "base64 0.22.1", + "byteorder", + "bytes", + "fallible-iterator 0.2.0", + "hmac 0.13.0", + "md-5", + "memchr", + "rand 0.10.3", + "sha2 0.11.0", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "851ca9db4932932d69f3ea811b1abe63087a0f740a47692619dd40d4899b68be" +dependencies = [ + "array-init", + "bytes", + "chrono", + "fallible-iterator 0.2.0", + "postgres-protocol", + "serde_core", + "serde_json", +] + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[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.119", +] + +[[package]] +name = "proc-macro-error-attr3" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e564d14133360e1ae169ffde5da25881b5fa47261665b8e5713c212c27799da" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error3" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0d4471b3436c22106b21913b1dda531558918ae9b7ec55d58aa84b43552233" +dependencies = [ + "proc-macro-error-attr3", + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "process-wrap" +version = "8.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9b56899ac93a78fc49e57d51ca29ceffaa6213ee51af2f8a01b1021ec3b4804" +dependencies = [ + "futures", + "indexmap 2.14.2", + "nix", + "tokio", + "tracing", + "windows", +] + +[[package]] +name = "profiling" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[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" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528ac67416ff8646872a3c02cad9cc4ee5dc9f9540c9b10771855c95cb2e5ae1" +dependencies = [ + "bytes", + "prost-derive 0.14.4", +] + +[[package]] +name = "prost-build" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042" +dependencies = [ + "heck", + "itertools 0.14.0", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost 0.14.4", + "prost-types", + "pulldown-cmark", + "pulldown-cmark-to-cmark", + "regex", + "syn 2.0.119", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "prost-derive" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b570b25f7617e43d59005d0990ccb79e950a423952cea19671b7a876da390adf" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "prost-types" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f94967dc7688f3054c7fac87473ffae4cc4c3904800e2d9f5b857246d8963b0a" +dependencies = [ + "prost 0.14.4", +] + +[[package]] +name = "pulldown-cmark" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f068eba8e7071c5f9511831b44f32c740d5adf574e990f946ddb53db2f314e" +dependencies = [ + "bitflags 2.13.2", + "memchr", + "unicase", +] + +[[package]] +name = "pulldown-cmark-to-cmark" +version = "22.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab1ad36992cead65f02aa399a373a42730922f1525d988172634fdefdecb8a60" +dependencies = [ + "pulldown-cmark", +] + +[[package]] +name = "pulley-interpreter" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "beafc309a2d35e16cc390644d88d14dfa45e45e15075ec6a9e37f6dfb43e926f" +dependencies = [ + "cranelift-bitset", + "log", + "pulley-macros", + "wasmtime-internal-math", +] + +[[package]] +name = "pulley-macros" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885fbb6c07454cfc8725a18a1da3cfc328ee8c53fb8d0671ea313edc8567947" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pulp" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046aa45b989642ec2e4717c8e72d677b13edd831a4d3b6cf37d9a3e54912496a" +dependencies = [ + "bytemuck", + "cfg-if", + "libm", + "num-complex", + "paste", + "pulp-wasm-simd-flag", + "raw-cpuid", + "reborrow", + "version_check", +] + +[[package]] +name = "pulp-wasm-simd-flag" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8f70e07b9c3962945a74e59ca1c511bba65b6419468acc217c457d93f3c740" + +[[package]] +name = "pxfm" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" + +[[package]] +name = "py_literal" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "102df7a3d46db9d3891f178dcc826dc270a6746277a9ae6436f8d29fd490a8e1" +dependencies = [ + "num-bigint", + "num-complex", + "num-traits", + "pest", + "pest_derive", +] + +[[package]] +name = "pyo3" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab53c047fcd1a1d2a8820fe84f05d6be69e9526be40cb03b73f86b6b03e6d87d" +dependencies = [ + "indoc", + "libc", + "memoffset", + "once_cell", + "portable-atomic", + "pyo3-build-config", + "pyo3-ffi", + "pyo3-macros", + "unindent", +] + +[[package]] +name = "pyo3-build-config" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b455933107de8642b4487ed26d912c2d899dec6114884214a0b3bb3be9261ea6" +dependencies = [ + "target-lexicon", +] + +[[package]] +name = "pyo3-ffi" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c85c9cbfaddf651b1221594209aed57e9e5cff63c4d11d1feead529b872a089" +dependencies = [ + "libc", + "pyo3-build-config", +] + +[[package]] +name = "pyo3-macros" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a5b10c9bf9888125d917fb4d2ca2d25c8df94c7ab5a52e13313a07e050a3b02" +dependencies = [ + "proc-macro2", + "pyo3-macros-backend", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pyo3-macros-backend" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b51720d314836e53327f5871d4c0cfb4fb37cc2c4a11cc71907a86342c40f9" +dependencies = [ + "heck", + "proc-macro2", + "pyo3-build-config", + "quote", + "syn 2.0.119", +] + +[[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.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" +dependencies = [ + "crossbeam-utils", + "libc", + "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 = "quickcheck" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95c589f335db0f6aaa168a7cd27b1fc6920f5e1470c804f814d9cd6e62a0f70b" +dependencies = [ + "env_logger", + "log", + "rand 0.10.3", +] + +[[package]] +name = "quinn" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.3", + "rustls", + "socket2 0.5.10", + "thiserror 2.0.21", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9746dbde176634f4f2f1faf2404e30a31b2bc1e9cafb5329c95d8177a18c9fc" +dependencies = [ + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand 0.10.3", + "rand_pcg", + "ring", + "rustc-hash 2.1.3", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.21", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.5.10", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + +[[package]] +name = "rand_xoshiro" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rapidhash" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da7e78a036ce858e8d55b7e7dc8ba3a88b78350fd2155d3591bbd966b58589e" +dependencies = [ + "rustversion", +] + +[[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.5", + "rand_chacha 0.9.0", + "simd_helpers", + "thiserror 2.0.21", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e52310197d971b0f5be7fe6b57530dcd27beb35c1b013f29d66c1ad73fbbcc45" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +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 = "reasoning-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9973747732ca39c3bb0a8e024947a23fbbbd11f8a545a66778bc8671ab578a" +dependencies = [ + "thiserror 2.0.21", + "tokio", +] + +[[package]] +name = "reborrow" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03251193000f4bd3b042892be858ee50e8b3719f2b08e5833ac4353724632430" + +[[package]] +name = "redis" +version = "0.27.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d8f99a4090c89cc489a94833c901ead69bfbf3877b4867d5482e321ee875bc" +dependencies = [ + "arc-swap", + "async-trait", + "backon", + "bytes", + "combine", + "futures", + "futures-util", + "itertools 0.13.0", + "itoa", + "num-bigint", + "percent-encoding", + "pin-project-lite", + "ryu", + "serde", + "serde_json", + "sha1_smol", + "socket2 0.5.10", + "tokio", + "tokio-util", + "url", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "redox_users" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0" +dependencies = [ + "libredox", + "thiserror 2.0.21", +] + +[[package]] +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "regalloc2" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08effbc1fa53aaebff69521a5c05640523fab037b34a4a2c109506bc938246fa" +dependencies = [ + "allocator-api2", + "bumpalo", + "hashbrown 0.15.5", + "log", + "rustc-hash 2.1.3", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "mime", + "mime_guess", + "native-tls", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-util", + "tower 0.5.3", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rmcp" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5947688160b56fb6c827e3c20a72c90392a1d7e9dec74749197aa1780ac42ca" +dependencies = [ + "base64 0.22.1", + "bytes", + "chrono", + "futures", + "http", + "http-body", + "http-body-util", + "oauth2", + "paste", + "pin-project-lite", + "process-wrap", + "rand 0.9.5", + "reqwest", + "rmcp-macros", + "schemars 1.2.2", + "serde", + "serde_json", + "sse-stream", + "thiserror 2.0.21", + "tokio", + "tokio-stream", + "tokio-util", + "tower-service", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "rmcp-macros" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01263441d3f8635c628e33856c468b96ebbce1af2d3699ea712ca71432d4ee7a" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.119", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid 0.9.6", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "sha2 0.10.9", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.13.2", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" +dependencies = [ + "bitflags 2.13.2", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustix-linux-procfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" +dependencies = [ + "once_cell", + "rustix 1.1.5", +] + +[[package]] +name = "rustls" +version = "0.23.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[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.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustpython-ast" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cdaf8ee5c1473b993b398c174641d3aa9da847af36e8d5eb8291930b72f31a5" +dependencies = [ + "is-macro", + "malachite-bigint", + "rustpython-parser-core", + "static_assertions", +] + +[[package]] +name = "rustpython-parser" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "868f724daac0caf9bd36d38caf45819905193a901e8f1c983345a68e18fb2abb" +dependencies = [ + "anyhow", + "is-macro", + "itertools 0.11.0", + "lalrpop-util", + "log", + "malachite-bigint", + "num-traits", + "phf 0.11.3", + "phf_codegen", + "rustc-hash 1.1.0", + "rustpython-ast", + "rustpython-parser-core", + "tiny-keccak", + "unic-emoji-char", + "unic-ucd-ident", + "unicode_names2", +] + +[[package]] +name = "rustpython-parser-core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b6c12fa273825edc7bccd9a734f0ad5ba4b8a2f4da5ff7efe946f066d0f4ad" +dependencies = [ + "is-macro", + "memchr", + "rustpython-parser-vendored", +] + +[[package]] +name = "rustpython-parser-vendored" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04fcea49a4630a3a5d940f4d514dc4f575ed63c14c3e3ed07146634aed7f67a6" +dependencies = [ + "memchr", + "once_cell", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive 0.8.22", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +dependencies = [ + "chrono", + "dyn-clone", + "ref-cast", + "schemars_derive 1.2.2", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals 0.29.1", + "syn 2.0.119", +] + +[[package]] +name = "schemars_derive" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals 0.30.0", + "syn 3.0.6", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.13.2", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "serde_derive_internals" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "indexmap 2.14.2", + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9adc193c780ef8f159aee8b61e2d5801aaa555e6eb0947fe45530ec506296f" +dependencies = [ + "base64 0.23.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.2", + "jiff", + "schemars 0.9.0", + "schemars 1.2.2", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e17bbc68e28663bbbb90df47e058aa7eda4fb445b89fe70457bb94fbccf6e49" +dependencies = [ + "darling 0.24.1", + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.14.2", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "serial_test" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "699f4197115b8a7e7ff19c9a315a4bd6fffec26cc4626ef45ecaea389e081c6d" +dependencies = [ + "futures-executor", + "futures-util", + "log", + "once_cell", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "sgl-model-gateway" +version = "0.3.2" +dependencies = [ + "anyhow", + "arc-swap", + "async-trait", + "axum 0.8.9", + "axum-server", + "base64 0.22.1", + "bitflags 2.13.2", + "blake3", + "bytemuck", + "bytes", + "chrono", + "clap", + "crdts", + "criterion", + "dashmap", + "data-connector", + "futures", + "futures-util", + "http", + "http-body", + "http-body-util", + "jsonwebtoken", + "k8s-openapi", + "kube", + "lazy_static", + "llm-tokenizer", + "memchr", + "metrics", + "metrics-exporter-prometheus", + "npyz", + "num-bigint", + "num-traits", + "once_cell", + "openai-harmony", + "openai-protocol", + "openmetrics-parser", + "openssl", + "opentelemetry", + "opentelemetry-otlp", + "opentelemetry-proto", + "opentelemetry_sdk", + "parking_lot", + "portpicker", + "prost 0.14.4", + "prost-types", + "rand 0.9.5", + "reasoning-parser", + "redis", + "regex", + "reqwest", + "rmcp", + "rsa", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_yaml", + "serial_test", + "sha2 0.10.9", + "smg-auth", + "smg-grpc-client", + "smg-mcp", + "smg-mesh", + "smg-wasm", + "subtle", + "tempfile", + "thiserror 2.0.21", + "tokio", + "tokio-stream", + "toml 0.9.12+spec-1.1.0", + "tonic 0.12.3", + "tonic 0.14.6", + "tonic-prost", + "tool-parser", + "tower 0.5.3", + "tower-http", + "tracing", + "tracing-appender", + "tracing-log", + "tracing-opentelemetry", + "tracing-subscriber", + "url", + "uuid", + "validator", + "wasm-encoder 0.242.0", + "wasmtime", + "wfaas", + "xxhash-rust", +] + +[[package]] +name = "sgl-model-gateway-python" +version = "0.3.2" +dependencies = [ + "once_cell", + "pyo3", + "sgl-model-gateway", + "tokio", +] + +[[package]] +name = "sha1" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror 2.0.21", + "time", +] + +[[package]] +name = "siphasher" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256" + +[[package]] +name = "sketches-ddsketch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e" +dependencies = [ + "serde", +] + +[[package]] +name = "smg-auth" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbad75b157c8330e79cddff933e54f475f84b776eb9999aec0a8ff733c3d71c4" +dependencies = [ + "axum 0.8.9", + "chrono", + "http", + "jsonwebtoken", + "lru", + "parking_lot", + "reqwest", + "serde", + "serde_json", + "sha2 0.10.9", + "subtle", + "thiserror 2.0.21", + "tracing", + "url", +] + +[[package]] +name = "smg-grpc-client" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a794c92aca789806e776224edc1cdc74f70d7c0dad21ce6a53bb02e7d44a6e8" +dependencies = [ + "futures", + "openai-protocol", + "prost 0.14.4", + "prost-build", + "prost-types", + "serde", + "serde_json", + "tokio", + "tonic 0.14.6", + "tonic-prost", + "tonic-prost-build", + "tracing", +] + +[[package]] +name = "smg-mcp" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb5e9f034b4c01eb6a9fc3b2b7a3fe7fdf309f5ce3cd5a2db722db36a4651a2" +dependencies = [ + "async-trait", + "axum 0.8.9", + "backoff", + "dashmap", + "lru", + "openai-protocol", + "parking_lot", + "reqwest", + "rmcp", + "serde", + "serde_json", + "serde_yaml", + "thiserror 2.0.21", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "smg-mesh" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55f219a43ec3213d4ff3b556571a99313b077fd0f7e9af389984a9b7100cde5" +dependencies = [ + "anyhow", + "async-trait", + "axum 0.8.9", + "chrono", + "crdts", + "dashmap", + "futures", + "http", + "kv-index", + "metrics", + "num-bigint", + "num-traits", + "parking_lot", + "prost 0.14.4", + "prost-build", + "prost-types", + "rand 0.9.5", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "thiserror 2.0.21", + "tokio", + "tokio-stream", + "tonic 0.14.6", + "tonic-prost", + "tonic-prost-build", + "tracing", +] + +[[package]] +name = "smg-wasm" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d2c969913f26ac4de277c7605172d9637907c5bbe38f228e26edbc65f996e1" +dependencies = [ + "async-channel", + "axum 0.8.9", + "chrono", + "lru", + "serde", + "sha2 0.10.9", + "thiserror 2.0.21", + "tokio", + "tracing", + "uuid", + "wasmtime", + "wasmtime-wasi", +] + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[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 = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der 0.7.10", +] + +[[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 = "sse-stream" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c25ac7aff0abd1dbc474536e40416e1102c7dd9bfba0b9861c6d357f835dcfb4" +dependencies = [ + "bytes", + "futures-util", + "http-body", + "http-body-util", + "pin-project-lite", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "system-configuration" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" +dependencies = [ + "bitflags 2.13.2", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "system-interface" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4592f674ce18521c2a81483873a49596655b179f71c5e05d10c1fe66c78745" +dependencies = [ + "bitflags 2.13.2", + "cap-fs-ext", + "cap-std", + "fd-lock", + "io-lifetimes", + "rustix 0.38.44", + "windows-sys 0.59.0", + "winx", +] + +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix 1.1.5", + "windows-sys 0.52.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl 2.0.21", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "thread_local" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tiff" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + +[[package]] +name = "tiktoken-rs" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a19830747d9034cd9da43a60eaa8e552dfda7712424aebf187b7a60126bae0d" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bstr", + "fancy-regex", + "lazy_static", + "regex", + "rustc-hash 1.1.0", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + +[[package]] +name = "tokenizers" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b238e22d44a15349529690fb07bd645cf58149a1b1e44d6cb5bd1641ff1a6223" +dependencies = [ + "ahash", + "aho-corasick", + "compact_str", + "dary_heap", + "derive_builder", + "esaxx-rs", + "getrandom 0.3.4", + "indicatif", + "itertools 0.14.0", + "log", + "macro_rules_attribute", + "monostate", + "onig", + "paste", + "rand 0.9.5", + "rayon", + "rayon-cond", + "regex", + "regex-syntax", + "serde", + "serde_json", + "spm_precompiled", + "thiserror 2.0.21", + "unicode-normalization-alignments", + "unicode-segmentation", + "unicode_categories", +] + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.6.5", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[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-postgres" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a528f7d280f6d5b9cd149635c8705b0dd049754bc67d81d31fa25169a93809d3" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator 0.2.0", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf 0.13.1", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand 0.10.3", + "socket2 0.6.5", + "tokio", + "tokio-util", + "whoami", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "libc", + "pin-project-lite", + "slab", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.14.2", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.14.2", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow 0.7.15", +] + +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow 1.0.4", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "toml_writer" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" + +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum 0.7.9", + "base64 0.22.1", + "bytes", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost 0.13.5", + "socket2 0.5.10", + "tokio", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" +dependencies = [ + "async-trait", + "axum 0.8.9", + "base64 0.22.1", + "bytes", + "flate2", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "socket2 0.6.5", + "sync_wrapper", + "tokio", + "tokio-stream", + "tower 0.5.3", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-build" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f61875ac5293cf72e6c8cf0158086428c82c37229e98c840878f1706b0322" +dependencies = [ + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tonic-prost" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50849f68853be452acf590cde0b146665b8d507b3b8af17261df47e02c209ea0" +dependencies = [ + "bytes", + "prost 0.14.4", + "tonic 0.14.6", +] + +[[package]] +name = "tonic-prost-build" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "654e5643eff75d7f8c99197ce1440ed19a3474eada74c12bbac488b2cafdae27" +dependencies = [ + "prettyplease", + "proc-macro2", + "prost-build", + "prost-types", + "quote", + "syn 2.0.119", + "tempfile", + "tonic-build", +] + +[[package]] +name = "tool-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5da20912ca7f54f4e694da0719aab7b3e925259f045fe4f15494717f3a440bb" +dependencies = [ + "async-trait", + "num-traits", + "openai-protocol", + "regex", + "rustpython-parser", + "serde", + "serde_json", + "thiserror 2.0.21", + "tokio", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.8", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "hdrhistogram", + "indexmap 2.14.2", + "pin-project-lite", + "slab", + "sync_wrapper", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "async-compression", + "base64 0.22.1", + "bitflags 2.13.2", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "tokio", + "tokio-util", + "tower 0.5.3", + "tower-layer", + "tower-service", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-appender" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "050686193eb999b4bb3bc2acfa891a13da00f79734704c4b8b4ef1a10b368a3c" +dependencies = [ + "crossbeam-channel", + "symlink", + "thiserror 2.0.21", + "time", + "tracing-subscriber", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-opentelemetry" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a971f6058498b5c0f1affa23e7ea202057a7301dbff68e968b2d578bcbd053" +dependencies = [ + "js-sys", + "once_cell", + "opentelemetry", + "opentelemetry_sdk", + "smallvec", + "tracing", + "tracing-core", + "tracing-log", + "tracing-subscriber", + "web-time", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "chrono", + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.5", + "sha1", + "thiserror 2.0.21", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "ulid" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "470dbf6591da1b39d43c14523b2b469c86879a53e8b758c8e090a470fe7b1fbe" +dependencies = [ + "rand 0.9.5", + "web-time", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-emoji-char" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b07221e68897210270a38bde4babb655869637af0f69407f96053a34f76494d" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "unicode_names2" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1673eca9782c84de5f81b82e4109dcfb3611c8ba0d52930ec4a9478f547b2dd" +dependencies = [ + "phf 0.11.3", + "unicode_names2_generator", +] + +[[package]] +name = "unicode_names2_generator" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91e5b84611016120197efd7dc93ef76774f4e084cd73c9fb3ea4a86c570c56e" +dependencies = [ + "getopts", + "log", + "phf_codegen", + "rand 0.8.8", +] + +[[package]] +name = "unindent" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" + +[[package]] +name = "unit-prefix" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7ac20be9b7726e0bbdbf974c059676d9acb1cd414961f570a4e8231cacd7fc" +dependencies = [ + "base64 0.23.1", + "cookie_store", + "der 0.8.2", + "flate2", + "log", + "native-tls", + "percent-encoding", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "socks", + "ureq-proto", + "utf8-zero", + "webpki-root-certs", + "webpki-roots", +] + +[[package]] +name = "ureq-proto" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86fd172ccca569e458f61b6bdd6220965a9ef36e672a6852953b51a0e1583be" +dependencies = [ + "base64 0.23.1", + "http", + "httparse", + "log", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef6dac1e96601b4fb3acccccff2139741fcb757cb9a36089bf5be91cfb285ce" +dependencies = [ + "getrandom 0.4.3", + "js-sys", + "serde_core", + "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 = "validator" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa" +dependencies = [ + "idna", + "once_cell", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240e4b81c20a1d6d50d1d7265c658dfbd204e8b9ac4d80f3c931f39462196335" +dependencies = [ + "darling 0.23.0", + "proc-macro-error3", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42" +dependencies = [ + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbab34de2d982e9b48e18d216d04c4a6f641066ff19ffb699980f591ee3610e" +dependencies = [ + "js-sys", + "tokio", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.6", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.239.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be00faa2b4950c76fe618c409d2c3ea5a3c9422013e079482d78544bb2d184c" +dependencies = [ + "leb128fmt", + "wasmparser 0.239.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.242.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67f90e55bc9c6ee6954a757cc6eb3424d96b442e5252ed10fea627e518878d36" +dependencies = [ + "leb128fmt", + "wasmparser 0.242.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.259.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d0246511d901aacf25d2dc9111f0054947de5e093fe662099e709ff7530dc3" +dependencies = [ + "leb128fmt", + "wasmparser 0.259.0", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmparser" +version = "0.239.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9d90bb93e764f6beabf1d02028c70a2156a6583e63ac4218dd07ef733368b0" +dependencies = [ + "bitflags 2.13.2", + "hashbrown 0.15.5", + "indexmap 2.14.2", + "semver", + "serde", +] + +[[package]] +name = "wasmparser" +version = "0.242.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3c6e611f4cd748d85c767815823b777dc56afca793fcda27beae4e85028849" +dependencies = [ + "bitflags 2.13.2", + "indexmap 2.14.2", + "semver", +] + +[[package]] +name = "wasmparser" +version = "0.259.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f7c12eac7bb587801590f6a67ff0bc84d0748513864b71108e4b311cc3df694" +dependencies = [ + "bitflags 2.13.2", + "indexmap 2.14.2", + "semver", +] + +[[package]] +name = "wasmprinter" +version = "0.239.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3981f3d51f39f24f5fc90f93049a90f08dbbca8deba602cd46bb8ca67a94718" +dependencies = [ + "anyhow", + "termcolor", + "wasmparser 0.239.0", +] + +[[package]] +name = "wasmtime" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81eafc07c867be94c47e0dc66355d9785e09107a18901f76a20701ba0663ad7" +dependencies = [ + "addr2line", + "anyhow", + "async-trait", + "bitflags 2.13.2", + "bumpalo", + "cc", + "cfg-if", + "encoding_rs", + "fxprof-processed-profile", + "gimli", + "hashbrown 0.15.5", + "indexmap 2.14.2", + "ittapi", + "libc", + "log", + "mach2", + "memfd", + "object", + "once_cell", + "postcard", + "pulley-interpreter", + "rayon", + "rustix 1.1.5", + "semver", + "serde", + "serde_derive", + "serde_json", + "smallvec", + "target-lexicon", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", + "wasmtime-environ", + "wasmtime-internal-cache", + "wasmtime-internal-component-macro", + "wasmtime-internal-component-util", + "wasmtime-internal-cranelift", + "wasmtime-internal-fiber", + "wasmtime-internal-jit-debug", + "wasmtime-internal-jit-icache-coherence", + "wasmtime-internal-math", + "wasmtime-internal-slab", + "wasmtime-internal-unwinder", + "wasmtime-internal-versioned-export-macros", + "wasmtime-internal-winch", + "wat", + "windows-sys 0.60.2", +] + +[[package]] +name = "wasmtime-environ" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78587abe085a44a13c90fa16fea6db014e9883e627a7044d7f0cb397ad08d1da" +dependencies = [ + "anyhow", + "cpp_demangle", + "cranelift-bitset", + "cranelift-entity", + "gimli", + "indexmap 2.14.2", + "log", + "object", + "postcard", + "rustc-demangle", + "semver", + "serde", + "serde_derive", + "smallvec", + "target-lexicon", + "wasm-encoder 0.239.0", + "wasmparser 0.239.0", + "wasmprinter", + "wasmtime-internal-component-util", +] + +[[package]] +name = "wasmtime-internal-cache" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78fb9299e318b0af3efb75d88321515a20a5ccb040bcde1f0f7d46d656fa8fef" +dependencies = [ + "anyhow", + "base64 0.22.1", + "directories-next", + "log", + "postcard", + "rustix 1.1.5", + "serde", + "serde_derive", + "sha2 0.10.9", + "toml 0.8.23", + "windows-sys 0.60.2", + "zstd 0.13.3", +] + +[[package]] +name = "wasmtime-internal-component-macro" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d843bb444f2d1509ea9304ad749242d1fa5de95cde67665bfcdcafa0f360925c" +dependencies = [ + "anyhow", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasmtime-internal-component-util", + "wasmtime-internal-wit-bindgen", + "wit-parser", +] + +[[package]] +name = "wasmtime-internal-component-util" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801ee1a80ab66f065a88c6a62f2d495d5540d027b366757c6a53e9c42f153aef" + +[[package]] +name = "wasmtime-internal-cranelift" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb50f1c50365c32e557266ca85acdf77696c44a3f98797ba6af58cebc6d6d1e" +dependencies = [ + "anyhow", + "cfg-if", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "gimli", + "itertools 0.14.0", + "log", + "object", + "pulley-interpreter", + "smallvec", + "target-lexicon", + "thiserror 2.0.21", + "wasmparser 0.239.0", + "wasmtime-environ", + "wasmtime-internal-math", + "wasmtime-internal-unwinder", + "wasmtime-internal-versioned-export-macros", +] + +[[package]] +name = "wasmtime-internal-fiber" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9308cdb17f8d51e3164185616d809e28c29a6515c03b9dd95c89436b71f6d154" +dependencies = [ + "anyhow", + "cc", + "cfg-if", + "libc", + "rustix 1.1.5", + "wasmtime-internal-versioned-export-macros", + "windows-sys 0.60.2", +] + +[[package]] +name = "wasmtime-internal-jit-debug" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c9b63a22bf2a8b6a149a41c6768bc17a8b2e3288a249cb8216987fbd7128e81" +dependencies = [ + "cc", + "object", + "rustix 1.1.5", + "wasmtime-internal-versioned-export-macros", +] + +[[package]] +name = "wasmtime-internal-jit-icache-coherence" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb8e042b6e3de2f3d708279f89f50b4b9aa1b9bab177300cdffb0ffcd2816df5" +dependencies = [ + "anyhow", + "cfg-if", + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "wasmtime-internal-math" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c1f0674f38cd7d014eb1a49ea1d1766cca1a64459e8856ee118a10005302e16" +dependencies = [ + "libm", +] + +[[package]] +name = "wasmtime-internal-slab" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb24b7535306713e7a250f8b71e35f05b6a5031bf9c3ed7330c308e899cbe7d3" + +[[package]] +name = "wasmtime-internal-unwinder" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21d5a80e2623a49cb8e8c419542337b8fe0260b162c40dcc201080a84cbe9b7c" +dependencies = [ + "anyhow", + "cfg-if", + "cranelift-codegen", + "log", + "object", +] + +[[package]] +name = "wasmtime-internal-versioned-export-macros" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23e277f734b9256359b21517c3b0c26a2a9de6c53a51b670ae55cdcde548bf4e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "wasmtime-internal-winch" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4dc9333737142f6ece4369c8bcdda03a11edbd43d8fbd3e15004c194b9b743" +dependencies = [ + "anyhow", + "cranelift-codegen", + "gimli", + "log", + "object", + "target-lexicon", + "wasmparser 0.239.0", + "wasmtime-environ", + "wasmtime-internal-cranelift", + "winch-codegen", +] + +[[package]] +name = "wasmtime-internal-wit-bindgen" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f758625553fe33fdce0713f63bb7784c4f5fecb7f7cd4813414519ec24b6a4c" +dependencies = [ + "anyhow", + "bitflags 2.13.2", + "heck", + "indexmap 2.14.2", + "wit-parser", +] + +[[package]] +name = "wasmtime-wasi" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55abdad51f519217927f45eaae73ca0cd46eb76688628a49784f41b5b19b8ed6" +dependencies = [ + "anyhow", + "async-trait", + "bitflags 2.13.2", + "bytes", + "cap-fs-ext", + "cap-net-ext", + "cap-rand", + "cap-std", + "cap-time-ext", + "fs-set-times", + "futures", + "io-extras", + "io-lifetimes", + "rustix 1.1.5", + "system-interface", + "thiserror 2.0.21", + "tokio", + "tracing", + "url", + "wasmtime", + "wasmtime-wasi-io", + "wiggle", + "windows-sys 0.60.2", +] + +[[package]] +name = "wasmtime-wasi-io" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d7f6e8ea0c4842e31b01721527a825f55ae73a2fa095d8b3f7ddbd75e3661" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "futures", + "wasmtime", +] + +[[package]] +name = "wast" +version = "35.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ef140f1b49946586078353a453a1d28ba90adfc54dde75710bc1931de204d68" +dependencies = [ + "leb128", +] + +[[package]] +name = "wast" +version = "259.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c69beba8d9da07af9a0971b559149a2ac4729895b55144de4fddbf5a02660648" +dependencies = [ + "bumpalo", + "leb128fmt", + "memchr", + "unicode-width", + "wasm-encoder 0.259.0", +] + +[[package]] +name = "wat" +version = "1.259.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6eec44b0c80391b20fb7ad9ea440c72c5d382385bdf74444bb18321c425017e" +dependencies = [ + "wast 259.0.0", +] + +[[package]] +name = "web-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "wfaas" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73c07fa5d59193a83b48bbafaf53a99bffc70872af47671ddb6392f531013196" +dependencies = [ + "async-trait", + "backoff", + "chrono", + "parking_lot", + "serde", + "thiserror 2.0.21", + "tokio", + "tracing", + "uuid", +] + +[[package]] +name = "whoami" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c" +dependencies = [ + "libc", + "libredox", + "objc2-system-configuration", + "wasite", + "web-sys", +] + +[[package]] +name = "wiggle" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9ee0c6dd73bdf0aff4404059bdc24ca61ad92056d20f4e59b8b0780789cafb4" +dependencies = [ + "anyhow", + "async-trait", + "bitflags 2.13.2", + "thiserror 2.0.21", + "tracing", + "wasmtime", + "wiggle-macro", +] + +[[package]] +name = "wiggle-generate" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e415549583fd492ccab881076fa5c41590362d3b5e99df793f619d67333c97b" +dependencies = [ + "anyhow", + "heck", + "proc-macro2", + "quote", + "syn 2.0.119", + "witx", +] + +[[package]] +name = "wiggle-macro" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a533b4fdc593bf9c4bf52ae0b3a126f15babfb25fce03bfe0bcc84e1172222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "wiggle-generate", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winch-codegen" +version = "38.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c0bb17ae9bf89ebc74512150e6ee0a27b1eac5ff3b54d8cec264f4b4255022d" +dependencies = [ + "anyhow", + "cranelift-assembler-x64", + "cranelift-codegen", + "gimli", + "regalloc2", + "smallvec", + "target-lexicon", + "thiserror 2.0.21", + "wasmparser 0.239.0", + "wasmtime-environ", + "wasmtime-internal-cranelift", + "wasmtime-internal-math", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +dependencies = [ + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" + +[[package]] +name = "winx" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d" +dependencies = [ + "bitflags 2.13.2", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-parser" +version = "0.239.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55c92c939d667b7bf0c6bf2d1f67196529758f99a2a45a3355cc56964fd5315d" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.14.2", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser 0.239.0", +] + +[[package]] +name = "witx" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e366f27a5cabcddb2706a78296a40b8fcc451e1a6aba2fc1d94b4a01bdaaef4b" +dependencies = [ + "anyhow", + "log", + "thiserror 1.0.69", + "wast 35.0.2", +] + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "xxhash-rust" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aee1b19627c7c60102ab80d3a9cbe18de90bfe03bfa6c3715447681f0e8c8af6" + +[[package]] +name = "y4m" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6df92bf3d9227be3d53173901ddbffac2babc27ae50f397776ffd6dc33f800cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac4f328cf2f05d084e496c3e9c3f33ed0a183656a16e1fcec4d464d8373aec82" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq 0.1.5", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac 0.12.1", + "pbkdf2", + "sha1", + "time", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe 7.3.0", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-safe" +version = "7.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.1.0+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef0a8027ec3ee71300ab3bcbcd0393f434aa72b91ca6d635a39941deae8eea0" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "zune-core" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" + +[[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.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" +dependencies = [ + "zune-core", +] diff --git a/sgl-model-gateway/Cargo.toml b/sgl-model-gateway/Cargo.toml index 12b06d94172e..6498b108a967 100644 --- a/sgl-model-gateway/Cargo.toml +++ b/sgl-model-gateway/Cargo.toml @@ -205,3 +205,6 @@ codegen-units = 1 [profile.dev-opt] inherits = "dev" opt-level = 1 + +[patch.crates-io] +openai-protocol = { path = "vendor/openai-protocol" } diff --git a/sgl-model-gateway/src/chat_protocol_tests.rs b/sgl-model-gateway/src/chat_protocol_tests.rs new file mode 100644 index 000000000000..76dc8d0e22f9 --- /dev/null +++ b/sgl-model-gateway/src/chat_protocol_tests.rs @@ -0,0 +1,78 @@ +#[cfg(test)] +mod tests { + use openai_protocol::{chat::ChatCompletionRequest, validated::Normalizable}; + use validator::Validate; + use serde_json::json; + + fn request(top_logprobs: u32) -> ChatCompletionRequest { + serde_json::from_value(json!({ + "model": "test", + "messages": [{"role": "user", "content": "hello"}], + "logprobs": true, + "top_logprobs": top_logprobs + })) + .unwrap() + } + + #[test] + fn accepts_extended_head_without_modifying_request() { + for count in [0, 16, 20, 21, 128] { + let mut body = request(count); + body.normalize(); + assert!(body.validate().is_ok(), "{count}"); + assert_eq!( + serde_json::to_value(&body).unwrap()["top_logprobs"], + count + ); + } + } + + #[test] + fn rejects_head_above_backend_limit() { + for count in [129, u32::MAX] { + let errors = request(count).validate().unwrap_err(); + assert!(errors.field_errors().contains_key("top_logprobs")); + } + } + + #[test] + fn preserves_other_protocol_validation() { + let mut body = request(128); + body.temperature = Some(3.0); + let errors = body.validate().unwrap_err(); + assert!(errors.field_errors().contains_key("temperature")); + } + + #[test] + fn optional_head_and_invalid_json_types() { + let value = json!({"model":"test","messages":[{"role":"user","content":"hello"}]}); + let body: ChatCompletionRequest = serde_json::from_value(value.clone()).unwrap(); + assert!(body.validate().is_ok()); + for bad in [json!(-1), json!(1.5), json!("128")] { + let mut value = value.clone(); + value["top_logprobs"] = bad; + assert!(serde_json::from_value::(value).is_err()); + } + } + #[test] + fn preserves_session_extensions() { + let mut value = serde_json::to_value(request(128)).unwrap(); + value["input_ids"] = json!([1, 2, 3]); + value["return_meta_info"] = json!(true); + let mut body: ChatCompletionRequest = serde_json::from_value(value).unwrap(); + body.normalize(); + assert!(body.validate().is_ok()); + let outgoing = serde_json::to_value(body).unwrap(); + assert_eq!(outgoing["input_ids"], json!([1, 2, 3])); + assert_eq!(outgoing["return_meta_info"], json!(true)); + assert_eq!(outgoing["top_logprobs"], json!(128)); + } + + #[test] + fn requires_logprobs_for_extended_head() { + let mut body = request(128); + body.logprobs = false; + assert!(body.validate().is_err()); + } + +} diff --git a/sgl-model-gateway/src/lib.rs b/sgl-model-gateway/src/lib.rs index 9f92b12ec6fd..dc5161ff5287 100644 --- a/sgl-model-gateway/src/lib.rs +++ b/sgl-model-gateway/src/lib.rs @@ -1,3 +1,5 @@ +#[cfg(test)] +mod chat_protocol_tests; pub mod app_context; pub use smg_auth as auth; pub mod config; diff --git a/sgl-model-gateway/vendor/README.md b/sgl-model-gateway/vendor/README.md new file mode 100644 index 000000000000..6250a8215cca --- /dev/null +++ b/sgl-model-gateway/vendor/README.md @@ -0,0 +1 @@ +openai-protocol 1.0.0 is vendored from crates.io under Apache-2.0. Local changes extend the chat top_logprobs maximum to128 and preserve input_ids and return_meta_info so session clients retain exact tokenization and replay metadata. Validation remains in the schema, including cross-field checks. All other protocol fields remain unchanged. diff --git a/sgl-model-gateway/vendor/openai-protocol/Cargo.toml b/sgl-model-gateway/vendor/openai-protocol/Cargo.toml new file mode 100644 index 000000000000..bb97a44d9ea9 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/Cargo.toml @@ -0,0 +1,77 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "openai-protocol" +version = "1.0.0" +authors = [ + "Simo Lin ", + "Chang Su ", + "Keyang Ru ", +] +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "OpenAI-compatible API protocol definitions and types" +readme = false +keywords = [ + "openai", + "llm", + "api", + "protocol", + "types", +] +categories = [ + "api-bindings", + "data-structures", +] +license = "Apache-2.0" +repository = "https://github.com/lightseekorg/smg" + +[features] +axum = ["dep:axum"] +default = [] + +[lib] +name = "openai_protocol" +path = "src/lib.rs" + +[dependencies.axum] +version = "0.8.6" +optional = true + +[dependencies.chrono] +version = "0.4" + +[dependencies.rand] +version = "0.9.2" + +[dependencies.serde] +version = "1.0" +features = ["derive"] + +[dependencies.serde_json] +version = "1.0" +features = ["preserve_order"] + +[dependencies.tokio] +version = "1.42.0" + +[dependencies.tracing] +version = "0.1" + +[dependencies.validator] +version = "0.20.0" +features = ["derive"] diff --git a/sgl-model-gateway/vendor/openai-protocol/Cargo.toml.orig b/sgl-model-gateway/vendor/openai-protocol/Cargo.toml.orig new file mode 100644 index 000000000000..590898e0f9ea --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/Cargo.toml.orig @@ -0,0 +1,29 @@ +[package] +name = "openai-protocol" +version = "1.0.0" +edition = "2021" +description = "OpenAI-compatible API protocol definitions and types" +license = "Apache-2.0" +repository = "https://github.com/lightseekorg/smg" +authors = [ + "Simo Lin ", + "Chang Su ", + "Keyang Ru ", +] +keywords = ["openai", "llm", "api", "protocol", "types"] +categories = ["api-bindings", "data-structures"] + +[features] +default = [] +axum = ["dep:axum"] + +[dependencies] +axum = { workspace = true, optional = true } +chrono.workspace = true +rand.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true, features = ["preserve_order"] } +tokio.workspace = true +tracing.workspace = true +# Only used by protocols +validator = { version = "0.20.0", features = ["derive"] } diff --git a/sgl-model-gateway/vendor/openai-protocol/src/builders/chat/mod.rs b/sgl-model-gateway/vendor/openai-protocol/src/builders/chat/mod.rs new file mode 100644 index 000000000000..61386b505c91 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/builders/chat/mod.rs @@ -0,0 +1,7 @@ +//! Builders for Chat Completion API response types + +pub mod response; +pub mod stream_response; + +pub use response::ChatCompletionResponseBuilder; +pub use stream_response::ChatCompletionStreamResponseBuilder; diff --git a/sgl-model-gateway/vendor/openai-protocol/src/builders/chat/response.rs b/sgl-model-gateway/vendor/openai-protocol/src/builders/chat/response.rs new file mode 100644 index 000000000000..3362078c51e5 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/builders/chat/response.rs @@ -0,0 +1,218 @@ +//! Builder for ChatCompletionResponse +//! +//! Provides an ergonomic fluent API for constructing chat completion responses. + +use crate::{chat::*, common::Usage}; + +/// Builder for ChatCompletionResponse +/// +/// Provides a fluent interface for constructing chat completion responses with sensible defaults. +#[must_use = "Builder does nothing until .build() is called"] +#[derive(Clone, Debug)] +pub struct ChatCompletionResponseBuilder { + id: String, + object: String, + created: u64, + model: String, + choices: Vec, + usage: Option, + system_fingerprint: Option, +} + +impl ChatCompletionResponseBuilder { + /// Create a new builder with required fields + /// + /// # Arguments + /// - `id`: Completion ID (e.g., "chatcmpl_abc123") + /// - `model`: Model name used for generation + pub fn new(id: impl Into, model: impl Into) -> Self { + Self { + id: id.into(), + object: "chat.completion".to_string(), + created: chrono::Utc::now().timestamp() as u64, + model: model.into(), + choices: Vec::new(), + usage: None, + system_fingerprint: None, + } + } + + /// Copy common fields from a ChatCompletionRequest + /// + /// This populates the model field from the request. + pub fn copy_from_request(mut self, request: &ChatCompletionRequest) -> Self { + self.model = request.model.clone(); + self + } + + /// Set the object type (default: "chat.completion") + pub fn object(mut self, object: impl Into) -> Self { + self.object = object.into(); + self + } + + /// Set the creation timestamp (default: current time) + pub fn created(mut self, timestamp: u64) -> Self { + self.created = timestamp; + self + } + + /// Set the choices + pub fn choices(mut self, choices: Vec) -> Self { + self.choices = choices; + self + } + + /// Add a single choice + pub fn add_choice(mut self, choice: ChatChoice) -> Self { + self.choices.push(choice); + self + } + + /// Set usage information + pub fn usage(mut self, usage: Usage) -> Self { + self.usage = Some(usage); + self + } + + /// Set usage if provided (handles Option) + pub fn maybe_usage(mut self, usage: Option) -> Self { + if let Some(u) = usage { + self.usage = Some(u); + } + self + } + + /// Set system fingerprint if provided (handles Option) + pub fn maybe_system_fingerprint(mut self, fingerprint: Option>) -> Self { + if let Some(fp) = fingerprint { + self.system_fingerprint = Some(fp.into()); + } + self + } + + /// Build the ChatCompletionResponse + pub fn build(self) -> ChatCompletionResponse { + ChatCompletionResponse { + id: self.id, + object: self.object, + created: self.created, + model: self.model, + choices: self.choices, + usage: self.usage, + system_fingerprint: self.system_fingerprint, + } + } +} + +// ============================================================================ +// Tests +// ============================================================================ + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_build_minimal() { + let response = ChatCompletionResponse::builder("chatcmpl_123", "gpt-4").build(); + + assert_eq!(response.id, "chatcmpl_123"); + assert_eq!(response.model, "gpt-4"); + assert_eq!(response.object, "chat.completion"); + assert!(response.choices.is_empty()); + assert!(response.usage.is_none()); + assert!(response.system_fingerprint.is_none()); + } + + #[test] + fn test_build_complete() { + let choice = ChatChoice { + index: 0, + message: ChatCompletionMessage { + role: "assistant".to_string(), + content: Some("Hello!".to_string()), + tool_calls: None, + reasoning_content: None, + }, + logprobs: None, + finish_reason: Some("stop".to_string()), + matched_stop: None, + hidden_states: None, + }; + + let usage = Usage { + prompt_tokens: 10, + completion_tokens: 20, + total_tokens: 30, + completion_tokens_details: None, + }; + + let response = ChatCompletionResponse::builder("chatcmpl_456", "gpt-4") + .choices(vec![choice.clone()]) + .maybe_usage(Some(usage)) + .maybe_system_fingerprint(Some("fp_123abc")) + .build(); + + assert_eq!(response.id, "chatcmpl_456"); + assert_eq!(response.choices.len(), 1); + assert_eq!(response.choices[0].index, 0); + assert!(response.usage.is_some()); + assert_eq!(response.system_fingerprint.as_ref().unwrap(), "fp_123abc"); + } + + #[test] + fn test_add_multiple_choices() { + let choice1 = ChatChoice { + index: 0, + message: ChatCompletionMessage { + role: "assistant".to_string(), + content: Some("Option 1".to_string()), + tool_calls: None, + reasoning_content: None, + }, + logprobs: None, + finish_reason: Some("stop".to_string()), + matched_stop: None, + hidden_states: None, + }; + + let choice2 = ChatChoice { + index: 1, + message: ChatCompletionMessage { + role: "assistant".to_string(), + content: Some("Option 2".to_string()), + tool_calls: None, + reasoning_content: None, + }, + logprobs: None, + finish_reason: Some("stop".to_string()), + matched_stop: None, + hidden_states: None, + }; + + let response = ChatCompletionResponse::builder("chatcmpl_789", "gpt-4") + .add_choice(choice1) + .add_choice(choice2) + .build(); + + assert_eq!(response.choices.len(), 2); + assert_eq!(response.choices[0].index, 0); + assert_eq!(response.choices[1].index, 1); + } + + #[test] + fn test_copy_from_request() { + let request = ChatCompletionRequest { + messages: vec![], + model: "gpt-3.5-turbo".to_string(), + ..Default::default() + }; + + let response = ChatCompletionResponse::builder("chatcmpl_101", "gpt-4") + .copy_from_request(&request) + .build(); + + assert_eq!(response.model, "gpt-3.5-turbo"); // Copied from request + } +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/builders/chat/stream_response.rs b/sgl-model-gateway/vendor/openai-protocol/src/builders/chat/stream_response.rs new file mode 100644 index 000000000000..85a67b1e1a77 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/builders/chat/stream_response.rs @@ -0,0 +1,421 @@ +//! Builder for ChatCompletionStreamResponse +//! +//! Provides an ergonomic fluent API for constructing streaming chat completion responses. + +use std::borrow::Cow; + +use crate::{ + chat::*, + common::{FunctionCallDelta, ToolCallDelta, Usage}, +}; + +/// Builder for ChatCompletionStreamResponse +/// +/// Provides a fluent interface for constructing streaming chat completion chunks with sensible defaults. +#[must_use = "Builder does nothing until .build() is called"] +#[derive(Clone, Debug)] +pub struct ChatCompletionStreamResponseBuilder { + id: String, + object: String, + created: u64, + model: String, + choices: Vec, + usage: Option, + system_fingerprint: Option, +} + +impl ChatCompletionStreamResponseBuilder { + /// Create a new builder with required fields + /// + /// # Arguments + /// - `id`: Completion ID (e.g., "chatcmpl_abc123") + /// - `model`: Model name used for generation + pub fn new(id: impl Into, model: impl Into) -> Self { + Self { + id: id.into(), + object: "chat.completion.chunk".to_string(), + created: chrono::Utc::now().timestamp() as u64, + model: model.into(), + choices: Vec::new(), + usage: None, + system_fingerprint: None, + } + } + + /// Copy common fields from a ChatCompletionRequest + /// + /// This populates the model field from the request. + pub fn copy_from_request(mut self, request: &ChatCompletionRequest) -> Self { + self.model = request.model.clone(); + self + } + + /// Set the object type (default: "chat.completion.chunk") + pub fn object(mut self, object: impl Into) -> Self { + self.object = object.into(); + self + } + + /// Set the creation timestamp (default: current time) + pub fn created(mut self, timestamp: u64) -> Self { + self.created = timestamp; + self + } + + /// Set the choices + pub fn choices(mut self, choices: Vec) -> Self { + self.choices = choices; + self + } + + /// Add a single choice (delta) + pub fn add_choice(mut self, choice: ChatStreamChoice) -> Self { + self.choices.push(choice); + self + } + + /// Set usage information (typically sent in final chunk) + pub fn usage(mut self, usage: Usage) -> Self { + self.usage = Some(usage); + self + } + + /// Set system fingerprint if provided (handles Option) + pub fn maybe_system_fingerprint(mut self, fingerprint: Option>) -> Self { + if let Some(fp) = fingerprint { + self.system_fingerprint = Some(fp.into()); + } + self + } + + /// Set usage if provided (handles Option) + pub fn maybe_usage(mut self, usage: Option) -> Self { + if let Some(u) = usage { + self.usage = Some(u); + } + self + } + + /// Add a choice delta that sets `role` and `content` + pub fn add_choice_content( + mut self, + index: u32, + role: impl Into, + content: impl Into, + ) -> Self { + self.choices.push(ChatStreamChoice { + index, + delta: ChatMessageDelta { + role: Some(role.into()), + content: Some(content.into()), + tool_calls: None, + reasoning_content: None, + }, + logprobs: None, + finish_reason: None, + matched_stop: None, + }); + self + } + + /// Add a choice delta that sets `role`, `content`, and `logprobs` + pub fn add_choice_content_with_logprobs( + mut self, + index: u32, + role: impl Into, + content: impl Into, + logprobs: Option, + ) -> Self { + self.choices.push(ChatStreamChoice { + index, + delta: ChatMessageDelta { + role: Some(role.into()), + content: Some(content.into()), + tool_calls: None, + reasoning_content: None, + }, + logprobs, + finish_reason: None, + matched_stop: None, + }); + self + } + + /// Add a choice delta that only sets `role` + pub fn add_choice_role(mut self, index: u32, role: impl Into) -> Self { + self.choices.push(ChatStreamChoice { + index, + delta: ChatMessageDelta { + role: Some(role.into()), + content: None, + tool_calls: None, + reasoning_content: None, + }, + logprobs: None, + finish_reason: None, + matched_stop: None, + }); + self + } + + /// Add a choice delta that appends a tool-call *arguments delta* + /// Uses `Cow` so you can pass `&str` or `String` without extra clones + pub fn add_choice_tool_args( + mut self, + index: u32, + args_delta: impl Into>, + ) -> Self { + self.choices.push(ChatStreamChoice { + index, + delta: ChatMessageDelta { + role: Some("assistant".to_string()), + content: None, + tool_calls: Some(vec![ToolCallDelta { + index: 0, + id: None, + tool_type: None, + function: Some(FunctionCallDelta { + name: None, + arguments: Some(args_delta.into().into_owned()), + }), + }]), + reasoning_content: None, + }, + logprobs: None, + finish_reason: None, + matched_stop: None, + }); + self + } + + /// Add a choice delta that sets reasoning content (for models that stream reasoning) + pub fn add_choice_reasoning(mut self, index: u32, reasoning: impl Into) -> Self { + self.choices.push(ChatStreamChoice { + index, + delta: ChatMessageDelta { + role: Some("assistant".to_string()), + content: None, + tool_calls: None, + reasoning_content: Some(reasoning.into()), + }, + logprobs: None, + finish_reason: None, + matched_stop: None, + }); + self + } + + /// Add a choice delta for tool call with function name and ID + pub fn add_choice_tool_name( + mut self, + index: u32, + tool_call_id: impl Into, + function_name: impl Into, + ) -> Self { + self.choices.push(ChatStreamChoice { + index, + delta: ChatMessageDelta { + role: Some("assistant".to_string()), + content: None, + tool_calls: Some(vec![ToolCallDelta { + index: 0, + id: Some(tool_call_id.into()), + tool_type: Some("function".to_string()), + function: Some(FunctionCallDelta { + name: Some(function_name.into()), + arguments: None, + }), + }]), + reasoning_content: None, + }, + logprobs: None, + finish_reason: None, + matched_stop: None, + }); + self + } + + /// Add a choice delta with a pre-constructed ToolCallDelta + /// Useful when you already have a ToolCallDelta object to emit + pub fn add_choice_tool_call_delta( + mut self, + index: u32, + tool_call_delta: ToolCallDelta, + ) -> Self { + self.choices.push(ChatStreamChoice { + index, + delta: ChatMessageDelta { + role: Some("assistant".to_string()), + content: None, + tool_calls: Some(vec![tool_call_delta]), + reasoning_content: None, + }, + logprobs: None, + finish_reason: None, + matched_stop: None, + }); + self + } + + /// Add a choice with finish_reason (final chunk) + /// This is used for the last chunk in a stream to signal completion + pub fn add_choice_finish_reason( + mut self, + index: u32, + finish_reason: impl Into, + matched_stop: Option, + ) -> Self { + self.choices.push(ChatStreamChoice { + index, + delta: ChatMessageDelta { + role: None, + content: None, + tool_calls: None, + reasoning_content: None, + }, + logprobs: None, + finish_reason: Some(finish_reason.into()), + matched_stop, + }); + self + } + + /// Build the ChatCompletionStreamResponse + pub fn build(self) -> ChatCompletionStreamResponse { + ChatCompletionStreamResponse { + id: self.id, + object: self.object, + created: self.created, + model: self.model, + system_fingerprint: self.system_fingerprint, + choices: self.choices, + usage: self.usage, + } + } +} + +// ============================================================================ +// Tests +// ============================================================================ + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_build_minimal() { + let chunk = ChatCompletionStreamResponseBuilder::new("chatcmpl_123", "gpt-4").build(); + + assert_eq!(chunk.id, "chatcmpl_123"); + assert_eq!(chunk.model, "gpt-4"); + assert_eq!(chunk.object, "chat.completion.chunk"); + assert!(chunk.choices.is_empty()); + assert!(chunk.usage.is_none()); + } + + #[test] + fn test_with_content_delta() { + let chunk = ChatCompletionStreamResponseBuilder::new("chatcmpl_456", "gpt-4") + .add_choice_content(0, "assistant", "Hello") + .build(); + + assert_eq!(chunk.choices.len(), 1); + assert_eq!(chunk.choices[0].index, 0); + assert_eq!(chunk.choices[0].delta.content.as_ref().unwrap(), "Hello"); + assert_eq!(chunk.choices[0].delta.role.as_ref().unwrap(), "assistant"); + assert!(chunk.choices[0].finish_reason.is_none()); + } + + #[test] + fn test_with_role_delta() { + let chunk = ChatCompletionStreamResponseBuilder::new("chatcmpl_789", "gpt-4") + .add_choice_role(0, "assistant") + .build(); + + assert_eq!(chunk.choices.len(), 1); + assert_eq!(chunk.choices[0].delta.role.as_ref().unwrap(), "assistant"); + assert!(chunk.choices[0].delta.content.is_none()); + } + + #[test] + fn test_with_finish_reason() { + let chunk = ChatCompletionStreamResponseBuilder::new("chatcmpl_101", "gpt-4") + .add_choice_finish_reason(0, "stop", None) + .build(); + + assert_eq!(chunk.choices.len(), 1); + assert_eq!(chunk.choices[0].finish_reason.as_ref().unwrap(), "stop"); + assert!(chunk.choices[0].delta.content.is_none()); + assert!(chunk.choices[0].delta.role.is_none()); + } + + #[test] + fn test_multiple_deltas() { + let chunk = ChatCompletionStreamResponseBuilder::new("chatcmpl_202", "gpt-4") + .add_choice_role(0, "assistant") + .add_choice_content(0, "assistant", "Hello") + .add_choice_content(0, "assistant", " world") + .add_choice_finish_reason(0, "stop", None) + .build(); + + assert_eq!(chunk.choices.len(), 4); // role + 2 content + finish + } + + #[test] + fn test_with_usage() { + let usage = Usage { + prompt_tokens: 10, + completion_tokens: 20, + total_tokens: 30, + completion_tokens_details: None, + }; + + let chunk = ChatCompletionStreamResponseBuilder::new("chatcmpl_303", "gpt-4") + .add_choice_finish_reason(0, "stop", None) + .usage(usage) + .build(); + + assert!(chunk.usage.is_some()); + assert_eq!(chunk.usage.as_ref().unwrap().total_tokens, 30); + } + + #[test] + fn test_copy_from_request() { + let request = ChatCompletionRequest { + messages: vec![], + model: "gpt-3.5-turbo".to_string(), + ..Default::default() + }; + + let chunk = ChatCompletionStreamResponseBuilder::new("chatcmpl_404", "gpt-4") + .copy_from_request(&request) + .add_choice_content(0, "assistant", "test") + .build(); + + assert_eq!(chunk.model, "gpt-3.5-turbo"); // Copied from request + } + + #[test] + fn test_add_choice_explicit() { + let choice = ChatStreamChoice { + index: 0, + delta: ChatMessageDelta { + role: Some("assistant".to_string()), + content: Some("Hello".to_string()), + tool_calls: None, + reasoning_content: None, + }, + logprobs: None, + finish_reason: None, + matched_stop: None, + }; + + let chunk = ChatCompletionStreamResponseBuilder::new("chatcmpl_505", "gpt-4") + .add_choice(choice) + .build(); + + assert_eq!(chunk.choices.len(), 1); + assert_eq!(chunk.choices[0].delta.role.as_ref().unwrap(), "assistant"); + assert_eq!(chunk.choices[0].delta.content.as_ref().unwrap(), "Hello"); + } +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/builders/mod.rs b/sgl-model-gateway/vendor/openai-protocol/src/builders/mod.rs new file mode 100644 index 000000000000..9208441245dc --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/builders/mod.rs @@ -0,0 +1,27 @@ +//! Builder patterns for protocol response types +//! +//! This module provides ergonomic builders for response types with many optional fields. +//! Builders help avoid telescoping constructors and make construction intent clear. +//! +//! # Organization +//! +//! Builders are organized by API: +//! - `chat/` - Chat Completion API builders (response, stream_response) +//! - `responses/` - Responses API builder (response) +//! +//! # Optional Fields +//! +//! For optional fields, builders provide `maybe_*` methods that handle `Option` directly: +//! ```ignore +//! builder +//! .field(value) +//! .maybe_optional_field(optional_value) // Accepts Option +//! .build() +//! ``` + +pub mod chat; +pub mod responses; + +// Re-export all builders for convenient access +pub use chat::{ChatCompletionResponseBuilder, ChatCompletionStreamResponseBuilder}; +pub use responses::ResponsesResponseBuilder; diff --git a/sgl-model-gateway/vendor/openai-protocol/src/builders/responses/mod.rs b/sgl-model-gateway/vendor/openai-protocol/src/builders/responses/mod.rs new file mode 100644 index 000000000000..aca9d2492314 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/builders/responses/mod.rs @@ -0,0 +1,5 @@ +//! Builders for Responses API response types + +pub mod response; + +pub use response::ResponsesResponseBuilder; diff --git a/sgl-model-gateway/vendor/openai-protocol/src/builders/responses/response.rs b/sgl-model-gateway/vendor/openai-protocol/src/builders/responses/response.rs new file mode 100644 index 000000000000..7db46c3f4528 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/builders/responses/response.rs @@ -0,0 +1,411 @@ +//! Builder for ResponsesResponse +//! +//! Provides an ergonomic fluent API for constructing ResponsesResponse instances. + +use std::collections::HashMap; + +use serde_json::Value; + +use crate::responses::*; + +/// Builder for ResponsesResponse +/// +/// Provides a fluent interface for constructing responses with sensible defaults. +#[must_use = "Builder does nothing until .build() is called"] +#[derive(Clone, Debug)] +pub struct ResponsesResponseBuilder { + id: String, + object: String, + created_at: i64, + status: ResponseStatus, + error: Option, + incomplete_details: Option, + instructions: Option, + max_output_tokens: Option, + model: String, + output: Vec, + parallel_tool_calls: bool, + previous_response_id: Option, + reasoning: Option, + store: bool, + temperature: Option, + text: Option, + tool_choice: String, + tools: Vec, + top_p: Option, + truncation: Option, + usage: Option, + user: Option, + safety_identifier: Option, + metadata: HashMap, +} + +impl ResponsesResponseBuilder { + /// Create a new builder with required fields + /// + /// # Arguments + /// - `id`: Response ID (e.g., "resp_abc123") + /// - `model`: Model name used for generation + pub fn new(id: impl Into, model: impl Into) -> Self { + Self { + id: id.into(), + object: "response".to_string(), + created_at: chrono::Utc::now().timestamp(), + status: ResponseStatus::InProgress, + error: None, + incomplete_details: None, + instructions: None, + max_output_tokens: None, + model: model.into(), + output: Vec::new(), + parallel_tool_calls: true, + previous_response_id: None, + reasoning: None, + store: true, + temperature: None, + text: None, + tool_choice: "auto".to_string(), + tools: Vec::new(), + top_p: None, + truncation: None, + usage: None, + user: None, + safety_identifier: None, + metadata: HashMap::new(), + } + } + + /// Copy common fields from a ResponsesRequest + /// + /// This populates fields like instructions, max_output_tokens, temperature, etc. + /// from the original request, making it easy to construct a response that mirrors + /// the request parameters. + /// + /// Note: `safety_identifier` is intentionally NOT copied as it is for content moderation + /// and should be set independently from the request's `user` field (which is for billing/tracking). + pub fn copy_from_request(mut self, request: &ResponsesRequest) -> Self { + self.instructions = request.instructions.clone(); + self.max_output_tokens = request.max_output_tokens; + self.parallel_tool_calls = request.parallel_tool_calls.unwrap_or(true); + self.previous_response_id = request.previous_response_id.clone(); + self.store = request.store.unwrap_or(true); + self.temperature = request.temperature; + self.tool_choice = if let Some(ref tc) = request.tool_choice { + serde_json::to_string(tc).unwrap_or_else(|_| "auto".to_string()) + } else { + "auto".to_string() + }; + self.tools = request.tools.clone().unwrap_or_default(); + self.top_p = request.top_p; + self.user = request.user.clone(); + self.metadata = request.metadata.clone().unwrap_or_default(); + self + } + + /// Set the object type (default: "response") + pub fn object(mut self, object: impl Into) -> Self { + self.object = object.into(); + self + } + + /// Set the creation timestamp (default: current time) + pub fn created_at(mut self, timestamp: i64) -> Self { + self.created_at = timestamp; + self + } + + /// Set the response status + pub fn status(mut self, status: ResponseStatus) -> Self { + self.status = status; + self + } + + /// Set error information (if status is failed) + pub fn error(mut self, error: Value) -> Self { + self.error = Some(error); + self + } + + /// Set incomplete details (if response was truncated) + pub fn incomplete_details(mut self, details: Value) -> Self { + self.incomplete_details = Some(details); + self + } + + /// Set system instructions + pub fn instructions(mut self, instructions: impl Into) -> Self { + self.instructions = Some(instructions.into()); + self + } + + /// Set max output tokens + pub fn max_output_tokens(mut self, tokens: u32) -> Self { + self.max_output_tokens = Some(tokens); + self + } + + /// Set output items + pub fn output(mut self, output: Vec) -> Self { + self.output = output; + self + } + + /// Add a single output item + pub fn add_output(mut self, item: ResponseOutputItem) -> Self { + self.output.push(item); + self + } + + /// Set whether parallel tool calls are enabled + pub fn parallel_tool_calls(mut self, enabled: bool) -> Self { + self.parallel_tool_calls = enabled; + self + } + + /// Set previous response ID (if continuation) + pub fn previous_response_id(mut self, id: impl Into) -> Self { + self.previous_response_id = Some(id.into()); + self + } + + /// Set reasoning information + pub fn reasoning(mut self, reasoning: ReasoningInfo) -> Self { + self.reasoning = Some(reasoning); + self + } + + /// Set whether the response is stored + pub fn store(mut self, store: bool) -> Self { + self.store = store; + self + } + + /// Set temperature setting + pub fn temperature(mut self, temperature: f32) -> Self { + self.temperature = Some(temperature); + self + } + + /// Set text format settings if provided (handles Option) + pub fn maybe_text(mut self, text: Option) -> Self { + if let Some(t) = text { + self.text = Some(t); + } + self + } + + /// Set tool choice setting + pub fn tool_choice(mut self, tool_choice: impl Into) -> Self { + self.tool_choice = tool_choice.into(); + self + } + + /// Set available tools + pub fn tools(mut self, tools: Vec) -> Self { + self.tools = tools; + self + } + + /// Set top-p setting + pub fn top_p(mut self, top_p: f32) -> Self { + self.top_p = Some(top_p); + self + } + + /// Set truncation strategy + pub fn truncation(mut self, truncation: impl Into) -> Self { + self.truncation = Some(truncation.into()); + self + } + + /// Set usage information + pub fn usage(mut self, usage: ResponsesUsage) -> Self { + self.usage = Some(usage); + self + } + + /// Set usage if provided (handles Option) + pub fn maybe_usage(mut self, usage: Option) -> Self { + if let Some(u) = usage { + self.usage = Some(u); + } + self + } + + /// Copy from request if provided (handles Option) + pub fn maybe_copy_from_request(mut self, request: Option<&ResponsesRequest>) -> Self { + if let Some(req) = request { + self = self.copy_from_request(req); + } + self + } + + /// Set user identifier + pub fn user(mut self, user: impl Into) -> Self { + self.user = Some(user.into()); + self + } + + /// Set safety identifier + pub fn safety_identifier(mut self, identifier: impl Into) -> Self { + self.safety_identifier = Some(identifier.into()); + self + } + + /// Set metadata + pub fn metadata(mut self, metadata: HashMap) -> Self { + self.metadata = metadata; + self + } + + /// Add a single metadata entry + pub fn add_metadata(mut self, key: impl Into, value: Value) -> Self { + self.metadata.insert(key.into(), value); + self + } + + /// Build the ResponsesResponse + pub fn build(self) -> ResponsesResponse { + ResponsesResponse { + id: self.id, + object: self.object, + created_at: self.created_at, + status: self.status, + error: self.error, + incomplete_details: self.incomplete_details, + instructions: self.instructions, + max_output_tokens: self.max_output_tokens, + model: self.model, + output: self.output, + parallel_tool_calls: self.parallel_tool_calls, + previous_response_id: self.previous_response_id, + reasoning: self.reasoning, + store: self.store, + temperature: self.temperature, + text: self.text, + tool_choice: self.tool_choice, + tools: self.tools, + top_p: self.top_p, + truncation: self.truncation, + usage: self.usage, + user: self.user, + safety_identifier: self.safety_identifier, + metadata: self.metadata, + } + } +} + +// ============================================================================ +// Tests +// ============================================================================ + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_build_minimal() { + let response = ResponsesResponse::builder("resp_123", "gpt-4").build(); + + assert_eq!(response.id, "resp_123"); + assert_eq!(response.model, "gpt-4"); + assert_eq!(response.object, "response"); + assert_eq!(response.status, ResponseStatus::InProgress); + assert!(response.output.is_empty()); + assert!(response.parallel_tool_calls); + assert!(response.store); + } + + #[test] + fn test_build_complete() { + let response = ResponsesResponse::builder("resp_123", "gpt-4") + .status(ResponseStatus::Completed) + .instructions("You are a helpful assistant") + .max_output_tokens(1000) + .temperature(0.7) + .top_p(0.9) + .parallel_tool_calls(false) + .store(false) + .build(); + + assert_eq!(response.status, ResponseStatus::Completed); + assert_eq!( + response.instructions.as_ref().unwrap(), + "You are a helpful assistant" + ); + assert_eq!(response.max_output_tokens, Some(1000)); + assert_eq!(response.temperature, Some(0.7)); + assert_eq!(response.top_p, Some(0.9)); + assert!(!response.parallel_tool_calls); + assert!(!response.store); + } + + #[test] + fn test_copy_from_request() { + let request = ResponsesRequest { + model: "gpt-4".to_string(), + input: ResponseInput::Text("test".to_string()), + instructions: Some("Be helpful".to_string()), + max_output_tokens: Some(500), + temperature: Some(0.8), + top_p: Some(0.95), + parallel_tool_calls: Some(false), + store: Some(false), + user: Some("user_123".to_string()), + metadata: Some(HashMap::from([( + "key".to_string(), + serde_json::json!("value"), + )])), + ..Default::default() + }; + + let response = ResponsesResponse::builder("resp_456", "gpt-4") + .copy_from_request(&request) + .status(ResponseStatus::Completed) + .build(); + + assert_eq!(response.instructions.as_ref().unwrap(), "Be helpful"); + assert_eq!(response.max_output_tokens, Some(500)); + assert_eq!(response.temperature, Some(0.8)); + assert_eq!(response.top_p, Some(0.95)); + assert!(!response.parallel_tool_calls); + assert!(!response.store); + assert_eq!(response.user.as_ref().unwrap(), "user_123"); + assert_eq!( + response.metadata.get("key").unwrap(), + &serde_json::json!("value") + ); + } + + #[test] + fn test_add_output_items() { + let response = ResponsesResponse::builder("resp_789", "gpt-4") + .add_output(ResponseOutputItem::Message { + id: "msg_1".to_string(), + role: "assistant".to_string(), + content: vec![], + status: "completed".to_string(), + }) + .add_output(ResponseOutputItem::Message { + id: "msg_2".to_string(), + role: "assistant".to_string(), + content: vec![], + status: "completed".to_string(), + }) + .build(); + + assert_eq!(response.output.len(), 2); + } + + #[test] + fn test_add_metadata() { + let response = ResponsesResponse::builder("resp_101", "gpt-4") + .add_metadata("key1", serde_json::json!("value1")) + .add_metadata("key2", serde_json::json!(42)) + .build(); + + assert_eq!(response.metadata.len(), 2); + assert_eq!(response.metadata.get("key1").unwrap(), "value1"); + assert_eq!(response.metadata.get("key2").unwrap(), 42); + } +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/chat.rs b/sgl-model-gateway/vendor/openai-protocol/src/chat.rs new file mode 100644 index 000000000000..f5d831041f99 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/chat.rs @@ -0,0 +1,807 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use validator::Validate; + +use super::{ + common::{ + default_model, default_true, validate_stop, ChatLogProbs, ContentPart, Function, + FunctionCall, FunctionChoice, GenerationRequest, ResponseFormat, StreamOptions, + StringOrArray, Tool, ToolCall, ToolCallDelta, ToolChoice, ToolChoiceValue, ToolReference, + Usage, + }, + sampling_params::{validate_top_k_value, validate_top_p_value}, +}; +use crate::{ + builders::{ChatCompletionResponseBuilder, ChatCompletionStreamResponseBuilder}, + validated::Normalizable, +}; + +// ============================================================================ +// Chat Messages +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(tag = "role")] +pub enum ChatMessage { + #[serde(rename = "system")] + System { + content: MessageContent, + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + }, + #[serde(rename = "user")] + User { + content: MessageContent, + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + }, + #[serde(rename = "assistant")] + Assistant { + #[serde(skip_serializing_if = "Option::is_none")] + content: Option, + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + tool_calls: Option>, + /// Reasoning content for O1-style models (SGLang extension) + #[serde(skip_serializing_if = "Option::is_none")] + reasoning_content: Option, + }, + #[serde(rename = "tool")] + Tool { + content: MessageContent, + tool_call_id: String, + }, + #[serde(rename = "function")] + Function { content: String, name: String }, + #[serde(rename = "developer")] + Developer { + content: MessageContent, + #[serde(skip_serializing_if = "Option::is_none")] + tools: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + }, +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[serde(untagged)] +pub enum MessageContent { + Text(String), + Parts(Vec), +} + +impl MessageContent { + /// Returns the text content, cloning only when necessary. + /// For simple text, returns a clone of the string. + /// For parts, concatenates text parts with spaces. + /// Optimized to avoid intermediate Vec allocation. + pub fn to_simple_string(&self) -> String { + match self { + MessageContent::Text(text) => text.clone(), + MessageContent::Parts(parts) => { + // Use fold to build string directly without intermediate Vec allocation + let mut result = String::new(); + let mut first = true; + for part in parts { + if let ContentPart::Text { text } = part { + if !first { + result.push(' '); + } + result.push_str(text); + first = false; + } + } + result + } + } + } + + /// Appends text content directly to a buffer, avoiding intermediate allocations. + /// Returns true if any content was appended. + #[inline] + pub fn append_text_to(&self, buffer: &mut String) -> bool { + match self { + MessageContent::Text(text) => { + if !text.is_empty() { + buffer.push_str(text); + true + } else { + false + } + } + MessageContent::Parts(parts) => { + let mut appended = false; + for part in parts { + if let ContentPart::Text { text } = part { + if !text.is_empty() { + if appended { + buffer.push(' '); + } + buffer.push_str(text); + appended = true; + } + } + } + appended + } + } + } + + /// Returns true if this content contains any non-empty text. + #[inline] + pub fn has_text(&self) -> bool { + match self { + MessageContent::Text(text) => !text.is_empty(), + MessageContent::Parts(parts) => parts + .iter() + .any(|part| matches!(part, ContentPart::Text { text } if !text.is_empty())), + } + } +} + +// ============================================================================ +// Chat Completion Request +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize, Default, Validate)] +#[validate(schema(function = "validate_chat_cross_parameters"))] +pub struct ChatCompletionRequest { + /// Pretokenized input supplied by a session client; bypasses chat templating. + #[serde(skip_serializing_if = "Option::is_none")] + pub input_ids: Option>, + + /// Request native chosen-token and candidate metadata from the backend. + #[serde(skip_serializing_if = "Option::is_none")] + pub return_meta_info: Option, + + /// A list of messages comprising the conversation so far + #[validate(custom(function = "validate_messages"))] + pub messages: Vec, + + /// ID of the model to use + #[serde(default = "default_model")] + pub model: String, + + /// Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = -2.0, max = 2.0))] + pub frequency_penalty: Option, + + /// Deprecated: Replaced by tool_choice + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use tool_choice instead")] + pub function_call: Option, + + /// Deprecated: Replaced by tools + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use tools instead")] + pub functions: Option>, + + /// Modify the likelihood of specified tokens appearing in the completion + #[serde(skip_serializing_if = "Option::is_none")] + pub logit_bias: Option>, + + /// Whether to return log probabilities of the output tokens + #[serde(default)] + pub logprobs: bool, + + /// Deprecated: Replaced by max_completion_tokens + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use max_completion_tokens instead")] + #[validate(range(min = 1))] + pub max_tokens: Option, + + /// An upper bound for the number of tokens that can be generated for a completion + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 1))] + pub max_completion_tokens: Option, + + /// Developer-defined tags and values used for filtering completions in the dashboard + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata: Option>, + + /// Output types that you would like the model to generate for this request + #[serde(skip_serializing_if = "Option::is_none")] + pub modalities: Option>, + + /// How many chat completion choices to generate for each input message + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 1, max = 10))] + pub n: Option, + + /// Whether to enable parallel function calling during tool use + #[serde(skip_serializing_if = "Option::is_none")] + pub parallel_tool_calls: Option, + + /// Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = -2.0, max = 2.0))] + pub presence_penalty: Option, + + /// Cache key for prompts (beta feature) + #[serde(skip_serializing_if = "Option::is_none")] + pub prompt_cache_key: Option, + + /// Effort level for reasoning models (low, medium, high) + #[serde(skip_serializing_if = "Option::is_none")] + pub reasoning_effort: Option, + + /// An object specifying the format that the model must output + #[serde(skip_serializing_if = "Option::is_none")] + pub response_format: Option, + + /// Safety identifier for content moderation + #[serde(skip_serializing_if = "Option::is_none")] + pub safety_identifier: Option, + + /// Deprecated: This feature is in Legacy mode + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "This feature is in Legacy mode")] + pub seed: Option, + + /// The service tier to use for this request + #[serde(skip_serializing_if = "Option::is_none")] + pub service_tier: Option, + + /// Up to 4 sequences where the API will stop generating further tokens + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(custom(function = "validate_stop"))] + pub stop: Option, + + /// If set, partial message deltas will be sent + #[serde(default)] + pub stream: bool, + + /// Options for streaming response + #[serde(skip_serializing_if = "Option::is_none")] + pub stream_options: Option, + + /// What sampling temperature to use, between 0 and 2 + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 0.0, max = 2.0))] + pub temperature: Option, + + /// Controls which (if any) tool is called by the model + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_choice: Option, + + /// A list of tools the model may call + #[serde(skip_serializing_if = "Option::is_none")] + pub tools: Option>, + + /// An integer between 0 and 128 specifying the number of most likely tokens to return + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 0, max = 128))] + pub top_logprobs: Option, + + /// An alternative to sampling with temperature + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(custom(function = "validate_top_p_value"))] + pub top_p: Option, + + /// Verbosity level for debugging + #[serde(skip_serializing_if = "Option::is_none")] + pub verbosity: Option, + + // ============================================================================= + // Engine-Specific Sampling Parameters + // ============================================================================= + // These parameters are extensions beyond the OpenAI API specification and + // control model generation behavior in engine-specific ways. + // ============================================================================= + /// Top-k sampling parameter (-1 to disable) + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(custom(function = "validate_top_k_value"))] + pub top_k: Option, + + /// Min-p nucleus sampling parameter + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 0.0, max = 1.0))] + pub min_p: Option, + + /// Minimum number of tokens to generate + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 1))] + pub min_tokens: Option, + + /// Repetition penalty for reducing repetitive text + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 0.0, max = 2.0))] + pub repetition_penalty: Option, + + /// Regex constraint for output generation + #[serde(skip_serializing_if = "Option::is_none")] + pub regex: Option, + + /// EBNF grammar constraint for structured output + #[serde(skip_serializing_if = "Option::is_none")] + pub ebnf: Option, + + /// Specific token IDs to use as stop conditions + #[serde(skip_serializing_if = "Option::is_none")] + pub stop_token_ids: Option>, + + /// Skip trimming stop tokens from output + #[serde(default)] + pub no_stop_trim: bool, + + /// Ignore end-of-sequence tokens during generation + #[serde(default)] + pub ignore_eos: bool, + + /// Continue generating from final assistant message + #[serde(default)] + pub continue_final_message: bool, + + /// Skip special tokens during detokenization + #[serde(default = "default_true")] + pub skip_special_tokens: bool, + + /// Path to LoRA adapter(s) for model customization + #[serde(skip_serializing_if = "Option::is_none")] + pub lora_path: Option, + + /// Session parameters for continual prompting + #[serde(skip_serializing_if = "Option::is_none")] + pub session_params: Option>, + + /// Separate reasoning content from final answer (O1-style models) + #[serde(default = "default_true")] + pub separate_reasoning: bool, + + /// Stream reasoning tokens during generation + #[serde(default = "default_true")] + pub stream_reasoning: bool, + + /// Chat template kwargs + #[serde(skip_serializing_if = "Option::is_none")] + pub chat_template_kwargs: Option>, + + /// Return model hidden states + #[serde(default)] + pub return_hidden_states: bool, + + /// Random seed for sampling for deterministic outputs + #[serde(skip_serializing_if = "Option::is_none")] + pub sampling_seed: Option, +} + +// ============================================================================ +// Validation Functions +// ============================================================================ + +/// Validates messages array is not empty and has valid content +fn validate_messages(messages: &[ChatMessage]) -> Result<(), validator::ValidationError> { + if messages.is_empty() { + return Err(validator::ValidationError::new("messages cannot be empty")); + } + + for msg in messages.iter() { + if let ChatMessage::User { content, .. } = msg { + match content { + MessageContent::Text(text) if text.is_empty() => { + return Err(validator::ValidationError::new( + "message content cannot be empty", + )); + } + MessageContent::Parts(parts) if parts.is_empty() => { + return Err(validator::ValidationError::new( + "message content parts cannot be empty", + )); + } + _ => {} + } + } + } + Ok(()) +} + +/// Schema-level validation for cross-field dependencies +fn validate_chat_cross_parameters( + req: &ChatCompletionRequest, +) -> Result<(), validator::ValidationError> { + // 1. Validate logprobs dependency + if req.top_logprobs.is_some() && !req.logprobs { + let mut e = validator::ValidationError::new("top_logprobs_requires_logprobs"); + e.message = Some("top_logprobs is only allowed when logprobs is enabled".into()); + return Err(e); + } + + // 2. Validate stream_options dependency + if req.stream_options.is_some() && !req.stream { + let mut e = validator::ValidationError::new("stream_options_requires_stream"); + e.message = + Some("The 'stream_options' parameter is only allowed when 'stream' is enabled".into()); + return Err(e); + } + + // 3. Validate token limits - min <= max + if let (Some(min), Some(max)) = (req.min_tokens, req.max_completion_tokens) { + if min > max { + let mut e = validator::ValidationError::new("min_tokens_exceeds_max"); + e.message = Some("min_tokens cannot exceed max_tokens/max_completion_tokens".into()); + return Err(e); + } + } + + // 4. Validate structured output conflicts + let has_json_format = matches!( + req.response_format, + Some(ResponseFormat::JsonObject | ResponseFormat::JsonSchema { .. }) + ); + + if has_json_format && req.regex.is_some() { + let mut e = validator::ValidationError::new("regex_conflicts_with_json"); + e.message = Some("cannot use regex constraint with JSON response format".into()); + return Err(e); + } + + if has_json_format && req.ebnf.is_some() { + let mut e = validator::ValidationError::new("ebnf_conflicts_with_json"); + e.message = Some("cannot use EBNF constraint with JSON response format".into()); + return Err(e); + } + + // 5. Validate mutually exclusive structured output constraints + let constraint_count = [ + req.regex.is_some(), + req.ebnf.is_some(), + matches!(req.response_format, Some(ResponseFormat::JsonSchema { .. })), + ] + .iter() + .filter(|&&x| x) + .count(); + + if constraint_count > 1 { + let mut e = validator::ValidationError::new("multiple_constraints"); + e.message = Some("only one structured output constraint (regex, ebnf, or json_schema) can be active at a time".into()); + return Err(e); + } + + // 6. Validate response format JSON schema name + if let Some(ResponseFormat::JsonSchema { json_schema }) = &req.response_format { + if json_schema.name.is_empty() { + let mut e = validator::ValidationError::new("json_schema_name_empty"); + e.message = Some("JSON schema name cannot be empty".into()); + return Err(e); + } + } + + // 7. Validate tool_choice requires tools (except for "none") + if let Some(ref tool_choice) = req.tool_choice { + let has_tools = req.tools.as_ref().is_some_and(|t| !t.is_empty()); + + // Check if tool_choice is anything other than "none" + let is_some_choice = !matches!(tool_choice, ToolChoice::Value(ToolChoiceValue::None)); + + if is_some_choice && !has_tools { + let mut e = validator::ValidationError::new("tool_choice_requires_tools"); + e.message = Some("Invalid value for 'tool_choice': 'tool_choice' is only allowed when 'tools' are specified.".into()); + return Err(e); + } + + // Additional validation when tools are present + if has_tools { + let tools = req.tools.as_ref().unwrap(); + + match tool_choice { + ToolChoice::Function { function, .. } => { + // Validate that the specified function name exists in tools + let function_exists = tools.iter().any(|tool| { + tool.tool_type == "function" && tool.function.name == function.name + }); + + if !function_exists { + let mut e = + validator::ValidationError::new("tool_choice_function_not_found"); + e.message = Some( + format!( + "Invalid value for 'tool_choice': function '{}' not found in 'tools'.", + function.name + ) + .into(), + ); + return Err(e); + } + } + ToolChoice::AllowedTools { + mode, + tools: allowed_tools, + .. + } => { + // Validate mode is "auto" or "required" + if mode != "auto" && mode != "required" { + let mut e = validator::ValidationError::new("tool_choice_invalid_mode"); + e.message = Some(format!( + "Invalid value for 'tool_choice.mode': must be 'auto' or 'required', got '{}'.", + mode + ).into()); + return Err(e); + } + + // Validate that all ToolReferences are Function type (Chat API only supports function tools) + for tool_ref in allowed_tools { + match tool_ref { + ToolReference::Function { name } => { + // Validate that the function exists in tools array + let tool_exists = tools.iter().any(|tool| { + tool.tool_type == "function" && tool.function.name == *name + }); + + if !tool_exists { + let mut e = validator::ValidationError::new( + "tool_choice_tool_not_found", + ); + e.message = Some( + format!( + "Invalid value for 'tool_choice.tools': tool '{}' not found in 'tools'.", + name + ) + .into(), + ); + return Err(e); + } + } + _ => { + // Chat Completion API only supports function tools in tool_choice + let mut e = validator::ValidationError::new( + "tool_choice_invalid_tool_type", + ); + e.message = Some( + format!( + "Invalid value for 'tool_choice.tools': Chat Completion API only supports function tools, got '{}'.", + tool_ref.identifier() + ) + .into(), + ); + return Err(e); + } + } + } + } + _ => {} + } + } + } + + Ok(()) +} + +// ============================================================================ +// Normalizable Implementation +// ============================================================================ + +impl Normalizable for ChatCompletionRequest { + /// Normalize the request by applying migrations and defaults: + /// 1. Migrate deprecated fields to their replacements + /// 2. Clear deprecated fields and log warnings + /// 3. Apply OpenAI defaults for tool_choice + fn normalize(&mut self) { + // Migrate deprecated max_tokens → max_completion_tokens + #[allow(deprecated)] + if self.max_completion_tokens.is_none() && self.max_tokens.is_some() { + self.max_completion_tokens = self.max_tokens; + self.max_tokens = None; // Clear deprecated field + } + + // Migrate deprecated functions → tools + #[allow(deprecated)] + if self.tools.is_none() && self.functions.is_some() { + tracing::warn!("functions is deprecated, use tools instead"); + self.tools = self.functions.as_ref().map(|functions| { + functions + .iter() + .map(|func| Tool { + tool_type: "function".to_string(), + function: func.clone(), + }) + .collect() + }); + self.functions = None; // Clear deprecated field + } + + // Migrate deprecated function_call → tool_choice + #[allow(deprecated)] + if self.tool_choice.is_none() && self.function_call.is_some() { + tracing::warn!("function_call is deprecated, use tool_choice instead"); + self.tool_choice = self.function_call.as_ref().map(|fc| match fc { + FunctionCall::None => ToolChoice::Value(ToolChoiceValue::None), + FunctionCall::Auto => ToolChoice::Value(ToolChoiceValue::Auto), + FunctionCall::Function { name } => ToolChoice::Function { + tool_type: "function".to_string(), + function: FunctionChoice { name: name.clone() }, + }, + }); + self.function_call = None; // Clear deprecated field + } + + // Apply tool_choice defaults + if self.tool_choice.is_none() { + if let Some(tools) = &self.tools { + let choice_value = if !tools.is_empty() { + ToolChoiceValue::Auto + } else { + ToolChoiceValue::None + }; + self.tool_choice = Some(ToolChoice::Value(choice_value)); + } + // If tools is None, leave tool_choice as None (don't set it) + } + } +} + +// ============================================================================ +// GenerationRequest Trait Implementation +// ============================================================================ + +impl GenerationRequest for ChatCompletionRequest { + fn is_stream(&self) -> bool { + self.stream + } + + fn get_model(&self) -> Option<&str> { + Some(&self.model) + } + + fn extract_text_for_routing(&self) -> String { + // Extract text from messages for routing decisions + // Use a single buffer to avoid intermediate Vec allocations + let mut buffer = String::new(); + let mut has_content = false; + + for msg in &self.messages { + match msg { + ChatMessage::System { content, .. } + | ChatMessage::User { content, .. } + | ChatMessage::Tool { content, .. } + | ChatMessage::Developer { content, .. } => { + if has_content && content.has_text() { + buffer.push(' '); + } + if content.append_text_to(&mut buffer) { + has_content = true; + } + } + ChatMessage::Assistant { + content, + reasoning_content, + .. + } => { + // Append main content + if let Some(c) = content { + if has_content && c.has_text() { + buffer.push(' '); + } + if c.append_text_to(&mut buffer) { + has_content = true; + } + } + // Append reasoning content + if let Some(reasoning) = reasoning_content { + if !reasoning.is_empty() { + if has_content { + buffer.push(' '); + } + buffer.push_str(reasoning); + has_content = true; + } + } + } + ChatMessage::Function { content, .. } => { + if !content.is_empty() { + if has_content { + buffer.push(' '); + } + buffer.push_str(content); + has_content = true; + } + } + } + } + + buffer + } +} + +// ============================================================================ +// Response Types +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ChatCompletionResponse { + pub id: String, + pub object: String, // "chat.completion" + pub created: u64, + pub model: String, + pub choices: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub usage: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub system_fingerprint: Option, +} + +impl ChatCompletionResponse { + /// Create a new builder for ChatCompletionResponse + pub fn builder( + id: impl Into, + model: impl Into, + ) -> ChatCompletionResponseBuilder { + ChatCompletionResponseBuilder::new(id, model) + } +} + +/// Response message structure for ChatCompletionResponse (different from request ChatMessage) +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ChatCompletionMessage { + pub role: String, // Always "assistant" for responses + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_calls: Option>, + pub reasoning_content: Option, + // Note: function_call is deprecated and not included + // Note: refusal, annotations, audio are not added yet +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ChatChoice { + pub index: u32, + pub message: ChatCompletionMessage, + #[serde(skip_serializing_if = "Option::is_none")] + pub logprobs: Option, + pub finish_reason: Option, // "stop", "length", "tool_calls", "content_filter", "function_call" + /// Information about which stop condition was matched + #[serde(skip_serializing_if = "Option::is_none")] + pub matched_stop: Option, // Can be string or integer + /// Hidden states from the model (SGLang extension) + #[serde(skip_serializing_if = "Option::is_none")] + pub hidden_states: Option>, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ChatCompletionStreamResponse { + pub id: String, + pub object: String, // "chat.completion.chunk" + pub created: u64, + pub model: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub system_fingerprint: Option, + pub choices: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub usage: Option, +} + +impl ChatCompletionStreamResponse { + /// Create a new builder for ChatCompletionStreamResponse + pub fn builder( + id: impl Into, + model: impl Into, + ) -> ChatCompletionStreamResponseBuilder { + ChatCompletionStreamResponseBuilder::new(id, model) + } +} + +/// Delta structure for streaming chat completion responses +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ChatMessageDelta { + #[serde(skip_serializing_if = "Option::is_none")] + pub role: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_calls: Option>, + pub reasoning_content: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ChatStreamChoice { + pub index: u32, + pub delta: ChatMessageDelta, + pub logprobs: Option, + pub finish_reason: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub matched_stop: Option, +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/classify.rs b/sgl-model-gateway/vendor/openai-protocol/src/classify.rs new file mode 100644 index 000000000000..492bf88b109c --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/classify.rs @@ -0,0 +1,121 @@ +//! Classify API protocol definitions. +//! +//! This module defines the request and response types for the `/v1/classify` API, +//! which is compatible with vLLM's classification endpoint. +//! +//! Classification reuses the embedding backend - the scheduler returns logits as +//! "embeddings", and the classify layer applies softmax + label mapping. + +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +use super::common::{GenerationRequest, UsageInfo}; + +// ============================================================================ +// Classify API +// ============================================================================ + +/// Classification request - compatible with vLLM's /v1/classify API +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ClassifyRequest { + /// ID of the model to use + pub model: String, + + /// Input can be a string, array of strings, or token IDs + /// - Single string: "text to classify" + /// - Array of strings: ["text1", "text2"] + /// - Token IDs: [1, 2, 3] (advanced usage) + pub input: Value, + + /// Optional user identifier + #[serde(skip_serializing_if = "Option::is_none")] + pub user: Option, + + /// SGLang extension: request id for tracking + #[serde(skip_serializing_if = "Option::is_none")] + pub rid: Option, + + /// SGLang extension: request priority + #[serde(skip_serializing_if = "Option::is_none")] + pub priority: Option, + + /// SGLang extension: enable/disable logging of metrics + #[serde(skip_serializing_if = "Option::is_none")] + pub log_metrics: Option, +} + +impl GenerationRequest for ClassifyRequest { + fn is_stream(&self) -> bool { + false // Classification is always non-streaming + } + + fn get_model(&self) -> Option<&str> { + Some(&self.model) + } + + fn extract_text_for_routing(&self) -> String { + match &self.input { + Value::String(s) => s.clone(), + Value::Array(arr) => arr + .iter() + .filter_map(|v| v.as_str()) + .collect::>() + .join(" "), + _ => String::new(), + } + } +} + +// ============================================================================ +// Classify Response +// ============================================================================ + +/// Single classification result +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ClassifyData { + /// Index of this result (for batch requests) + pub index: u32, + /// Predicted class label (from id2label mapping) + pub label: String, + /// Probability distribution over all classes (softmax of logits) + pub probs: Vec, + /// Number of classes + pub num_classes: u32, +} + +/// Classification response +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ClassifyResponse { + /// Unique request ID (format: "classify-{uuid}") + pub id: String, + /// Always "list" + pub object: String, + /// Unix timestamp (seconds since epoch) + pub created: u64, + /// Model name + pub model: String, + /// Classification results (one per input in batch) + pub data: Vec, + /// Token usage info + pub usage: UsageInfo, +} + +impl ClassifyResponse { + /// Create a new ClassifyResponse with the given data + pub fn new( + id: String, + model: String, + created: u64, + data: Vec, + usage: UsageInfo, + ) -> Self { + Self { + id, + object: "list".to_string(), + created, + model, + data, + usage, + } + } +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/common.rs b/sgl-model-gateway/vendor/openai-protocol/src/common.rs new file mode 100644 index 000000000000..83e2d238afb7 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/common.rs @@ -0,0 +1,524 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use validator; + +use super::UNKNOWN_MODEL_ID; + +// ============================================================================ +// Default value helpers +// ============================================================================ + +/// Default model value when not specified +pub(crate) fn default_model() -> String { + UNKNOWN_MODEL_ID.to_string() +} + +/// Helper function for serde default value (returns true) +pub fn default_true() -> bool { + true +} + +// ============================================================================ +// GenerationRequest Trait +// ============================================================================ + +/// Trait for unified access to generation request properties +/// Implemented by ChatCompletionRequest, CompletionRequest, GenerateRequest, +/// EmbeddingRequest, RerankRequest, and ResponsesRequest +pub trait GenerationRequest: Send + Sync { + /// Check if the request is for streaming + fn is_stream(&self) -> bool; + + /// Get the model name if specified + fn get_model(&self) -> Option<&str>; + + /// Extract text content for routing decisions + fn extract_text_for_routing(&self) -> String; +} + +// ============================================================================ +// String/Array Utilities +// ============================================================================ + +/// A type that can be either a single string or an array of strings +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[serde(untagged)] +pub enum StringOrArray { + String(String), + Array(Vec), +} + +impl StringOrArray { + /// Get the number of items in the StringOrArray + pub fn len(&self) -> usize { + match self { + StringOrArray::String(_) => 1, + StringOrArray::Array(arr) => arr.len(), + } + } + + /// Check if the StringOrArray is empty + pub fn is_empty(&self) -> bool { + match self { + StringOrArray::String(s) => s.is_empty(), + StringOrArray::Array(arr) => arr.is_empty(), + } + } + + /// Convert to a vector of strings (clones the data) + pub fn to_vec(&self) -> Vec { + match self { + StringOrArray::String(s) => vec![s.clone()], + StringOrArray::Array(arr) => arr.clone(), + } + } + + /// Returns an iterator over string references without cloning. + /// Use this instead of `to_vec()` when you only need to iterate. + pub fn iter(&self) -> StringOrArrayIter<'_> { + StringOrArrayIter { + inner: self, + index: 0, + } + } + + /// Returns the first string, or None if empty + pub fn first(&self) -> Option<&str> { + match self { + StringOrArray::String(s) => { + if s.is_empty() { + None + } else { + Some(s) + } + } + StringOrArray::Array(arr) => arr.first().map(|s| s.as_str()), + } + } +} + +/// Iterator over StringOrArray that yields string references without cloning +pub struct StringOrArrayIter<'a> { + inner: &'a StringOrArray, + index: usize, +} + +impl<'a> Iterator for StringOrArrayIter<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option { + match self.inner { + StringOrArray::String(s) => { + if self.index == 0 { + self.index = 1; + Some(s.as_str()) + } else { + None + } + } + StringOrArray::Array(arr) => { + if self.index < arr.len() { + let item = &arr[self.index]; + self.index += 1; + Some(item.as_str()) + } else { + None + } + } + } + } + + fn size_hint(&self) -> (usize, Option) { + let remaining = match self.inner { + StringOrArray::String(_) => 1 - self.index, + StringOrArray::Array(arr) => arr.len() - self.index, + }; + (remaining, Some(remaining)) + } +} + +impl<'a> ExactSizeIterator for StringOrArrayIter<'a> {} + +/// Validates stop sequences (max 4, non-empty strings) +/// Used by both ChatCompletionRequest and ResponsesRequest +pub fn validate_stop(stop: &StringOrArray) -> Result<(), validator::ValidationError> { + match stop { + StringOrArray::String(s) => { + if s.is_empty() { + return Err(validator::ValidationError::new( + "stop sequences cannot be empty", + )); + } + } + StringOrArray::Array(arr) => { + if arr.len() > 4 { + return Err(validator::ValidationError::new( + "maximum 4 stop sequences allowed", + )); + } + for s in arr { + if s.is_empty() { + return Err(validator::ValidationError::new( + "stop sequences cannot be empty", + )); + } + } + } + } + Ok(()) +} + +// ============================================================================ +// Content Parts (for multimodal messages) +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[serde(tag = "type")] +pub enum ContentPart { + #[serde(rename = "text")] + Text { text: String }, + #[serde(rename = "image_url")] + ImageUrl { image_url: ImageUrl }, + #[serde(rename = "video_url")] + VideoUrl { video_url: VideoUrl }, +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +pub struct ImageUrl { + pub url: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, // "auto", "low", or "high" +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +pub struct VideoUrl { + pub url: String, +} + +// ============================================================================ +// Response Format (for structured outputs) +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(tag = "type")] +pub enum ResponseFormat { + #[serde(rename = "text")] + Text, + #[serde(rename = "json_object")] + JsonObject, + #[serde(rename = "json_schema")] + JsonSchema { json_schema: JsonSchemaFormat }, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct JsonSchemaFormat { + pub name: String, + pub schema: Value, + #[serde(skip_serializing_if = "Option::is_none")] + pub strict: Option, +} + +// ============================================================================ +// Streaming +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct StreamOptions { + #[serde(skip_serializing_if = "Option::is_none")] + pub include_usage: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ToolCallDelta { + pub index: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "type")] + pub tool_type: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub function: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct FunctionCallDelta { + #[serde(skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub arguments: Option, +} + +// ============================================================================ +// Tools and Function Calling +// ============================================================================ + +/// Tool choice value for simple string options +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum ToolChoiceValue { + Auto, + Required, + None, +} + +/// Tool choice for both Chat Completion and Responses APIs +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ToolChoice { + Value(ToolChoiceValue), + Function { + #[serde(rename = "type")] + tool_type: String, // "function" + function: FunctionChoice, + }, + AllowedTools { + #[serde(rename = "type")] + tool_type: String, // "allowed_tools" + mode: String, // "auto" | "required" TODO: need validation + tools: Vec, + }, +} + +impl Default for ToolChoice { + fn default() -> Self { + Self::Value(ToolChoiceValue::Auto) + } +} + +impl ToolChoice { + /// Serialize tool_choice to string for ResponsesResponse + /// + /// Returns the JSON-serialized tool_choice or "auto" as default + pub fn serialize_to_string(tool_choice: &Option) -> String { + tool_choice + .as_ref() + .map(|tc| serde_json::to_string(tc).unwrap_or_else(|_| "auto".to_string())) + .unwrap_or_else(|| "auto".to_string()) + } +} + +/// Function choice specification for ToolChoice::Function +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct FunctionChoice { + pub name: String, +} + +/// Tool reference for ToolChoice::AllowedTools +/// +/// Represents a reference to a specific tool in the allowed_tools array. +/// Different tool types have different required fields. +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(tag = "type")] +#[serde(rename_all = "snake_case")] +pub enum ToolReference { + /// Reference to a function tool + #[serde(rename = "function")] + Function { name: String }, + + /// Reference to an MCP tool + #[serde(rename = "mcp")] + Mcp { + server_label: String, + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + }, + + /// File search hosted tool + #[serde(rename = "file_search")] + FileSearch, + + /// Web search preview hosted tool + #[serde(rename = "web_search_preview")] + WebSearchPreview, + + /// Computer use preview hosted tool + #[serde(rename = "computer_use_preview")] + ComputerUsePreview, + + /// Code interpreter hosted tool + #[serde(rename = "code_interpreter")] + CodeInterpreter, + + /// Image generation hosted tool + #[serde(rename = "image_generation")] + ImageGeneration, +} + +impl ToolReference { + /// Get a unique identifier for this tool reference + pub fn identifier(&self) -> String { + match self { + ToolReference::Function { name } => format!("function:{}", name), + ToolReference::Mcp { server_label, name } => { + if let Some(n) = name { + format!("mcp:{}:{}", server_label, n) + } else { + format!("mcp:{}", server_label) + } + } + ToolReference::FileSearch => "file_search".to_string(), + ToolReference::WebSearchPreview => "web_search_preview".to_string(), + ToolReference::ComputerUsePreview => "computer_use_preview".to_string(), + ToolReference::CodeInterpreter => "code_interpreter".to_string(), + ToolReference::ImageGeneration => "image_generation".to_string(), + } + } + + /// Get the tool name if this is a function tool + pub fn function_name(&self) -> Option<&str> { + match self { + ToolReference::Function { name } => Some(name.as_str()), + _ => None, + } + } +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Tool { + #[serde(rename = "type")] + pub tool_type: String, // "function" + pub function: Function, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Function { + pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + pub parameters: Value, // JSON Schema + /// Whether to enable strict schema adherence (OpenAI structured outputs) + #[serde(skip_serializing_if = "Option::is_none")] + pub strict: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ToolCall { + pub id: String, + #[serde(rename = "type")] + pub tool_type: String, // "function" + pub function: FunctionCallResponse, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum FunctionCall { + None, + Auto, + Function { name: String }, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct FunctionCallResponse { + pub name: String, + #[serde(default)] + pub arguments: Option, // JSON string +} + +// ============================================================================ +// Usage and Logging +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Usage { + pub prompt_tokens: u32, + pub completion_tokens: u32, + pub total_tokens: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_tokens_details: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CompletionTokensDetails { + pub reasoning_tokens: Option, +} + +/// Usage information (used by rerank and other endpoints) +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct UsageInfo { + pub prompt_tokens: u32, + pub completion_tokens: u32, + pub total_tokens: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub reasoning_tokens: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub prompt_tokens_details: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct PromptTokenUsageInfo { + pub cached_tokens: u32, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct LogProbs { + pub tokens: Vec, + pub token_logprobs: Vec>, + pub top_logprobs: Vec>>, + pub text_offset: Vec, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ChatLogProbs { + Detailed { + #[serde(skip_serializing_if = "Option::is_none")] + content: Option>, + }, + Raw(Value), +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ChatLogProbsContent { + pub token: String, + pub logprob: f32, + pub bytes: Option>, + pub top_logprobs: Vec, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct TopLogProb { + pub token: String, + pub logprob: f32, + pub bytes: Option>, +} + +// ============================================================================ +// Error Types +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ErrorResponse { + pub error: ErrorDetail, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ErrorDetail { + pub message: String, + #[serde(rename = "type")] + pub error_type: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub param: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub code: Option, +} + +// ============================================================================ +// Input Types +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum InputIds { + Single(Vec), + Batch(Vec>), +} + +/// LoRA adapter path - can be single path or batch of paths (SGLang extension) +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum LoRAPath { + Single(Option), + Batch(Vec>), +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/completion.rs b/sgl-model-gateway/vendor/openai-protocol/src/completion.rs new file mode 100644 index 000000000000..c6a4f638aeb4 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/completion.rs @@ -0,0 +1,214 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use serde_json::{Map, Value}; + +use super::common::*; + +// ============================================================================ +// Completions API (v1/completions) - DEPRECATED but still supported +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CompletionRequest { + /// ID of the model to use (required for OpenAI, optional for some implementations, such as SGLang) + pub model: String, + + /// The prompt(s) to generate completions for + pub prompt: StringOrArray, + + /// The suffix that comes after a completion of inserted text + #[serde(skip_serializing_if = "Option::is_none")] + pub suffix: Option, + + /// The maximum number of tokens to generate + #[serde(skip_serializing_if = "Option::is_none")] + pub max_tokens: Option, + + /// What sampling temperature to use, between 0 and 2 + #[serde(skip_serializing_if = "Option::is_none")] + pub temperature: Option, + + /// An alternative to sampling with temperature (nucleus sampling) + #[serde(skip_serializing_if = "Option::is_none")] + pub top_p: Option, + + /// How many completions to generate for each prompt + #[serde(skip_serializing_if = "Option::is_none")] + pub n: Option, + + /// Whether to stream back partial progress + #[serde(default)] + pub stream: bool, + + /// Options for streaming response + #[serde(skip_serializing_if = "Option::is_none")] + pub stream_options: Option, + + /// Include the log probabilities on the logprobs most likely tokens + #[serde(skip_serializing_if = "Option::is_none")] + pub logprobs: Option, + + /// Echo back the prompt in addition to the completion + #[serde(default)] + pub echo: bool, + + /// Up to 4 sequences where the API will stop generating further tokens + #[serde(skip_serializing_if = "Option::is_none")] + pub stop: Option, + + /// Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far + #[serde(skip_serializing_if = "Option::is_none")] + pub presence_penalty: Option, + + /// Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far + #[serde(skip_serializing_if = "Option::is_none")] + pub frequency_penalty: Option, + + /// Generates best_of completions server-side and returns the "best" + #[serde(skip_serializing_if = "Option::is_none")] + pub best_of: Option, + + /// Modify the likelihood of specified tokens appearing in the completion + #[serde(skip_serializing_if = "Option::is_none")] + pub logit_bias: Option>, + + /// A unique identifier representing your end-user + #[serde(skip_serializing_if = "Option::is_none")] + pub user: Option, + + /// If specified, our system will make a best effort to sample deterministically + #[serde(skip_serializing_if = "Option::is_none")] + pub seed: Option, + + // -------- Engine Specific Sampling Parameters -------- + /// Top-k sampling parameter (-1 to disable) + #[serde(skip_serializing_if = "Option::is_none")] + pub top_k: Option, + + /// Min-p nucleus sampling parameter + #[serde(skip_serializing_if = "Option::is_none")] + pub min_p: Option, + + /// Minimum number of tokens to generate + #[serde(skip_serializing_if = "Option::is_none")] + pub min_tokens: Option, + + /// Repetition penalty for reducing repetitive text + #[serde(skip_serializing_if = "Option::is_none")] + pub repetition_penalty: Option, + + /// Regex constraint for output generation + #[serde(skip_serializing_if = "Option::is_none")] + pub regex: Option, + + /// EBNF grammar constraint for structured output + #[serde(skip_serializing_if = "Option::is_none")] + pub ebnf: Option, + + /// JSON schema constraint for structured output + #[serde(skip_serializing_if = "Option::is_none")] + pub json_schema: Option, + + /// Specific token IDs to use as stop conditions + #[serde(skip_serializing_if = "Option::is_none")] + pub stop_token_ids: Option>, + + /// Skip trimming stop tokens from output + #[serde(default)] + pub no_stop_trim: bool, + + /// Ignore end-of-sequence tokens during generation + #[serde(default)] + pub ignore_eos: bool, + + /// Skip special tokens during detokenization + #[serde(default = "default_true")] + pub skip_special_tokens: bool, + + /// Path to LoRA adapter(s) for model customization + #[serde(skip_serializing_if = "Option::is_none")] + pub lora_path: Option, + + /// Session parameters for continual prompting + #[serde(skip_serializing_if = "Option::is_none")] + pub session_params: Option>, + + /// Return model hidden states + #[serde(default)] + pub return_hidden_states: bool, + + /// Sampling seed for deterministic outputs + #[serde(skip_serializing_if = "Option::is_none")] + pub sampling_seed: Option, + + /// Additional fields including bootstrap info for PD routing + #[serde(flatten)] + pub other: Map, +} + +impl GenerationRequest for CompletionRequest { + fn is_stream(&self) -> bool { + self.stream + } + + fn get_model(&self) -> Option<&str> { + Some(&self.model) + } + + fn extract_text_for_routing(&self) -> String { + match &self.prompt { + StringOrArray::String(s) => s.clone(), + StringOrArray::Array(v) => v.join(" "), + } + } +} + +// ============================================================================ +// Response Types +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CompletionResponse { + pub id: String, + pub object: String, // "text_completion" + pub created: u64, + pub model: String, + pub choices: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub usage: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub system_fingerprint: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CompletionChoice { + pub text: String, + pub index: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub logprobs: Option, + pub finish_reason: Option, // "stop", "length", "content_filter", etc. + /// Information about which stop condition was matched + #[serde(skip_serializing_if = "Option::is_none")] + pub matched_stop: Option, // Can be string or integer +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CompletionStreamResponse { + pub id: String, + pub object: String, // "text_completion" + pub created: u64, + pub choices: Vec, + pub model: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub system_fingerprint: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct CompletionStreamChoice { + pub text: String, + pub index: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub logprobs: Option, + pub finish_reason: Option, +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/embedding.rs b/sgl-model-gateway/vendor/openai-protocol/src/embedding.rs new file mode 100644 index 000000000000..12e3daf19cde --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/embedding.rs @@ -0,0 +1,76 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +use super::common::{GenerationRequest, UsageInfo}; + +// ============================================================================ +// Embedding API +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct EmbeddingRequest { + /// ID of the model to use + pub model: String, + + /// Input can be a string, array of strings, tokens, or batch inputs + pub input: Value, + + /// Optional encoding format (e.g., "float", "base64") + #[serde(skip_serializing_if = "Option::is_none")] + pub encoding_format: Option, + + /// Optional user identifier + #[serde(skip_serializing_if = "Option::is_none")] + pub user: Option, + + /// Optional number of dimensions for the embedding + #[serde(skip_serializing_if = "Option::is_none")] + pub dimensions: Option, + + /// SGLang extension: request id for tracking + #[serde(skip_serializing_if = "Option::is_none")] + pub rid: Option, + + /// SGLang extension: enable/disable logging of metrics for this request + #[serde(skip_serializing_if = "Option::is_none")] + pub log_metrics: Option, +} + +impl GenerationRequest for EmbeddingRequest { + fn is_stream(&self) -> bool { + // Embeddings are non-streaming + false + } + + fn get_model(&self) -> Option<&str> { + Some(&self.model) + } + + fn extract_text_for_routing(&self) -> String { + // Best effort: extract text content for routing decisions + match &self.input { + Value::String(s) => s.clone(), + Value::Array(arr) => arr + .iter() + .filter_map(|v| v.as_str()) + .collect::>() + .join(" "), + _ => String::new(), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EmbeddingObject { + pub object: String, // "embedding" + pub embedding: Vec, + pub index: u32, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EmbeddingResponse { + pub object: String, // "list" + pub data: Vec, + pub model: String, + pub usage: UsageInfo, +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/event_types.rs b/sgl-model-gateway/vendor/openai-protocol/src/event_types.rs new file mode 100644 index 000000000000..c36dc5d4512f --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/event_types.rs @@ -0,0 +1,228 @@ +use std::fmt; + +/// Response lifecycle events +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ResponseEvent { + Created, + InProgress, + Completed, +} + +impl ResponseEvent { + pub const CREATED: &'static str = "response.created"; + pub const IN_PROGRESS: &'static str = "response.in_progress"; + pub const COMPLETED: &'static str = "response.completed"; + + pub const fn as_str(&self) -> &'static str { + match self { + Self::Created => Self::CREATED, + Self::InProgress => Self::IN_PROGRESS, + Self::Completed => Self::COMPLETED, + } + } +} + +impl fmt::Display for ResponseEvent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +/// Output item events for streaming +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum OutputItemEvent { + Added, + Done, + Delta, +} + +impl OutputItemEvent { + pub const ADDED: &'static str = "response.output_item.added"; + pub const DONE: &'static str = "response.output_item.done"; + pub const DELTA: &'static str = "response.output_item.delta"; + + pub const fn as_str(&self) -> &'static str { + match self { + Self::Added => Self::ADDED, + Self::Done => Self::DONE, + Self::Delta => Self::DELTA, + } + } +} + +impl fmt::Display for OutputItemEvent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +/// Function call argument streaming events +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum FunctionCallEvent { + ArgumentsDelta, + ArgumentsDone, +} + +impl FunctionCallEvent { + pub const ARGUMENTS_DELTA: &'static str = "response.function_call_arguments.delta"; + pub const ARGUMENTS_DONE: &'static str = "response.function_call_arguments.done"; + + pub const fn as_str(&self) -> &'static str { + match self { + Self::ArgumentsDelta => Self::ARGUMENTS_DELTA, + Self::ArgumentsDone => Self::ARGUMENTS_DONE, + } + } +} + +impl fmt::Display for FunctionCallEvent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +/// Content part streaming events +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ContentPartEvent { + Added, + Done, +} + +impl ContentPartEvent { + pub const ADDED: &'static str = "response.content_part.added"; + pub const DONE: &'static str = "response.content_part.done"; + + pub const fn as_str(&self) -> &'static str { + match self { + Self::Added => Self::ADDED, + Self::Done => Self::DONE, + } + } +} + +impl fmt::Display for ContentPartEvent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +/// Output text streaming events +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum OutputTextEvent { + Delta, + Done, +} + +impl OutputTextEvent { + pub const DELTA: &'static str = "response.output_text.delta"; + pub const DONE: &'static str = "response.output_text.done"; + + pub const fn as_str(&self) -> &'static str { + match self { + Self::Delta => Self::DELTA, + Self::Done => Self::DONE, + } + } +} + +impl fmt::Display for OutputTextEvent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +// ============================================================================ +// MCP Events +// ============================================================================ + +/// MCP (Model Context Protocol) call events +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum McpEvent { + CallArgumentsDelta, + CallArgumentsDone, + CallInProgress, + CallCompleted, + CallFailed, + ListToolsInProgress, + ListToolsCompleted, +} + +impl McpEvent { + pub const CALL_ARGUMENTS_DELTA: &'static str = "response.mcp_call_arguments.delta"; + pub const CALL_ARGUMENTS_DONE: &'static str = "response.mcp_call_arguments.done"; + pub const CALL_IN_PROGRESS: &'static str = "response.mcp_call.in_progress"; + pub const CALL_COMPLETED: &'static str = "response.mcp_call.completed"; + pub const CALL_FAILED: &'static str = "response.mcp_call.failed"; + pub const LIST_TOOLS_IN_PROGRESS: &'static str = "response.mcp_list_tools.in_progress"; + pub const LIST_TOOLS_COMPLETED: &'static str = "response.mcp_list_tools.completed"; + + pub const fn as_str(&self) -> &'static str { + match self { + Self::CallArgumentsDelta => Self::CALL_ARGUMENTS_DELTA, + Self::CallArgumentsDone => Self::CALL_ARGUMENTS_DONE, + Self::CallInProgress => Self::CALL_IN_PROGRESS, + Self::CallCompleted => Self::CALL_COMPLETED, + Self::CallFailed => Self::CALL_FAILED, + Self::ListToolsInProgress => Self::LIST_TOOLS_IN_PROGRESS, + Self::ListToolsCompleted => Self::LIST_TOOLS_COMPLETED, + } + } +} + +impl fmt::Display for McpEvent { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +/// Item type discriminators used in output items +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ItemType { + FunctionCall, + FunctionToolCall, + McpCall, + Function, + McpListTools, +} + +impl ItemType { + pub const FUNCTION_CALL: &'static str = "function_call"; + pub const FUNCTION_TOOL_CALL: &'static str = "function_tool_call"; + pub const MCP_CALL: &'static str = "mcp_call"; + pub const FUNCTION: &'static str = "function"; + pub const MCP_LIST_TOOLS: &'static str = "mcp_list_tools"; + + pub const fn as_str(&self) -> &'static str { + match self { + Self::FunctionCall => Self::FUNCTION_CALL, + Self::FunctionToolCall => Self::FUNCTION_TOOL_CALL, + Self::McpCall => Self::MCP_CALL, + Self::Function => Self::FUNCTION, + Self::McpListTools => Self::MCP_LIST_TOOLS, + } + } + + /// Check if this is a function call variant (FunctionCall or FunctionToolCall) + pub const fn is_function_call(&self) -> bool { + matches!(self, Self::FunctionCall | Self::FunctionToolCall) + } +} + +impl fmt::Display for ItemType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(self.as_str()) + } +} + +/// Check if an event type string matches any response lifecycle event +pub fn is_response_event(event_type: &str) -> bool { + matches!( + event_type, + ResponseEvent::CREATED | ResponseEvent::IN_PROGRESS | ResponseEvent::COMPLETED + ) +} + +/// Check if an item type string is a function call variant +pub fn is_function_call_type(item_type: &str) -> bool { + item_type == ItemType::FUNCTION_CALL || item_type == ItemType::FUNCTION_TOOL_CALL +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/generate.rs b/sgl-model-gateway/vendor/openai-protocol/src/generate.rs new file mode 100644 index 000000000000..0c81184745df --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/generate.rs @@ -0,0 +1,297 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use validator::Validate; + +use super::{ + common::{default_true, GenerationRequest, InputIds}, + sampling_params::SamplingParams, +}; +use crate::validated::Normalizable; + +// ============================================================================ +// SGLang Generate API (native format) +// ============================================================================ + +#[derive(Clone, Debug, Serialize, Deserialize, Validate)] +#[validate(schema(function = "validate_generate_request"))] +pub struct GenerateRequest { + /// Text input - SGLang native format + #[serde(skip_serializing_if = "Option::is_none")] + pub text: Option, + + pub model: Option, + + /// Input IDs for tokenized input + #[serde(skip_serializing_if = "Option::is_none")] + pub input_ids: Option, + + /// Input embeddings for direct embedding input + /// Can be a 2D array (single request) or 3D array (batch of requests) + /// Placeholder for future use + #[serde(skip_serializing_if = "Option::is_none")] + pub input_embeds: Option, + + /// Image input data + /// Can be an image instance, file name, URL, or base64 encoded string + /// Supports single images, lists of images, or nested lists for batch processing + /// Placeholder for future use + #[serde(skip_serializing_if = "Option::is_none")] + pub image_data: Option, + + /// Video input data + /// Can be a file name, URL, or base64 encoded string + /// Supports single videos, lists of videos, or nested lists for batch processing + /// Placeholder for future use + #[serde(skip_serializing_if = "Option::is_none")] + pub video_data: Option, + + /// Audio input data + /// Can be a file name, URL, or base64 encoded string + /// Supports single audio files, lists of audio, or nested lists for batch processing + /// Placeholder for future use + #[serde(skip_serializing_if = "Option::is_none")] + pub audio_data: Option, + + /// Sampling parameters (sglang style) + #[serde(skip_serializing_if = "Option::is_none")] + pub sampling_params: Option, + + /// Whether to return logprobs + #[serde(skip_serializing_if = "Option::is_none")] + pub return_logprob: Option, + + /// If return logprobs, the start location in the prompt for returning logprobs. + #[serde(skip_serializing_if = "Option::is_none")] + pub logprob_start_len: Option, + + /// If return logprobs, the number of top logprobs to return at each position. + #[serde(skip_serializing_if = "Option::is_none")] + pub top_logprobs_num: Option, + + /// If return logprobs, the token ids to return logprob for. + #[serde(skip_serializing_if = "Option::is_none")] + pub token_ids_logprob: Option>, + + /// Whether to detokenize tokens in text in the returned logprobs. + #[serde(default)] + pub return_text_in_logprobs: bool, + + /// Whether to stream the response + #[serde(default)] + pub stream: bool, + + /// Whether to log metrics for this request (e.g. health_generate calls do not log metrics) + #[serde(default = "default_true")] + pub log_metrics: bool, + + /// Return model hidden states + #[serde(default)] + pub return_hidden_states: bool, + + /// The modalities of the image data [image, multi-images, video] + #[serde(skip_serializing_if = "Option::is_none")] + pub modalities: Option>, + + /// Session parameters for continual prompting + #[serde(skip_serializing_if = "Option::is_none")] + pub session_params: Option>, + + /// Path to LoRA adapter(s) for model customization + #[serde(skip_serializing_if = "Option::is_none")] + pub lora_path: Option, + + /// LoRA adapter ID (if pre-loaded) + #[serde(skip_serializing_if = "Option::is_none")] + pub lora_id: Option, + + /// Custom logit processor for advanced sampling control. Must be a serialized instance + /// of `CustomLogitProcessor` in python/sglang/srt/sampling/custom_logit_processor.py + /// Use the processor's `to_str()` method to generate the serialized string. + #[serde(skip_serializing_if = "Option::is_none")] + pub custom_logit_processor: Option, + + /// For disaggregated inference + #[serde(skip_serializing_if = "Option::is_none")] + pub bootstrap_host: Option, + + /// For disaggregated inference + #[serde(skip_serializing_if = "Option::is_none")] + pub bootstrap_port: Option, + + /// For disaggregated inference + #[serde(skip_serializing_if = "Option::is_none")] + pub bootstrap_room: Option, + + /// For disaggregated inference + #[serde(skip_serializing_if = "Option::is_none")] + pub bootstrap_pair_key: Option, + + /// Data parallel rank routing + #[serde(skip_serializing_if = "Option::is_none")] + pub data_parallel_rank: Option, + + /// Background response + #[serde(default)] + pub background: bool, + + /// Conversation ID for tracking + #[serde(skip_serializing_if = "Option::is_none")] + pub conversation_id: Option, + + /// Priority for the request + #[serde(skip_serializing_if = "Option::is_none")] + pub priority: Option, + + /// Extra key for classifying the request (e.g. cache_salt) + #[serde(skip_serializing_if = "Option::is_none")] + pub extra_key: Option, + + /// Whether to disallow logging for this request (e.g. due to ZDR) + #[serde(default)] + pub no_logs: bool, + + /// Custom metric labels + #[serde(skip_serializing_if = "Option::is_none")] + pub custom_labels: Option>, + + /// Whether to return bytes for image generation + #[serde(default)] + pub return_bytes: bool, + + /// Whether to return entropy + #[serde(default)] + pub return_entropy: bool, + + /// Request ID for tracking (inherited from BaseReq in Python) + #[serde(skip_serializing_if = "Option::is_none")] + pub rid: Option, +} + +impl Normalizable for GenerateRequest { + // Use default no-op implementation - no normalization needed for GenerateRequest +} + +/// Validation function for GenerateRequest - ensure exactly one input type is provided +fn validate_generate_request(req: &GenerateRequest) -> Result<(), validator::ValidationError> { + // Exactly one of text or input_ids must be provided + // Note: input_embeds not yet supported in Rust implementation + let has_text = req.text.is_some(); + let has_input_ids = req.input_ids.is_some(); + + let count = [has_text, has_input_ids].iter().filter(|&&x| x).count(); + + if count == 0 { + return Err(validator::ValidationError::new( + "Either text or input_ids should be provided.", + )); + } + + if count > 1 { + return Err(validator::ValidationError::new( + "Either text or input_ids should be provided.", + )); + } + + Ok(()) +} + +impl GenerationRequest for GenerateRequest { + fn is_stream(&self) -> bool { + self.stream + } + + fn get_model(&self) -> Option<&str> { + // Generate requests have an optional model field + if let Some(s) = &self.model { + Some(s.as_str()) + } else { + None + } + } + + fn extract_text_for_routing(&self) -> String { + // Check fields in priority order: text, input_ids + if let Some(ref text) = self.text { + return text.clone(); + } + + if let Some(ref input_ids) = self.input_ids { + return match input_ids { + InputIds::Single(ids) => ids + .iter() + .map(|&id| id.to_string()) + .collect::>() + .join(" "), + InputIds::Batch(batches) => batches + .iter() + .flat_map(|batch| batch.iter().map(|&id| id.to_string())) + .collect::>() + .join(" "), + }; + } + + // No text input found + String::new() + } +} + +// ============================================================================ +// SGLang Generate Response Types +// ============================================================================ + +/// SGLang generate response (single completion or array for n>1) +/// +/// Format for n=1: +/// ```json +/// { +/// "text": "...", +/// "output_ids": [...], +/// "meta_info": { ... } +/// } +/// ``` +/// +/// Format for n>1: +/// ```json +/// [ +/// {"text": "...", "output_ids": [...], "meta_info": {...}}, +/// {"text": "...", "output_ids": [...], "meta_info": {...}} +/// ] +/// ``` +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GenerateResponse { + pub text: String, + pub output_ids: Vec, + pub meta_info: GenerateMetaInfo, +} + +/// Metadata for a single generate completion +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GenerateMetaInfo { + pub id: String, + pub finish_reason: GenerateFinishReason, + pub prompt_tokens: u32, + pub weight_version: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub input_token_logprobs: Option>>>, + #[serde(skip_serializing_if = "Option::is_none")] + pub output_token_logprobs: Option>>>, + pub completion_tokens: u32, + pub cached_tokens: u32, + pub e2e_latency: f64, + #[serde(skip_serializing_if = "Option::is_none")] + pub matched_stop: Option, +} + +/// Finish reason for generate endpoint +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "lowercase")] +pub enum GenerateFinishReason { + Length { + length: u32, + }, + Stop, + #[serde(untagged)] + Other(Value), +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/lib.rs b/sgl-model-gateway/vendor/openai-protocol/src/lib.rs new file mode 100644 index 000000000000..6196611473e3 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/lib.rs @@ -0,0 +1,25 @@ +// Protocol definitions and validation for various LLM APIs +// This module provides a structured approach to handling different API protocols + +/// Default model identifier used when no model is specified. +/// +/// This constant should be used instead of hardcoded "unknown" strings +/// throughout the codebase for consistency. +pub const UNKNOWN_MODEL_ID: &str = "unknown"; + +pub mod builders; +pub mod chat; +pub mod classify; +pub mod common; +pub mod completion; +pub mod embedding; +pub mod event_types; +pub mod generate; +pub mod messages; +pub mod parser; +pub mod rerank; +pub mod responses; +pub mod sampling_params; +pub mod tokenize; +pub mod validated; +pub mod worker_spec; diff --git a/sgl-model-gateway/vendor/openai-protocol/src/messages.rs b/sgl-model-gateway/vendor/openai-protocol/src/messages.rs new file mode 100644 index 000000000000..b180e1224d84 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/messages.rs @@ -0,0 +1,1726 @@ +//! Anthropic Messages API protocol definitions +//! +//! This module provides Rust types for the Anthropic Messages API. +//! See: https://docs.anthropic.com/en/api/messages + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +// ============================================================================ +// Request Types +// ============================================================================ + +/// Request to create a message using the Anthropic Messages API. +/// +/// This is the main request type for `/v1/messages` endpoint. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CreateMessageRequest { + /// The model that will complete your prompt. + pub model: String, + + /// Input messages for the conversation. + pub messages: Vec, + + /// The maximum number of tokens to generate before stopping. + pub max_tokens: u32, + + /// An object describing metadata about the request. + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata: Option, + + /// Service tier for the request (auto or standard_only). + #[serde(skip_serializing_if = "Option::is_none")] + pub service_tier: Option, + + /// Custom text sequences that will cause the model to stop generating. + #[serde(skip_serializing_if = "Option::is_none")] + pub stop_sequences: Option>, + + /// Whether to incrementally stream the response using server-sent events. + #[serde(skip_serializing_if = "Option::is_none")] + pub stream: Option, + + /// System prompt for providing context and instructions. + #[serde(skip_serializing_if = "Option::is_none")] + pub system: Option, + + /// Amount of randomness injected into the response (0.0 to 1.0). + #[serde(skip_serializing_if = "Option::is_none")] + pub temperature: Option, + + /// Configuration for extended thinking. + #[serde(skip_serializing_if = "Option::is_none")] + pub thinking: Option, + + /// How the model should use the provided tools. + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_choice: Option, + + /// Definitions of tools that the model may use. + #[serde(skip_serializing_if = "Option::is_none")] + pub tools: Option>, + + /// Only sample from the top K options for each subsequent token. + #[serde(skip_serializing_if = "Option::is_none")] + pub top_k: Option, + + /// Use nucleus sampling. + #[serde(skip_serializing_if = "Option::is_none")] + pub top_p: Option, + + // Beta features + /// Container configuration for code execution (beta). + #[serde(skip_serializing_if = "Option::is_none")] + pub container: Option, + + /// MCP servers to be utilized in this request (beta). + #[serde(skip_serializing_if = "Option::is_none")] + pub mcp_servers: Option>, +} + +impl CreateMessageRequest { + /// Check if the request is for streaming + pub fn is_stream(&self) -> bool { + self.stream.unwrap_or(false) + } + + /// Get the model name + pub fn get_model(&self) -> &str { + &self.model + } +} + +/// Request metadata +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Metadata { + /// An external identifier for the user who is associated with the request. + #[serde(skip_serializing_if = "Option::is_none")] + pub user_id: Option, +} + +/// Service tier options +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum ServiceTier { + Auto, + StandardOnly, +} + +/// System content can be a string or an array of text blocks +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum SystemContent { + String(String), + Blocks(Vec), +} + +/// A single input message in a conversation +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct InputMessage { + /// The role of the message sender (user or assistant) + pub role: Role, + + /// The content of the message + pub content: InputContent, +} + +/// Role of a message sender +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "lowercase")] +pub enum Role { + User, + Assistant, +} + +/// Input content can be a string or an array of content blocks +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum InputContent { + String(String), + Blocks(Vec), +} + +// ============================================================================ +// Input Content Blocks +// ============================================================================ + +/// Input content block types +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum InputContentBlock { + /// Text content + Text(TextBlock), + /// Image content + Image(ImageBlock), + /// Document content + Document(DocumentBlock), + /// Tool use block (for assistant messages) + ToolUse(ToolUseBlock), + /// Tool result block (for user messages) + ToolResult(ToolResultBlock), + /// Thinking block + Thinking(ThinkingBlock), + /// Redacted thinking block + RedactedThinking(RedactedThinkingBlock), + /// Server tool use block + ServerToolUse(ServerToolUseBlock), + /// Search result block + SearchResult(SearchResultBlock), + /// Web search tool result block + WebSearchToolResult(WebSearchToolResultBlock), +} + +/// Text content block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TextBlock { + /// The text content + pub text: String, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, + + /// Citations for this text block + #[serde(skip_serializing_if = "Option::is_none")] + pub citations: Option>, +} + +/// Image content block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ImageBlock { + /// The image source + pub source: ImageSource, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Image source (base64 or URL) +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ImageSource { + Base64 { media_type: String, data: String }, + Url { url: String }, +} + +/// Document content block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DocumentBlock { + /// The document source + pub source: DocumentSource, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, + + /// Optional title for the document + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option, + + /// Optional context for the document + #[serde(skip_serializing_if = "Option::is_none")] + pub context: Option, + + /// Citations configuration + #[serde(skip_serializing_if = "Option::is_none")] + pub citations: Option, +} + +/// Document source (base64, text, or URL) +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum DocumentSource { + Base64 { media_type: String, data: String }, + Text { data: String }, + Url { url: String }, + Content { content: Vec }, +} + +/// Tool use block (in assistant messages) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ToolUseBlock { + /// Unique identifier for this tool use + pub id: String, + + /// Name of the tool being used + pub name: String, + + /// Input arguments for the tool + pub input: Value, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Tool result block (in user messages) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ToolResultBlock { + /// The ID of the tool use this is a result for + pub tool_use_id: String, + + /// The result content (string or blocks) + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option, + + /// Whether this result indicates an error + #[serde(skip_serializing_if = "Option::is_none")] + pub is_error: Option, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Tool result content (string or blocks) +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ToolResultContent { + String(String), + Blocks(Vec), +} + +/// Content blocks allowed in tool results +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ToolResultContentBlock { + Text(TextBlock), + Image(ImageBlock), + Document(DocumentBlock), + SearchResult(SearchResultBlock), +} + +/// Thinking block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ThinkingBlock { + /// The thinking content + pub thinking: String, + + /// Signature for the thinking block + pub signature: String, +} + +/// Redacted thinking block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RedactedThinkingBlock { + /// The encrypted/redacted data + pub data: String, +} + +/// Server tool use block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ServerToolUseBlock { + /// Unique identifier for this tool use + pub id: String, + + /// Name of the server tool + pub name: String, + + /// Input arguments for the tool + pub input: Value, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Search result block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SearchResultBlock { + /// Source URL or identifier + pub source: String, + + /// Title of the search result + pub title: String, + + /// Content of the search result + pub content: Vec, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, + + /// Citations configuration + #[serde(skip_serializing_if = "Option::is_none")] + pub citations: Option, +} + +/// Web search tool result block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebSearchToolResultBlock { + /// The tool use ID this result is for + pub tool_use_id: String, + + /// The search results or error + pub content: WebSearchToolResultContent, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Web search tool result content +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum WebSearchToolResultContent { + Results(Vec), + Error(WebSearchToolResultError), +} + +/// Web search result block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebSearchResultBlock { + /// Title of the search result + pub title: String, + + /// URL of the search result + pub url: String, + + /// Encrypted content + pub encrypted_content: String, + + /// Page age (if available) + #[serde(skip_serializing_if = "Option::is_none")] + pub page_age: Option, +} + +/// Web search tool result error +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebSearchToolResultError { + #[serde(rename = "type")] + pub error_type: String, + pub error_code: WebSearchToolResultErrorCode, +} + +/// Web search tool result error codes +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum WebSearchToolResultErrorCode { + InvalidToolInput, + Unavailable, + MaxUsesExceeded, + TooManyRequests, + QueryTooLong, +} + +/// Cache control configuration +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum CacheControl { + Ephemeral, +} + +/// Citations configuration +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CitationsConfig { + #[serde(skip_serializing_if = "Option::is_none")] + pub enabled: Option, +} + +/// Citation types +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum Citation { + CharLocation(CharLocationCitation), + PageLocation(PageLocationCitation), + ContentBlockLocation(ContentBlockLocationCitation), + WebSearchResultLocation(WebSearchResultLocationCitation), + SearchResultLocation(SearchResultLocationCitation), +} + +/// Character location citation +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CharLocationCitation { + pub cited_text: String, + pub document_index: u32, + pub document_title: Option, + pub start_char_index: u32, + pub end_char_index: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub file_id: Option, +} + +/// Page location citation +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PageLocationCitation { + pub cited_text: String, + pub document_index: u32, + pub document_title: Option, + pub start_page_number: u32, + pub end_page_number: u32, +} + +/// Content block location citation +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ContentBlockLocationCitation { + pub cited_text: String, + pub document_index: u32, + pub document_title: Option, + pub start_block_index: u32, + pub end_block_index: u32, +} + +/// Web search result location citation +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebSearchResultLocationCitation { + pub cited_text: String, + pub url: String, + pub title: Option, + pub encrypted_index: String, +} + +/// Search result location citation +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SearchResultLocationCitation { + pub cited_text: String, + pub search_result_index: u32, + pub source: String, + pub title: Option, + pub start_block_index: u32, + pub end_block_index: u32, +} + +// ============================================================================ +// Tool Definitions +// ============================================================================ + +/// Tool definition +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum Tool { + /// Custom tool definition + Custom(CustomTool), + /// Bash tool (computer use) + Bash(BashTool), + /// Text editor tool (computer use) + TextEditor(TextEditorTool), + /// Web search tool + WebSearch(WebSearchTool), +} + +/// Custom tool definition +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CustomTool { + /// Name of the tool + pub name: String, + + /// Optional type (defaults to "custom") + #[serde(rename = "type", skip_serializing_if = "Option::is_none")] + pub tool_type: Option, + + /// Description of what this tool does + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + + /// JSON schema for the tool's input + pub input_schema: InputSchema, + + /// Cache control for this tool + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// JSON Schema for tool input +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct InputSchema { + #[serde(rename = "type")] + pub schema_type: String, + + #[serde(skip_serializing_if = "Option::is_none")] + pub properties: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub required: Option>, + + /// Additional properties can be stored here + #[serde(flatten)] + pub additional: HashMap, +} + +/// Bash tool for computer use +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BashTool { + #[serde(rename = "type")] + pub tool_type: String, // "bash_20250124" + + pub name: String, // "bash" + + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Text editor tool for computer use +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TextEditorTool { + #[serde(rename = "type")] + pub tool_type: String, // "text_editor_20250124", etc. + + pub name: String, // "str_replace_editor" + + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Web search tool +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebSearchTool { + #[serde(rename = "type")] + pub tool_type: String, // "web_search_20250305" + + pub name: String, // "web_search" + + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_domains: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub blocked_domains: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub max_uses: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub user_location: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// User location for web search +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct UserLocation { + #[serde(rename = "type")] + pub location_type: String, // "approximate" + + #[serde(skip_serializing_if = "Option::is_none")] + pub city: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub region: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub country: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub timezone: Option, +} + +// ============================================================================ +// Tool Choice +// ============================================================================ + +/// How the model should use the provided tools +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ToolChoice { + /// The model will automatically decide whether to use tools + Auto { + #[serde(skip_serializing_if = "Option::is_none")] + disable_parallel_tool_use: Option, + }, + /// The model will use any available tools + Any { + #[serde(skip_serializing_if = "Option::is_none")] + disable_parallel_tool_use: Option, + }, + /// The model will use the specified tool + Tool { + name: String, + #[serde(skip_serializing_if = "Option::is_none")] + disable_parallel_tool_use: Option, + }, + /// The model will not use tools + None, +} + +// ============================================================================ +// Thinking Configuration +// ============================================================================ + +/// Configuration for extended thinking +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ThinkingConfig { + /// Enable extended thinking + Enabled { + /// Budget in tokens for thinking (minimum 1024) + budget_tokens: u32, + }, + /// Disable extended thinking + Disabled, +} + +// ============================================================================ +// Response Types +// ============================================================================ + +/// Response message from the API +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Message { + /// Unique object identifier + pub id: String, + + /// Object type (always "message") + #[serde(rename = "type")] + pub message_type: String, + + /// Conversational role (always "assistant") + pub role: String, + + /// Content generated by the model + pub content: Vec, + + /// The model that generated the message + pub model: String, + + /// The reason the model stopped generating + pub stop_reason: Option, + + /// Which custom stop sequence was generated (if any) + pub stop_sequence: Option, + + /// Billing and rate-limit usage + pub usage: Usage, +} + +/// Output content block types +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ContentBlock { + /// Text content + Text { + text: String, + #[serde(skip_serializing_if = "Option::is_none")] + citations: Option>, + }, + /// Tool use by the model + ToolUse { + id: String, + name: String, + input: Value, + }, + /// Thinking content + Thinking { thinking: String, signature: String }, + /// Redacted thinking content + RedactedThinking { data: String }, + /// Server tool use + ServerToolUse { + id: String, + name: String, + input: Value, + }, + /// Web search tool result + WebSearchToolResult { + tool_use_id: String, + content: WebSearchToolResultContent, + }, +} + +/// Stop reasons +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum StopReason { + /// The model reached a natural stopping point + EndTurn, + /// We exceeded the requested max_tokens + MaxTokens, + /// One of the custom stop_sequences was generated + StopSequence, + /// The model invoked one or more tools + ToolUse, + /// We paused a long-running turn + PauseTurn, + /// Streaming classifiers intervened + Refusal, +} + +/// Billing and rate-limit usage +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Usage { + /// The number of input tokens used + pub input_tokens: u32, + + /// The number of output tokens used + pub output_tokens: u32, + + /// The number of input tokens used to create the cache entry + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_creation_input_tokens: Option, + + /// The number of input tokens read from the cache + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_read_input_tokens: Option, + + /// Breakdown of cached tokens by TTL + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_creation: Option, + + /// Server tool usage information + #[serde(skip_serializing_if = "Option::is_none")] + pub server_tool_use: Option, + + /// Service tier used for the request + #[serde(skip_serializing_if = "Option::is_none")] + pub service_tier: Option, +} + +/// Cache creation breakdown +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CacheCreation { + #[serde(flatten)] + pub tokens_by_ttl: HashMap, +} + +/// Server tool usage information +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ServerToolUsage { + pub web_search_requests: u32, +} + +// ============================================================================ +// Streaming Event Types +// ============================================================================ + +/// Server-sent event wrapper +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum MessageStreamEvent { + /// Start of a new message + MessageStart { message: Message }, + /// Update to a message + MessageDelta { + delta: MessageDelta, + usage: MessageDeltaUsage, + }, + /// End of a message + MessageStop, + /// Start of a content block + ContentBlockStart { + index: u32, + content_block: ContentBlock, + }, + /// Update to a content block + ContentBlockDelta { + index: u32, + delta: ContentBlockDelta, + }, + /// End of a content block + ContentBlockStop { index: u32 }, + /// Ping event (for keep-alive) + Ping, + /// Error event + Error { error: ErrorResponse }, +} + +/// Message delta for streaming updates +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MessageDelta { + #[serde(skip_serializing_if = "Option::is_none")] + pub stop_reason: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub stop_sequence: Option, +} + +/// Usage delta for streaming updates +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MessageDeltaUsage { + pub output_tokens: u32, + + #[serde(skip_serializing_if = "Option::is_none")] + pub input_tokens: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_creation_input_tokens: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_read_input_tokens: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub server_tool_use: Option, +} + +/// Content block delta for streaming updates +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ContentBlockDelta { + /// Text delta + TextDelta { text: String }, + /// JSON input delta (for tool use) + InputJsonDelta { partial_json: String }, + /// Thinking delta + ThinkingDelta { thinking: String }, + /// Signature delta + SignatureDelta { signature: String }, + /// Citations delta + CitationsDelta { citation: Citation }, +} + +// ============================================================================ +// Error Types +// ============================================================================ + +/// Error response +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ErrorResponse { + #[serde(rename = "type")] + pub error_type: String, + + pub message: String, +} + +/// API error types +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ApiError { + InvalidRequestError { message: String }, + AuthenticationError { message: String }, + BillingError { message: String }, + PermissionError { message: String }, + NotFoundError { message: String }, + RateLimitError { message: String }, + TimeoutError { message: String }, + ApiError { message: String }, + OverloadedError { message: String }, +} + +// ============================================================================ +// Count Tokens Types +// ============================================================================ + +/// Request to count tokens in a message +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CountMessageTokensRequest { + /// The model to use for token counting + pub model: String, + + /// Input messages + pub messages: Vec, + + /// System prompt + #[serde(skip_serializing_if = "Option::is_none")] + pub system: Option, + + /// Thinking configuration + #[serde(skip_serializing_if = "Option::is_none")] + pub thinking: Option, + + /// Tool choice + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_choice: Option, + + /// Tool definitions + #[serde(skip_serializing_if = "Option::is_none")] + pub tools: Option>, +} + +/// Response from token counting +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CountMessageTokensResponse { + pub input_tokens: u32, +} + +// ============================================================================ +// Model Info Types +// ============================================================================ + +/// Model information +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ModelInfo { + /// Object type (always "model") + #[serde(rename = "type")] + pub model_type: String, + + /// Model ID + pub id: String, + + /// Display name + pub display_name: String, + + /// When the model was created + pub created_at: String, +} + +/// List of models response +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ListModelsResponse { + pub data: Vec, + pub has_more: bool, + pub first_id: Option, + pub last_id: Option, +} + +// ============================================================================ +// Beta Features - Container & MCP Configuration +// ============================================================================ + +/// Container configuration for code execution (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ContainerConfig { + /// Container ID for reuse across requests + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, + + /// Skills to be loaded in the container + #[serde(skip_serializing_if = "Option::is_none")] + pub skills: Option>, +} + +/// MCP server configuration (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct McpServerConfig { + /// Name of the MCP server + pub name: String, + + /// MCP server URL + pub url: String, + + /// Authorization token (if required) + #[serde(skip_serializing_if = "Option::is_none")] + pub authorization_token: Option, + + /// Tool configuration for this server + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_configuration: Option, +} + +/// MCP tool configuration +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct McpToolConfiguration { + /// Whether to allow all tools + #[serde(skip_serializing_if = "Option::is_none")] + pub enabled: Option, + + /// Allowed tool names + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_tools: Option>, +} + +// ============================================================================ +// Beta Features - MCP Tool Types +// ============================================================================ + +/// MCP tool use block (beta) - for assistant messages +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct McpToolUseBlock { + /// Unique identifier for this tool use + pub id: String, + + /// Name of the tool being used + pub name: String, + + /// Name of the MCP server + pub server_name: String, + + /// Input arguments for the tool + pub input: Value, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// MCP tool result block (beta) - for user messages +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct McpToolResultBlock { + /// The ID of the tool use this is a result for + pub tool_use_id: String, + + /// The result content + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option, + + /// Whether this result indicates an error + #[serde(skip_serializing_if = "Option::is_none")] + pub is_error: Option, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// MCP toolset definition (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct McpToolset { + #[serde(rename = "type")] + pub toolset_type: String, // "mcp_toolset" + + /// Name of the MCP server to configure tools for + pub mcp_server_name: String, + + /// Default configuration applied to all tools from this server + #[serde(skip_serializing_if = "Option::is_none")] + pub default_config: Option, + + /// Configuration overrides for specific tools + #[serde(skip_serializing_if = "Option::is_none")] + pub configs: Option>, + + /// Cache control for this toolset + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Default configuration for MCP tools +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct McpToolDefaultConfig { + /// Whether tools are enabled + #[serde(skip_serializing_if = "Option::is_none")] + pub enabled: Option, + + /// Whether to defer loading + #[serde(skip_serializing_if = "Option::is_none")] + pub defer_loading: Option, +} + +/// Per-tool MCP configuration +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct McpToolConfig { + /// Whether this tool is enabled + #[serde(skip_serializing_if = "Option::is_none")] + pub enabled: Option, + + /// Whether to defer loading + #[serde(skip_serializing_if = "Option::is_none")] + pub defer_loading: Option, +} + +// ============================================================================ +// Beta Features - Code Execution Types +// ============================================================================ + +/// Code execution tool (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CodeExecutionTool { + #[serde(rename = "type")] + pub tool_type: String, // "code_execution_20250522" or "code_execution_20250825" + + pub name: String, // "code_execution" + + /// Allowed callers for this tool + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_callers: Option>, + + /// Whether to defer loading + #[serde(skip_serializing_if = "Option::is_none")] + pub defer_loading: Option, + + /// Whether to use strict mode + #[serde(skip_serializing_if = "Option::is_none")] + pub strict: Option, + + /// Cache control for this tool + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Code execution result block (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CodeExecutionResultBlock { + /// Stdout output + pub stdout: String, + + /// Stderr output + pub stderr: String, + + /// Return code + pub return_code: i32, + + /// Output files + pub content: Vec, +} + +/// Code execution output file reference +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CodeExecutionOutputBlock { + #[serde(rename = "type")] + pub block_type: String, // "code_execution_output" + + /// File ID + pub file_id: String, +} + +/// Code execution tool result block (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CodeExecutionToolResultBlock { + /// The ID of the tool use this is a result for + pub tool_use_id: String, + + /// The result content (success or error) + pub content: CodeExecutionToolResultContent, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Code execution tool result content +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CodeExecutionToolResultContent { + Success(CodeExecutionResultBlock), + Error(CodeExecutionToolResultError), +} + +/// Code execution tool result error +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CodeExecutionToolResultError { + #[serde(rename = "type")] + pub error_type: String, // "code_execution_tool_result_error" + + pub error_code: CodeExecutionToolResultErrorCode, +} + +/// Code execution error codes +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum CodeExecutionToolResultErrorCode { + Unavailable, + CodeExecutionExceededTimeout, + ContainerExpired, + InvalidToolInput, +} + +/// Bash code execution result block (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BashCodeExecutionResultBlock { + /// Stdout output + pub stdout: String, + + /// Stderr output + pub stderr: String, + + /// Return code + pub return_code: i32, + + /// Output files + pub content: Vec, +} + +/// Bash code execution output file reference +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BashCodeExecutionOutputBlock { + #[serde(rename = "type")] + pub block_type: String, // "bash_code_execution_output" + + /// File ID + pub file_id: String, +} + +/// Bash code execution tool result block (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BashCodeExecutionToolResultBlock { + /// The ID of the tool use this is a result for + pub tool_use_id: String, + + /// The result content (success or error) + pub content: BashCodeExecutionToolResultContent, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Bash code execution tool result content +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum BashCodeExecutionToolResultContent { + Success(BashCodeExecutionResultBlock), + Error(BashCodeExecutionToolResultError), +} + +/// Bash code execution tool result error +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BashCodeExecutionToolResultError { + #[serde(rename = "type")] + pub error_type: String, // "bash_code_execution_tool_result_error" + + pub error_code: BashCodeExecutionToolResultErrorCode, +} + +/// Bash code execution error codes +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum BashCodeExecutionToolResultErrorCode { + Unavailable, + CodeExecutionExceededTimeout, + ContainerExpired, + InvalidToolInput, +} + +/// Text editor code execution tool result block (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TextEditorCodeExecutionToolResultBlock { + /// The ID of the tool use this is a result for + pub tool_use_id: String, + + /// The result content + pub content: TextEditorCodeExecutionToolResultContent, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Text editor code execution result content +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum TextEditorCodeExecutionToolResultContent { + CreateResult(TextEditorCodeExecutionCreateResultBlock), + StrReplaceResult(TextEditorCodeExecutionStrReplaceResultBlock), + ViewResult(TextEditorCodeExecutionViewResultBlock), + Error(TextEditorCodeExecutionToolResultError), +} + +/// Text editor create result block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TextEditorCodeExecutionCreateResultBlock { + #[serde(rename = "type")] + pub block_type: String, // "text_editor_code_execution_create_result" +} + +/// Text editor str_replace result block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TextEditorCodeExecutionStrReplaceResultBlock { + #[serde(rename = "type")] + pub block_type: String, // "text_editor_code_execution_str_replace_result" + + /// Snippet of content around the replacement + #[serde(skip_serializing_if = "Option::is_none")] + pub snippet: Option, +} + +/// Text editor view result block +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TextEditorCodeExecutionViewResultBlock { + #[serde(rename = "type")] + pub block_type: String, // "text_editor_code_execution_view_result" + + /// Content of the viewed file + pub content: String, +} + +/// Text editor code execution tool result error +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TextEditorCodeExecutionToolResultError { + #[serde(rename = "type")] + pub error_type: String, + + pub error_code: TextEditorCodeExecutionToolResultErrorCode, +} + +/// Text editor code execution error codes +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum TextEditorCodeExecutionToolResultErrorCode { + Unavailable, + InvalidToolInput, + FileNotFound, + ContainerExpired, +} + +// ============================================================================ +// Beta Features - Web Fetch Types +// ============================================================================ + +/// Web fetch tool (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebFetchTool { + #[serde(rename = "type")] + pub tool_type: String, // "web_fetch_20250305" or similar + + pub name: String, // "web_fetch" + + /// Allowed callers for this tool + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_callers: Option>, + + /// Maximum number of uses + #[serde(skip_serializing_if = "Option::is_none")] + pub max_uses: Option, + + /// Cache control for this tool + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Web fetch result block (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebFetchResultBlock { + #[serde(rename = "type")] + pub block_type: String, // "web_fetch_result" + + /// The URL that was fetched + pub url: String, + + /// The document content + pub content: DocumentBlock, + + /// When the content was retrieved + #[serde(skip_serializing_if = "Option::is_none")] + pub retrieved_at: Option, +} + +/// Web fetch tool result block (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebFetchToolResultBlock { + /// The ID of the tool use this is a result for + pub tool_use_id: String, + + /// The result content (success or error) + pub content: WebFetchToolResultContent, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Web fetch tool result content +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum WebFetchToolResultContent { + Success(WebFetchResultBlock), + Error(WebFetchToolResultError), +} + +/// Web fetch tool result error +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WebFetchToolResultError { + #[serde(rename = "type")] + pub error_type: String, // "web_fetch_tool_result_error" + + pub error_code: WebFetchToolResultErrorCode, +} + +/// Web fetch error codes +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum WebFetchToolResultErrorCode { + InvalidToolInput, + Unavailable, + MaxUsesExceeded, + TooManyRequests, + UrlNotAllowed, + FetchFailed, + ContentTooLarge, +} + +// ============================================================================ +// Beta Features - Tool Search Types +// ============================================================================ + +/// Tool search tool (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ToolSearchTool { + #[serde(rename = "type")] + pub tool_type: String, // "tool_search_tool_regex" or "tool_search_tool_bm25" + + pub name: String, + + /// Allowed callers for this tool + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_callers: Option>, + + /// Cache control for this tool + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +/// Tool reference block (beta) - returned by tool search +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ToolReferenceBlock { + #[serde(rename = "type")] + pub block_type: String, // "tool_reference" + + /// Tool name + pub tool_name: String, + + /// Tool description + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, +} + +/// Tool search result block (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ToolSearchResultBlock { + #[serde(rename = "type")] + pub block_type: String, // "tool_search_tool_search_result" + + /// Tool name + pub tool_name: String, + + /// Relevance score + #[serde(skip_serializing_if = "Option::is_none")] + pub score: Option, +} + +/// Tool search tool result block (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ToolSearchToolResultBlock { + /// The ID of the tool use this is a result for + pub tool_use_id: String, + + /// The search results + pub content: Vec, + + /// Cache control for this block + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +// ============================================================================ +// Beta Features - Container Upload Types +// ============================================================================ + +/// Container upload block (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ContainerUploadBlock { + #[serde(rename = "type")] + pub block_type: String, // "container_upload" + + /// File ID + pub file_id: String, + + /// File name + pub file_name: String, + + /// File path in container + #[serde(skip_serializing_if = "Option::is_none")] + pub file_path: Option, +} + +// ============================================================================ +// Beta Features - Memory Tool Types +// ============================================================================ + +/// Memory tool (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct MemoryTool { + #[serde(rename = "type")] + pub tool_type: String, // "memory_20250818" + + pub name: String, // "memory" + + /// Allowed callers for this tool + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_callers: Option>, + + /// Whether to defer loading + #[serde(skip_serializing_if = "Option::is_none")] + pub defer_loading: Option, + + /// Whether to use strict mode + #[serde(skip_serializing_if = "Option::is_none")] + pub strict: Option, + + /// Input examples + #[serde(skip_serializing_if = "Option::is_none")] + pub input_examples: Option>, + + /// Cache control for this tool + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +// ============================================================================ +// Beta Features - Computer Use Tool Types +// ============================================================================ + +/// Computer use tool (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ComputerUseTool { + #[serde(rename = "type")] + pub tool_type: String, // "computer_20241022" or "computer_20250124" + + pub name: String, // "computer" + + /// Display width + pub display_width_px: u32, + + /// Display height + pub display_height_px: u32, + + /// Display number (optional) + #[serde(skip_serializing_if = "Option::is_none")] + pub display_number: Option, + + /// Allowed callers for this tool + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_callers: Option>, + + /// Cache control for this tool + #[serde(skip_serializing_if = "Option::is_none")] + pub cache_control: Option, +} + +// ============================================================================ +// Beta Features - Extended Input Content Block Enum +// ============================================================================ + +/// Beta input content block types (extends InputContentBlock) +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum BetaInputContentBlock { + // Standard types + Text(TextBlock), + Image(ImageBlock), + Document(DocumentBlock), + ToolUse(ToolUseBlock), + ToolResult(ToolResultBlock), + Thinking(ThinkingBlock), + RedactedThinking(RedactedThinkingBlock), + ServerToolUse(ServerToolUseBlock), + SearchResult(SearchResultBlock), + WebSearchToolResult(WebSearchToolResultBlock), + + // Beta MCP types + McpToolUse(McpToolUseBlock), + McpToolResult(McpToolResultBlock), + + // Beta code execution types + CodeExecutionToolResult(CodeExecutionToolResultBlock), + BashCodeExecutionToolResult(BashCodeExecutionToolResultBlock), + TextEditorCodeExecutionToolResult(TextEditorCodeExecutionToolResultBlock), + + // Beta web fetch types + WebFetchToolResult(WebFetchToolResultBlock), + + // Beta tool search types + ToolSearchToolResult(ToolSearchToolResultBlock), + ToolReference(ToolReferenceBlock), + + // Beta container types + ContainerUpload(ContainerUploadBlock), +} + +/// Beta output content block types (extends ContentBlock) +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum BetaContentBlock { + // Standard types + Text { + text: String, + #[serde(skip_serializing_if = "Option::is_none")] + citations: Option>, + }, + ToolUse { + id: String, + name: String, + input: Value, + }, + Thinking { + thinking: String, + signature: String, + }, + RedactedThinking { + data: String, + }, + ServerToolUse { + id: String, + name: String, + input: Value, + }, + WebSearchToolResult { + tool_use_id: String, + content: WebSearchToolResultContent, + }, + + // Beta MCP types + McpToolUse { + id: String, + name: String, + server_name: String, + input: Value, + }, + McpToolResult { + tool_use_id: String, + #[serde(skip_serializing_if = "Option::is_none")] + content: Option, + #[serde(skip_serializing_if = "Option::is_none")] + is_error: Option, + }, + + // Beta code execution types + CodeExecutionToolResult { + tool_use_id: String, + content: CodeExecutionToolResultContent, + }, + BashCodeExecutionToolResult { + tool_use_id: String, + content: BashCodeExecutionToolResultContent, + }, + TextEditorCodeExecutionToolResult { + tool_use_id: String, + content: TextEditorCodeExecutionToolResultContent, + }, + + // Beta web fetch types + WebFetchToolResult { + tool_use_id: String, + content: WebFetchToolResultContent, + }, + + // Beta tool search types + ToolSearchToolResult { + tool_use_id: String, + content: Vec, + }, + ToolReference { + tool_name: String, + #[serde(skip_serializing_if = "Option::is_none")] + description: Option, + }, + + // Beta container types + ContainerUpload { + file_id: String, + file_name: String, + #[serde(skip_serializing_if = "Option::is_none")] + file_path: Option, + }, +} + +/// Beta tool definition (extends Tool) +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum BetaTool { + // Standard tools + Custom(CustomTool), + Bash(BashTool), + TextEditor(TextEditorTool), + WebSearch(WebSearchTool), + + // Beta tools + CodeExecution(CodeExecutionTool), + McpToolset(McpToolset), + WebFetch(WebFetchTool), + ToolSearch(ToolSearchTool), + Memory(MemoryTool), + ComputerUse(ComputerUseTool), +} + +/// Server tool names for beta features +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum BetaServerToolName { + WebSearch, + WebFetch, + CodeExecution, + BashCodeExecution, + TextEditorCodeExecution, + ToolSearchToolRegex, + ToolSearchToolBm25, +} + +/// Server tool caller types (beta) +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum ServerToolCaller { + /// Direct caller (the model itself) + Direct, + /// Code execution caller + #[serde(rename = "code_execution_20250825")] + CodeExecution20250825, +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/parser.rs b/sgl-model-gateway/vendor/openai-protocol/src/parser.rs new file mode 100644 index 000000000000..3d1f03f74694 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/parser.rs @@ -0,0 +1,23 @@ +use serde::Deserialize; + +use crate::common::Tool; + +/// Request to parse function calls from model output text +#[derive(Deserialize)] +pub struct ParseFunctionCallRequest { + /// The text to parse for function calls + pub text: String, + /// The parser type/name to use for parsing (e.g., "json", "pythonic") + pub tool_call_parser: String, + /// The list of available tools that the model can call + pub tools: Vec, +} + +/// Request to separate reasoning from normal text in model output +#[derive(Deserialize)] +pub struct SeparateReasoningRequest { + /// The text to parse for reasoning content + pub text: String, + /// The parser type/name to use for reasoning detection (e.g., "step3", "deepseek_r1") + pub reasoning_parser: String, +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/rerank.rs b/sgl-model-gateway/vendor/openai-protocol/src/rerank.rs new file mode 100644 index 000000000000..6775f5d8a407 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/rerank.rs @@ -0,0 +1,212 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use validator::Validate; + +use super::common::{default_model, default_true, GenerationRequest, StringOrArray, UsageInfo}; + +fn default_rerank_object() -> String { + "rerank".to_string() +} + +/// TODO: Create timestamp should not be in protocol layer +fn current_timestamp() -> i64 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap_or_else(|_| std::time::Duration::from_secs(0)) + .as_secs() as i64 +} + +// ============================================================================ +// Rerank API +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize, Validate)] +#[validate(schema(function = "validate_rerank_request"))] +pub struct RerankRequest { + /// The query text to rank documents against + #[validate(custom(function = "validate_query"))] + pub query: String, + + /// List of documents to be ranked + #[validate(custom(function = "validate_documents"))] + pub documents: Vec, + + /// Model to use for reranking + #[serde(default = "default_model")] + pub model: String, + + /// Maximum number of documents to return (optional) + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 1))] + pub top_k: Option, + + /// Whether to return documents in addition to scores + #[serde(default = "default_true")] + pub return_documents: bool, + + // SGLang specific extensions + /// Request ID for tracking + pub rid: Option, + + /// User identifier + pub user: Option, +} + +impl GenerationRequest for RerankRequest { + fn get_model(&self) -> Option<&str> { + Some(&self.model) + } + + fn is_stream(&self) -> bool { + false // Reranking doesn't support streaming + } + + fn extract_text_for_routing(&self) -> String { + self.query.clone() + } +} + +impl super::validated::Normalizable for RerankRequest { + // Use default no-op normalization +} + +// ============================================================================ +// Validation Functions +// ============================================================================ + +/// Validates that the query is not empty +fn validate_query(query: &str) -> Result<(), validator::ValidationError> { + if query.trim().is_empty() { + return Err(validator::ValidationError::new("query cannot be empty")); + } + Ok(()) +} + +/// Validates that the documents list is not empty +fn validate_documents(documents: &[String]) -> Result<(), validator::ValidationError> { + if documents.is_empty() { + return Err(validator::ValidationError::new( + "documents list cannot be empty", + )); + } + Ok(()) +} + +/// Schema-level validation for cross-field dependencies +fn validate_rerank_request(req: &RerankRequest) -> Result<(), validator::ValidationError> { + // Validate top_k if specified + if let Some(k) = req.top_k { + if k > req.documents.len() { + // This is allowed but we log a warning + tracing::warn!( + "top_k ({}) is greater than number of documents ({})", + k, + req.documents.len() + ); + } + } + Ok(()) +} + +impl RerankRequest { + /// Get the effective top_k value + pub fn effective_top_k(&self) -> usize { + self.top_k.unwrap_or(self.documents.len()) + } +} + +/// Individual rerank result +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RerankResult { + /// Relevance score for the document + pub score: f32, + + /// The document text (if return_documents was true) + #[serde(skip_serializing_if = "Option::is_none")] + pub document: Option, + + /// Original index of the document in the request + pub index: usize, + + /// Additional metadata about the ranking + #[serde(skip_serializing_if = "Option::is_none")] + pub meta_info: Option>, +} + +/// Rerank response containing sorted results +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RerankResponse { + /// Ranked results sorted by score (highest first) + pub results: Vec, + + /// Model used for reranking + pub model: String, + + /// Usage information + pub usage: Option, + + /// Response object type + #[serde(default = "default_rerank_object")] + pub object: String, + + /// Response ID + pub id: Option, + + /// Creation timestamp + pub created: i64, +} + +impl RerankResponse { + /// Create a new RerankResponse with the given results and model + pub fn new( + results: Vec, + model: String, + request_id: Option, + ) -> Self { + RerankResponse { + results, + model, + usage: None, + object: default_rerank_object(), + id: request_id, + created: current_timestamp(), + } + } + + /// Apply top_k limit to results + pub fn apply_top_k(&mut self, k: usize) { + self.results.truncate(k); + } + + /// Drop documents from results (when return_documents is false) + pub fn drop_documents(&mut self) { + for result in &mut self.results { + result.document = None; + } + } +} + +/// V1 API compatibility format for rerank requests +/// Matches Python's V1RerankReqInput +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct V1RerankReqInput { + pub query: String, + pub documents: Vec, +} + +/// Convert V1RerankReqInput to RerankRequest +impl From for RerankRequest { + fn from(v1: V1RerankReqInput) -> Self { + RerankRequest { + query: v1.query, + documents: v1.documents, + model: default_model(), + top_k: None, + return_documents: true, + rid: None, + user: None, + } + } +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/responses.rs b/sgl-model-gateway/vendor/openai-protocol/src/responses.rs new file mode 100644 index 000000000000..68f649f243c0 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/responses.rs @@ -0,0 +1,1298 @@ +// OpenAI Responses API types +// https://platform.openai.com/docs/api-reference/responses + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use validator::Validate; + +use super::{ + common::{ + default_model, default_true, validate_stop, ChatLogProbs, Function, GenerationRequest, + PromptTokenUsageInfo, StringOrArray, ToolChoice, ToolChoiceValue, ToolReference, UsageInfo, + }, + sampling_params::{validate_top_k_value, validate_top_p_value}, +}; +use crate::{builders::ResponsesResponseBuilder, validated::Normalizable}; + +// ============================================================================ +// Response Tools (MCP and others) +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ResponseTool { + #[serde(rename = "type")] + pub r#type: ResponseToolType, + // Function tool fields (used when type == "function") + // In Responses API, function fields are flattened at the top level + #[serde(flatten)] + #[serde(skip_serializing_if = "Option::is_none")] + pub function: Option, + // MCP-specific fields (used when type == "mcp") + #[serde(skip_serializing_if = "Option::is_none")] + pub server_url: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub authorization: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub server_label: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub server_description: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub require_approval: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub allowed_tools: Option>, +} + +impl Default for ResponseTool { + fn default() -> Self { + Self { + r#type: ResponseToolType::WebSearchPreview, + function: None, + server_url: None, + authorization: None, + server_label: None, + server_description: None, + require_approval: None, + allowed_tools: None, + } + } +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum ResponseToolType { + Function, + WebSearchPreview, + CodeInterpreter, + Mcp, +} + +// ============================================================================ +// Reasoning Parameters +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ResponseReasoningParam { + #[serde(default = "default_reasoning_effort")] + #[serde(skip_serializing_if = "Option::is_none")] + pub effort: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub summary: Option, +} + +fn default_reasoning_effort() -> Option { + Some(ReasoningEffort::Medium) +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum ReasoningEffort { + Minimal, + Low, + Medium, + High, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum ReasoningSummary { + Auto, + Concise, + Detailed, +} + +// ============================================================================ +// Input/Output Items +// ============================================================================ + +/// Content can be either a simple string or array of content parts (for SimpleInputMessage) +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum StringOrContentParts { + String(String), + Array(Vec), +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(tag = "type")] +#[serde(rename_all = "snake_case")] +pub enum ResponseInputOutputItem { + #[serde(rename = "message")] + Message { + id: String, + role: String, + content: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + status: Option, + }, + #[serde(rename = "reasoning")] + Reasoning { + id: String, + summary: Vec, + #[serde(skip_serializing_if = "Vec::is_empty")] + #[serde(default)] + content: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + status: Option, + }, + #[serde(rename = "function_call")] + FunctionToolCall { + id: String, + call_id: String, + name: String, + arguments: String, + #[serde(skip_serializing_if = "Option::is_none")] + output: Option, + #[serde(skip_serializing_if = "Option::is_none")] + status: Option, + }, + #[serde(rename = "function_call_output")] + FunctionCallOutput { + id: Option, + call_id: String, + output: String, + #[serde(skip_serializing_if = "Option::is_none")] + status: Option, + }, + #[serde(untagged)] + SimpleInputMessage { + content: StringOrContentParts, + role: String, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "type")] + r#type: Option, + }, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(tag = "type")] +#[serde(rename_all = "snake_case")] +pub enum ResponseContentPart { + #[serde(rename = "output_text")] + OutputText { + text: String, + #[serde(default)] + #[serde(skip_serializing_if = "Vec::is_empty")] + annotations: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + logprobs: Option, + }, + #[serde(rename = "input_text")] + InputText { text: String }, + #[serde(other)] + Unknown, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(tag = "type")] +#[serde(rename_all = "snake_case")] +pub enum ResponseReasoningContent { + #[serde(rename = "reasoning_text")] + ReasoningText { text: String }, +} + +/// MCP Tool information for the mcp_list_tools output item +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct McpToolInfo { + pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub description: Option, + pub input_schema: Value, + #[serde(skip_serializing_if = "Option::is_none")] + pub annotations: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(tag = "type")] +#[serde(rename_all = "snake_case")] +pub enum ResponseOutputItem { + #[serde(rename = "message")] + Message { + id: String, + role: String, + content: Vec, + status: String, + }, + #[serde(rename = "reasoning")] + Reasoning { + id: String, + summary: Vec, + content: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + status: Option, + }, + #[serde(rename = "function_call")] + FunctionToolCall { + id: String, + call_id: String, + name: String, + arguments: String, + #[serde(skip_serializing_if = "Option::is_none")] + output: Option, + status: String, + }, + #[serde(rename = "mcp_list_tools")] + McpListTools { + id: String, + server_label: String, + tools: Vec, + }, + #[serde(rename = "mcp_call")] + McpCall { + id: String, + status: String, + #[serde(skip_serializing_if = "Option::is_none")] + approval_request_id: Option, + arguments: String, + #[serde(skip_serializing_if = "Option::is_none")] + error: Option, + name: String, + output: String, + server_label: String, + }, +} + +// ============================================================================ +// Configuration Enums +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize, Default)] +#[serde(rename_all = "snake_case")] +pub enum ServiceTier { + #[default] + Auto, + Default, + Flex, + Scale, + Priority, +} + +#[derive(Debug, Clone, Deserialize, Serialize, Default)] +#[serde(rename_all = "snake_case")] +pub enum Truncation { + Auto, + #[default] + Disabled, +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum ResponseStatus { + Queued, + InProgress, + Completed, + Failed, + Cancelled, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ReasoningInfo { + #[serde(skip_serializing_if = "Option::is_none")] + pub effort: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub summary: Option, +} + +// ============================================================================ +// Text Format (structured outputs) +// ============================================================================ + +/// Text configuration for structured output requests +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct TextConfig { + #[serde(skip_serializing_if = "Option::is_none")] + pub format: Option, +} + +/// Text format: text (default), json_object (legacy), or json_schema (recommended) +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(tag = "type")] +pub enum TextFormat { + #[serde(rename = "text")] + Text, + + #[serde(rename = "json_object")] + JsonObject, + + #[serde(rename = "json_schema")] + JsonSchema { + name: String, + schema: Value, + #[serde(skip_serializing_if = "Option::is_none")] + description: Option, + #[serde(skip_serializing_if = "Option::is_none")] + strict: Option, + }, +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum IncludeField { + #[serde(rename = "code_interpreter_call.outputs")] + CodeInterpreterCallOutputs, + #[serde(rename = "computer_call_output.output.image_url")] + ComputerCallOutputImageUrl, + #[serde(rename = "file_search_call.results")] + FileSearchCallResults, + #[serde(rename = "message.input_image.image_url")] + MessageInputImageUrl, + #[serde(rename = "message.output_text.logprobs")] + MessageOutputTextLogprobs, + #[serde(rename = "reasoning.encrypted_content")] + ReasoningEncryptedContent, +} + +// ============================================================================ +// Usage Types (Responses API format) +// ============================================================================ + +/// OpenAI Responses API usage format (different from standard UsageInfo) +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ResponseUsage { + pub input_tokens: u32, + pub output_tokens: u32, + pub total_tokens: u32, + #[serde(skip_serializing_if = "Option::is_none")] + pub input_tokens_details: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub output_tokens_details: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ResponsesUsage { + Classic(UsageInfo), + Modern(ResponseUsage), +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct InputTokensDetails { + pub cached_tokens: u32, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct OutputTokensDetails { + pub reasoning_tokens: u32, +} + +impl UsageInfo { + /// Convert to OpenAI Responses API format + pub fn to_response_usage(&self) -> ResponseUsage { + ResponseUsage { + input_tokens: self.prompt_tokens, + output_tokens: self.completion_tokens, + total_tokens: self.total_tokens, + input_tokens_details: self.prompt_tokens_details.as_ref().map(|details| { + InputTokensDetails { + cached_tokens: details.cached_tokens, + } + }), + output_tokens_details: self.reasoning_tokens.map(|tokens| OutputTokensDetails { + reasoning_tokens: tokens, + }), + } + } +} + +impl From for ResponseUsage { + fn from(usage: UsageInfo) -> Self { + usage.to_response_usage() + } +} + +impl ResponseUsage { + /// Convert back to standard UsageInfo format + pub fn to_usage_info(&self) -> UsageInfo { + UsageInfo { + prompt_tokens: self.input_tokens, + completion_tokens: self.output_tokens, + total_tokens: self.total_tokens, + reasoning_tokens: self + .output_tokens_details + .as_ref() + .map(|details| details.reasoning_tokens), + prompt_tokens_details: self.input_tokens_details.as_ref().map(|details| { + PromptTokenUsageInfo { + cached_tokens: details.cached_tokens, + } + }), + } + } +} + +#[derive(Debug, Clone, Default, Deserialize, Serialize)] +pub struct ResponsesGetParams { + #[serde(default)] + pub include: Vec, + #[serde(default)] + pub include_obfuscation: Option, + #[serde(default)] + pub starting_after: Option, + #[serde(default)] + pub stream: Option, +} + +impl ResponsesUsage { + pub fn to_response_usage(&self) -> ResponseUsage { + match self { + ResponsesUsage::Classic(usage) => usage.to_response_usage(), + ResponsesUsage::Modern(usage) => usage.clone(), + } + } + + pub fn to_usage_info(&self) -> UsageInfo { + match self { + ResponsesUsage::Classic(usage) => usage.clone(), + ResponsesUsage::Modern(usage) => usage.to_usage_info(), + } + } +} + +// ============================================================================ +// Helper Functions for Defaults +// ============================================================================ + +fn default_top_k() -> i32 { + -1 +} + +fn default_repetition_penalty() -> f32 { + 1.0 +} + +fn default_temperature() -> Option { + Some(1.0) +} + +fn default_top_p() -> Option { + Some(1.0) +} + +// ============================================================================ +// Request/Response Types +// ============================================================================ + +#[derive(Debug, Clone, Deserialize, Serialize, Validate)] +#[validate(schema(function = "validate_responses_cross_parameters"))] +pub struct ResponsesRequest { + /// Run the request in the background + #[serde(skip_serializing_if = "Option::is_none")] + pub background: Option, + + /// Fields to include in the response + #[serde(skip_serializing_if = "Option::is_none")] + pub include: Option>, + + /// Input content - can be string or structured items + #[validate(custom(function = "validate_response_input"))] + pub input: ResponseInput, + + /// System instructions for the model + #[serde(skip_serializing_if = "Option::is_none")] + pub instructions: Option, + + /// Maximum number of output tokens + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 1))] + pub max_output_tokens: Option, + + /// Maximum number of tool calls + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 1))] + pub max_tool_calls: Option, + + /// Additional metadata + #[serde(skip_serializing_if = "Option::is_none")] + pub metadata: Option>, + + /// Model to use + #[serde(default = "default_model")] + pub model: String, + + /// Optional conversation id to persist input/output as items + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(custom(function = "validate_conversation_id"))] + pub conversation: Option, + + /// Whether to enable parallel tool calls + #[serde(skip_serializing_if = "Option::is_none")] + pub parallel_tool_calls: Option, + + /// ID of previous response to continue from + #[serde(skip_serializing_if = "Option::is_none")] + pub previous_response_id: Option, + + /// Reasoning configuration + #[serde(skip_serializing_if = "Option::is_none")] + pub reasoning: Option, + + /// Service tier + #[serde(skip_serializing_if = "Option::is_none")] + pub service_tier: Option, + + /// Whether to store the response + #[serde(skip_serializing_if = "Option::is_none")] + pub store: Option, + + /// Whether to stream the response + #[serde(default)] + pub stream: Option, + + /// Temperature for sampling + #[serde( + default = "default_temperature", + skip_serializing_if = "Option::is_none" + )] + #[validate(range(min = 0.0, max = 2.0))] + pub temperature: Option, + + /// Tool choice behavior + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_choice: Option, + + /// Available tools + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(custom(function = "validate_response_tools"))] + pub tools: Option>, + + /// Number of top logprobs to return + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 0, max = 20))] + pub top_logprobs: Option, + + /// Top-p sampling parameter + #[serde(default = "default_top_p", skip_serializing_if = "Option::is_none")] + #[validate(custom(function = "validate_top_p_value"))] + pub top_p: Option, + + /// Truncation behavior + #[serde(skip_serializing_if = "Option::is_none")] + pub truncation: Option, + + /// Text format for structured outputs (text, json_object, json_schema) + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(custom(function = "validate_text_format"))] + pub text: Option, + + /// User identifier + #[serde(skip_serializing_if = "Option::is_none")] + pub user: Option, + + /// Request ID + #[serde(skip_serializing_if = "Option::is_none")] + pub request_id: Option, + + /// Request priority + #[serde(default)] + pub priority: i32, + + /// Frequency penalty + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = -2.0, max = 2.0))] + pub frequency_penalty: Option, + + /// Presence penalty + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = -2.0, max = 2.0))] + pub presence_penalty: Option, + + /// Stop sequences + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(custom(function = "validate_stop"))] + pub stop: Option, + + /// Top-k sampling parameter (SGLang extension) + #[serde(default = "default_top_k")] + #[validate(custom(function = "validate_top_k_value"))] + pub top_k: i32, + + /// Min-p sampling parameter (SGLang extension) + #[serde(default)] + #[validate(range(min = 0.0, max = 1.0))] + pub min_p: f32, + + /// Repetition penalty (SGLang extension) + #[serde(default = "default_repetition_penalty")] + #[validate(range(min = 0.0, max = 2.0))] + pub repetition_penalty: f32, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ResponseInput { + Items(Vec), + Text(String), +} + +impl Default for ResponsesRequest { + fn default() -> Self { + Self { + background: None, + include: None, + input: ResponseInput::Text(String::new()), + instructions: None, + max_output_tokens: None, + max_tool_calls: None, + metadata: None, + model: default_model(), + conversation: None, + parallel_tool_calls: None, + previous_response_id: None, + reasoning: None, + service_tier: None, + store: None, + stream: None, + temperature: None, + tool_choice: None, + tools: None, + top_logprobs: None, + top_p: None, + truncation: None, + text: None, + user: None, + request_id: None, + priority: 0, + frequency_penalty: None, + presence_penalty: None, + stop: None, + top_k: default_top_k(), + min_p: 0.0, + repetition_penalty: default_repetition_penalty(), + } + } +} + +impl Normalizable for ResponsesRequest { + /// Normalize the request by applying defaults: + /// 1. Apply tool_choice defaults based on tools presence + /// 2. Apply parallel_tool_calls defaults + /// 3. Apply store field defaults + fn normalize(&mut self) { + // 1. Apply tool_choice defaults + if self.tool_choice.is_none() { + if let Some(tools) = &self.tools { + let choice_value = if !tools.is_empty() { + ToolChoiceValue::Auto + } else { + ToolChoiceValue::None + }; + self.tool_choice = Some(ToolChoice::Value(choice_value)); + } + // If tools is None, leave tool_choice as None (don't set it) + } + + // 2. Apply default for parallel_tool_calls if tools are present + if self.parallel_tool_calls.is_none() && self.tools.is_some() { + self.parallel_tool_calls = Some(true); + } + + // 3. Ensure store defaults to true if not specified + if self.store.is_none() { + self.store = Some(true); + } + } +} + +impl GenerationRequest for ResponsesRequest { + fn is_stream(&self) -> bool { + self.stream.unwrap_or(false) + } + + fn get_model(&self) -> Option<&str> { + Some(self.model.as_str()) + } + + fn extract_text_for_routing(&self) -> String { + match &self.input { + ResponseInput::Text(text) => text.clone(), + ResponseInput::Items(items) => items + .iter() + .filter_map(|item| match item { + ResponseInputOutputItem::Message { content, .. } => { + let texts: Vec = content + .iter() + .filter_map(|part| match part { + ResponseContentPart::OutputText { text, .. } => Some(text.clone()), + ResponseContentPart::InputText { text } => Some(text.clone()), + ResponseContentPart::Unknown => None, + }) + .collect(); + if texts.is_empty() { + None + } else { + Some(texts.join(" ")) + } + } + ResponseInputOutputItem::SimpleInputMessage { content, .. } => { + match content { + StringOrContentParts::String(s) => Some(s.clone()), + StringOrContentParts::Array(parts) => { + // SimpleInputMessage only supports InputText + let texts: Vec = parts + .iter() + .filter_map(|part| match part { + ResponseContentPart::InputText { text } => { + Some(text.clone()) + } + _ => None, + }) + .collect(); + if texts.is_empty() { + None + } else { + Some(texts.join(" ")) + } + } + } + } + ResponseInputOutputItem::Reasoning { content, .. } => { + let texts: Vec = content + .iter() + .map(|part| match part { + ResponseReasoningContent::ReasoningText { text } => text.clone(), + }) + .collect(); + if texts.is_empty() { + None + } else { + Some(texts.join(" ")) + } + } + ResponseInputOutputItem::FunctionToolCall { arguments, .. } => { + Some(arguments.clone()) + } + ResponseInputOutputItem::FunctionCallOutput { output, .. } => { + Some(output.clone()) + } + }) + .collect::>() + .join(" "), + } + } +} + +/// Validate conversation ID format +pub fn validate_conversation_id(conv_id: &str) -> Result<(), validator::ValidationError> { + if !conv_id.starts_with("conv_") { + let mut error = validator::ValidationError::new("invalid_conversation_id"); + error.message = Some(std::borrow::Cow::Owned(format!( + "Invalid 'conversation': '{}'. Expected an ID that begins with 'conv_'.", + conv_id + ))); + return Err(error); + } + + // Check if the conversation ID contains only valid characters + let is_valid = conv_id + .chars() + .all(|c| c.is_alphanumeric() || c == '_' || c == '-'); + + if !is_valid { + let mut error = validator::ValidationError::new("invalid_conversation_id"); + error.message = Some(std::borrow::Cow::Owned(format!( + "Invalid 'conversation': '{}'. Expected an ID that contains letters, numbers, underscores, or dashes, but this value contained additional characters.", + conv_id + ))); + return Err(error); + } + Ok(()) +} + +/// Validates tool_choice requires tools and references exist +fn validate_tool_choice_with_tools( + request: &ResponsesRequest, +) -> Result<(), validator::ValidationError> { + let Some(tool_choice) = &request.tool_choice else { + return Ok(()); + }; + + let has_tools = request.tools.as_ref().is_some_and(|t| !t.is_empty()); + let is_some_choice = !matches!(tool_choice, ToolChoice::Value(ToolChoiceValue::None)); + + // Check if tool_choice requires tools but none are provided + if is_some_choice && !has_tools { + let mut e = validator::ValidationError::new("tool_choice_requires_tools"); + e.message = Some("Invalid value for 'tool_choice': 'tool_choice' is only allowed when 'tools' are specified.".into()); + return Err(e); + } + + // Validate tool references exist when tools are present + if !has_tools { + return Ok(()); + } + + // Extract function tool names from ResponseTools + let tools = request.tools.as_ref().unwrap(); + let function_tool_names: Vec<&str> = tools + .iter() + .filter_map(|t| match t.r#type { + ResponseToolType::Function => t.function.as_ref().map(|f| f.name.as_str()), + _ => None, + }) + .collect(); + + // Validate tool references exist + match tool_choice { + ToolChoice::Function { function, .. } => { + if !function_tool_names.contains(&function.name.as_str()) { + let mut e = validator::ValidationError::new("tool_choice_function_not_found"); + e.message = Some( + format!( + "Invalid value for 'tool_choice': function '{}' not found in 'tools'.", + function.name + ) + .into(), + ); + return Err(e); + } + } + ToolChoice::AllowedTools { + mode, + tools: allowed_tools, + .. + } => { + // Validate mode is "auto" or "required" + if mode != "auto" && mode != "required" { + let mut e = validator::ValidationError::new("tool_choice_invalid_mode"); + e.message = Some( + format!( + "Invalid value for 'tool_choice.mode': must be 'auto' or 'required', got '{}'.", + mode + ) + .into(), + ); + return Err(e); + } + + // Validate that all function tool references exist + for tool_ref in allowed_tools { + if let ToolReference::Function { name } = tool_ref { + if !function_tool_names.contains(&name.as_str()) { + let mut e = validator::ValidationError::new("tool_choice_tool_not_found"); + e.message = Some( + format!( + "Invalid value for 'tool_choice.tools': tool '{}' not found in 'tools'.", + name + ) + .into(), + ); + return Err(e); + } + } + // Note: MCP and hosted tools don't need existence validation here + // as they are resolved dynamically at runtime + } + } + _ => {} + } + + Ok(()) +} + +/// Schema-level validation for cross-field dependencies +fn validate_responses_cross_parameters( + request: &ResponsesRequest, +) -> Result<(), validator::ValidationError> { + // 1. Validate tool_choice requires tools (enhanced) + validate_tool_choice_with_tools(request)?; + + // 2. Validate top_logprobs requires include field + if request.top_logprobs.is_some() { + let has_logprobs_include = request + .include + .as_ref() + .is_some_and(|inc| inc.contains(&IncludeField::MessageOutputTextLogprobs)); + + if !has_logprobs_include { + let mut e = validator::ValidationError::new("top_logprobs_requires_include"); + e.message = Some( + "top_logprobs requires include field with 'message.output_text.logprobs'".into(), + ); + return Err(e); + } + } + + // 3. Validate background/stream conflict + if request.background == Some(true) && request.stream == Some(true) { + let mut e = validator::ValidationError::new("background_conflicts_with_stream"); + e.message = Some("Cannot use background mode with streaming".into()); + return Err(e); + } + + // 4. Validate conversation and previous_response_id are mutually exclusive + if request.conversation.is_some() && request.previous_response_id.is_some() { + let mut e = validator::ValidationError::new("mutually_exclusive_parameters"); + e.message = Some("Mutually exclusive parameters. Ensure you are only providing one of: 'previous_response_id' or 'conversation'.".into()); + return Err(e); + } + + // 5. Validate input items structure + if let ResponseInput::Items(items) = &request.input { + // Check for at least one valid input message + let has_valid_input = items.iter().any(|item| { + matches!( + item, + ResponseInputOutputItem::Message { .. } + | ResponseInputOutputItem::SimpleInputMessage { .. } + ) + }); + + if !has_valid_input { + let mut e = validator::ValidationError::new("input_missing_user_message"); + e.message = Some("Input items must contain at least one message".into()); + return Err(e); + } + } + + // 6. Validate text format conflicts (for future structured output constraints) + // Currently, Responses API doesn't have regex/ebnf like Chat API, + // but this is here for completeness and future-proofing + + Ok(()) +} + +// ============================================================================ +// Field-Level Validation Functions +// ============================================================================ + +/// Validates response input is not empty and has valid content +fn validate_response_input(input: &ResponseInput) -> Result<(), validator::ValidationError> { + match input { + ResponseInput::Text(text) => { + if text.is_empty() { + let mut e = validator::ValidationError::new("input_text_empty"); + e.message = Some("Input text cannot be empty".into()); + return Err(e); + } + } + ResponseInput::Items(items) => { + if items.is_empty() { + let mut e = validator::ValidationError::new("input_items_empty"); + e.message = Some("Input items cannot be empty".into()); + return Err(e); + } + // Validate each item has valid content + for item in items { + validate_input_item(item)?; + } + } + } + Ok(()) +} + +/// Validates individual input items have valid content +fn validate_input_item(item: &ResponseInputOutputItem) -> Result<(), validator::ValidationError> { + match item { + ResponseInputOutputItem::Message { content, .. } => { + if content.is_empty() { + let mut e = validator::ValidationError::new("message_content_empty"); + e.message = Some("Message content cannot be empty".into()); + return Err(e); + } + } + ResponseInputOutputItem::SimpleInputMessage { content, .. } => match content { + StringOrContentParts::String(s) if s.is_empty() => { + let mut e = validator::ValidationError::new("message_content_empty"); + e.message = Some("Message content cannot be empty".into()); + return Err(e); + } + StringOrContentParts::Array(parts) if parts.is_empty() => { + let mut e = validator::ValidationError::new("message_content_empty"); + e.message = Some("Message content parts cannot be empty".into()); + return Err(e); + } + _ => {} + }, + ResponseInputOutputItem::Reasoning { .. } => { + // Reasoning content can be empty - no validation needed + } + ResponseInputOutputItem::FunctionCallOutput { output, .. } => { + if output.is_empty() { + let mut e = validator::ValidationError::new("function_output_empty"); + e.message = Some("Function call output cannot be empty".into()); + return Err(e); + } + } + _ => {} + } + Ok(()) +} + +/// Validates ResponseTool structure based on tool type +fn validate_response_tools(tools: &[ResponseTool]) -> Result<(), validator::ValidationError> { + for tool in tools { + match tool.r#type { + ResponseToolType::Function => { + if tool.function.is_none() { + let mut e = validator::ValidationError::new("function_tool_missing_function"); + e.message = Some("Function tool must have a function definition".into()); + return Err(e); + } + } + ResponseToolType::Mcp => { + if tool.server_url.is_none() { + let mut e = validator::ValidationError::new("mcp_tool_missing_server_url"); + e.message = Some("MCP tool must have a server_url".into()); + return Err(e); + } + } + _ => {} + } + } + Ok(()) +} + +/// Validates text format configuration (JSON schema name cannot be empty) +fn validate_text_format(text: &TextConfig) -> Result<(), validator::ValidationError> { + if let Some(TextFormat::JsonSchema { name, .. }) = &text.format { + if name.is_empty() { + let mut e = validator::ValidationError::new("json_schema_name_empty"); + e.message = Some("JSON schema name cannot be empty".into()); + return Err(e); + } + } + Ok(()) +} + +/// Normalize a SimpleInputMessage to a proper Message item +/// +/// This helper converts SimpleInputMessage (which can have flexible content) +/// into a fully-structured Message item with a generated ID, role, and content array. +/// +/// SimpleInputMessage items are converted to Message items with IDs generated using +/// the centralized ID generation pattern with "msg_" prefix for consistency. +/// +/// # Arguments +/// * `item` - The input item to normalize +/// +/// # Returns +/// A normalized ResponseInputOutputItem (either Message if converted, or original if not SimpleInputMessage) +pub fn normalize_input_item(item: &ResponseInputOutputItem) -> ResponseInputOutputItem { + match item { + ResponseInputOutputItem::SimpleInputMessage { content, role, .. } => { + let content_vec = match content { + StringOrContentParts::String(s) => { + vec![ResponseContentPart::InputText { text: s.clone() }] + } + StringOrContentParts::Array(parts) => parts.clone(), + }; + + ResponseInputOutputItem::Message { + id: generate_id("msg"), + role: role.clone(), + content: content_vec, + status: Some("completed".to_string()), + } + } + _ => item.clone(), + } +} + +pub fn generate_id(prefix: &str) -> String { + use rand::RngCore; + let mut rng = rand::rng(); + // Generate exactly 50 hex characters (25 bytes) for the part after the underscore + let mut bytes = [0u8; 25]; + rng.fill_bytes(&mut bytes); + let hex_string: String = bytes.iter().map(|b| format!("{:02x}", b)).collect(); + format!("{}_{}", prefix, hex_string) +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ResponsesResponse { + /// Response ID + pub id: String, + + /// Object type + #[serde(default = "default_object_type")] + pub object: String, + + /// Creation timestamp + pub created_at: i64, + + /// Response status + pub status: ResponseStatus, + + /// Error information if status is failed + #[serde(skip_serializing_if = "Option::is_none")] + pub error: Option, + + /// Incomplete details if response was truncated + #[serde(skip_serializing_if = "Option::is_none")] + pub incomplete_details: Option, + + /// System instructions used + #[serde(skip_serializing_if = "Option::is_none")] + pub instructions: Option, + + /// Max output tokens setting + #[serde(skip_serializing_if = "Option::is_none")] + pub max_output_tokens: Option, + + /// Model name + pub model: String, + + /// Output items + #[serde(default)] + pub output: Vec, + + /// Whether parallel tool calls are enabled + #[serde(default = "default_true")] + pub parallel_tool_calls: bool, + + /// Previous response ID if this is a continuation + #[serde(skip_serializing_if = "Option::is_none")] + pub previous_response_id: Option, + + /// Reasoning information + #[serde(skip_serializing_if = "Option::is_none")] + pub reasoning: Option, + + /// Whether the response is stored + #[serde(default = "default_true")] + pub store: bool, + + /// Temperature setting used + #[serde(skip_serializing_if = "Option::is_none")] + pub temperature: Option, + + /// Text format settings + #[serde(skip_serializing_if = "Option::is_none")] + pub text: Option, + + /// Tool choice setting + #[serde(default = "default_tool_choice")] + pub tool_choice: String, + + /// Available tools + #[serde(default)] + pub tools: Vec, + + /// Top-p setting used + #[serde(skip_serializing_if = "Option::is_none")] + pub top_p: Option, + + /// Truncation strategy used + #[serde(skip_serializing_if = "Option::is_none")] + pub truncation: Option, + + /// Usage information + #[serde(skip_serializing_if = "Option::is_none")] + pub usage: Option, + + /// User identifier + #[serde(skip_serializing_if = "Option::is_none")] + pub user: Option, + + /// Safety identifier for content moderation + #[serde(skip_serializing_if = "Option::is_none")] + pub safety_identifier: Option, + + /// Additional metadata + #[serde(default)] + pub metadata: HashMap, +} + +fn default_object_type() -> String { + "response".to_string() +} + +fn default_tool_choice() -> String { + "auto".to_string() +} + +impl ResponsesResponse { + /// Create a builder for constructing a ResponsesResponse + pub fn builder(id: impl Into, model: impl Into) -> ResponsesResponseBuilder { + ResponsesResponseBuilder::new(id, model) + } + + /// Check if the response is complete + pub fn is_complete(&self) -> bool { + matches!(self.status, ResponseStatus::Completed) + } + + /// Check if the response is in progress + pub fn is_in_progress(&self) -> bool { + matches!(self.status, ResponseStatus::InProgress) + } + + /// Check if the response failed + pub fn is_failed(&self) -> bool { + matches!(self.status, ResponseStatus::Failed) + } +} + +impl ResponseOutputItem { + /// Create a new message output item + pub fn new_message( + id: String, + role: String, + content: Vec, + status: String, + ) -> Self { + Self::Message { + id, + role, + content, + status, + } + } + + /// Create a new reasoning output item + pub fn new_reasoning( + id: String, + summary: Vec, + content: Vec, + status: Option, + ) -> Self { + Self::Reasoning { + id, + summary, + content, + status, + } + } + + /// Create a new function tool call output item + pub fn new_function_tool_call( + id: String, + call_id: String, + name: String, + arguments: String, + output: Option, + status: String, + ) -> Self { + Self::FunctionToolCall { + id, + call_id, + name, + arguments, + output, + status, + } + } +} + +impl ResponseContentPart { + /// Create a new text content part + pub fn new_text( + text: String, + annotations: Vec, + logprobs: Option, + ) -> Self { + Self::OutputText { + text, + annotations, + logprobs, + } + } +} + +impl ResponseReasoningContent { + /// Create a new reasoning text content + pub fn new_reasoning_text(text: String) -> Self { + Self::ReasoningText { text } + } +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/sampling_params.rs b/sgl-model-gateway/vendor/openai-protocol/src/sampling_params.rs new file mode 100644 index 000000000000..9055a53dd30c --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/sampling_params.rs @@ -0,0 +1,119 @@ +use serde::{Deserialize, Serialize}; +use validator::Validate; + +use super::common::StringOrArray; + +/// Sampling parameters for text generation +#[derive(Debug, Clone, Deserialize, Serialize, Default, Validate)] +#[validate(schema(function = "validate_sampling_params"))] +pub struct SamplingParams { + /// Temperature for sampling (must be >= 0.0, no upper limit) + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 0.0))] + pub temperature: Option, + /// Maximum number of new tokens to generate (must be >= 0) + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 0))] + pub max_new_tokens: Option, + /// Top-p nucleus sampling (0.0 < top_p <= 1.0) + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(custom(function = "validate_top_p_value"))] + pub top_p: Option, + /// Top-k sampling (-1 to disable, or >= 1) + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(custom(function = "validate_top_k_value"))] + pub top_k: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = -2.0, max = 2.0))] + pub frequency_penalty: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = -2.0, max = 2.0))] + pub presence_penalty: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 0.0, max = 2.0))] + pub repetition_penalty: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub stop: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub ignore_eos: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub skip_special_tokens: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub json_schema: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub regex: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub ebnf: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[validate(range(min = 0.0, max = 1.0))] + pub min_p: Option, + /// Minimum number of new tokens (validated in schema function for cross-field check with max_new_tokens) + #[serde(skip_serializing_if = "Option::is_none")] + pub min_new_tokens: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub stop_token_ids: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub no_stop_trim: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub n: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub sampling_seed: Option, +} + +// ============================================================================ +// Shared Validation Functions +// ============================================================================ + +/// Validates top_p: 0.0 < top_p <= 1.0 (can't use range validator for open interval) +pub fn validate_top_p_value(top_p: f32) -> Result<(), validator::ValidationError> { + if !(top_p > 0.0 && top_p <= 1.0) { + return Err(validator::ValidationError::new( + "top_p must be in (0, 1] - greater than 0.0 and at most 1.0", + )); + } + Ok(()) +} + +/// Validates top_k: -1 (disabled) or >= 1 (special -1 case - can't use range validator) +pub fn validate_top_k_value(top_k: i32) -> Result<(), validator::ValidationError> { + if top_k != -1 && top_k < 1 { + return Err(validator::ValidationError::new( + "top_k must be -1 (disabled) or at least 1", + )); + } + Ok(()) +} + +// ============================================================================ +// SamplingParams-Specific Validation +// ============================================================================ + +/// Validation function for SamplingParams - cross-field validation only +fn validate_sampling_params(params: &SamplingParams) -> Result<(), validator::ValidationError> { + // 1. Cross-field validation: min_new_tokens <= max_new_tokens + if let (Some(min), Some(max)) = (params.min_new_tokens, params.max_new_tokens) { + if min > max { + return Err(validator::ValidationError::new( + "min_new_tokens cannot exceed max_new_tokens", + )); + } + } + + // 2. Validate mutually exclusive structured output constraints + let constraint_count = [ + params.regex.is_some(), + params.ebnf.is_some(), + params.json_schema.is_some(), + ] + .iter() + .filter(|&&x| x) + .count(); + + if constraint_count > 1 { + return Err(validator::ValidationError::new( + "only one of regex, ebnf, or json_schema can be set", + )); + } + + Ok(()) +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/tokenize.rs b/sgl-model-gateway/vendor/openai-protocol/src/tokenize.rs new file mode 100644 index 000000000000..62a19c23bd8f --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/tokenize.rs @@ -0,0 +1,279 @@ +//! Tokenize and Detokenize API protocol types +//! +//! These types mirror the SGLang Python implementation for compatibility. +//! See: python/sglang/srt/entrypoints/openai/protocol.py + +use serde::{Deserialize, Serialize}; + +use super::UNKNOWN_MODEL_ID; + +// ============================================================================ +// Tokenize API +// ============================================================================ + +/// Request schema for the /v1/tokenize endpoint +/// +/// Supports both single string and batch tokenization. +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct TokenizeRequest { + /// Model name for tokenizer selection + #[serde(default = "default_model_name")] + pub model: String, + + /// Text(s) to tokenize - can be a single string or array of strings + pub prompt: StringOrArray, +} + +/// Response schema for the /v1/tokenize endpoint +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TokenizeResponse { + /// Token IDs - single list for single input, nested list for batch + pub tokens: TokensResult, + + /// Token count(s) - single int for single input, list for batch + pub count: CountResult, + + /// Character count(s) of input - single int for single input, list for batch + pub char_count: CountResult, +} + +/// Token IDs result - either single or batch +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum TokensResult { + Single(Vec), + Batch(Vec>), +} + +/// Count result - either single or batch +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CountResult { + Single(i32), + Batch(Vec), +} + +// ============================================================================ +// Detokenize API +// ============================================================================ + +/// Request schema for the /v1/detokenize endpoint +/// +/// Supports both single sequence and batch detokenization. +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct DetokenizeRequest { + /// Model name for tokenizer selection + #[serde(default = "default_model_name")] + pub model: String, + + /// Token IDs to detokenize - single list or batch (list of lists) + pub tokens: TokensInput, + + /// Whether to skip special tokens (e.g., padding or EOS) during decoding + #[serde(default = "default_true")] + pub skip_special_tokens: bool, +} + +/// Token input - either single sequence or batch +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum TokensInput { + /// Single sequence of token IDs + Single(Vec), + /// Batch of token sequences + Batch(Vec>), +} + +impl TokensInput { + /// Check if this is a batch input + pub fn is_batch(&self) -> bool { + matches!(self, TokensInput::Batch(_)) + } + + /// Get the sequences (always returns a vec of vecs for uniform processing) + pub fn sequences(&self) -> Vec<&[u32]> { + match self { + TokensInput::Single(seq) => vec![seq.as_slice()], + TokensInput::Batch(seqs) => seqs.iter().map(|s| s.as_slice()).collect(), + } + } +} + +/// Response schema for the /v1/detokenize endpoint +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DetokenizeResponse { + /// Decoded text - single string for single input, list for batch + pub text: TextResult, +} + +/// Text result - either single or batch +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum TextResult { + Single(String), + Batch(Vec), +} + +// ============================================================================ +// Tokenizer Management API +// ============================================================================ + +/// Request schema for adding a tokenizer +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct AddTokenizerRequest { + /// Name to register the tokenizer under + pub name: String, + + /// Source: either a local path or HuggingFace model ID + pub source: String, + + /// Optional path to chat template file + #[serde(skip_serializing_if = "Option::is_none")] + pub chat_template_path: Option, +} + +/// Response schema for adding a tokenizer (async) +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AddTokenizerResponse { + /// Unique identifier for the tokenizer (UUID) + pub id: String, + /// Status of the request: "pending", "processing", "completed", "failed" + pub status: String, + pub message: String, + /// Vocabulary size of the loaded tokenizer (only set on completion) + #[serde(skip_serializing_if = "Option::is_none")] + pub vocab_size: Option, +} + +/// Response schema for listing tokenizers +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ListTokenizersResponse { + pub tokenizers: Vec, +} + +/// Information about a registered tokenizer +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TokenizerInfo { + /// Unique identifier (UUID) + pub id: String, + /// User-provided name + pub name: String, + /// Source path or HuggingFace model ID + pub source: String, + pub vocab_size: usize, +} + +/// Request schema for removing a tokenizer +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct RemoveTokenizerRequest { + /// Name of the tokenizer to remove + pub name: String, +} + +/// Response schema for removing a tokenizer +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RemoveTokenizerResponse { + pub success: bool, + pub message: String, +} + +// ============================================================================ +// Helper Types +// ============================================================================ + +/// String or array of strings (for flexible input) +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum StringOrArray { + Single(String), + Array(Vec), +} + +impl StringOrArray { + /// Check if this is a batch (array) input + pub fn is_batch(&self) -> bool { + matches!(self, StringOrArray::Array(_)) + } + + /// Get all strings as a slice (converts single to vec) + pub fn as_strings(&self) -> Vec<&str> { + match self { + StringOrArray::Single(s) => vec![s.as_str()], + StringOrArray::Array(arr) => arr.iter().map(|s| s.as_str()).collect(), + } + } +} + +// ============================================================================ +// Default Functions +// ============================================================================ + +fn default_model_name() -> String { + UNKNOWN_MODEL_ID.to_string() +} + +fn default_true() -> bool { + true +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_tokenize_request_single() { + let json = r#"{"prompt": "Hello world"}"#; + let req: TokenizeRequest = serde_json::from_str(json).unwrap(); + assert_eq!(req.model, "unknown"); + assert!(matches!(req.prompt, StringOrArray::Single(_))); + } + + #[test] + fn test_tokenize_request_batch() { + let json = r#"{"model": "llama", "prompt": ["Hello", "World"]}"#; + let req: TokenizeRequest = serde_json::from_str(json).unwrap(); + assert_eq!(req.model, "llama"); + assert!(matches!(req.prompt, StringOrArray::Array(_))); + } + + #[test] + fn test_detokenize_request_single() { + let json = r#"{"tokens": [1, 2, 3]}"#; + let req: DetokenizeRequest = serde_json::from_str(json).unwrap(); + assert!(matches!(req.tokens, TokensInput::Single(_))); + assert!(req.skip_special_tokens); + } + + #[test] + fn test_detokenize_request_batch() { + let json = r#"{"tokens": [[1, 2], [3, 4, 5]], "skip_special_tokens": false}"#; + let req: DetokenizeRequest = serde_json::from_str(json).unwrap(); + assert!(matches!(req.tokens, TokensInput::Batch(_))); + assert!(!req.skip_special_tokens); + } + + #[test] + fn test_tokenize_response_single() { + let resp = TokenizeResponse { + tokens: TokensResult::Single(vec![1, 2, 3]), + count: CountResult::Single(3), + char_count: CountResult::Single(11), + }; + let json = serde_json::to_string(&resp).unwrap(); + assert!(json.contains("[1,2,3]")); + assert!(json.contains("\"count\":3")); + assert!(json.contains("\"char_count\":11")); + } + + #[test] + fn test_tokenize_response_batch() { + let resp = TokenizeResponse { + tokens: TokensResult::Batch(vec![vec![1, 2], vec![3, 4, 5]]), + count: CountResult::Batch(vec![2, 3]), + char_count: CountResult::Batch(vec![5, 5]), + }; + let json = serde_json::to_string(&resp).unwrap(); + assert!(json.contains("[[1,2],[3,4,5]]")); + assert!(json.contains("[2,3]")); + } +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/validated.rs b/sgl-model-gateway/vendor/openai-protocol/src/validated.rs new file mode 100644 index 000000000000..15c759f55ecc --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/validated.rs @@ -0,0 +1,172 @@ +// Validated JSON extractor for automatic request validation +// +// This module provides a ValidatedJson extractor that automatically validates +// requests using the validator crate's Validate trait. + +/// Trait for request types that need post-deserialization normalization +pub trait Normalizable { + /// Normalize the request by applying defaults and transformations + fn normalize(&mut self) { + // Default: no-op + } +} + +#[cfg(feature = "axum")] +use axum::{ + extract::{rejection::JsonRejection, FromRequest, Request}, + http::StatusCode, + response::{IntoResponse, Response}, + Json, +}; +#[cfg(feature = "axum")] +use serde::de::DeserializeOwned; +#[cfg(feature = "axum")] +use serde_json::json; +#[cfg(feature = "axum")] +use validator::Validate; + +/// A JSON extractor that automatically validates and normalizes the request body +/// +/// This extractor deserializes the request body and automatically calls `.validate()` +/// on types that implement the `Validate` trait. If validation fails, it returns +/// a 400 Bad Request with detailed error information. +/// +/// # Example +/// +/// ```rust,ignore +/// async fn create_chat( +/// ValidatedJson(request): ValidatedJson, +/// ) -> Response { +/// // request is guaranteed to be valid here +/// process_request(request).await +/// } +/// ``` +#[cfg(feature = "axum")] +pub struct ValidatedJson(pub T); + +#[cfg(feature = "axum")] +impl FromRequest for ValidatedJson +where + T: DeserializeOwned + Validate + Normalizable + Send, + S: Send + Sync, +{ + type Rejection = Response; + + async fn from_request(req: Request, state: &S) -> Result { + // First, extract and deserialize the JSON + let Json(mut data) = + Json::::from_request(req, state) + .await + .map_err(|err: JsonRejection| { + let error_message = match err { + JsonRejection::JsonDataError(e) => { + format!("Invalid JSON data: {}", e) + } + JsonRejection::JsonSyntaxError(e) => { + format!("JSON syntax error: {}", e) + } + JsonRejection::MissingJsonContentType(_) => { + "Missing Content-Type: application/json header".to_string() + } + _ => format!("Failed to parse JSON: {}", err), + }; + + ( + StatusCode::BAD_REQUEST, + Json(json!({ + "error": { + "message": error_message, + "type": "invalid_request_error", + "code": "json_parse_error" + } + })), + ) + .into_response() + })?; + + // Normalize the request (apply defaults based on other fields) + data.normalize(); + + // Then, automatically validate the data + data.validate().map_err(|validation_errors| { + ( + StatusCode::BAD_REQUEST, + Json(json!({ + "error": { + "message": validation_errors.to_string(), + "type": "invalid_request_error", + "code": 400 + } + })), + ) + .into_response() + })?; + + Ok(ValidatedJson(data)) + } +} + +// Implement Deref to allow transparent access to the inner value +#[cfg(feature = "axum")] +impl std::ops::Deref for ValidatedJson { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[cfg(feature = "axum")] +impl std::ops::DerefMut for ValidatedJson { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[cfg(all(test, feature = "axum"))] +mod tests { + use serde::{Deserialize, Serialize}; + use validator::Validate; + + use super::*; + + #[derive(Debug, Deserialize, Serialize, Validate)] + struct TestRequest { + #[validate(range(min = 0.0, max = 1.0))] + value: f32, + #[validate(length(min = 1))] + name: String, + } + + impl Normalizable for TestRequest { + // Use default no-op implementation + } + + #[tokio::test] + async fn test_validated_json_valid() { + // This test is conceptual - actual testing would require Axum test harness + let request = TestRequest { + value: 0.5, + name: "test".to_string(), + }; + assert!(request.validate().is_ok()); + } + + #[tokio::test] + async fn test_validated_json_invalid_range() { + let request = TestRequest { + value: 1.5, // Out of range + name: "test".to_string(), + }; + assert!(request.validate().is_err()); + } + + #[tokio::test] + async fn test_validated_json_invalid_length() { + let request = TestRequest { + value: 0.5, + name: "".to_string(), // Empty name + }; + assert!(request.validate().is_err()); + } +} diff --git a/sgl-model-gateway/vendor/openai-protocol/src/worker_spec.rs b/sgl-model-gateway/vendor/openai-protocol/src/worker_spec.rs new file mode 100644 index 000000000000..230a0f1ffcc1 --- /dev/null +++ b/sgl-model-gateway/vendor/openai-protocol/src/worker_spec.rs @@ -0,0 +1,469 @@ +//! Worker management API specifications +//! +//! Defines the request/response structures for worker management endpoints + +use std::collections::HashMap; + +#[cfg(feature = "axum")] +use axum::{ + http::StatusCode, + response::{IntoResponse, Response}, + Json, +}; +use serde::{Deserialize, Serialize}; +#[cfg(feature = "axum")] +use serde_json::{json, Value}; + +use super::UNKNOWN_MODEL_ID; + +/// Worker configuration for API requests +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct WorkerConfigRequest { + /// Worker URL (required) + pub url: String, + + /// Worker API key (optional) + #[serde(skip_serializing_if = "Option::is_none")] + pub api_key: Option, + + /// Model ID (optional, will query from server if not provided) + #[serde(skip_serializing_if = "Option::is_none")] + pub model_id: Option, + + /// Worker priority (optional, default: 50, higher = preferred) + #[serde(skip_serializing_if = "Option::is_none")] + pub priority: Option, + + /// Worker cost factor (optional, default: 1.0) + #[serde(skip_serializing_if = "Option::is_none")] + pub cost: Option, + + /// Worker type (optional: "regular", "prefill", "decode") + #[serde(skip_serializing_if = "Option::is_none")] + pub worker_type: Option, + + /// Bootstrap port for prefill workers (optional) + #[serde(skip_serializing_if = "Option::is_none")] + pub bootstrap_port: Option, + + /// Runtime type (optional: "sglang", "vllm", default: "sglang") + /// Only relevant for gRPC workers + #[serde(skip_serializing_if = "Option::is_none")] + pub runtime: Option, + + // gRPC-specific configuration (optional, ignored in HTTP mode) + /// Tokenizer path for gRPC mode + #[serde(skip_serializing_if = "Option::is_none")] + pub tokenizer_path: Option, + + /// Reasoning parser type for gRPC mode + #[serde(skip_serializing_if = "Option::is_none")] + pub reasoning_parser: Option, + + /// Tool parser type for gRPC mode + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_parser: Option, + + /// Chat template for gRPC mode + #[serde(skip_serializing_if = "Option::is_none")] + pub chat_template: Option, + + /// Additional labels (optional) + #[serde(default, skip_serializing_if = "HashMap::is_empty")] + pub labels: HashMap, + + /// Health check timeout in seconds (default: 30) + #[serde(default = "default_health_check_timeout")] + pub health_check_timeout_secs: u64, + + /// Health check interval in seconds (default: 60) + #[serde(default = "default_health_check_interval")] + pub health_check_interval_secs: u64, + + /// Number of successful health checks needed to mark worker as healthy (default: 2) + #[serde(default = "default_health_success_threshold")] + pub health_success_threshold: u32, + + /// Number of failed health checks before marking worker as unhealthy (default: 3) + #[serde(default = "default_health_failure_threshold")] + pub health_failure_threshold: u32, + + /// Disable periodic health checks for this worker (default: false) + #[serde(default)] + pub disable_health_check: bool, + + /// Maximum connection attempts during worker registration (default: 20) + #[serde(default = "default_max_connection_attempts")] + pub max_connection_attempts: u32, + + /// Enable data parallelism aware scheduling (default: false) + #[serde(default)] + pub dp_aware: bool, +} + +// Default value functions for serde +fn default_health_check_timeout() -> u64 { + 30 +} + +fn default_health_check_interval() -> u64 { + 60 +} + +fn default_health_success_threshold() -> u32 { + 2 +} + +fn default_health_failure_threshold() -> u32 { + 3 +} + +fn default_max_connection_attempts() -> u32 { + 20 +} + +/// Worker information for API responses +#[derive(Debug, Clone, Serialize)] +pub struct WorkerInfo { + /// Worker unique identifier + pub id: String, + + /// Worker URL + pub url: String, + + /// Model ID this worker serves + pub model_id: String, + + /// Worker priority + pub priority: u32, + + /// Worker cost factor + pub cost: f32, + + /// Worker type + pub worker_type: String, + + /// Whether the worker is healthy + pub is_healthy: bool, + + /// Current load on the worker + pub load: usize, + + /// Connection mode (http or grpc) + pub connection_mode: String, + + /// Runtime type (sglang or vllm, for gRPC workers) + #[serde(skip_serializing_if = "Option::is_none")] + pub runtime_type: Option, + + // gRPC-specific fields (None for HTTP workers) + #[serde(skip_serializing_if = "Option::is_none")] + pub tokenizer_path: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub reasoning_parser: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_parser: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub chat_template: Option, + + /// Bootstrap port for prefill workers + #[serde(skip_serializing_if = "Option::is_none")] + pub bootstrap_port: Option, + + /// Additional metadata + #[serde(skip_serializing_if = "HashMap::is_empty")] + pub metadata: HashMap, + + /// Whether health checks are disabled for this worker + pub disable_health_check: bool, + + /// Job status for async operations (if available) + #[serde(skip_serializing_if = "Option::is_none")] + pub job_status: Option, +} + +impl WorkerInfo { + /// Create a partial WorkerInfo for pending workers (not yet registered). + /// Used when a worker ID maps to a URL but the worker is still being registered. + pub fn pending(worker_id: &str, url: String, job_status: Option) -> Self { + Self { + id: worker_id.to_string(), + url, + model_id: UNKNOWN_MODEL_ID.to_string(), + priority: 0, + cost: 1.0, + worker_type: UNKNOWN_MODEL_ID.to_string(), + is_healthy: false, + load: 0, + connection_mode: UNKNOWN_MODEL_ID.to_string(), + runtime_type: None, + tokenizer_path: None, + reasoning_parser: None, + tool_parser: None, + chat_template: None, + bootstrap_port: None, + metadata: HashMap::new(), + disable_health_check: false, + job_status, + } + } +} + +/// Job status for async control plane operations +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct JobStatus { + pub job_type: String, + pub worker_url: String, + pub status: String, + pub message: Option, + pub timestamp: u64, +} + +impl JobStatus { + /// Create a pending job status + pub fn pending(job_type: &str, worker_url: &str) -> Self { + Self { + job_type: job_type.to_string(), + worker_url: worker_url.to_string(), + status: "pending".to_string(), + message: None, + timestamp: std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), + } + } + + /// Create a processing job status + pub fn processing(job_type: &str, worker_url: &str) -> Self { + Self { + job_type: job_type.to_string(), + worker_url: worker_url.to_string(), + status: "processing".to_string(), + message: None, + timestamp: std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), + } + } + + /// Create a failed job status + pub fn failed(job_type: &str, worker_url: &str, error: String) -> Self { + Self { + job_type: job_type.to_string(), + worker_url: worker_url.to_string(), + status: "failed".to_string(), + message: Some(error), + timestamp: std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(), + } + } +} + +/// Worker list response +#[derive(Debug, Clone, Serialize)] +pub struct WorkerListResponse { + /// List of workers + pub workers: Vec, + + /// Total count + pub total: usize, + + /// Statistics + pub stats: WorkerStats, +} + +/// Worker statistics +#[derive(Debug, Clone, Serialize)] +pub struct WorkerStats { + pub total_workers: usize, + pub healthy_workers: usize, + pub total_models: usize, + pub total_load: usize, + pub by_type: WorkerTypeStats, +} + +/// Worker statistics by type +#[derive(Debug, Clone, Serialize)] +pub struct WorkerTypeStats { + pub regular: usize, + pub prefill: usize, + pub decode: usize, +} + +/// Worker update request +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WorkerUpdateRequest { + /// Update priority + #[serde(skip_serializing_if = "Option::is_none")] + pub priority: Option, + + /// Update cost + #[serde(skip_serializing_if = "Option::is_none")] + pub cost: Option, + + /// Update labels + #[serde(skip_serializing_if = "Option::is_none")] + pub labels: Option>, + + /// Update API key (for key rotation) + #[serde(skip_serializing_if = "Option::is_none")] + pub api_key: Option, + + /// Update health check timeout in seconds + #[serde(skip_serializing_if = "Option::is_none")] + pub health_check_timeout_secs: Option, + + /// Update health check interval in seconds + #[serde(skip_serializing_if = "Option::is_none")] + pub health_check_interval_secs: Option, + + /// Update health success threshold + #[serde(skip_serializing_if = "Option::is_none")] + pub health_success_threshold: Option, + + /// Update health failure threshold + #[serde(skip_serializing_if = "Option::is_none")] + pub health_failure_threshold: Option, + + /// Disable periodic health checks for this worker + #[serde(skip_serializing_if = "Option::is_none")] + pub disable_health_check: Option, +} + +/// Generic API response +#[derive(Debug, Clone, Serialize)] +pub struct WorkerApiResponse { + pub success: bool, + pub message: String, + + #[serde(skip_serializing_if = "Option::is_none")] + pub worker: Option, +} + +/// Error response +#[derive(Debug, Clone, Serialize)] +pub struct WorkerErrorResponse { + pub error: String, + pub code: String, +} + +/// Server info response from /get_server_info endpoint +#[derive(Debug, Clone, Deserialize)] +pub struct ServerInfo { + #[serde(skip_serializing_if = "Option::is_none")] + pub model_id: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub model_path: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub priority: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub cost: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub worker_type: Option, + + // gRPC-specific + #[serde(skip_serializing_if = "Option::is_none")] + pub tokenizer_path: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub reasoning_parser: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub tool_parser: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub chat_template: Option, +} + +/// Result from flush cache operations across workers +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct FlushCacheResult { + /// URLs of workers where cache flush succeeded + pub successful: Vec, + /// URLs and error messages for workers where cache flush failed + pub failed: Vec<(String, String)>, + /// Total number of workers attempted + pub total_workers: usize, + /// Number of HTTP workers (gRPC workers don't support flush cache) + pub http_workers: usize, + /// Human-readable summary message + pub message: String, +} + +/// Result from getting worker loads +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct WorkerLoadsResult { + /// Worker URL and load pairs + pub loads: Vec, + /// Total number of workers + pub total_workers: usize, + /// Number of workers with successful load fetches + pub successful: usize, + /// Number of workers with failed load fetches + pub failed: usize, +} + +/// Individual worker load information +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct WorkerLoadInfo { + /// Worker URL + pub worker: String, + /// Worker type (regular, prefill, decode) + #[serde(skip_serializing_if = "Option::is_none")] + pub worker_type: Option, + /// Current load (-1 indicates failure to fetch) + pub load: isize, +} + +#[cfg(feature = "axum")] +impl IntoResponse for FlushCacheResult { + fn into_response(self) -> Response { + let status = if self.failed.is_empty() { + StatusCode::OK + } else { + StatusCode::PARTIAL_CONTENT + }; + + let mut body = json!({ + "status": if self.failed.is_empty() { "success" } else { "partial_success" }, + "message": self.message, + "workers_flushed": self.successful.len(), + "total_http_workers": self.http_workers, + "total_workers": self.total_workers + }); + + if !self.failed.is_empty() { + body["successful"] = json!(self.successful); + body["failed"] = json!(self + .failed + .into_iter() + .map(|(url, err)| json!({"worker": url, "error": err})) + .collect::>()); + } + + (status, Json(body)).into_response() + } +} + +#[cfg(feature = "axum")] +impl IntoResponse for WorkerLoadsResult { + fn into_response(self) -> Response { + let loads: Vec = self + .loads + .iter() + .map(|info| json!({"worker": &info.worker, "load": info.load})) + .collect(); + Json(json!({"workers": loads})).into_response() + } +}