simple-agents-py 0.1.5__tar.gz → 0.1.6__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.1.5 → simple_agents_py-0.1.6}/Cargo.lock +13 -11
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/Cargo.toml +1 -1
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/PKG-INFO +1 -1
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-py/Cargo.toml +2 -1
- simple_agents_py-0.1.6/crates/simple-agents-py/py.typed +1 -0
- simple_agents_py-0.1.6/crates/simple-agents-py/simple_agents_py.pyi +45 -0
- simple_agents_py-0.1.6/crates/simple-agents-py/src/lib.rs +398 -0
- simple_agents_py-0.1.6/py.typed +1 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/pyproject.toml +2 -1
- simple_agents_py-0.1.6/simple_agents_py.pyi +45 -0
- simple_agents_py-0.1.5/crates/simple-agents-py/src/lib.rs +0 -182
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/README.md +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/Cargo.toml +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/README.md +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/TEST_GUIDE.md +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/TODO.md +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/examples/basic_usage.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/examples/mock_provider.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/cache.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/coercion.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/config.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/error.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/lib.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/message.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/provider.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/request.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/response.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/router.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/validation.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/tests/integration_test.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-cache/Cargo.toml +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-cache/src/lib.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-cache/src/memory.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-cache/src/noop.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-core/Cargo.toml +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-core/README.md +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-core/examples/basic_client.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-core/src/client.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-core/src/healing.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-core/src/lib.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-core/src/middleware.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-core/src/routing.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-core/tests/client_integration.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/Cargo.toml +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/README.md +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/benches/parser_benchmarks.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/examples/basic_healing.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/examples/coercion_demo.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/examples/streaming_annotations.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/examples/streaming_partial_types.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/src/coercion.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/src/lib.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/src/parser.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/src/schema.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/src/streaming.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/src/string_utils.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/tests/parser_tests.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/tests/property_tests.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/tests/stream_annotations_tests.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/tests/streaming_tests.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-macros/Cargo.toml +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-macros/README.md +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-macros/src/lib.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-macros/src/partial.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-macros/tests/partial_type_tests.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/Cargo.toml +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/README.md +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/anthropic_basic.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/anthropic_structured_output.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/cache_usage.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/custom_api.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/healing_fallback.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/openai_basic.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/openai_structured_output.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/openrouter_basic.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/retry_demo.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/streaming.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/streaming_structured.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/streaming_with_healing.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/test_local_api.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/examples/test_reqwest.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/run_integration_tests.sh +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/anthropic/error.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/anthropic/mod.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/anthropic/models.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/anthropic/streaming.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/common/error.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/common/http_client.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/common/mod.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/healing_integration.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/lib.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/metrics.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/openai/error.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/openai/mod.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/openai/models.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/openai/streaming.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/openrouter/mod.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/rate_limit.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/retry.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/schema_converter.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/streaming_structured.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/utils.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/tests/README.md +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/tests/healing_integration_tests.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/tests/openai_integration.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-py/README.md +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-py/tests/test_client.py +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/Cargo.toml +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/examples/round_robin_router.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/circuit_breaker.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/cost.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/fallback.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/health.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/latency.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/lib.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/retry.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/round_robin.rs +0 -0
- {simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/tests/health_tracker_integration.rs +0 -0
|
@@ -1494,6 +1494,7 @@ dependencies = [
|
|
|
1494
1494
|
"pyo3-build-config",
|
|
1495
1495
|
"pyo3-ffi",
|
|
1496
1496
|
"pyo3-macros",
|
|
1497
|
+
"serde",
|
|
1497
1498
|
"unindent",
|
|
1498
1499
|
]
|
|
1499
1500
|
|
|
@@ -2025,7 +2026,7 @@ dependencies = [
|
|
|
2025
2026
|
|
|
2026
2027
|
[[package]]
|
|
2027
2028
|
name = "simple-agent-type"
|
|
2028
|
-
version = "0.1.
|
|
2029
|
+
version = "0.1.6"
|
|
2029
2030
|
dependencies = [
|
|
2030
2031
|
"async-trait",
|
|
2031
2032
|
"blake3",
|
|
@@ -2040,7 +2041,7 @@ dependencies = [
|
|
|
2040
2041
|
|
|
2041
2042
|
[[package]]
|
|
2042
2043
|
name = "simple-agents-cache"
|
|
2043
|
-
version = "0.1.
|
|
2044
|
+
version = "0.1.6"
|
|
2044
2045
|
dependencies = [
|
|
2045
2046
|
"async-trait",
|
|
2046
2047
|
"simple-agent-type",
|
|
@@ -2049,7 +2050,7 @@ dependencies = [
|
|
|
2049
2050
|
|
|
2050
2051
|
[[package]]
|
|
2051
2052
|
name = "simple-agents-cli"
|
|
2052
|
-
version = "0.1.
|
|
2053
|
+
version = "0.1.6"
|
|
2053
2054
|
dependencies = [
|
|
2054
2055
|
"clap",
|
|
2055
2056
|
"serde",
|
|
@@ -2066,7 +2067,7 @@ dependencies = [
|
|
|
2066
2067
|
|
|
2067
2068
|
[[package]]
|
|
2068
2069
|
name = "simple-agents-core"
|
|
2069
|
-
version = "0.1.
|
|
2070
|
+
version = "0.1.6"
|
|
2070
2071
|
dependencies = [
|
|
2071
2072
|
"async-trait",
|
|
2072
2073
|
"serde",
|
|
@@ -2093,7 +2094,7 @@ dependencies = [
|
|
|
2093
2094
|
|
|
2094
2095
|
[[package]]
|
|
2095
2096
|
name = "simple-agents-ffi"
|
|
2096
|
-
version = "0.1.
|
|
2097
|
+
version = "0.1.6"
|
|
2097
2098
|
dependencies = [
|
|
2098
2099
|
"async-trait",
|
|
2099
2100
|
"simple-agent-type",
|
|
@@ -2104,7 +2105,7 @@ dependencies = [
|
|
|
2104
2105
|
|
|
2105
2106
|
[[package]]
|
|
2106
2107
|
name = "simple-agents-healing"
|
|
2107
|
-
version = "0.1.
|
|
2108
|
+
version = "0.1.6"
|
|
2108
2109
|
dependencies = [
|
|
2109
2110
|
"criterion",
|
|
2110
2111
|
"proptest",
|
|
@@ -2120,7 +2121,7 @@ dependencies = [
|
|
|
2120
2121
|
|
|
2121
2122
|
[[package]]
|
|
2122
2123
|
name = "simple-agents-macros"
|
|
2123
|
-
version = "0.1.
|
|
2124
|
+
version = "0.1.6"
|
|
2124
2125
|
dependencies = [
|
|
2125
2126
|
"proc-macro2",
|
|
2126
2127
|
"quote",
|
|
@@ -2132,7 +2133,7 @@ dependencies = [
|
|
|
2132
2133
|
|
|
2133
2134
|
[[package]]
|
|
2134
2135
|
name = "simple-agents-napi"
|
|
2135
|
-
version = "0.1.
|
|
2136
|
+
version = "0.1.6"
|
|
2136
2137
|
dependencies = [
|
|
2137
2138
|
"napi",
|
|
2138
2139
|
"napi-derive",
|
|
@@ -2144,7 +2145,7 @@ dependencies = [
|
|
|
2144
2145
|
|
|
2145
2146
|
[[package]]
|
|
2146
2147
|
name = "simple-agents-providers"
|
|
2147
|
-
version = "0.1.
|
|
2148
|
+
version = "0.1.6"
|
|
2148
2149
|
dependencies = [
|
|
2149
2150
|
"async-trait",
|
|
2150
2151
|
"bytes",
|
|
@@ -2172,10 +2173,11 @@ dependencies = [
|
|
|
2172
2173
|
|
|
2173
2174
|
[[package]]
|
|
2174
2175
|
name = "simple-agents-py"
|
|
2175
|
-
version = "0.1.
|
|
2176
|
+
version = "0.1.6"
|
|
2176
2177
|
dependencies = [
|
|
2177
2178
|
"pyo3",
|
|
2178
2179
|
"reqwest",
|
|
2180
|
+
"serde_json",
|
|
2179
2181
|
"simple-agent-type",
|
|
2180
2182
|
"simple-agents-core",
|
|
2181
2183
|
"simple-agents-providers",
|
|
@@ -2184,7 +2186,7 @@ dependencies = [
|
|
|
2184
2186
|
|
|
2185
2187
|
[[package]]
|
|
2186
2188
|
name = "simple-agents-router"
|
|
2187
|
-
version = "0.1.
|
|
2189
|
+
version = "0.1.6"
|
|
2188
2190
|
dependencies = [
|
|
2189
2191
|
"async-trait",
|
|
2190
2192
|
"rand 0.8.5",
|
|
@@ -10,9 +10,10 @@ name = "simple_agents_py"
|
|
|
10
10
|
crate-type = ["cdylib"]
|
|
11
11
|
|
|
12
12
|
[dependencies]
|
|
13
|
-
pyo3 = { version = "0.22", features = ["extension-module", "abi3-py312"] }
|
|
13
|
+
pyo3 = { version = "0.22", features = ["extension-module", "abi3-py312", "serde"] }
|
|
14
14
|
tokio = { workspace = true }
|
|
15
15
|
reqwest = { workspace = true }
|
|
16
|
+
serde_json = { workspace = true }
|
|
16
17
|
|
|
17
18
|
simple-agents-core = { path = "../simple-agents-core", version = "0.1.0" }
|
|
18
19
|
simple-agents-providers = { path = "../simple-agents-providers", version = "0.1.0" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
class Client:
|
|
2
|
+
def __init__(
|
|
3
|
+
self,
|
|
4
|
+
provider: str,
|
|
5
|
+
api_key: str | None = None,
|
|
6
|
+
api_base: str | None = None,
|
|
7
|
+
) -> None: ...
|
|
8
|
+
|
|
9
|
+
def complete(
|
|
10
|
+
self,
|
|
11
|
+
model: str,
|
|
12
|
+
prompt: str,
|
|
13
|
+
max_tokens: int | None = None,
|
|
14
|
+
temperature: float | None = None,
|
|
15
|
+
) -> str: ...
|
|
16
|
+
|
|
17
|
+
def complete_messages(
|
|
18
|
+
self,
|
|
19
|
+
model: str,
|
|
20
|
+
messages: list[dict[str, object]],
|
|
21
|
+
max_tokens: int | None = None,
|
|
22
|
+
temperature: float | None = None,
|
|
23
|
+
top_p: float | None = None,
|
|
24
|
+
) -> str: ...
|
|
25
|
+
|
|
26
|
+
def complete_json(
|
|
27
|
+
self,
|
|
28
|
+
model: str,
|
|
29
|
+
messages: list[dict[str, object]],
|
|
30
|
+
max_tokens: int | None = None,
|
|
31
|
+
temperature: float | None = None,
|
|
32
|
+
top_p: float | None = None,
|
|
33
|
+
) -> str: ...
|
|
34
|
+
|
|
35
|
+
def complete_json_schema(
|
|
36
|
+
self,
|
|
37
|
+
model: str,
|
|
38
|
+
messages: list[dict[str, object]],
|
|
39
|
+
schema: dict[str, object],
|
|
40
|
+
schema_name: str,
|
|
41
|
+
max_tokens: int | None = None,
|
|
42
|
+
temperature: float | None = None,
|
|
43
|
+
top_p: float | None = None,
|
|
44
|
+
strict: bool = True,
|
|
45
|
+
) -> str: ...
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
//! Python bindings for SimpleAgents using PyO3.
|
|
2
|
+
|
|
3
|
+
#![allow(clippy::useless_conversion)]
|
|
4
|
+
|
|
5
|
+
use pyo3::exceptions::PyRuntimeError;
|
|
6
|
+
use pyo3::prelude::*;
|
|
7
|
+
use pyo3::types::{PyDict, PyList};
|
|
8
|
+
use reqwest::Client as HttpClient;
|
|
9
|
+
use simple_agents_core::{SimpleAgentsClient, SimpleAgentsClientBuilder};
|
|
10
|
+
use simple_agents_providers::anthropic::AnthropicProvider;
|
|
11
|
+
use simple_agents_providers::openai::OpenAIProvider;
|
|
12
|
+
use simple_agents_providers::openrouter::OpenRouterProvider;
|
|
13
|
+
use simple_agent_type::message::Message;
|
|
14
|
+
use simple_agent_type::prelude::{ApiKey, CompletionRequest, Provider, Result, SimpleAgentsError};
|
|
15
|
+
use simple_agent_type::request::{JsonSchemaFormat, ResponseFormat};
|
|
16
|
+
use std::sync::{Arc, Mutex};
|
|
17
|
+
use std::time::Duration;
|
|
18
|
+
|
|
19
|
+
type Runtime = tokio::runtime::Runtime;
|
|
20
|
+
|
|
21
|
+
#[pyclass]
|
|
22
|
+
struct Client {
|
|
23
|
+
runtime: Mutex<Runtime>,
|
|
24
|
+
client: SimpleAgentsClient,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fn provider_from_params(
|
|
28
|
+
provider_name: &str,
|
|
29
|
+
api_key: Option<&str>,
|
|
30
|
+
api_base: Option<&str>,
|
|
31
|
+
) -> Result<Arc<dyn Provider>> {
|
|
32
|
+
let api_key = match api_key {
|
|
33
|
+
Some(value) => Some(ApiKey::new(value)?),
|
|
34
|
+
None => None,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
match provider_name {
|
|
38
|
+
"openai" => {
|
|
39
|
+
let provider = match api_key {
|
|
40
|
+
Some(api_key) => match api_base {
|
|
41
|
+
Some(api_base) => {
|
|
42
|
+
if is_local_base(api_base) {
|
|
43
|
+
let client = HttpClient::builder()
|
|
44
|
+
.timeout(Duration::from_secs(30))
|
|
45
|
+
.pool_max_idle_per_host(10)
|
|
46
|
+
.pool_idle_timeout(Duration::from_secs(90))
|
|
47
|
+
.no_proxy()
|
|
48
|
+
.build()
|
|
49
|
+
.map_err(|e| {
|
|
50
|
+
SimpleAgentsError::Config(format!(
|
|
51
|
+
"Failed to create HTTP client: {}",
|
|
52
|
+
e
|
|
53
|
+
))
|
|
54
|
+
})?;
|
|
55
|
+
OpenAIProvider::with_client(api_key, api_base.to_string(), client)?
|
|
56
|
+
} else {
|
|
57
|
+
OpenAIProvider::with_base_url(api_key, api_base.to_string())?
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
None => OpenAIProvider::new(api_key)?,
|
|
61
|
+
},
|
|
62
|
+
None => OpenAIProvider::from_env()?,
|
|
63
|
+
};
|
|
64
|
+
Ok(Arc::new(provider))
|
|
65
|
+
}
|
|
66
|
+
"anthropic" => {
|
|
67
|
+
let provider = match api_key {
|
|
68
|
+
Some(api_key) => match api_base {
|
|
69
|
+
Some(api_base) => {
|
|
70
|
+
AnthropicProvider::with_base_url(api_key, api_base.to_string())?
|
|
71
|
+
}
|
|
72
|
+
None => AnthropicProvider::new(api_key)?,
|
|
73
|
+
},
|
|
74
|
+
None => AnthropicProvider::from_env()?,
|
|
75
|
+
};
|
|
76
|
+
Ok(Arc::new(provider))
|
|
77
|
+
}
|
|
78
|
+
"openrouter" => {
|
|
79
|
+
let provider = match api_key {
|
|
80
|
+
Some(api_key) => match api_base {
|
|
81
|
+
Some(api_base) => {
|
|
82
|
+
OpenRouterProvider::with_base_url(api_key, api_base.to_string())?
|
|
83
|
+
}
|
|
84
|
+
None => OpenRouterProvider::new(api_key)?,
|
|
85
|
+
},
|
|
86
|
+
None => OpenRouterProvider::from_env()?,
|
|
87
|
+
};
|
|
88
|
+
Ok(Arc::new(provider))
|
|
89
|
+
}
|
|
90
|
+
_ => Err(SimpleAgentsError::Config(format!(
|
|
91
|
+
"Unknown provider '{provider_name}'"
|
|
92
|
+
))),
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fn is_local_base(api_base: &str) -> bool {
|
|
97
|
+
api_base.contains("localhost") || api_base.contains("127.0.0.1")
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
fn build_request(
|
|
101
|
+
model: &str,
|
|
102
|
+
prompt: &str,
|
|
103
|
+
max_tokens: Option<u32>,
|
|
104
|
+
temperature: Option<f32>,
|
|
105
|
+
) -> Result<CompletionRequest> {
|
|
106
|
+
if model.is_empty() {
|
|
107
|
+
return Err(SimpleAgentsError::Config(
|
|
108
|
+
"model cannot be empty".to_string(),
|
|
109
|
+
));
|
|
110
|
+
}
|
|
111
|
+
if prompt.is_empty() {
|
|
112
|
+
return Err(SimpleAgentsError::Config(
|
|
113
|
+
"prompt cannot be empty".to_string(),
|
|
114
|
+
));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let mut builder = CompletionRequest::builder()
|
|
118
|
+
.model(model)
|
|
119
|
+
.message(Message::user(prompt));
|
|
120
|
+
|
|
121
|
+
if let Some(max_tokens) = max_tokens {
|
|
122
|
+
builder = builder.max_tokens(max_tokens);
|
|
123
|
+
}
|
|
124
|
+
if let Some(temperature) = temperature {
|
|
125
|
+
builder = builder.temperature(temperature);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
builder.build()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fn build_request_with_messages(
|
|
132
|
+
model: &str,
|
|
133
|
+
messages: Vec<Message>,
|
|
134
|
+
max_tokens: Option<u32>,
|
|
135
|
+
temperature: Option<f32>,
|
|
136
|
+
top_p: Option<f32>,
|
|
137
|
+
response_format: Option<ResponseFormat>,
|
|
138
|
+
) -> Result<CompletionRequest> {
|
|
139
|
+
if model.is_empty() {
|
|
140
|
+
return Err(SimpleAgentsError::Config(
|
|
141
|
+
"model cannot be empty".to_string(),
|
|
142
|
+
));
|
|
143
|
+
}
|
|
144
|
+
if messages.is_empty() {
|
|
145
|
+
return Err(SimpleAgentsError::Config(
|
|
146
|
+
"messages cannot be empty".to_string(),
|
|
147
|
+
));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let mut builder = CompletionRequest::builder().model(model);
|
|
151
|
+
for message in messages {
|
|
152
|
+
builder = builder.message(message);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if let Some(max_tokens) = max_tokens {
|
|
156
|
+
builder = builder.max_tokens(max_tokens);
|
|
157
|
+
}
|
|
158
|
+
if let Some(temperature) = temperature {
|
|
159
|
+
builder = builder.temperature(temperature);
|
|
160
|
+
}
|
|
161
|
+
if let Some(top_p) = top_p {
|
|
162
|
+
builder = builder.top_p(top_p);
|
|
163
|
+
}
|
|
164
|
+
if let Some(format) = response_format {
|
|
165
|
+
builder = builder.response_format(format);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
builder.build()
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
fn parse_messages(messages: &PyAny) -> Result<Vec<Message>> {
|
|
172
|
+
let list: &PyList = messages.downcast().map_err(|_| {
|
|
173
|
+
SimpleAgentsError::Config("messages must be a list of dicts".to_string())
|
|
174
|
+
})?;
|
|
175
|
+
let mut result = Vec::with_capacity(list.len());
|
|
176
|
+
|
|
177
|
+
for (idx, item) in list.iter().enumerate() {
|
|
178
|
+
let dict: &PyDict = item
|
|
179
|
+
.downcast()
|
|
180
|
+
.map_err(|_| SimpleAgentsError::Config(format!("message[{idx}] must be a dict")))?;
|
|
181
|
+
|
|
182
|
+
let role_obj = dict.get_item("role").ok_or_else(|| {
|
|
183
|
+
SimpleAgentsError::Config(format!("message[{idx}] missing 'role'"))
|
|
184
|
+
})?;
|
|
185
|
+
let role: &str = role_obj.extract().map_err(|_| {
|
|
186
|
+
SimpleAgentsError::Config(format!("message[{idx}].role must be a string"))
|
|
187
|
+
})?;
|
|
188
|
+
|
|
189
|
+
let content_obj = dict.get_item("content").ok_or_else(|| {
|
|
190
|
+
SimpleAgentsError::Config(format!("message[{idx}] missing 'content'"))
|
|
191
|
+
})?;
|
|
192
|
+
let content: &str = content_obj.extract().map_err(|_| {
|
|
193
|
+
SimpleAgentsError::Config(format!(
|
|
194
|
+
"message[{idx}].content must be a string"
|
|
195
|
+
))
|
|
196
|
+
})?;
|
|
197
|
+
|
|
198
|
+
let mut message = match role {
|
|
199
|
+
"user" => Message::user(content),
|
|
200
|
+
"assistant" => Message::assistant(content),
|
|
201
|
+
"system" => Message::system(content),
|
|
202
|
+
"tool" => {
|
|
203
|
+
let tool_call_id = dict
|
|
204
|
+
.get_item("tool_call_id")
|
|
205
|
+
.ok_or_else(|| {
|
|
206
|
+
SimpleAgentsError::Config(format!(
|
|
207
|
+
"message[{idx}] missing 'tool_call_id' for tool role"
|
|
208
|
+
))
|
|
209
|
+
})?
|
|
210
|
+
.extract::<String>()
|
|
211
|
+
.map_err(|_| {
|
|
212
|
+
SimpleAgentsError::Config(format!(
|
|
213
|
+
"message[{idx}].tool_call_id must be a string"
|
|
214
|
+
))
|
|
215
|
+
})?;
|
|
216
|
+
Message::tool(content, tool_call_id)
|
|
217
|
+
}
|
|
218
|
+
_ => {
|
|
219
|
+
return Err(SimpleAgentsError::Config(format!(
|
|
220
|
+
"message[{idx}].role must be one of: user, assistant, system, tool"
|
|
221
|
+
)))
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
if let Some(name_obj) = dict.get_item("name") {
|
|
226
|
+
if !name_obj.is_none() {
|
|
227
|
+
let name: String = name_obj.extract().map_err(|_| {
|
|
228
|
+
SimpleAgentsError::Config(format!("message[{idx}].name must be a string"))
|
|
229
|
+
})?;
|
|
230
|
+
message = message.with_name(name);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
result.push(message);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
Ok(result)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
fn py_err(error: SimpleAgentsError) -> PyErr {
|
|
241
|
+
PyRuntimeError::new_err(error.to_string())
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
#[pymethods]
|
|
245
|
+
#[allow(clippy::useless_conversion)]
|
|
246
|
+
impl Client {
|
|
247
|
+
#[new]
|
|
248
|
+
#[pyo3(signature = (provider, api_key=None, api_base=None))]
|
|
249
|
+
fn new(provider: &str, api_key: Option<String>, api_base: Option<String>) -> PyResult<Self> {
|
|
250
|
+
let provider = provider_from_params(
|
|
251
|
+
provider,
|
|
252
|
+
api_key.as_deref(),
|
|
253
|
+
api_base.as_deref(),
|
|
254
|
+
)
|
|
255
|
+
.map_err(py_err)?;
|
|
256
|
+
let client = SimpleAgentsClientBuilder::new()
|
|
257
|
+
.with_provider(provider)
|
|
258
|
+
.build()
|
|
259
|
+
.map_err(py_err)?;
|
|
260
|
+
let runtime = Runtime::new().map_err(|e| PyRuntimeError::new_err(e.to_string()))?;
|
|
261
|
+
|
|
262
|
+
Ok(Self {
|
|
263
|
+
runtime: Mutex::new(runtime),
|
|
264
|
+
client,
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
#[pyo3(signature = (model, prompt, max_tokens=None, temperature=None))]
|
|
269
|
+
fn complete(
|
|
270
|
+
&self,
|
|
271
|
+
model: &str,
|
|
272
|
+
prompt: &str,
|
|
273
|
+
max_tokens: Option<u32>,
|
|
274
|
+
temperature: Option<f32>,
|
|
275
|
+
) -> PyResult<String> {
|
|
276
|
+
let request = build_request(model, prompt, max_tokens, temperature).map_err(py_err)?;
|
|
277
|
+
let runtime = self
|
|
278
|
+
.runtime
|
|
279
|
+
.lock()
|
|
280
|
+
.map_err(|_| PyRuntimeError::new_err("runtime lock poisoned"))?;
|
|
281
|
+
let response = runtime
|
|
282
|
+
.block_on(self.client.complete(&request))
|
|
283
|
+
.map_err(py_err)?;
|
|
284
|
+
|
|
285
|
+
Ok(response.content().unwrap_or_default().to_string())
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
#[pyo3(signature = (model, messages, max_tokens=None, temperature=None, top_p=None))]
|
|
289
|
+
fn complete_messages(
|
|
290
|
+
&self,
|
|
291
|
+
model: &str,
|
|
292
|
+
messages: &PyAny,
|
|
293
|
+
max_tokens: Option<u32>,
|
|
294
|
+
temperature: Option<f32>,
|
|
295
|
+
top_p: Option<f32>,
|
|
296
|
+
) -> PyResult<String> {
|
|
297
|
+
let messages = parse_messages(messages).map_err(py_err)?;
|
|
298
|
+
let request = build_request_with_messages(
|
|
299
|
+
model,
|
|
300
|
+
messages,
|
|
301
|
+
max_tokens,
|
|
302
|
+
temperature,
|
|
303
|
+
top_p,
|
|
304
|
+
None,
|
|
305
|
+
)
|
|
306
|
+
.map_err(py_err)?;
|
|
307
|
+
let runtime = self
|
|
308
|
+
.runtime
|
|
309
|
+
.lock()
|
|
310
|
+
.map_err(|_| PyRuntimeError::new_err("runtime lock poisoned"))?;
|
|
311
|
+
let response = runtime
|
|
312
|
+
.block_on(self.client.complete(&request))
|
|
313
|
+
.map_err(py_err)?;
|
|
314
|
+
|
|
315
|
+
Ok(response.content().unwrap_or_default().to_string())
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
#[pyo3(signature = (model, messages, max_tokens=None, temperature=None, top_p=None))]
|
|
319
|
+
fn complete_json(
|
|
320
|
+
&self,
|
|
321
|
+
model: &str,
|
|
322
|
+
messages: &PyAny,
|
|
323
|
+
max_tokens: Option<u32>,
|
|
324
|
+
temperature: Option<f32>,
|
|
325
|
+
top_p: Option<f32>,
|
|
326
|
+
) -> PyResult<String> {
|
|
327
|
+
let messages = parse_messages(messages).map_err(py_err)?;
|
|
328
|
+
let request = build_request_with_messages(
|
|
329
|
+
model,
|
|
330
|
+
messages,
|
|
331
|
+
max_tokens,
|
|
332
|
+
temperature,
|
|
333
|
+
top_p,
|
|
334
|
+
Some(ResponseFormat::JsonObject),
|
|
335
|
+
)
|
|
336
|
+
.map_err(py_err)?;
|
|
337
|
+
let runtime = self
|
|
338
|
+
.runtime
|
|
339
|
+
.lock()
|
|
340
|
+
.map_err(|_| PyRuntimeError::new_err("runtime lock poisoned"))?;
|
|
341
|
+
let response = runtime
|
|
342
|
+
.block_on(self.client.complete(&request))
|
|
343
|
+
.map_err(py_err)?;
|
|
344
|
+
|
|
345
|
+
Ok(response.content().unwrap_or_default().to_string())
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
#[pyo3(signature = (model, messages, schema, schema_name, max_tokens=None, temperature=None, top_p=None, strict=True))]
|
|
349
|
+
fn complete_json_schema(
|
|
350
|
+
&self,
|
|
351
|
+
model: &str,
|
|
352
|
+
messages: &PyAny,
|
|
353
|
+
schema: &PyAny,
|
|
354
|
+
schema_name: &str,
|
|
355
|
+
max_tokens: Option<u32>,
|
|
356
|
+
temperature: Option<f32>,
|
|
357
|
+
top_p: Option<f32>,
|
|
358
|
+
strict: bool,
|
|
359
|
+
) -> PyResult<String> {
|
|
360
|
+
let messages = parse_messages(messages).map_err(py_err)?;
|
|
361
|
+
let schema_value: serde_json::Value = schema.extract().map_err(|_| {
|
|
362
|
+
py_err(SimpleAgentsError::Config(
|
|
363
|
+
"schema must be JSON-serializable".to_string(),
|
|
364
|
+
))
|
|
365
|
+
})?;
|
|
366
|
+
let response_format = ResponseFormat::JsonSchema {
|
|
367
|
+
json_schema: JsonSchemaFormat {
|
|
368
|
+
name: schema_name.to_string(),
|
|
369
|
+
schema: schema_value,
|
|
370
|
+
strict: Some(strict),
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
let request = build_request_with_messages(
|
|
374
|
+
model,
|
|
375
|
+
messages,
|
|
376
|
+
max_tokens,
|
|
377
|
+
temperature,
|
|
378
|
+
top_p,
|
|
379
|
+
Some(response_format),
|
|
380
|
+
)
|
|
381
|
+
.map_err(py_err)?;
|
|
382
|
+
let runtime = self
|
|
383
|
+
.runtime
|
|
384
|
+
.lock()
|
|
385
|
+
.map_err(|_| PyRuntimeError::new_err("runtime lock poisoned"))?;
|
|
386
|
+
let response = runtime
|
|
387
|
+
.block_on(self.client.complete(&request))
|
|
388
|
+
.map_err(py_err)?;
|
|
389
|
+
|
|
390
|
+
Ok(response.content().unwrap_or_default().to_string())
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
#[pymodule]
|
|
395
|
+
fn simple_agents_py(_py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
396
|
+
module.add_class::<Client>()?;
|
|
397
|
+
Ok(())
|
|
398
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simple-agents-py"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.6"
|
|
8
8
|
description = "Python bindings for SimpleAgents"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -23,6 +23,7 @@ dev = ["pytest>=8.0"]
|
|
|
23
23
|
[tool.maturin]
|
|
24
24
|
bindings = "pyo3"
|
|
25
25
|
module-name = "simple_agents_py"
|
|
26
|
+
include = ["simple_agents_py.pyi", "py.typed"]
|
|
26
27
|
manifest-path = "crates/simple-agents-py/Cargo.toml"
|
|
27
28
|
|
|
28
29
|
[tool.pytest.ini_options]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
class Client:
|
|
2
|
+
def __init__(
|
|
3
|
+
self,
|
|
4
|
+
provider: str,
|
|
5
|
+
api_key: str | None = None,
|
|
6
|
+
api_base: str | None = None,
|
|
7
|
+
) -> None: ...
|
|
8
|
+
|
|
9
|
+
def complete(
|
|
10
|
+
self,
|
|
11
|
+
model: str,
|
|
12
|
+
prompt: str,
|
|
13
|
+
max_tokens: int | None = None,
|
|
14
|
+
temperature: float | None = None,
|
|
15
|
+
) -> str: ...
|
|
16
|
+
|
|
17
|
+
def complete_messages(
|
|
18
|
+
self,
|
|
19
|
+
model: str,
|
|
20
|
+
messages: list[dict[str, object]],
|
|
21
|
+
max_tokens: int | None = None,
|
|
22
|
+
temperature: float | None = None,
|
|
23
|
+
top_p: float | None = None,
|
|
24
|
+
) -> str: ...
|
|
25
|
+
|
|
26
|
+
def complete_json(
|
|
27
|
+
self,
|
|
28
|
+
model: str,
|
|
29
|
+
messages: list[dict[str, object]],
|
|
30
|
+
max_tokens: int | None = None,
|
|
31
|
+
temperature: float | None = None,
|
|
32
|
+
top_p: float | None = None,
|
|
33
|
+
) -> str: ...
|
|
34
|
+
|
|
35
|
+
def complete_json_schema(
|
|
36
|
+
self,
|
|
37
|
+
model: str,
|
|
38
|
+
messages: list[dict[str, object]],
|
|
39
|
+
schema: dict[str, object],
|
|
40
|
+
schema_name: str,
|
|
41
|
+
max_tokens: int | None = None,
|
|
42
|
+
temperature: float | None = None,
|
|
43
|
+
top_p: float | None = None,
|
|
44
|
+
strict: bool = True,
|
|
45
|
+
) -> str: ...
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
//! Python bindings for SimpleAgents using PyO3.
|
|
2
|
-
|
|
3
|
-
#![allow(clippy::useless_conversion)]
|
|
4
|
-
|
|
5
|
-
use pyo3::exceptions::PyRuntimeError;
|
|
6
|
-
use pyo3::prelude::*;
|
|
7
|
-
use reqwest::Client as HttpClient;
|
|
8
|
-
use simple_agents_core::{SimpleAgentsClient, SimpleAgentsClientBuilder};
|
|
9
|
-
use simple_agents_providers::anthropic::AnthropicProvider;
|
|
10
|
-
use simple_agents_providers::openai::OpenAIProvider;
|
|
11
|
-
use simple_agents_providers::openrouter::OpenRouterProvider;
|
|
12
|
-
use simple_agent_type::message::Message;
|
|
13
|
-
use simple_agent_type::prelude::{ApiKey, CompletionRequest, Provider, Result, SimpleAgentsError};
|
|
14
|
-
use std::sync::{Arc, Mutex};
|
|
15
|
-
use std::time::Duration;
|
|
16
|
-
|
|
17
|
-
type Runtime = tokio::runtime::Runtime;
|
|
18
|
-
|
|
19
|
-
#[pyclass]
|
|
20
|
-
struct Client {
|
|
21
|
-
runtime: Mutex<Runtime>,
|
|
22
|
-
client: SimpleAgentsClient,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
fn provider_from_params(
|
|
26
|
-
provider_name: &str,
|
|
27
|
-
api_key: Option<&str>,
|
|
28
|
-
api_base: Option<&str>,
|
|
29
|
-
) -> Result<Arc<dyn Provider>> {
|
|
30
|
-
let api_key = match api_key {
|
|
31
|
-
Some(value) => Some(ApiKey::new(value)?),
|
|
32
|
-
None => None,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
match provider_name {
|
|
36
|
-
"openai" => {
|
|
37
|
-
let provider = match api_key {
|
|
38
|
-
Some(api_key) => match api_base {
|
|
39
|
-
Some(api_base) => {
|
|
40
|
-
if is_local_base(api_base) {
|
|
41
|
-
let client = HttpClient::builder()
|
|
42
|
-
.timeout(Duration::from_secs(30))
|
|
43
|
-
.pool_max_idle_per_host(10)
|
|
44
|
-
.pool_idle_timeout(Duration::from_secs(90))
|
|
45
|
-
.no_proxy()
|
|
46
|
-
.build()
|
|
47
|
-
.map_err(|e| {
|
|
48
|
-
SimpleAgentsError::Config(format!(
|
|
49
|
-
"Failed to create HTTP client: {}",
|
|
50
|
-
e
|
|
51
|
-
))
|
|
52
|
-
})?;
|
|
53
|
-
OpenAIProvider::with_client(api_key, api_base.to_string(), client)?
|
|
54
|
-
} else {
|
|
55
|
-
OpenAIProvider::with_base_url(api_key, api_base.to_string())?
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
None => OpenAIProvider::new(api_key)?,
|
|
59
|
-
},
|
|
60
|
-
None => OpenAIProvider::from_env()?,
|
|
61
|
-
};
|
|
62
|
-
Ok(Arc::new(provider))
|
|
63
|
-
}
|
|
64
|
-
"anthropic" => {
|
|
65
|
-
let provider = match api_key {
|
|
66
|
-
Some(api_key) => match api_base {
|
|
67
|
-
Some(api_base) => {
|
|
68
|
-
AnthropicProvider::with_base_url(api_key, api_base.to_string())?
|
|
69
|
-
}
|
|
70
|
-
None => AnthropicProvider::new(api_key)?,
|
|
71
|
-
},
|
|
72
|
-
None => AnthropicProvider::from_env()?,
|
|
73
|
-
};
|
|
74
|
-
Ok(Arc::new(provider))
|
|
75
|
-
}
|
|
76
|
-
"openrouter" => {
|
|
77
|
-
let provider = match api_key {
|
|
78
|
-
Some(api_key) => match api_base {
|
|
79
|
-
Some(api_base) => {
|
|
80
|
-
OpenRouterProvider::with_base_url(api_key, api_base.to_string())?
|
|
81
|
-
}
|
|
82
|
-
None => OpenRouterProvider::new(api_key)?,
|
|
83
|
-
},
|
|
84
|
-
None => OpenRouterProvider::from_env()?,
|
|
85
|
-
};
|
|
86
|
-
Ok(Arc::new(provider))
|
|
87
|
-
}
|
|
88
|
-
_ => Err(SimpleAgentsError::Config(format!(
|
|
89
|
-
"Unknown provider '{provider_name}'"
|
|
90
|
-
))),
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
fn is_local_base(api_base: &str) -> bool {
|
|
95
|
-
api_base.contains("localhost") || api_base.contains("127.0.0.1")
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
fn build_request(
|
|
99
|
-
model: &str,
|
|
100
|
-
prompt: &str,
|
|
101
|
-
max_tokens: Option<u32>,
|
|
102
|
-
temperature: Option<f32>,
|
|
103
|
-
) -> Result<CompletionRequest> {
|
|
104
|
-
if model.is_empty() {
|
|
105
|
-
return Err(SimpleAgentsError::Config(
|
|
106
|
-
"model cannot be empty".to_string(),
|
|
107
|
-
));
|
|
108
|
-
}
|
|
109
|
-
if prompt.is_empty() {
|
|
110
|
-
return Err(SimpleAgentsError::Config(
|
|
111
|
-
"prompt cannot be empty".to_string(),
|
|
112
|
-
));
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
let mut builder = CompletionRequest::builder()
|
|
116
|
-
.model(model)
|
|
117
|
-
.message(Message::user(prompt));
|
|
118
|
-
|
|
119
|
-
if let Some(max_tokens) = max_tokens {
|
|
120
|
-
builder = builder.max_tokens(max_tokens);
|
|
121
|
-
}
|
|
122
|
-
if let Some(temperature) = temperature {
|
|
123
|
-
builder = builder.temperature(temperature);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
builder.build()
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
fn py_err(error: SimpleAgentsError) -> PyErr {
|
|
130
|
-
PyRuntimeError::new_err(error.to_string())
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
#[pymethods]
|
|
134
|
-
#[allow(clippy::useless_conversion)]
|
|
135
|
-
impl Client {
|
|
136
|
-
#[new]
|
|
137
|
-
#[pyo3(signature = (provider, api_key=None, api_base=None))]
|
|
138
|
-
fn new(provider: &str, api_key: Option<String>, api_base: Option<String>) -> PyResult<Self> {
|
|
139
|
-
let provider = provider_from_params(
|
|
140
|
-
provider,
|
|
141
|
-
api_key.as_deref(),
|
|
142
|
-
api_base.as_deref(),
|
|
143
|
-
)
|
|
144
|
-
.map_err(py_err)?;
|
|
145
|
-
let client = SimpleAgentsClientBuilder::new()
|
|
146
|
-
.with_provider(provider)
|
|
147
|
-
.build()
|
|
148
|
-
.map_err(py_err)?;
|
|
149
|
-
let runtime = Runtime::new().map_err(|e| PyRuntimeError::new_err(e.to_string()))?;
|
|
150
|
-
|
|
151
|
-
Ok(Self {
|
|
152
|
-
runtime: Mutex::new(runtime),
|
|
153
|
-
client,
|
|
154
|
-
})
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
#[pyo3(signature = (model, prompt, max_tokens=None, temperature=None))]
|
|
158
|
-
fn complete(
|
|
159
|
-
&self,
|
|
160
|
-
model: &str,
|
|
161
|
-
prompt: &str,
|
|
162
|
-
max_tokens: Option<u32>,
|
|
163
|
-
temperature: Option<f32>,
|
|
164
|
-
) -> PyResult<String> {
|
|
165
|
-
let request = build_request(model, prompt, max_tokens, temperature).map_err(py_err)?;
|
|
166
|
-
let runtime = self
|
|
167
|
-
.runtime
|
|
168
|
-
.lock()
|
|
169
|
-
.map_err(|_| PyRuntimeError::new_err("runtime lock poisoned"))?;
|
|
170
|
-
let response = runtime
|
|
171
|
-
.block_on(self.client.complete(&request))
|
|
172
|
-
.map_err(py_err)?;
|
|
173
|
-
|
|
174
|
-
Ok(response.content().unwrap_or_default().to_string())
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
#[pymodule]
|
|
179
|
-
fn simple_agents_py(_py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
180
|
-
module.add_class::<Client>()?;
|
|
181
|
-
Ok(())
|
|
182
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/examples/basic_usage.rs
RENAMED
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/examples/mock_provider.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/src/validation.rs
RENAMED
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agent-type/tests/integration_test.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-core/examples/basic_client.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-core/src/middleware.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/src/coercion.rs
RENAMED
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/src/parser.rs
RENAMED
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/src/schema.rs
RENAMED
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/src/streaming.rs
RENAMED
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/src/string_utils.rs
RENAMED
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-healing/tests/parser_tests.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-macros/src/partial.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/common/error.rs
RENAMED
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/common/mod.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/metrics.rs
RENAMED
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/openai/error.rs
RENAMED
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/openai/mod.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/rate_limit.rs
RENAMED
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/retry.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/src/utils.rs
RENAMED
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-providers/tests/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-py/tests/test_client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/circuit_breaker.rs
RENAMED
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/fallback.rs
RENAMED
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/latency.rs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{simple_agents_py-0.1.5 → simple_agents_py-0.1.6}/crates/simple-agents-router/src/round_robin.rs
RENAMED
|
File without changes
|
|
File without changes
|