mirror of
https://github.com/RightNow-AI/openfang.git
synced 2026-08-14 08:52:02 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acf2587e46 | ||
|
|
4583157b49 | ||
|
|
7185ea8808 |
Generated
+90
-90
@@ -139,7 +139,7 @@ version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -150,7 +150,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -893,7 +893,7 @@ version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1029,27 +1029,27 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-assembler-x64"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "046d4b584c3bb9b5eb500c8f29549bec36be11000f1ba2a927cef3d1a9875691"
|
||||
checksum = "adc822414b18d1f5b1b33ce1441534e311e62fef86ebb5b9d382af857d0272c9"
|
||||
dependencies = [
|
||||
"cranelift-assembler-x64-meta",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-assembler-x64-meta"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9b194a7870becb1490366fc0ae392ccd188065ff35f8391e77ac659db6fb977"
|
||||
checksum = "8c646808b06f4532478d8d6057d74f15c3322f10d995d9486e7dcea405bf521a"
|
||||
dependencies = [
|
||||
"cranelift-srcgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb6a4ab44c6b371e661846b97dab687387a60ac4e2f864e2d4257284aad9e889"
|
||||
checksum = "7b5996f01a686b2349cdb379083ec5ad3e8cb8767fb2d495d3a4f2ee4163a18d"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
"wasmtime-internal-core",
|
||||
@@ -1057,9 +1057,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bitset"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8b7a44150c2f471a94023482bda1902710746e4bed9f9973d60c5a94319b06d"
|
||||
checksum = "523fea83273f6a985520f57788809a4de2165794d9ab00fb1254fceb4f5aa00c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@@ -1068,9 +1068,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01b06598133b1dd76758b8b95f8d6747c124124aade50cea96a3d88b962da9fa"
|
||||
checksum = "d73d1e372730b5f64ed1a2bd9f01fe4686c8ec14a28034e3084e530c8d951878"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"cranelift-assembler-x64",
|
||||
@@ -1096,9 +1096,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6190e2e7bcf0a678da2f715363d34ed530fedf7a2f0ab75edaefef72a70465ff"
|
||||
checksum = "b0319c18165e93dc1ebf78946a8da0b1c341c95b4a39729a69574671639bdb5f"
|
||||
dependencies = [
|
||||
"cranelift-assembler-x64-meta",
|
||||
"cranelift-codegen-shared",
|
||||
@@ -1109,24 +1109,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f583cf203d1aa8b79560e3b01f929bdacf9070b015eec4ea9c46e22a3f83e4a0"
|
||||
checksum = "9195cd8aeecb55e401aa96b2eaa55921636e8246c127ed7908f7ef7e0d40f270"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-control"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "803159df35cc398ae54473c150b16d6c77e92ab2948be638488de126a3328fbc"
|
||||
checksum = "8976c2154b74136322befc74222ab5c7249edd7e2604f8cbef2b94975541ffb9"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3109e417257082d88087f5bcce677525bdaa8322b88dd7f175ed1a1fd41d546c"
|
||||
checksum = "6038b3147c7982f4951150d5f96c7c06c1e7214b99d4b4a98607aadf8ded89d1"
|
||||
dependencies = [
|
||||
"cranelift-bitset",
|
||||
"serde",
|
||||
@@ -1136,9 +1136,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14db6b0e0e4994c581092df78d837be2072578f7cb2528f96a6cf895e56dee63"
|
||||
checksum = "4cbd294abe236e23cc3d907b0936226b6a8342db7636daa9c7c72be1e323420e"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
@@ -1148,15 +1148,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-isle"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec66ea5025c7317383699778282ac98741d68444f956e3b1d7b62f12b7216e67"
|
||||
checksum = "b5a90b6ed3aba84189352a87badeb93b2126d3724225a42dc67fdce53d1b139c"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "373ade56438e6232619d85678477d0a88a31b3581936e0503e61e96b546b0800"
|
||||
checksum = "c3ec0cc1a54e22925eacf4fc3dc815f907734d3b377899d19d52bec04863e853"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"libc",
|
||||
@@ -1165,9 +1165,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-srcgen"
|
||||
version = "0.130.1"
|
||||
version = "0.130.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef53619d3cd5c78fd998c6d9420547af26b72e6456f94c2a8a2334cb76b42baa"
|
||||
checksum = "948865622f87f30907bb46fbb081b235ae63c1896a99a83c26a003305c1fa82d"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
@@ -1555,7 +1555,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.5.2",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1805,7 +1805,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3739,7 +3739,7 @@ version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3959,7 +3959,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-api"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"argon2",
|
||||
"async-trait",
|
||||
@@ -4001,7 +4001,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-channels"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"async-trait",
|
||||
@@ -4040,7 +4040,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-cli"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"clap_complete",
|
||||
@@ -4068,7 +4068,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-desktop"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"open",
|
||||
@@ -4094,7 +4094,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-extensions"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"argon2",
|
||||
@@ -4122,7 +4122,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-hands"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dashmap",
|
||||
@@ -4142,7 +4142,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-kernel"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -4182,7 +4182,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-memory"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -4202,7 +4202,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-migrate"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dirs 6.0.0",
|
||||
@@ -4221,7 +4221,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-runtime"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4257,7 +4257,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-skills"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"ed25519-dalek",
|
||||
@@ -4282,7 +4282,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-types"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bitflags 2.11.0",
|
||||
@@ -4302,7 +4302,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-wire"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -4399,7 +4399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5024,7 +5024,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
"itertools 0.13.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
@@ -5032,9 +5032,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pulley-interpreter"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "010dec3755eb61b2f1051ecb3611b718460b7a74c131e474de2af20a845938af"
|
||||
checksum = "7ec12fe19a9588315a49fe5704502a9c02d6a198303314b0c7c86123b06d29e5"
|
||||
dependencies = [
|
||||
"cranelift-bitset",
|
||||
"log",
|
||||
@@ -5044,9 +5044,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pulley-macros"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad360c32e85ca4b083ac0e2b6856e8f11c3d5060dafa7d5dc57b370857fa3018"
|
||||
checksum = "36f7d5ef31ebf1b46cd7e722ffef934e670d7e462f49aa01cde07b9b76dca580"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -5709,7 +5709,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.12.1",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5768,7 +5768,7 @@ dependencies = [
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"webpki-root-certs",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5779,9 +5779,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
|
||||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.103.10"
|
||||
version = "0.103.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
|
||||
checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
|
||||
dependencies = [
|
||||
"aws-lc-rs",
|
||||
"ring",
|
||||
@@ -6314,7 +6314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7050,7 +7050,7 @@ dependencies = [
|
||||
"getrandom 0.4.2",
|
||||
"once_cell",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7622,7 +7622,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
|
||||
dependencies = [
|
||||
"memoffset",
|
||||
"tempfile",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8066,9 +8066,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce205cd643d661b5ba5ba4717e13730262e8cdbc8f2eacbc7b906d45c1a74026"
|
||||
checksum = "efb1ed5899dde98357cfdcf647a4614498798719793898245b4b34e663addabf"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"async-trait",
|
||||
@@ -8119,9 +8119,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-environ"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b8b78abf3677d4a0a5db82e5015b4d085ff3a1b8b472cbb8c70d4b769f019ce"
|
||||
checksum = "4172382dcc785c31d0e862c6780a18f5dd437914d22c4691351f965ef751c821"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cpp_demangle",
|
||||
@@ -8150,9 +8150,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-cache"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e4fd4103ba413c0da2e636f73490c6c8e446d708cbde7573703941bc3d6a448"
|
||||
checksum = "4ed398988226d7aa0505ac6bb576e09532ad722d702ec4e66365d78ed695c95f"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"directories-next",
|
||||
@@ -8170,9 +8170,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-component-macro"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d3d6914f34be2f9d78d8ee9f422e834dfc204e71ccce697205fae95fed87892"
|
||||
checksum = "ae5ec9fff073ff13b81732d56a9515d761c245750bcda09093827f84130ebc25"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
@@ -8185,15 +8185,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-component-util"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3751b0616b914fdd87fe1bf804694a078f321b000338e6476bc48a4d6e454f21"
|
||||
checksum = "935d9ab293ba27d1ec9aa7bc1b3a43993dbe961af2a8f23f90a11e1331b4c13f"
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-core"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22632b187e1b0716f1b9ac57ad29013bed33175fcb19e10bb6896126f82fac67"
|
||||
checksum = "9a3820b174f477d2a7083209d1ad5353fcdb11eaea434b2137b8681029460dd3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hashbrown 0.16.1",
|
||||
@@ -8203,9 +8203,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-cranelift"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b3ca07b3e0bb3429674b173b5800577719d600774dd81bff58f775c0aaa64ee"
|
||||
checksum = "d1679d205caf9766c6aa309d45bb3e7c634d7725e3164404df33824b9f7c4fb7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cranelift-codegen",
|
||||
@@ -8230,9 +8230,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-fiber"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20c8b2c9704eb1f33ead025ec16038277ccb63d0a14c31e99d5b765d7c36da55"
|
||||
checksum = "f1e505254058be5b0df458d670ee42d9eafe2349d04c1296e9dc01071dc20a85"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
@@ -8245,9 +8245,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-jit-debug"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d950310d07391d34369f62c48336ebb14eacbd4d6f772bb5f349c24e838e0664"
|
||||
checksum = "1c2e05b345f1773e59c20e6ad7298fd6857cdea245023d88bb659c96d8f0ea72"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"object",
|
||||
@@ -8257,9 +8257,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-jit-icache-coherence"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3606662c156962d096be3127b8b8ae8ee2f8be3f896dad29259ff01ddb64abfd"
|
||||
checksum = "b86701b234a4643e3f111869aa792b3a05a06e02d486ee9cb6c04dae16b52dab"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -8269,9 +8269,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-unwinder"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75eef0747e52dc545b075f64fd0e0cc237ae738e641266b1970e07e2d744bc32"
|
||||
checksum = "f63558d801beb83dde9b336eb4ae049019aee26627926edb32cd119d7e4c83cd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cranelift-codegen",
|
||||
@@ -8282,9 +8282,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-versioned-export-macros"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b0a5dab02a8fb527f547855ecc0e05f9fdc3d5bd57b8b080349408f9a6cece"
|
||||
checksum = "737c4d956fc3a848541a064afb683dd2771132a6b125be5baaf95c4379aa47df"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -8293,9 +8293,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-winch"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8007342bd12ff400293a817973f7ecd6f1d9a8549a53369a9c1af357166f1f1e"
|
||||
checksum = "f599b79545e3bba0b7913406055ebede5bb0dabee9ba2015ef25a9f4c9f47807"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"gimli",
|
||||
@@ -8310,9 +8310,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-wit-bindgen"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7900c3e3c1d6e475bc225d73b02d6d5484815f260022e6964dca9558e50dd01a"
|
||||
checksum = "2192a77a00b9a67800c2b4e1c70fb6abca79d6b529e53a2ef9dcdcc36090330d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitflags 2.11.0",
|
||||
@@ -8495,7 +8495,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8506,9 +8506,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "winch-codegen"
|
||||
version = "43.0.1"
|
||||
version = "43.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb9f45f7172a2628c8317766e427babc0a400f9d10b1c0f0b0617c5ed5b79de6"
|
||||
checksum = "52dbb0cf07b0dfe7b7a1ca8efb8f94ba98bd0fb144c411ea1665c78f0449e958"
|
||||
dependencies = [
|
||||
"cranelift-assembler-x64",
|
||||
"cranelift-codegen",
|
||||
@@ -9236,7 +9236,7 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0 OR MIT"
|
||||
repository = "https://github.com/RightNow-AI/openfang"
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/language-Rust-orange?style=flat-square" alt="Rust" />
|
||||
<img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="MIT" />
|
||||
<img src="https://img.shields.io/badge/version-0.6.8-green?style=flat-square" alt="v0.6.8" />
|
||||
<img src="https://img.shields.io/badge/tests-2,669%2B%20passing-brightgreen?style=flat-square" alt="Tests" />
|
||||
<img src="https://img.shields.io/badge/version-0.6.9-green?style=flat-square" alt="v0.6.9" />
|
||||
<img src="https://img.shields.io/badge/tests-2,696%2B%20passing-brightgreen?style=flat-square" alt="Tests" />
|
||||
<img src="https://img.shields.io/badge/clippy-0%20warnings-brightgreen?style=flat-square" alt="Clippy" />
|
||||
<a href="https://www.buymeacoffee.com/openfang" target="_blank"><img src="https://img.shields.io/badge/Buy%20Me%20a%20Coffee-FFDD00?style=flat-square&logo=buy-me-a-coffee&logoColor=black" alt="Buy Me A Coffee" /></a>
|
||||
</p>
|
||||
|
||||
@@ -3856,7 +3856,10 @@ pub async fn audit_append(
|
||||
};
|
||||
let outcome = req.outcome.clone().unwrap_or_else(|| "ok".to_string());
|
||||
|
||||
let hash = state.kernel.audit_log.record(agent_id, action, detail, outcome);
|
||||
let hash = state
|
||||
.kernel
|
||||
.audit_log
|
||||
.record(agent_id, action, detail, outcome);
|
||||
let seq = state.kernel.audit_log.len().saturating_sub(1) as u64;
|
||||
|
||||
(
|
||||
@@ -10063,7 +10066,9 @@ pub async fn clone_agent(
|
||||
Err(e) => {
|
||||
return (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(serde_json::json!({"error": format!("Failed to serialize manifest: {e}")})),
|
||||
Json(
|
||||
serde_json::json!({"error": format!("Failed to serialize manifest: {e}")}),
|
||||
),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -10240,7 +10245,12 @@ pub async fn list_agent_files(
|
||||
// Identity files live in the agent's private state directory (see #1097).
|
||||
// Fall back to the legacy workspace location for agents created before the
|
||||
// split so existing on-disk files remain reachable.
|
||||
let workspace = match entry.manifest.state_dir.as_ref().or(entry.manifest.workspace.as_ref()) {
|
||||
let workspace = match entry
|
||||
.manifest
|
||||
.state_dir
|
||||
.as_ref()
|
||||
.or(entry.manifest.workspace.as_ref())
|
||||
{
|
||||
Some(ws) => ws.clone(),
|
||||
None => {
|
||||
return (
|
||||
|
||||
@@ -167,8 +167,7 @@ mod tests {
|
||||
fn skill_install_request_defaults_back_compat() {
|
||||
// Existing callers send `{"name": "..."}` only. New optional fields
|
||||
// must default cleanly (issue #1170).
|
||||
let req: SkillInstallRequest =
|
||||
serde_json::from_str(r#"{"name":"github-helper"}"#).unwrap();
|
||||
let req: SkillInstallRequest = serde_json::from_str(r#"{"name":"github-helper"}"#).unwrap();
|
||||
assert_eq!(req.name, "github-helper");
|
||||
assert!(!req.require_signed);
|
||||
assert!(req.allowed_signer_keys.is_empty());
|
||||
|
||||
@@ -1048,7 +1048,9 @@ async fn handle_command(
|
||||
"command": cmd,
|
||||
"message": format!("Hand '{}' deactivated.", instance.hand_id),
|
||||
}),
|
||||
Err(e) => serde_json::json!({"type": "error", "content": format!("Stop failed: {e}")}),
|
||||
Err(e) => {
|
||||
serde_json::json!({"type": "error", "content": format!("Stop failed: {e}")})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match state.kernel.stop_agent_run(agent_id) {
|
||||
@@ -1058,7 +1060,9 @@ async fn handle_command(
|
||||
Ok(false) => {
|
||||
serde_json::json!({"type": "command_result", "command": cmd, "message": "No active run to cancel."})
|
||||
}
|
||||
Err(e) => serde_json::json!({"type": "error", "content": format!("Stop failed: {e}")}),
|
||||
Err(e) => {
|
||||
serde_json::json!({"type": "error", "content": format!("Stop failed: {e}")})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1812,10 +1816,7 @@ mod tests {
|
||||
// Cookie signed with the wrong secret must fail.
|
||||
let bad = crate::session_auth::create_session_token("alice", "other-secret", 1);
|
||||
let mut headers = axum::http::HeaderMap::new();
|
||||
headers.insert(
|
||||
"cookie",
|
||||
format!("openfang_session={bad}").parse().unwrap(),
|
||||
);
|
||||
headers.insert("cookie", format!("openfang_session={bad}").parse().unwrap());
|
||||
let uri = empty_uri();
|
||||
let ctx = WsAuthCtx {
|
||||
api_key: "secret",
|
||||
|
||||
@@ -1660,10 +1660,7 @@ async fn test_clone_agent_happy_path() {
|
||||
assert_eq!(manifest["description"], "Cloned for user 1");
|
||||
assert_eq!(
|
||||
manifest["tags"].as_array().unwrap(),
|
||||
&vec![
|
||||
serde_json::json!("clone"),
|
||||
serde_json::json!("user-1"),
|
||||
]
|
||||
&vec![serde_json::json!("clone"), serde_json::json!("user-1"),]
|
||||
);
|
||||
// Inherited from template — the system_prompt should match.
|
||||
assert_eq!(
|
||||
@@ -1678,10 +1675,7 @@ async fn test_clone_agent_happy_path() {
|
||||
.await
|
||||
.unwrap();
|
||||
let agents: Vec<serde_json::Value> = resp.json().await.unwrap();
|
||||
let names: Vec<&str> = agents
|
||||
.iter()
|
||||
.map(|a| a["name"].as_str().unwrap())
|
||||
.collect();
|
||||
let names: Vec<&str> = agents.iter().map(|a| a["name"].as_str().unwrap()).collect();
|
||||
assert!(names.contains(&"test-agent"));
|
||||
assert!(names.contains(&"cloned-user-1"));
|
||||
}
|
||||
@@ -1731,10 +1725,7 @@ async fn test_clone_agent_name_collision() {
|
||||
"duplicate name must return 409 Conflict"
|
||||
);
|
||||
let body: serde_json::Value = resp.json().await.unwrap();
|
||||
assert!(body["error"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains("already exists"));
|
||||
assert!(body["error"].as_str().unwrap().contains("already exists"));
|
||||
|
||||
// Cloning into the template's own name must also be rejected.
|
||||
let resp = client
|
||||
|
||||
@@ -144,8 +144,7 @@ impl MatrixAdapter {
|
||||
&& status == reqwest::StatusCode::UNAUTHORIZED
|
||||
&& is_unknown_token_body(&body_text)
|
||||
{
|
||||
match try_refresh_tokens(&self.client, &self.homeserver_url, &self.tokens)
|
||||
.await
|
||||
match try_refresh_tokens(&self.client, &self.homeserver_url, &self.tokens).await
|
||||
{
|
||||
Ok(()) => {
|
||||
info!("Matrix: access token refreshed via MSC2918, retrying send");
|
||||
@@ -717,7 +716,8 @@ mod tests {
|
||||
#[test]
|
||||
fn test_is_unknown_token_body() {
|
||||
// Real matrix.org body for M_UNKNOWN_TOKEN under MAS.
|
||||
let body = r#"{"errcode":"M_UNKNOWN_TOKEN","error":"Token is not active","soft_logout":true}"#;
|
||||
let body =
|
||||
r#"{"errcode":"M_UNKNOWN_TOKEN","error":"Token is not active","soft_logout":true}"#;
|
||||
assert!(is_unknown_token_body(body));
|
||||
assert!(!is_hard_logout(body));
|
||||
|
||||
@@ -740,19 +740,17 @@ mod tests {
|
||||
// access and refresh tokens and returns the new pair.
|
||||
use axum::{routing::post, Json, Router};
|
||||
|
||||
async fn refresh_handler(
|
||||
Json(body): Json<serde_json::Value>,
|
||||
) -> Json<serde_json::Value> {
|
||||
let incoming = body
|
||||
.get("refresh_token")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
assert_eq!(incoming, "old_refresh");
|
||||
Json(serde_json::json!({
|
||||
"access_token": "new_access",
|
||||
"refresh_token": "new_refresh",
|
||||
"expires_in_ms": 3_600_000u64,
|
||||
}))
|
||||
async fn refresh_handler(Json(body): Json<serde_json::Value>) -> Json<serde_json::Value> {
|
||||
let incoming = body
|
||||
.get("refresh_token")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("");
|
||||
assert_eq!(incoming, "old_refresh");
|
||||
Json(serde_json::json!({
|
||||
"access_token": "new_access",
|
||||
"refresh_token": "new_refresh",
|
||||
"expires_in_ms": 3_600_000u64,
|
||||
}))
|
||||
}
|
||||
|
||||
let app = Router::new().route("/_matrix/client/v3/refresh", post(refresh_handler));
|
||||
@@ -779,10 +777,7 @@ mod tests {
|
||||
drop(guard);
|
||||
|
||||
// Refresh with no refresh token configured must fail cleanly.
|
||||
let no_refresh: TokenPair = Arc::new(RwLock::new((
|
||||
Zeroizing::new("a".to_string()),
|
||||
None,
|
||||
)));
|
||||
let no_refresh: TokenPair = Arc::new(RwLock::new((Zeroizing::new("a".to_string()), None)));
|
||||
let err = try_refresh_tokens(&client, &homeserver, &no_refresh)
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
@@ -722,7 +722,8 @@ mod tests {
|
||||
assert_eq!(resolved, None);
|
||||
|
||||
// Missing channel_id on the wire — no match (the binding is restrictive).
|
||||
let resolved = router.resolve_with_channel_id(&ChannelType::Discord, "any-user", None, None);
|
||||
let resolved =
|
||||
router.resolve_with_channel_id(&ChannelType::Discord, "any-user", None, None);
|
||||
assert_eq!(resolved, None);
|
||||
}
|
||||
|
||||
|
||||
@@ -329,9 +329,7 @@ impl ChannelAdapter for SlackAdapter {
|
||||
// connection during the rotation overlap. Ack on
|
||||
// both, but only forward to the agent once.
|
||||
if is_duplicate_envelope(&seen_envelopes, envelope_id) {
|
||||
debug!(
|
||||
"Slack: skipping duplicate envelope_id {envelope_id}"
|
||||
);
|
||||
debug!("Slack: skipping duplicate envelope_id {envelope_id}");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1234,9 +1234,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(msg.channel, ChannelType::Telegram);
|
||||
assert_eq!(msg.sender.display_name, "Alice Smith");
|
||||
assert_eq!(msg.sender.platform_id, "111222333");
|
||||
@@ -1267,9 +1275,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// The chat_id (used for replies) stays on sender.platform_id.
|
||||
assert_eq!(msg.sender.platform_id, "-1009876543210");
|
||||
@@ -1308,9 +1324,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let tg_id = msg
|
||||
.metadata
|
||||
@@ -1345,9 +1369,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
match &msg.content {
|
||||
ChannelContent::Command { name, args } => {
|
||||
assert_eq!(name, "agent");
|
||||
@@ -1379,8 +1411,16 @@ mod tests {
|
||||
let client = test_client();
|
||||
|
||||
// Empty allowed_users = allow all
|
||||
let msg =
|
||||
parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new()).await;
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await;
|
||||
assert!(msg.is_some());
|
||||
|
||||
// Non-matching allowed_users = filter out
|
||||
@@ -1434,9 +1474,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(msg.channel, ChannelType::Telegram);
|
||||
assert_eq!(msg.sender.display_name, "Alice Smith");
|
||||
assert!(matches!(msg.content, ChannelContent::Text(ref t) if t == "Edited message!"));
|
||||
@@ -1472,9 +1520,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
match &msg.content {
|
||||
ChannelContent::Command { name, args } => {
|
||||
assert_eq!(name, "agents");
|
||||
@@ -1498,9 +1554,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(matches!(msg.content, ChannelContent::Location { .. }));
|
||||
}
|
||||
|
||||
@@ -1524,9 +1588,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
// With a fake token, getFile will fail, so we get a text fallback
|
||||
match &msg.content {
|
||||
ChannelContent::Text(t) => {
|
||||
@@ -1561,9 +1633,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
match &msg.content {
|
||||
ChannelContent::Text(t) => {
|
||||
assert!(t.contains("Document received"));
|
||||
@@ -1594,9 +1674,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
match &msg.content {
|
||||
ChannelContent::Text(t) => {
|
||||
assert!(t.contains("Voice message"));
|
||||
@@ -1627,9 +1715,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(msg.thread_id, Some("42".to_string()));
|
||||
assert!(msg.is_group);
|
||||
}
|
||||
@@ -1649,9 +1745,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(msg.thread_id, None);
|
||||
assert!(!msg.is_group);
|
||||
}
|
||||
@@ -1673,9 +1777,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(msg.thread_id, Some("99".to_string()));
|
||||
}
|
||||
|
||||
@@ -1871,9 +1983,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(msg.sender.display_name, "My Channel");
|
||||
assert_eq!(msg.sender.platform_id, "-1001234567890");
|
||||
assert!(
|
||||
@@ -1895,8 +2015,16 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg =
|
||||
parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new()).await;
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await;
|
||||
assert!(msg.is_none());
|
||||
}
|
||||
|
||||
@@ -2162,9 +2290,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
match &msg.content {
|
||||
ChannelContent::Text(t) => {
|
||||
assert!(t.starts_with("[Replying to Bob: We should use Rust]\n\n"));
|
||||
@@ -2204,9 +2340,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
match &msg.content {
|
||||
ChannelContent::Text(t) => {
|
||||
assert!(t.starts_with("[Replying to Carol: Sunset view]\n\n"));
|
||||
@@ -2245,9 +2389,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
match &msg.content {
|
||||
ChannelContent::Text(t) => {
|
||||
assert_eq!(t, "What was that?");
|
||||
@@ -2283,9 +2435,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
match &msg.content {
|
||||
ChannelContent::Text(t) => {
|
||||
assert!(t.starts_with("[Replying to Unknown: Anonymous message]\n\n"));
|
||||
@@ -2310,9 +2470,17 @@ mod tests {
|
||||
});
|
||||
|
||||
let client = test_client();
|
||||
let msg = parse_telegram_update(&update, &[], "fake:token", &client, DEFAULT_API_URL, None, &HashMap::new())
|
||||
.await
|
||||
.unwrap();
|
||||
let msg = parse_telegram_update(
|
||||
&update,
|
||||
&[],
|
||||
"fake:token",
|
||||
&client,
|
||||
DEFAULT_API_URL,
|
||||
None,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
match &msg.content {
|
||||
ChannelContent::Text(t) => {
|
||||
assert_eq!(t, "Just a normal message");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "OpenFang",
|
||||
"version": "0.6.8",
|
||||
"version": "0.6.9",
|
||||
"identifier": "ai.openfang.desktop",
|
||||
"build": {},
|
||||
"app": {
|
||||
|
||||
@@ -1086,11 +1086,10 @@ impl OpenFangKernel {
|
||||
openfang_runtime::media_understanding::MediaEngine::new(config.media.clone());
|
||||
// Closes #1051: thread MediaConfig URL overrides into the TTS engine
|
||||
// so local OpenAI/ElevenLabs-compatible services can be targeted.
|
||||
let tts_engine = openfang_runtime::tts::TtsEngine::new(config.tts.clone())
|
||||
.with_base_urls(
|
||||
config.media.tts_openai_base_url.clone(),
|
||||
config.media.tts_elevenlabs_base_url.clone(),
|
||||
);
|
||||
let tts_engine = openfang_runtime::tts::TtsEngine::new(config.tts.clone()).with_base_urls(
|
||||
config.media.tts_openai_base_url.clone(),
|
||||
config.media.tts_elevenlabs_base_url.clone(),
|
||||
);
|
||||
let mut pairing = crate::pairing::PairingManager::new(config.pairing.clone());
|
||||
|
||||
// Load paired devices from database and set up persistence callback
|
||||
@@ -1246,16 +1245,16 @@ impl OpenFangKernel {
|
||||
}
|
||||
|
||||
let audit_log_for_cb = Arc::clone(&kernel.audit_log);
|
||||
kernel.hand_registry.set_audit_callback(Arc::new(
|
||||
move |hand_id: &str, hash: &str| {
|
||||
kernel
|
||||
.hand_registry
|
||||
.set_audit_callback(Arc::new(move |hand_id: &str, hash: &str| {
|
||||
audit_log_for_cb.record(
|
||||
"kernel",
|
||||
openfang_runtime::audit::AuditAction::ConfigChange,
|
||||
format!("HAND.toml reload hand={hand_id} sha256={hash}"),
|
||||
"ok",
|
||||
);
|
||||
},
|
||||
));
|
||||
}));
|
||||
}
|
||||
|
||||
// Restore persisted agents from SQLite
|
||||
@@ -1541,9 +1540,7 @@ impl OpenFangKernel {
|
||||
}
|
||||
}
|
||||
if auto_spawned > 0 {
|
||||
info!(
|
||||
"Auto-spawned {auto_spawned} agent(s) from ~/.openfang/agents"
|
||||
);
|
||||
info!("Auto-spawned {auto_spawned} agent(s) from ~/.openfang/agents");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1705,7 +1702,10 @@ impl OpenFangKernel {
|
||||
// does not specify one. When the user sets `workspace = "/path"` in
|
||||
// agent.toml we leave that path alone — only data/, output/, skills/
|
||||
// get created lazily so private state never pollutes the target dir.
|
||||
let workspace_dir = manifest.workspace.clone().unwrap_or_else(|| state_dir.clone());
|
||||
let workspace_dir = manifest
|
||||
.workspace
|
||||
.clone()
|
||||
.unwrap_or_else(|| state_dir.clone());
|
||||
ensure_state_dir(&state_dir, &workspace_dir)?;
|
||||
ensure_workspace(&workspace_dir)?;
|
||||
if manifest.generate_identity_files {
|
||||
@@ -2127,7 +2127,10 @@ impl OpenFangKernel {
|
||||
// to the same path unless the manifest already pinned one. See #1097.
|
||||
if manifest.state_dir.is_none() {
|
||||
let state_dir = self.config.effective_workspaces_dir().join(&manifest.name);
|
||||
let workspace_dir = manifest.workspace.clone().unwrap_or_else(|| state_dir.clone());
|
||||
let workspace_dir = manifest
|
||||
.workspace
|
||||
.clone()
|
||||
.unwrap_or_else(|| state_dir.clone());
|
||||
if let Err(e) = ensure_state_dir(&state_dir, &workspace_dir) {
|
||||
warn!(agent_id = %agent_id, "Failed to backfill state_dir (streaming): {e}");
|
||||
}
|
||||
@@ -2699,7 +2702,10 @@ impl OpenFangKernel {
|
||||
// state_dir). See issue #1097.
|
||||
if manifest.state_dir.is_none() {
|
||||
let state_dir = self.config.effective_workspaces_dir().join(&manifest.name);
|
||||
let workspace_dir = manifest.workspace.clone().unwrap_or_else(|| state_dir.clone());
|
||||
let workspace_dir = manifest
|
||||
.workspace
|
||||
.clone()
|
||||
.unwrap_or_else(|| state_dir.clone());
|
||||
if let Err(e) = ensure_state_dir(&state_dir, &workspace_dir) {
|
||||
warn!(agent_id = %agent_id, "Failed to backfill state_dir: {e}");
|
||||
}
|
||||
@@ -5511,9 +5517,7 @@ impl OpenFangKernel {
|
||||
}
|
||||
for var in skill.manifest.config.values() {
|
||||
if let Some(env_name) = var.env.as_deref() {
|
||||
if let Some(providers) =
|
||||
env_to_provider.get(&env_name.to_ascii_uppercase())
|
||||
{
|
||||
if let Some(providers) = env_to_provider.get(&env_name.to_ascii_uppercase()) {
|
||||
for provider in providers {
|
||||
set.insert(provider.clone());
|
||||
}
|
||||
@@ -5528,9 +5532,7 @@ impl OpenFangKernel {
|
||||
// wired that provider into their MCP server.
|
||||
for server in &self.config.mcp_servers {
|
||||
for env_name in &server.env {
|
||||
if let Some(providers) =
|
||||
env_to_provider.get(&env_name.to_ascii_uppercase())
|
||||
{
|
||||
if let Some(providers) = env_to_provider.get(&env_name.to_ascii_uppercase()) {
|
||||
for provider in providers {
|
||||
set.insert(provider.clone());
|
||||
}
|
||||
@@ -8022,8 +8024,7 @@ mod tests {
|
||||
|
||||
assert_eq!(merged.description, "new", "TOML edits must apply");
|
||||
assert_eq!(
|
||||
merged.workspace,
|
||||
entry.workspace,
|
||||
merged.workspace, entry.workspace,
|
||||
"kernel-assigned workspace must survive a TOML edit that omits it"
|
||||
);
|
||||
assert!(
|
||||
@@ -8438,9 +8439,7 @@ mod tests {
|
||||
let first_instance_id = instance.instance_id;
|
||||
|
||||
// Sanity: hand is Active and re-activation is rejected.
|
||||
assert!(kernel
|
||||
.activate_hand("lead", HashMap::new(), None)
|
||||
.is_err());
|
||||
assert!(kernel.activate_hand("lead", HashMap::new(), None).is_err());
|
||||
|
||||
// Simulate what POST /api/agents/{id}/stop now does for a hand-owned
|
||||
// agent: look up the instance and deactivate the hand (which also
|
||||
@@ -8880,7 +8879,8 @@ mod tests {
|
||||
"fallback timeout edits must be hot-reloadable"
|
||||
);
|
||||
assert!(
|
||||
plan.hot_actions.contains(&HotAction::ReloadFallbackProviders),
|
||||
plan.hot_actions
|
||||
.contains(&HotAction::ReloadFallbackProviders),
|
||||
"ReloadFallbackProviders must be present in the plan"
|
||||
);
|
||||
|
||||
@@ -9160,9 +9160,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_1188_referenced_providers_walks_mcp_env() {
|
||||
use openfang_types::config::{
|
||||
DefaultModelConfig, McpServerConfigEntry, McpTransportEntry,
|
||||
};
|
||||
use openfang_types::config::{DefaultModelConfig, McpServerConfigEntry, McpTransportEntry};
|
||||
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let home_dir = tmp.path().join("openfang-1188-mcp");
|
||||
|
||||
@@ -69,8 +69,7 @@ fn env_timeout_secs(var: &str) -> Option<u64> {
|
||||
fn tool_timeout_for(tool_name: &str) -> Option<Duration> {
|
||||
let secs = match tool_name {
|
||||
"agent_send" | "agent_spawn" => {
|
||||
env_timeout_secs("OPENFANG_AGENT_TOOL_TIMEOUT_SECS")
|
||||
.unwrap_or(AGENT_TOOL_TIMEOUT_SECS)
|
||||
env_timeout_secs("OPENFANG_AGENT_TOOL_TIMEOUT_SECS").unwrap_or(AGENT_TOOL_TIMEOUT_SECS)
|
||||
}
|
||||
_ => env_timeout_secs("OPENFANG_TOOL_TIMEOUT_SECS").unwrap_or(TOOL_TIMEOUT_SECS),
|
||||
};
|
||||
@@ -3271,7 +3270,9 @@ mod tests {
|
||||
assert_eq!(blocks.len(), 2, "must preserve thinking + text");
|
||||
match &blocks[0] {
|
||||
ContentBlock::Thinking {
|
||||
thinking, signature, ..
|
||||
thinking,
|
||||
signature,
|
||||
..
|
||||
} => {
|
||||
assert_eq!(thinking, "Let me reason carefully...");
|
||||
assert_eq!(signature.as_deref(), Some("sig_anthropic_xyz"));
|
||||
@@ -3367,7 +3368,10 @@ mod tests {
|
||||
let has_redacted = blocks
|
||||
.iter()
|
||||
.any(|b| matches!(b, ContentBlock::RedactedThinking { .. }));
|
||||
assert!(has_thinking, "Thinking block must be preserved on MaxTokens");
|
||||
assert!(
|
||||
has_thinking,
|
||||
"Thinking block must be preserved on MaxTokens"
|
||||
);
|
||||
assert!(
|
||||
has_redacted,
|
||||
"RedactedThinking block must be preserved on MaxTokens"
|
||||
@@ -3409,9 +3413,9 @@ mod tests {
|
||||
MessageContent::Blocks(b) => b,
|
||||
other => panic!("expected Blocks content for redacted-only turn, got {other:?}"),
|
||||
};
|
||||
let has_redacted = blocks
|
||||
.iter()
|
||||
.any(|b| matches!(b, ContentBlock::RedactedThinking { data } if data == "encrypted_only"));
|
||||
let has_redacted = blocks.iter().any(
|
||||
|b| matches!(b, ContentBlock::RedactedThinking { data } if data == "encrypted_only"),
|
||||
);
|
||||
assert!(
|
||||
has_redacted,
|
||||
"RedactedThinking-only turn must be preserved as Blocks"
|
||||
|
||||
@@ -189,7 +189,9 @@ enum ContentBlockAccum {
|
||||
/// Redacted (encrypted) thinking block streamed from Anthropic.
|
||||
/// The opaque `data` blob arrives on `content_block_start` and must be
|
||||
/// persisted so the next turn can echo it back verbatim.
|
||||
RedactedThinking { data: String },
|
||||
RedactedThinking {
|
||||
data: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -454,10 +456,8 @@ impl LlmDriver for AnthropicDriver {
|
||||
"thinking" => {
|
||||
// Some API versions ship the signature on
|
||||
// content_block_start instead of as a delta.
|
||||
let initial_sig = block["signature"]
|
||||
.as_str()
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
let initial_sig =
|
||||
block["signature"].as_str().unwrap_or("").to_string();
|
||||
blocks.push(ContentBlockAccum::Thinking {
|
||||
thinking: String::new(),
|
||||
signature: initial_sig,
|
||||
@@ -470,10 +470,7 @@ impl LlmDriver for AnthropicDriver {
|
||||
// verbatim so we can echo it back on the
|
||||
// next request — API rejects history
|
||||
// that strips redacted_thinking blocks.
|
||||
let data = block["data"]
|
||||
.as_str()
|
||||
.unwrap_or("")
|
||||
.to_string();
|
||||
let data = block["data"].as_str().unwrap_or("").to_string();
|
||||
blocks.push(ContentBlockAccum::RedactedThinking { data });
|
||||
}
|
||||
_ => {}
|
||||
@@ -751,9 +748,7 @@ fn convert_message(msg: &Message) -> ApiMessage {
|
||||
if data.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(ApiContentBlock::RedactedThinking {
|
||||
data: data.clone(),
|
||||
})
|
||||
Some(ApiContentBlock::RedactedThinking { data: data.clone() })
|
||||
}
|
||||
}
|
||||
ContentBlock::Unknown => None,
|
||||
|
||||
@@ -328,9 +328,7 @@ fn convert_content_block(block: &ContentBlock) -> Option<BedrockContentBlock> {
|
||||
}
|
||||
}
|
||||
// Image, Thinking, and Unknown are not supported — silently drop
|
||||
ContentBlock::Image { .. }
|
||||
| ContentBlock::Thinking { .. }
|
||||
| ContentBlock::Unknown => None,
|
||||
ContentBlock::Image { .. } | ContentBlock::Thinking { .. } | ContentBlock::Unknown => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ use openfang_types::model_catalog::{
|
||||
HUGGINGFACE_BASE_URL, KIMI_CODING_BASE_URL, LEMONADE_BASE_URL, LMSTUDIO_BASE_URL,
|
||||
MINIMAX_BASE_URL, MISTRAL_BASE_URL, MOONSHOT_BASE_URL, NOVITA_BASE_URL, NVIDIA_NIM_BASE_URL,
|
||||
OLLAMA_BASE_URL, OPENAI_BASE_URL, OPENROUTER_BASE_URL, PERPLEXITY_BASE_URL, QIANFAN_BASE_URL,
|
||||
QWEN_BASE_URL, REPLICATE_BASE_URL, REQUESTY_BASE_URL, SAMBANOVA_BASE_URL, TOGETHER_BASE_URL, VENICE_BASE_URL,
|
||||
VLLM_BASE_URL, VOLCENGINE_BASE_URL, VOLCENGINE_CODING_BASE_URL, XAI_BASE_URL, ZAI_BASE_URL,
|
||||
ZAI_CODING_BASE_URL, ZHIPU_BASE_URL, ZHIPU_CODING_BASE_URL,
|
||||
QWEN_BASE_URL, REPLICATE_BASE_URL, REQUESTY_BASE_URL, SAMBANOVA_BASE_URL, TOGETHER_BASE_URL,
|
||||
VENICE_BASE_URL, VLLM_BASE_URL, VOLCENGINE_BASE_URL, VOLCENGINE_CODING_BASE_URL, XAI_BASE_URL,
|
||||
ZAI_BASE_URL, ZAI_CODING_BASE_URL, ZHIPU_BASE_URL, ZHIPU_CODING_BASE_URL,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
@@ -460,8 +460,8 @@ impl LlmDriver for OpenAIDriver {
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
reasoning_content: None,
|
||||
reasoning: None,
|
||||
});
|
||||
reasoning: None,
|
||||
});
|
||||
}
|
||||
|
||||
// Convert messages
|
||||
@@ -474,8 +474,8 @@ impl LlmDriver for OpenAIDriver {
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
reasoning_content: None,
|
||||
reasoning: None,
|
||||
});
|
||||
reasoning: None,
|
||||
});
|
||||
}
|
||||
(Role::User, MessageContent::Text(text)) => {
|
||||
oai_messages.push(OaiMessage {
|
||||
@@ -484,8 +484,8 @@ impl LlmDriver for OpenAIDriver {
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
reasoning_content: None,
|
||||
reasoning: None,
|
||||
});
|
||||
reasoning: None,
|
||||
});
|
||||
}
|
||||
(Role::Assistant, MessageContent::Text(text)) => {
|
||||
oai_messages.push(OaiMessage {
|
||||
@@ -494,8 +494,8 @@ impl LlmDriver for OpenAIDriver {
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
reasoning_content: None,
|
||||
reasoning: None,
|
||||
});
|
||||
reasoning: None,
|
||||
});
|
||||
}
|
||||
(Role::User, MessageContent::Blocks(blocks)) => {
|
||||
// Handle tool results and images in user messages
|
||||
@@ -519,8 +519,8 @@ impl LlmDriver for OpenAIDriver {
|
||||
tool_calls: None,
|
||||
tool_call_id: Some(tool_use_id.clone()),
|
||||
reasoning_content: None,
|
||||
reasoning: None,
|
||||
});
|
||||
reasoning: None,
|
||||
});
|
||||
}
|
||||
ContentBlock::Text { text, .. } => {
|
||||
parts.push(OaiContentPart::Text { text: text.clone() });
|
||||
@@ -543,8 +543,8 @@ impl LlmDriver for OpenAIDriver {
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
reasoning_content: None,
|
||||
reasoning: None,
|
||||
});
|
||||
reasoning: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
(Role::Assistant, MessageContent::Blocks(blocks)) => {
|
||||
@@ -915,8 +915,8 @@ impl LlmDriver for OpenAIDriver {
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
reasoning_content: None,
|
||||
reasoning: None,
|
||||
});
|
||||
reasoning: None,
|
||||
});
|
||||
}
|
||||
|
||||
for msg in &request.messages {
|
||||
@@ -928,8 +928,8 @@ impl LlmDriver for OpenAIDriver {
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
reasoning_content: None,
|
||||
reasoning: None,
|
||||
});
|
||||
reasoning: None,
|
||||
});
|
||||
}
|
||||
(Role::User, MessageContent::Text(text)) => {
|
||||
oai_messages.push(OaiMessage {
|
||||
@@ -938,8 +938,8 @@ impl LlmDriver for OpenAIDriver {
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
reasoning_content: None,
|
||||
reasoning: None,
|
||||
});
|
||||
reasoning: None,
|
||||
});
|
||||
}
|
||||
(Role::Assistant, MessageContent::Text(text)) => {
|
||||
oai_messages.push(OaiMessage {
|
||||
@@ -948,8 +948,8 @@ impl LlmDriver for OpenAIDriver {
|
||||
tool_calls: None,
|
||||
tool_call_id: None,
|
||||
reasoning_content: None,
|
||||
reasoning: None,
|
||||
});
|
||||
reasoning: None,
|
||||
});
|
||||
}
|
||||
(Role::User, MessageContent::Blocks(blocks)) => {
|
||||
for block in blocks {
|
||||
@@ -969,8 +969,8 @@ impl LlmDriver for OpenAIDriver {
|
||||
tool_calls: None,
|
||||
tool_call_id: Some(tool_use_id.clone()),
|
||||
reasoning_content: None,
|
||||
reasoning: None,
|
||||
});
|
||||
reasoning: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1492,7 +1492,9 @@ impl LlmDriver for OpenAIDriver {
|
||||
// non-zero output_tokens so the agent loop doesn't misclassify
|
||||
// this as a "silent failure" and loop unnecessarily.
|
||||
if !content.is_empty() && usage.input_tokens == 0 && usage.output_tokens == 0 {
|
||||
debug!("Stream has content but no usage stats — setting synthetic output_tokens=1");
|
||||
debug!(
|
||||
"Stream has content but no usage stats — setting synthetic output_tokens=1"
|
||||
);
|
||||
usage.output_tokens = 1;
|
||||
}
|
||||
|
||||
@@ -1956,10 +1958,7 @@ mod tests {
|
||||
/// the upstream server is pre- or post-vLLM 0.19.
|
||||
#[test]
|
||||
fn test_assemble_emits_both_reasoning_fields_for_vllm_compat() {
|
||||
let driver = OpenAIDriver::new(
|
||||
"test".to_string(),
|
||||
"http://localhost:8000/v1".to_string(),
|
||||
);
|
||||
let driver = OpenAIDriver::new("test".to_string(), "http://localhost:8000/v1".to_string());
|
||||
let blocks = vec![
|
||||
ContentBlock::Thinking {
|
||||
thinking: "MARKER-vllm-019".to_string(),
|
||||
@@ -1994,8 +1993,7 @@ mod tests {
|
||||
/// change in #1157.
|
||||
#[test]
|
||||
fn test_assemble_no_reasoning_fields_for_plain_model() {
|
||||
let driver =
|
||||
OpenAIDriver::new("test".to_string(), "https://api.openai.com/v1".to_string());
|
||||
let driver = OpenAIDriver::new("test".to_string(), "https://api.openai.com/v1".to_string());
|
||||
let blocks = vec![ContentBlock::Text {
|
||||
text: "hi".to_string(),
|
||||
provider_metadata: None,
|
||||
@@ -2014,18 +2012,14 @@ mod tests {
|
||||
/// understand the new name.
|
||||
#[test]
|
||||
fn test_assemble_moonshot_keeps_legacy_field_only() {
|
||||
let driver = OpenAIDriver::new(
|
||||
"test".to_string(),
|
||||
"https://api.moonshot.cn/v1".to_string(),
|
||||
);
|
||||
let blocks = vec![
|
||||
ContentBlock::ToolUse {
|
||||
id: "call_1".to_string(),
|
||||
name: "search".to_string(),
|
||||
input: serde_json::json!({"q": "x"}),
|
||||
provider_metadata: None,
|
||||
},
|
||||
];
|
||||
let driver =
|
||||
OpenAIDriver::new("test".to_string(), "https://api.moonshot.cn/v1".to_string());
|
||||
let blocks = vec![ContentBlock::ToolUse {
|
||||
id: "call_1".to_string(),
|
||||
name: "search".to_string(),
|
||||
input: serde_json::json!({"q": "x"}),
|
||||
provider_metadata: None,
|
||||
}];
|
||||
let msg = assemble_assistant_message(&blocks, "kimi-k2", &driver);
|
||||
assert_eq!(
|
||||
msg.reasoning_content.as_deref(),
|
||||
@@ -2174,7 +2168,10 @@ mod tests {
|
||||
Some(OaiMessageContent::Text(t)) => t,
|
||||
_ => panic!("expected text content"),
|
||||
};
|
||||
assert_eq!(content, "answer", "visible content must not include <think>");
|
||||
assert_eq!(
|
||||
content, "answer",
|
||||
"visible content must not include <think>"
|
||||
);
|
||||
assert_eq!(
|
||||
msg.reasoning_content.as_deref(),
|
||||
Some("internal chain-of-thought"),
|
||||
@@ -2186,8 +2183,7 @@ mod tests {
|
||||
/// assistant message — preserve the legacy shape.
|
||||
#[test]
|
||||
fn test_assemble_assistant_no_thinking_is_plain() {
|
||||
let driver =
|
||||
OpenAIDriver::new("test".to_string(), "https://api.openai.com/v1".to_string());
|
||||
let driver = OpenAIDriver::new("test".to_string(), "https://api.openai.com/v1".to_string());
|
||||
let blocks = vec![ContentBlock::Text {
|
||||
text: "Hi.".to_string(),
|
||||
provider_metadata: None,
|
||||
|
||||
@@ -258,7 +258,6 @@ fn host_net_fetch(state: &GuestState, params: &serde_json::Value) -> serde_json:
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shell (capability-checked)
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -561,7 +560,10 @@ mod tests {
|
||||
assert!(web_fetch::check_ssrf("http://127.0.0.1:8080/secret", &no_allow).is_err());
|
||||
assert!(web_fetch::check_ssrf("http://localhost:3000/api", &no_allow).is_err());
|
||||
assert!(web_fetch::check_ssrf("http://169.254.169.254/metadata", &no_allow).is_err());
|
||||
assert!(web_fetch::check_ssrf("http://metadata.google.internal/v1/instance", &no_allow).is_err());
|
||||
assert!(
|
||||
web_fetch::check_ssrf("http://metadata.google.internal/v1/instance", &no_allow)
|
||||
.is_err()
|
||||
);
|
||||
// These were previously missing from host_functions — now covered:
|
||||
assert!(web_fetch::check_ssrf("http://[::1]:8080/secret", &no_allow).is_err());
|
||||
assert!(web_fetch::check_ssrf("http://100.100.100.200/metadata", &no_allow).is_err());
|
||||
|
||||
@@ -10,8 +10,8 @@ use openfang_types::model_catalog::{
|
||||
HUGGINGFACE_BASE_URL, KIMI_CODING_BASE_URL, LEMONADE_BASE_URL, LMSTUDIO_BASE_URL,
|
||||
MINIMAX_BASE_URL, MISTRAL_BASE_URL, MOONSHOT_BASE_URL, NVIDIA_NIM_BASE_URL, OLLAMA_BASE_URL,
|
||||
OPENAI_BASE_URL, OPENROUTER_BASE_URL, PERPLEXITY_BASE_URL, QIANFAN_BASE_URL, QWEN_BASE_URL,
|
||||
REPLICATE_BASE_URL, REQUESTY_BASE_URL, SAMBANOVA_BASE_URL, TOGETHER_BASE_URL, VENICE_BASE_URL, VLLM_BASE_URL,
|
||||
VOLCENGINE_BASE_URL, VOLCENGINE_CODING_BASE_URL, XAI_BASE_URL, ZAI_BASE_URL,
|
||||
REPLICATE_BASE_URL, REQUESTY_BASE_URL, SAMBANOVA_BASE_URL, TOGETHER_BASE_URL, VENICE_BASE_URL,
|
||||
VLLM_BASE_URL, VOLCENGINE_BASE_URL, VOLCENGINE_CODING_BASE_URL, XAI_BASE_URL, ZAI_BASE_URL,
|
||||
ZAI_CODING_BASE_URL, ZHIPU_BASE_URL, ZHIPU_CODING_BASE_URL,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
@@ -1052,10 +1052,7 @@ fn builtin_aliases() -> HashMap<String, String> {
|
||||
),
|
||||
("free", "openrouter/meta-llama/llama-3.3-70b-instruct:free"),
|
||||
("free-reasoning", "openrouter/deepseek/deepseek-r1:free"),
|
||||
(
|
||||
"openrouter/free-coder",
|
||||
"openrouter/qwen/qwen3-coder:free",
|
||||
),
|
||||
("openrouter/free-coder", "openrouter/qwen/qwen3-coder:free"),
|
||||
(
|
||||
"openrouter/free-large",
|
||||
"openrouter/openai/gpt-oss-120b:free",
|
||||
@@ -4715,9 +4712,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_openrouter_free_alias_supports_tools() {
|
||||
let catalog = ModelCatalog::new();
|
||||
let entry = catalog.find_model("openrouter/free").expect(
|
||||
"openrouter/free alias must resolve to a known model",
|
||||
);
|
||||
let entry = catalog
|
||||
.find_model("openrouter/free")
|
||||
.expect("openrouter/free alias must resolve to a known model");
|
||||
assert_eq!(entry.provider, "openrouter");
|
||||
assert!(
|
||||
entry.supports_tools,
|
||||
@@ -4730,9 +4727,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_openrouter_free_short_alias_supports_tools() {
|
||||
let catalog = ModelCatalog::new();
|
||||
let entry = catalog
|
||||
.find_model("free")
|
||||
.expect("free alias must resolve");
|
||||
let entry = catalog.find_model("free").expect("free alias must resolve");
|
||||
assert_eq!(entry.provider, "openrouter");
|
||||
assert!(
|
||||
entry.supports_tools,
|
||||
|
||||
@@ -3119,8 +3119,7 @@ async fn tool_image_generate(
|
||||
|
||||
// Closes #1051: route to a local OpenAI-compatible image generation
|
||||
// service when `media.image_gen_base_url` is set.
|
||||
let base_url_override = media_engine
|
||||
.and_then(|e| e.config().image_gen_base_url.as_deref());
|
||||
let base_url_override = media_engine.and_then(|e| e.config().image_gen_base_url.as_deref());
|
||||
let result = crate::image_gen::generate_image(&request, base_url_override).await?;
|
||||
|
||||
// Save images to workspace if available
|
||||
@@ -3636,9 +3635,9 @@ fn tool_skill_describe(
|
||||
.ok_or("Missing 'name' parameter")?
|
||||
.trim();
|
||||
let registry = skill_registry.ok_or("No skill registry available")?;
|
||||
let skill = registry
|
||||
.get(name)
|
||||
.ok_or_else(|| format!("Skill '{name}' not found. Use skill_list to see installed skills."))?;
|
||||
let skill = registry.get(name).ok_or_else(|| {
|
||||
format!("Skill '{name}' not found. Use skill_list to see installed skills.")
|
||||
})?;
|
||||
let body = skill
|
||||
.manifest
|
||||
.prompt_context
|
||||
@@ -3672,9 +3671,9 @@ async fn tool_skill_execute(
|
||||
.ok_or("Missing 'skill' parameter")?
|
||||
.trim();
|
||||
let registry = skill_registry.ok_or("No skill registry available")?;
|
||||
let skill = registry
|
||||
.get(skill_name)
|
||||
.ok_or_else(|| format!("Skill '{skill_name}' not found. Use skill_list to see installed skills."))?;
|
||||
let skill = registry.get(skill_name).ok_or_else(|| {
|
||||
format!("Skill '{skill_name}' not found. Use skill_list to see installed skills.")
|
||||
})?;
|
||||
|
||||
// If no tool name was given, default behavior depends on runtime.
|
||||
// For prompt-only skills, return the SKILL.md body (most useful response
|
||||
@@ -4017,14 +4016,14 @@ mod tests {
|
||||
async fn test_create_directory_creates_nested() {
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let root = tmp.path();
|
||||
let result = tool_create_directory(
|
||||
&serde_json::json!({"path": "a/b/c"}),
|
||||
Some(root),
|
||||
)
|
||||
.await;
|
||||
let result = tool_create_directory(&serde_json::json!({"path": "a/b/c"}), Some(root)).await;
|
||||
assert!(result.is_ok(), "Expected Ok, got: {:?}", result);
|
||||
let expected = root.join("a").join("b").join("c");
|
||||
assert!(expected.is_dir(), "Expected directory to exist: {}", expected.display());
|
||||
assert!(
|
||||
expected.is_dir(),
|
||||
"Expected directory to exist: {}",
|
||||
expected.display()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -4032,18 +4031,10 @@ mod tests {
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let root = tmp.path();
|
||||
// First create
|
||||
let r1 = tool_create_directory(
|
||||
&serde_json::json!({"path": "data/logs"}),
|
||||
Some(root),
|
||||
)
|
||||
.await;
|
||||
let r1 = tool_create_directory(&serde_json::json!({"path": "data/logs"}), Some(root)).await;
|
||||
assert!(r1.is_ok());
|
||||
// Second create on existing dir should also succeed
|
||||
let r2 = tool_create_directory(
|
||||
&serde_json::json!({"path": "data/logs"}),
|
||||
Some(root),
|
||||
)
|
||||
.await;
|
||||
let r2 = tool_create_directory(&serde_json::json!({"path": "data/logs"}), Some(root)).await;
|
||||
assert!(r2.is_ok(), "Expected idempotent success, got: {:?}", r2);
|
||||
}
|
||||
|
||||
@@ -4063,23 +4054,27 @@ mod tests {
|
||||
"test-id",
|
||||
"create_directory",
|
||||
&serde_json::json!({"path": "nested/folder"}),
|
||||
None, // kernel
|
||||
None, // allowed_tools
|
||||
None, // caller_agent_id
|
||||
None, // skill_registry
|
||||
None, // mcp_connections
|
||||
None, // web_ctx
|
||||
None, // browser_ctx
|
||||
None, // allowed_env_vars
|
||||
None, // kernel
|
||||
None, // allowed_tools
|
||||
None, // caller_agent_id
|
||||
None, // skill_registry
|
||||
None, // mcp_connections
|
||||
None, // web_ctx
|
||||
None, // browser_ctx
|
||||
None, // allowed_env_vars
|
||||
Some(root.as_path()), // workspace_root
|
||||
None, // media_engine
|
||||
None, // exec_policy
|
||||
None, // tts_engine
|
||||
None, // docker_config
|
||||
None, // process_manager
|
||||
None, // media_engine
|
||||
None, // exec_policy
|
||||
None, // tts_engine
|
||||
None, // docker_config
|
||||
None, // process_manager
|
||||
)
|
||||
.await;
|
||||
assert!(!result.is_error, "Expected success, got: {}", result.content);
|
||||
assert!(
|
||||
!result.is_error,
|
||||
"Expected success, got: {}",
|
||||
result.content
|
||||
);
|
||||
assert!(root.join("nested").join("folder").is_dir());
|
||||
}
|
||||
|
||||
|
||||
@@ -60,11 +60,8 @@ impl InstallOptions {
|
||||
|
||||
/// Well-known filenames the installer searches for a detached signature
|
||||
/// envelope, in priority order.
|
||||
const SIGNATURE_CANDIDATES: &[&str] = &[
|
||||
"signature.json",
|
||||
"skill.toml.sig.json",
|
||||
"SKILL.md.sig.json",
|
||||
];
|
||||
const SIGNATURE_CANDIDATES: &[&str] =
|
||||
&["signature.json", "skill.toml.sig.json", "SKILL.md.sig.json"];
|
||||
|
||||
/// Normalize a manifest text for content-binding comparison.
|
||||
///
|
||||
@@ -167,10 +164,7 @@ pub fn load_signature(skill_dir: &Path) -> Result<Option<SignedManifest>, SkillE
|
||||
/// Returns `SkillError::SecurityBlocked` when enforcement is on and the
|
||||
/// skill fails any of those checks. On failure the caller is expected to
|
||||
/// remove `skill_dir` to keep the skills directory clean.
|
||||
pub fn enforce_require_signed(
|
||||
skill_dir: &Path,
|
||||
opts: &InstallOptions,
|
||||
) -> Result<(), SkillError> {
|
||||
pub fn enforce_require_signed(skill_dir: &Path, opts: &InstallOptions) -> Result<(), SkillError> {
|
||||
if !opts.require_signed {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -214,8 +208,7 @@ pub fn enforce_require_signed(
|
||||
// CRLF→LF normalization (applied symmetrically to both sides).
|
||||
// `package.json` is included because openclaw_compat treats it as a
|
||||
// valid SKILL manifest source.
|
||||
const MANIFEST_CANDIDATES: &[&str] =
|
||||
&["skill.toml", "SKILL.md", "skill.md", "package.json"];
|
||||
const MANIFEST_CANDIDATES: &[&str] = &["skill.toml", "SKILL.md", "skill.md", "package.json"];
|
||||
let normalized_envelope = normalize_manifest_text(&envelope.manifest);
|
||||
let mut bound = false;
|
||||
for name in MANIFEST_CANDIDATES {
|
||||
|
||||
@@ -434,7 +434,9 @@ mod tests {
|
||||
let restored: ContentBlock = serde_json::from_str(&serialized).unwrap();
|
||||
match restored {
|
||||
ContentBlock::Thinking {
|
||||
thinking, signature, ..
|
||||
thinking,
|
||||
signature,
|
||||
..
|
||||
} => {
|
||||
assert_eq!(thinking, "Let me reason about this carefully...");
|
||||
assert_eq!(
|
||||
@@ -517,7 +519,9 @@ mod tests {
|
||||
assert_eq!(blocks.len(), 2);
|
||||
match &blocks[0] {
|
||||
ContentBlock::Thinking {
|
||||
thinking, signature, ..
|
||||
thinking,
|
||||
signature,
|
||||
..
|
||||
} => {
|
||||
assert_eq!(thinking, "Internal reasoning");
|
||||
assert_eq!(signature.as_deref(), Some("sig_xyz"));
|
||||
@@ -547,8 +551,7 @@ mod tests {
|
||||
fn test_provider_msg_id_is_recorded_but_not_primary() {
|
||||
// The LLM-supplied identifier is preserved for debugging only — the
|
||||
// server-generated `msg_id` is unchanged and remains the primary key.
|
||||
let msg =
|
||||
Message::assistant("hi").with_provider_msg_id("msg_abc123_anthropic_collidable");
|
||||
let msg = Message::assistant("hi").with_provider_msg_id("msg_abc123_anthropic_collidable");
|
||||
assert_eq!(
|
||||
msg.provider_msg_id.as_deref(),
|
||||
Some("msg_abc123_anthropic_collidable")
|
||||
|
||||
Reference in New Issue
Block a user