simple-agents-py 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/Cargo.lock +14 -12
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/Cargo.toml +1 -1
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/PKG-INFO +1 -1
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-cache/src/memory.rs +47 -3
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-core/Cargo.toml +5 -3
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-core/src/client.rs +323 -28
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-core/src/middleware.rs +5 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/Cargo.toml +1 -1
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/Cargo.toml +3 -3
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/Cargo.toml +5 -5
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/uv.lock +1 -1
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/pyproject.toml +1 -1
- simple_agents_py-0.2.0/crates/simple-agent-type/TODO.md +0 -590
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/README.md +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/Cargo.toml +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/README.md +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/TEST_GUIDE.md +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/examples/basic_usage.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/examples/mock_provider.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/cache.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/coercion.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/config.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/error.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/lib.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/message.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/provider.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/request.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/response.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/router.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/tool.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/src/validation.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agent-type/tests/integration_test.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-cache/Cargo.toml +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-cache/src/lib.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-cache/src/noop.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-core/README.md +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-core/examples/basic_client.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-core/src/healing.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-core/src/lib.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-core/src/routing.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-core/tests/client_integration.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/README.md +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/benches/parser_benchmarks.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/examples/basic_healing.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/examples/coercion_demo.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/examples/streaming_annotations.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/examples/streaming_partial_types.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/src/coercion.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/src/lib.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/src/parser.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/src/schema.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/src/streaming.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/src/string_utils.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/tests/parser_tests.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/tests/property_tests.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/tests/stream_annotations_tests.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-healing/tests/streaming_tests.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-macros/Cargo.toml +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-macros/README.md +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-macros/src/lib.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-macros/src/partial.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-macros/tests/partial_type_tests.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/README.md +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/anthropic_basic.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/anthropic_structured_output.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/cache_usage.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/custom_api.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/healing_fallback.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/openai_basic.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/openai_structured_output.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/openrouter_basic.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/retry_demo.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/streaming.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/streaming_structured.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/streaming_with_healing.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/test_local_api.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/examples/test_reqwest.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/run_integration_tests.sh +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/anthropic/error.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/anthropic/mod.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/anthropic/models.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/anthropic/streaming.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/common/error.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/common/http_client.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/common/mod.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/healing_integration.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/lib.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/metrics.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/openai/error.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/openai/mod.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/openai/models.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/openai/streaming.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/openrouter/mod.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/rate_limit.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/retry.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/schema_converter.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/streaming_structured.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/src/utils.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/tests/README.md +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/tests/healing_integration_tests.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-providers/tests/openai_integration.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/README.md +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/examples/client_builder_demo.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/examples/direct_healing_demo.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/examples/healing_demo.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/examples/routing_config_demo.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/examples/streaming_demo.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/examples/streaming_parser_demo.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/examples/structured_streaming_demo.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/py.typed +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/simple_agents_py.pyi +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/src/lib.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/tests/test_client.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/tests/test_client_builder.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/tests/test_direct_healing.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/tests/test_healing.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/tests/test_integration_openai.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/tests/test_routing_config.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/tests/test_streaming.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/tests/test_streaming_parser.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-py/tests/test_structured_streaming.py +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-router/Cargo.toml +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-router/examples/round_robin_router.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-router/src/circuit_breaker.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-router/src/cost.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-router/src/fallback.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-router/src/health.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-router/src/latency.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-router/src/lib.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-router/src/retry.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-router/src/round_robin.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-router/tests/health_tracker_integration.rs +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/py.typed +0 -0
- {simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/simple_agents_py.pyi +0 -0
|
@@ -2142,7 +2142,7 @@ checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
|
|
|
2142
2142
|
|
|
2143
2143
|
[[package]]
|
|
2144
2144
|
name = "simple-agent-type"
|
|
2145
|
-
version = "0.2.
|
|
2145
|
+
version = "0.2.2"
|
|
2146
2146
|
dependencies = [
|
|
2147
2147
|
"async-trait",
|
|
2148
2148
|
"blake3",
|
|
@@ -2157,7 +2157,7 @@ dependencies = [
|
|
|
2157
2157
|
|
|
2158
2158
|
[[package]]
|
|
2159
2159
|
name = "simple-agents-cache"
|
|
2160
|
-
version = "0.2.
|
|
2160
|
+
version = "0.2.2"
|
|
2161
2161
|
dependencies = [
|
|
2162
2162
|
"async-trait",
|
|
2163
2163
|
"simple-agent-type",
|
|
@@ -2166,7 +2166,7 @@ dependencies = [
|
|
|
2166
2166
|
|
|
2167
2167
|
[[package]]
|
|
2168
2168
|
name = "simple-agents-cli"
|
|
2169
|
-
version = "0.2.
|
|
2169
|
+
version = "0.2.2"
|
|
2170
2170
|
dependencies = [
|
|
2171
2171
|
"clap",
|
|
2172
2172
|
"serde",
|
|
@@ -2183,10 +2183,11 @@ dependencies = [
|
|
|
2183
2183
|
|
|
2184
2184
|
[[package]]
|
|
2185
2185
|
name = "simple-agents-core"
|
|
2186
|
-
version = "0.2.
|
|
2186
|
+
version = "0.2.2"
|
|
2187
2187
|
dependencies = [
|
|
2188
2188
|
"async-trait",
|
|
2189
2189
|
"futures-core",
|
|
2190
|
+
"futures-util",
|
|
2190
2191
|
"serde",
|
|
2191
2192
|
"serde_json",
|
|
2192
2193
|
"simple-agent-type",
|
|
@@ -2194,11 +2195,12 @@ dependencies = [
|
|
|
2194
2195
|
"simple-agents-healing",
|
|
2195
2196
|
"simple-agents-router",
|
|
2196
2197
|
"tokio",
|
|
2198
|
+
"tracing",
|
|
2197
2199
|
]
|
|
2198
2200
|
|
|
2199
2201
|
[[package]]
|
|
2200
2202
|
name = "simple-agents-examples"
|
|
2201
|
-
version = "0.2.
|
|
2203
|
+
version = "0.2.2"
|
|
2202
2204
|
dependencies = [
|
|
2203
2205
|
"dotenv",
|
|
2204
2206
|
"futures-util",
|
|
@@ -2211,7 +2213,7 @@ dependencies = [
|
|
|
2211
2213
|
|
|
2212
2214
|
[[package]]
|
|
2213
2215
|
name = "simple-agents-ffi"
|
|
2214
|
-
version = "0.2.
|
|
2216
|
+
version = "0.2.2"
|
|
2215
2217
|
dependencies = [
|
|
2216
2218
|
"async-trait",
|
|
2217
2219
|
"simple-agent-type",
|
|
@@ -2222,7 +2224,7 @@ dependencies = [
|
|
|
2222
2224
|
|
|
2223
2225
|
[[package]]
|
|
2224
2226
|
name = "simple-agents-healing"
|
|
2225
|
-
version = "0.2.
|
|
2227
|
+
version = "0.2.2"
|
|
2226
2228
|
dependencies = [
|
|
2227
2229
|
"criterion",
|
|
2228
2230
|
"proptest",
|
|
@@ -2238,7 +2240,7 @@ dependencies = [
|
|
|
2238
2240
|
|
|
2239
2241
|
[[package]]
|
|
2240
2242
|
name = "simple-agents-macros"
|
|
2241
|
-
version = "0.2.
|
|
2243
|
+
version = "0.2.2"
|
|
2242
2244
|
dependencies = [
|
|
2243
2245
|
"proc-macro2",
|
|
2244
2246
|
"quote",
|
|
@@ -2250,7 +2252,7 @@ dependencies = [
|
|
|
2250
2252
|
|
|
2251
2253
|
[[package]]
|
|
2252
2254
|
name = "simple-agents-napi"
|
|
2253
|
-
version = "0.2.
|
|
2255
|
+
version = "0.2.2"
|
|
2254
2256
|
dependencies = [
|
|
2255
2257
|
"napi",
|
|
2256
2258
|
"napi-derive",
|
|
@@ -2262,7 +2264,7 @@ dependencies = [
|
|
|
2262
2264
|
|
|
2263
2265
|
[[package]]
|
|
2264
2266
|
name = "simple-agents-providers"
|
|
2265
|
-
version = "0.2.
|
|
2267
|
+
version = "0.2.2"
|
|
2266
2268
|
dependencies = [
|
|
2267
2269
|
"async-trait",
|
|
2268
2270
|
"bytes",
|
|
@@ -2290,7 +2292,7 @@ dependencies = [
|
|
|
2290
2292
|
|
|
2291
2293
|
[[package]]
|
|
2292
2294
|
name = "simple-agents-py"
|
|
2293
|
-
version = "0.2.
|
|
2295
|
+
version = "0.2.2"
|
|
2294
2296
|
dependencies = [
|
|
2295
2297
|
"async-trait",
|
|
2296
2298
|
"futures-util",
|
|
@@ -2309,7 +2311,7 @@ dependencies = [
|
|
|
2309
2311
|
|
|
2310
2312
|
[[package]]
|
|
2311
2313
|
name = "simple-agents-router"
|
|
2312
|
-
version = "0.2.
|
|
2314
|
+
version = "0.2.2"
|
|
2313
2315
|
dependencies = [
|
|
2314
2316
|
"async-trait",
|
|
2315
2317
|
"futures-core",
|
|
@@ -132,11 +132,31 @@ impl InMemoryCache {
|
|
|
132
132
|
#[async_trait]
|
|
133
133
|
impl Cache for InMemoryCache {
|
|
134
134
|
async fn get(&self, key: &str) -> Result<Option<Vec<u8>>> {
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
{
|
|
136
|
+
let store = self.store.read().await;
|
|
137
|
+
match store.get(key) {
|
|
138
|
+
Some(entry) if !entry.is_expired() => {
|
|
139
|
+
drop(store);
|
|
140
|
+
|
|
141
|
+
let mut store = self.store.write().await;
|
|
142
|
+
if let Some(entry) = store.get_mut(key) {
|
|
143
|
+
if entry.is_expired() {
|
|
144
|
+
store.remove(key);
|
|
145
|
+
return Ok(None);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
entry.touch();
|
|
149
|
+
return Ok(Some(entry.data.clone()));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return Ok(None);
|
|
153
|
+
}
|
|
154
|
+
Some(_) => {} // expired; clean up below
|
|
155
|
+
None => return Ok(None),
|
|
156
|
+
}
|
|
157
|
+
}
|
|
137
158
|
|
|
138
159
|
let mut store = self.store.write().await;
|
|
139
|
-
|
|
140
160
|
if let Some(entry) = store.get_mut(key) {
|
|
141
161
|
if entry.is_expired() {
|
|
142
162
|
store.remove(key);
|
|
@@ -162,6 +182,9 @@ impl Cache for InMemoryCache {
|
|
|
162
182
|
store.insert(key.to_string(), entry);
|
|
163
183
|
}
|
|
164
184
|
|
|
185
|
+
// Periodically clear expired entries before enforcing limits
|
|
186
|
+
self.evict_expired().await;
|
|
187
|
+
|
|
165
188
|
// Evict if needed
|
|
166
189
|
self.evict_lru().await;
|
|
167
190
|
|
|
@@ -324,6 +347,27 @@ mod tests {
|
|
|
324
347
|
assert!(cache.get("key3").await.unwrap().is_some());
|
|
325
348
|
}
|
|
326
349
|
|
|
350
|
+
#[tokio::test]
|
|
351
|
+
async fn test_concurrent_gets_do_not_serialize_readers() {
|
|
352
|
+
let cache = Arc::new(InMemoryCache::new(1024, 10));
|
|
353
|
+
cache
|
|
354
|
+
.set("shared", b"value".to_vec(), Duration::from_secs(60))
|
|
355
|
+
.await
|
|
356
|
+
.unwrap();
|
|
357
|
+
|
|
358
|
+
let mut handles = Vec::new();
|
|
359
|
+
for _ in 0..25 {
|
|
360
|
+
let cache = cache.clone();
|
|
361
|
+
handles.push(tokio::spawn(
|
|
362
|
+
async move { cache.get("shared").await.unwrap() },
|
|
363
|
+
));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
for handle in handles {
|
|
367
|
+
assert_eq!(handle.await.unwrap(), Some(b"value".to_vec()));
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
327
371
|
#[tokio::test]
|
|
328
372
|
async fn test_cache_name() {
|
|
329
373
|
let cache = InMemoryCache::new(1024, 10);
|
|
@@ -16,11 +16,13 @@ async-trait.workspace = true
|
|
|
16
16
|
serde.workspace = true
|
|
17
17
|
serde_json.workspace = true
|
|
18
18
|
tokio.workspace = true
|
|
19
|
+
futures-util.workspace = true
|
|
20
|
+
tracing = "0.1"
|
|
19
21
|
|
|
20
22
|
simple-agent-type = { workspace = true }
|
|
21
|
-
simple-agents-router = { path = "../simple-agents-router", version = "0.2.
|
|
22
|
-
simple-agents-cache = { path = "../simple-agents-cache", version = "0.2.
|
|
23
|
-
simple-agents-healing = { path = "../simple-agents-healing", version = "0.2.
|
|
23
|
+
simple-agents-router = { path = "../simple-agents-router", version = "0.2.2" }
|
|
24
|
+
simple-agents-cache = { path = "../simple-agents-cache", version = "0.2.2" }
|
|
25
|
+
simple-agents-healing = { path = "../simple-agents-healing", version = "0.2.2" }
|
|
24
26
|
futures-core = "0.3"
|
|
25
27
|
|
|
26
28
|
[dev-dependencies]
|
|
@@ -4,6 +4,9 @@ use crate::healing::{HealedJsonResponse, HealedSchemaResponse, HealingSettings};
|
|
|
4
4
|
use crate::middleware::Middleware;
|
|
5
5
|
use crate::routing::{RouterEngine, RoutingMode};
|
|
6
6
|
use async_trait::async_trait;
|
|
7
|
+
use futures_util::future::BoxFuture;
|
|
8
|
+
use futures_util::stream::{self, Stream};
|
|
9
|
+
use futures_util::StreamExt;
|
|
7
10
|
use simple_agent_type::cache::Cache;
|
|
8
11
|
use simple_agent_type::cache::CacheKey;
|
|
9
12
|
use simple_agent_type::prelude::{
|
|
@@ -13,8 +16,10 @@ use simple_agents_healing::coercion::CoercionEngine;
|
|
|
13
16
|
use simple_agents_healing::parser::JsonishParser;
|
|
14
17
|
use simple_agents_healing::schema::Schema;
|
|
15
18
|
use std::collections::HashMap;
|
|
16
|
-
use std::sync::
|
|
19
|
+
use std::sync::Arc;
|
|
17
20
|
use std::time::{Duration, Instant};
|
|
21
|
+
use tokio::sync::RwLock;
|
|
22
|
+
use tracing::debug;
|
|
18
23
|
|
|
19
24
|
/// Mode for completion post-processing.
|
|
20
25
|
pub enum CompletionMode {
|
|
@@ -75,29 +80,30 @@ impl SimpleAgentsClient {
|
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
/// List registered provider names.
|
|
78
|
-
pub fn provider_names(&self) -> Result<Vec<String>> {
|
|
79
|
-
let state = self.state.read().
|
|
80
|
-
SimpleAgentsError::Config("provider registry lock poisoned".to_string())
|
|
81
|
-
})?;
|
|
83
|
+
pub async fn provider_names(&self) -> Result<Vec<String>> {
|
|
84
|
+
let state = self.state.read().await;
|
|
82
85
|
Ok(state.provider_map.keys().cloned().collect())
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
/// Retrieve a provider by name.
|
|
86
|
-
pub fn provider(&self, name: &str) -> Result<Option<Arc<dyn Provider>>> {
|
|
87
|
-
let state = self.state.read().
|
|
88
|
-
SimpleAgentsError::Config("provider registry lock poisoned".to_string())
|
|
89
|
-
})?;
|
|
89
|
+
pub async fn provider(&self, name: &str) -> Result<Option<Arc<dyn Provider>>> {
|
|
90
|
+
let state = self.state.read().await;
|
|
90
91
|
Ok(state.provider_map.get(name).cloned())
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
/// Register an additional provider and rebuild the router.
|
|
94
|
-
pub fn register_provider(&self, provider: Arc<dyn Provider>) -> Result<()> {
|
|
95
|
-
let mut state = self.state.write().
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
state
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
pub async fn register_provider(&self, provider: Arc<dyn Provider>) -> Result<()> {
|
|
96
|
+
let mut state = self.state.write().await;
|
|
97
|
+
let name = provider.name().to_string();
|
|
98
|
+
|
|
99
|
+
if state.provider_map.contains_key(&name) {
|
|
100
|
+
return Err(SimpleAgentsError::Config(format!(
|
|
101
|
+
"provider already registered: {}",
|
|
102
|
+
name
|
|
103
|
+
)));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
state.provider_map.insert(name, provider.clone());
|
|
101
107
|
state.providers.push(provider);
|
|
102
108
|
state.router = Arc::new(self.routing_mode.build_router(state.providers.clone())?);
|
|
103
109
|
Ok(())
|
|
@@ -154,9 +160,7 @@ impl SimpleAgentsClient {
|
|
|
154
160
|
|
|
155
161
|
let start = Instant::now();
|
|
156
162
|
let router = {
|
|
157
|
-
let state = self.state.read().
|
|
158
|
-
SimpleAgentsError::Config("provider registry lock poisoned".to_string())
|
|
159
|
-
})?;
|
|
163
|
+
let state = self.state.read().await;
|
|
160
164
|
state.router.clone()
|
|
161
165
|
};
|
|
162
166
|
let response = router.complete(request).await;
|
|
@@ -225,19 +229,24 @@ impl SimpleAgentsClient {
|
|
|
225
229
|
) -> Result<Box<dyn futures_core::Stream<Item = Result<CompletionChunk>> + Send + Unpin>> {
|
|
226
230
|
request.validate()?;
|
|
227
231
|
self.before_request(request).await?;
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
232
|
+
debug!(
|
|
233
|
+
model = %request.model,
|
|
234
|
+
stream = ?request.stream,
|
|
235
|
+
"SimpleAgentsClient.stream start"
|
|
231
236
|
);
|
|
232
237
|
|
|
233
238
|
let router = {
|
|
234
|
-
let state = self.state.read().
|
|
235
|
-
SimpleAgentsError::Config("provider registry lock poisoned".to_string())
|
|
236
|
-
})?;
|
|
239
|
+
let state = self.state.read().await;
|
|
237
240
|
state.router.clone()
|
|
238
241
|
};
|
|
239
242
|
|
|
240
|
-
|
|
243
|
+
let start = Instant::now();
|
|
244
|
+
let middleware = self.middleware.clone();
|
|
245
|
+
let instrumented_request = request.clone();
|
|
246
|
+
let inner = router.stream(request).await?;
|
|
247
|
+
|
|
248
|
+
let wrapped = Self::instrument_stream(inner, instrumented_request, middleware, start);
|
|
249
|
+
Ok(Box::new(wrapped))
|
|
241
250
|
}
|
|
242
251
|
|
|
243
252
|
fn ensure_healing_enabled(&self) -> Result<()> {
|
|
@@ -300,6 +309,69 @@ impl SimpleAgentsClient {
|
|
|
300
309
|
}
|
|
301
310
|
}
|
|
302
311
|
|
|
312
|
+
impl SimpleAgentsClient {
|
|
313
|
+
fn instrument_stream(
|
|
314
|
+
inner: Box<dyn Stream<Item = Result<CompletionChunk>> + Send + Unpin>,
|
|
315
|
+
request: CompletionRequest,
|
|
316
|
+
middleware: Vec<Arc<dyn Middleware>>,
|
|
317
|
+
start: Instant,
|
|
318
|
+
) -> impl Stream<Item = Result<CompletionChunk>> + Send + Unpin {
|
|
319
|
+
struct StreamState {
|
|
320
|
+
inner: Box<dyn Stream<Item = Result<CompletionChunk>> + Send + Unpin>,
|
|
321
|
+
middleware: Vec<Arc<dyn Middleware>>,
|
|
322
|
+
request: CompletionRequest,
|
|
323
|
+
start: Instant,
|
|
324
|
+
done: bool,
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
stream::unfold(
|
|
328
|
+
StreamState {
|
|
329
|
+
inner,
|
|
330
|
+
middleware,
|
|
331
|
+
request,
|
|
332
|
+
start,
|
|
333
|
+
done: false,
|
|
334
|
+
},
|
|
335
|
+
|mut state| -> BoxFuture<Option<(Result<CompletionChunk>, StreamState)>> {
|
|
336
|
+
Box::pin(async move {
|
|
337
|
+
if state.done {
|
|
338
|
+
return None;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
match state.inner.next().await {
|
|
342
|
+
Some(Ok(chunk)) => Some((Ok(chunk), state)),
|
|
343
|
+
Some(Err(err)) => {
|
|
344
|
+
let latency = state.start.elapsed();
|
|
345
|
+
for middleware in &state.middleware {
|
|
346
|
+
if let Err(mw_err) =
|
|
347
|
+
middleware.on_error(&state.request, &err, latency).await
|
|
348
|
+
{
|
|
349
|
+
state.done = true;
|
|
350
|
+
return Some((Err(mw_err), state));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
state.done = true;
|
|
354
|
+
Some((Err(err), state))
|
|
355
|
+
}
|
|
356
|
+
None => {
|
|
357
|
+
let latency = state.start.elapsed();
|
|
358
|
+
for middleware in &state.middleware {
|
|
359
|
+
if let Err(mw_err) =
|
|
360
|
+
middleware.after_stream(&state.request, latency).await
|
|
361
|
+
{
|
|
362
|
+
state.done = true;
|
|
363
|
+
return Some((Err(mw_err), state));
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
None
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
})
|
|
370
|
+
},
|
|
371
|
+
)
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
303
375
|
/// Builder for `SimpleAgentsClient`.
|
|
304
376
|
pub struct SimpleAgentsClientBuilder {
|
|
305
377
|
providers: Vec<Arc<dyn Provider>>,
|
|
@@ -413,8 +485,11 @@ impl Middleware for () {
|
|
|
413
485
|
#[cfg(test)]
|
|
414
486
|
mod tests {
|
|
415
487
|
use super::*;
|
|
488
|
+
use futures_util::{stream, StreamExt};
|
|
489
|
+
use simple_agent_type::error::ProviderError;
|
|
416
490
|
use simple_agent_type::prelude::*;
|
|
417
491
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
492
|
+
use std::time::Duration;
|
|
418
493
|
|
|
419
494
|
struct MockProvider {
|
|
420
495
|
name: &'static str,
|
|
@@ -481,10 +556,230 @@ mod tests {
|
|
|
481
556
|
.unwrap();
|
|
482
557
|
|
|
483
558
|
let second = Arc::new(MockProvider::new("p2"));
|
|
484
|
-
client.register_provider(second).unwrap();
|
|
559
|
+
client.register_provider(second).await.unwrap();
|
|
485
560
|
|
|
486
|
-
let names = client.provider_names().unwrap();
|
|
561
|
+
let names = client.provider_names().await.unwrap();
|
|
487
562
|
assert!(names.contains(&"p1".to_string()));
|
|
488
563
|
assert!(names.contains(&"p2".to_string()));
|
|
489
564
|
}
|
|
565
|
+
|
|
566
|
+
#[tokio::test]
|
|
567
|
+
async fn duplicate_provider_registration_fails() {
|
|
568
|
+
let provider = Arc::new(MockProvider::new("p1"));
|
|
569
|
+
let client = SimpleAgentsClientBuilder::new()
|
|
570
|
+
.with_provider(provider.clone())
|
|
571
|
+
.build()
|
|
572
|
+
.unwrap();
|
|
573
|
+
|
|
574
|
+
let result = client.register_provider(provider).await;
|
|
575
|
+
assert!(matches!(
|
|
576
|
+
result,
|
|
577
|
+
Err(SimpleAgentsError::Config(msg)) if msg.contains("provider already registered")
|
|
578
|
+
));
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
#[derive(Default)]
|
|
582
|
+
struct RecordingMiddleware {
|
|
583
|
+
before: AtomicUsize,
|
|
584
|
+
after_stream: AtomicUsize,
|
|
585
|
+
errors: AtomicUsize,
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
#[async_trait]
|
|
589
|
+
impl Middleware for RecordingMiddleware {
|
|
590
|
+
async fn before_request(&self, _request: &CompletionRequest) -> Result<()> {
|
|
591
|
+
self.before.fetch_add(1, Ordering::Relaxed);
|
|
592
|
+
Ok(())
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
async fn after_stream(
|
|
596
|
+
&self,
|
|
597
|
+
_request: &CompletionRequest,
|
|
598
|
+
_latency: Duration,
|
|
599
|
+
) -> Result<()> {
|
|
600
|
+
self.after_stream.fetch_add(1, Ordering::Relaxed);
|
|
601
|
+
Ok(())
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
async fn on_error(
|
|
605
|
+
&self,
|
|
606
|
+
_request: &CompletionRequest,
|
|
607
|
+
_error: &SimpleAgentsError,
|
|
608
|
+
_latency: Duration,
|
|
609
|
+
) -> Result<()> {
|
|
610
|
+
self.errors.fetch_add(1, Ordering::Relaxed);
|
|
611
|
+
Ok(())
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
fn name(&self) -> &str {
|
|
615
|
+
"recording"
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
struct StreamingProvider {
|
|
620
|
+
name: &'static str,
|
|
621
|
+
fail_after_first: bool,
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
impl StreamingProvider {
|
|
625
|
+
fn new(name: &'static str, fail_after_first: bool) -> Self {
|
|
626
|
+
Self {
|
|
627
|
+
name,
|
|
628
|
+
fail_after_first,
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
fn build_chunk(id: &str, content: &str) -> CompletionChunk {
|
|
633
|
+
CompletionChunk {
|
|
634
|
+
id: id.to_string(),
|
|
635
|
+
model: "test-model".to_string(),
|
|
636
|
+
choices: vec![ChoiceDelta {
|
|
637
|
+
index: 0,
|
|
638
|
+
delta: MessageDelta {
|
|
639
|
+
role: Some(Role::Assistant),
|
|
640
|
+
content: Some(content.to_string()),
|
|
641
|
+
},
|
|
642
|
+
finish_reason: None,
|
|
643
|
+
}],
|
|
644
|
+
created: None,
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
#[async_trait]
|
|
650
|
+
impl Provider for StreamingProvider {
|
|
651
|
+
fn name(&self) -> &str {
|
|
652
|
+
self.name
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
fn transform_request(&self, _req: &CompletionRequest) -> Result<ProviderRequest> {
|
|
656
|
+
Ok(ProviderRequest::new("http://example.com"))
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
async fn execute(&self, _req: ProviderRequest) -> Result<ProviderResponse> {
|
|
660
|
+
Ok(ProviderResponse::new(
|
|
661
|
+
200,
|
|
662
|
+
serde_json::json!({"content": "ok"}),
|
|
663
|
+
))
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
fn transform_response(&self, _resp: ProviderResponse) -> Result<CompletionResponse> {
|
|
667
|
+
Ok(CompletionResponse {
|
|
668
|
+
id: "resp_stream".to_string(),
|
|
669
|
+
model: "test-model".to_string(),
|
|
670
|
+
choices: vec![CompletionChoice {
|
|
671
|
+
index: 0,
|
|
672
|
+
message: Message::assistant("ok"),
|
|
673
|
+
finish_reason: FinishReason::Stop,
|
|
674
|
+
logprobs: None,
|
|
675
|
+
}],
|
|
676
|
+
usage: Usage::new(1, 1),
|
|
677
|
+
created: None,
|
|
678
|
+
provider: Some(self.name.to_string()),
|
|
679
|
+
healing_metadata: None,
|
|
680
|
+
})
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
async fn execute_stream(
|
|
684
|
+
&self,
|
|
685
|
+
_req: ProviderRequest,
|
|
686
|
+
) -> Result<Box<dyn futures_core::Stream<Item = Result<CompletionChunk>> + Send + Unpin>>
|
|
687
|
+
{
|
|
688
|
+
let stream = if self.fail_after_first {
|
|
689
|
+
let items: Vec<Result<CompletionChunk>> = vec![
|
|
690
|
+
Ok(Self::build_chunk("chunk-1", "hello")),
|
|
691
|
+
Err(SimpleAgentsError::Provider(ProviderError::ServerError(
|
|
692
|
+
"stream error".to_string(),
|
|
693
|
+
))),
|
|
694
|
+
];
|
|
695
|
+
stream::iter(items)
|
|
696
|
+
} else {
|
|
697
|
+
let items: Vec<Result<CompletionChunk>> =
|
|
698
|
+
vec![Ok(Self::build_chunk("chunk-1", "hello"))];
|
|
699
|
+
stream::iter(items)
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
Ok(Box::new(stream))
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
#[tokio::test]
|
|
707
|
+
async fn streaming_invokes_after_stream_on_success() {
|
|
708
|
+
let provider = Arc::new(StreamingProvider::new("p1", false));
|
|
709
|
+
let middleware = Arc::new(RecordingMiddleware::default());
|
|
710
|
+
|
|
711
|
+
let client = SimpleAgentsClientBuilder::new()
|
|
712
|
+
.with_provider(provider)
|
|
713
|
+
.with_middleware(middleware.clone())
|
|
714
|
+
.build()
|
|
715
|
+
.unwrap();
|
|
716
|
+
|
|
717
|
+
let request = CompletionRequest::builder()
|
|
718
|
+
.model("gpt-4")
|
|
719
|
+
.message(Message::user("Hi"))
|
|
720
|
+
.stream(true)
|
|
721
|
+
.build()
|
|
722
|
+
.unwrap();
|
|
723
|
+
|
|
724
|
+
let outcome = client
|
|
725
|
+
.complete(&request, CompletionOptions::default())
|
|
726
|
+
.await
|
|
727
|
+
.unwrap();
|
|
728
|
+
|
|
729
|
+
let mut collected = Vec::new();
|
|
730
|
+
match outcome {
|
|
731
|
+
CompletionOutcome::Stream(mut stream) => {
|
|
732
|
+
while let Some(chunk) = stream.next().await {
|
|
733
|
+
collected.push(chunk.unwrap());
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
_ => panic!("expected stream outcome"),
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
assert_eq!(collected.len(), 1);
|
|
740
|
+
assert_eq!(middleware.before.load(Ordering::Relaxed), 1);
|
|
741
|
+
assert_eq!(middleware.after_stream.load(Ordering::Relaxed), 1);
|
|
742
|
+
assert_eq!(middleware.errors.load(Ordering::Relaxed), 0);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
#[tokio::test]
|
|
746
|
+
async fn streaming_invokes_on_error_on_failure() {
|
|
747
|
+
let provider = Arc::new(StreamingProvider::new("p1", true));
|
|
748
|
+
let middleware = Arc::new(RecordingMiddleware::default());
|
|
749
|
+
|
|
750
|
+
let client = SimpleAgentsClientBuilder::new()
|
|
751
|
+
.with_provider(provider)
|
|
752
|
+
.with_middleware(middleware.clone())
|
|
753
|
+
.build()
|
|
754
|
+
.unwrap();
|
|
755
|
+
|
|
756
|
+
let request = CompletionRequest::builder()
|
|
757
|
+
.model("gpt-4")
|
|
758
|
+
.message(Message::user("Hi"))
|
|
759
|
+
.stream(true)
|
|
760
|
+
.build()
|
|
761
|
+
.unwrap();
|
|
762
|
+
|
|
763
|
+
let outcome = client
|
|
764
|
+
.complete(&request, CompletionOptions::default())
|
|
765
|
+
.await
|
|
766
|
+
.unwrap();
|
|
767
|
+
|
|
768
|
+
let mut chunks = Vec::new();
|
|
769
|
+
match outcome {
|
|
770
|
+
CompletionOutcome::Stream(mut stream) => {
|
|
771
|
+
while let Some(chunk) = stream.next().await {
|
|
772
|
+
chunks.push(chunk);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
_ => panic!("expected stream outcome"),
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
assert_eq!(middleware.before.load(Ordering::Relaxed), 1);
|
|
779
|
+
assert_eq!(middleware.after_stream.load(Ordering::Relaxed), 0);
|
|
780
|
+
assert_eq!(middleware.errors.load(Ordering::Relaxed), 1);
|
|
781
|
+
assert_eq!(chunks.len(), 2);
|
|
782
|
+
assert!(chunks[0].as_ref().is_ok());
|
|
783
|
+
assert!(chunks[1].is_err());
|
|
784
|
+
}
|
|
490
785
|
}
|
{simple_agents_py-0.2.0 → simple_agents_py-0.2.2}/crates/simple-agents-core/src/middleware.rs
RENAMED
|
@@ -24,6 +24,11 @@ pub trait Middleware: Send + Sync {
|
|
|
24
24
|
Ok(())
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
/// Called when a streaming request completes successfully.
|
|
28
|
+
async fn after_stream(&self, _request: &CompletionRequest, _latency: Duration) -> Result<()> {
|
|
29
|
+
Ok(())
|
|
30
|
+
}
|
|
31
|
+
|
|
27
32
|
/// Called when a response is served from cache.
|
|
28
33
|
async fn on_cache_hit(
|
|
29
34
|
&self,
|
|
@@ -32,7 +32,7 @@ regex-support = ["regex"]
|
|
|
32
32
|
tokio = { version = "1.41", features = ["full"] }
|
|
33
33
|
proptest = "1.5"
|
|
34
34
|
criterion = { version = "0.5", features = ["html_reports"] }
|
|
35
|
-
simple-agents-macros = { path = "../simple-agents-macros", version = "0.2.
|
|
35
|
+
simple-agents-macros = { path = "../simple-agents-macros", version = "0.2.2" }
|
|
36
36
|
|
|
37
37
|
[[test]]
|
|
38
38
|
name = "parser_tests"
|
|
@@ -10,7 +10,7 @@ readme = "README.md"
|
|
|
10
10
|
|
|
11
11
|
[dependencies]
|
|
12
12
|
simple-agent-type = { workspace = true }
|
|
13
|
-
simple-agents-healing = { path = "../simple-agents-healing", version = "0.2.
|
|
13
|
+
simple-agents-healing = { path = "../simple-agents-healing", version = "0.2.2" }
|
|
14
14
|
reqwest = { version = "0.12", features = ["json", "stream", "default-tls", "http2", "gzip", "brotli", "deflate"], default-features = false }
|
|
15
15
|
tokio = { version = "1.42", features = ["full"] }
|
|
16
16
|
futures = "0.3"
|
|
@@ -34,6 +34,6 @@ prometheus = ["dep:metrics-exporter-prometheus"]
|
|
|
34
34
|
[dev-dependencies]
|
|
35
35
|
tokio-test = "0.4"
|
|
36
36
|
tracing-subscriber = "0.3"
|
|
37
|
-
simple-agents-cache = { path = "../simple-agents-cache", version = "0.2.
|
|
38
|
-
simple-agents-macros = { path = "../simple-agents-macros", version = "0.2.
|
|
37
|
+
simple-agents-cache = { path = "../simple-agents-cache", version = "0.2.2" }
|
|
38
|
+
simple-agents-macros = { path = "../simple-agents-macros", version = "0.2.2" }
|
|
39
39
|
dotenv = "0.15"
|