simple-agents-py 0.1.11__tar.gz → 0.1.15__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.
Files changed (137) hide show
  1. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/Cargo.lock +18 -11
  2. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/Cargo.toml +1 -1
  3. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/PKG-INFO +151 -13
  4. {simple_agents_py-0.1.11/crates/simple-agents-py → simple_agents_py-0.1.15}/README.md +150 -12
  5. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/src/lib.rs +7 -0
  6. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/src/message.rs +20 -0
  7. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/src/provider.rs +50 -5
  8. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/src/request.rs +23 -0
  9. simple_agents_py-0.1.15/crates/simple-agent-type/src/tool.rs +93 -0
  10. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-core/Cargo.toml +4 -3
  11. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-core/src/client.rs +24 -2
  12. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-core/src/routing.rs +22 -1
  13. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/Cargo.toml +1 -1
  14. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/src/coercion.rs +25 -0
  15. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/Cargo.toml +3 -3
  16. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/anthropic/mod.rs +7 -0
  17. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/openai/mod.rs +2 -0
  18. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/openai/models.rs +10 -0
  19. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/openrouter/mod.rs +2 -0
  20. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-py/Cargo.toml +7 -2
  21. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15/crates/simple-agents-py}/README.md +150 -12
  22. simple_agents_py-0.1.15/crates/simple-agents-py/examples/client_builder_demo.py +298 -0
  23. simple_agents_py-0.1.15/crates/simple-agents-py/examples/direct_healing_demo.py +73 -0
  24. simple_agents_py-0.1.15/crates/simple-agents-py/examples/healing_demo.py +48 -0
  25. simple_agents_py-0.1.15/crates/simple-agents-py/examples/routing_config_demo.py +469 -0
  26. simple_agents_py-0.1.15/crates/simple-agents-py/examples/streaming_demo.py +121 -0
  27. simple_agents_py-0.1.15/crates/simple-agents-py/examples/streaming_parser_demo.py +192 -0
  28. simple_agents_py-0.1.15/crates/simple-agents-py/examples/structured_streaming_demo.py +244 -0
  29. simple_agents_py-0.1.15/crates/simple-agents-py/simple_agents_py.pyi +240 -0
  30. simple_agents_py-0.1.15/crates/simple-agents-py/src/lib.rs +2538 -0
  31. simple_agents_py-0.1.15/crates/simple-agents-py/tests/test_client_builder.py +312 -0
  32. simple_agents_py-0.1.15/crates/simple-agents-py/tests/test_direct_healing.py +109 -0
  33. simple_agents_py-0.1.15/crates/simple-agents-py/tests/test_healing.py +79 -0
  34. simple_agents_py-0.1.15/crates/simple-agents-py/tests/test_integration_openai.py +77 -0
  35. simple_agents_py-0.1.15/crates/simple-agents-py/tests/test_routing_config.py +402 -0
  36. simple_agents_py-0.1.15/crates/simple-agents-py/tests/test_streaming.py +118 -0
  37. simple_agents_py-0.1.15/crates/simple-agents-py/tests/test_streaming_parser.py +178 -0
  38. simple_agents_py-0.1.15/crates/simple-agents-py/tests/test_structured_streaming.py +192 -0
  39. simple_agents_py-0.1.15/crates/simple-agents-py/uv.lock +199 -0
  40. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-router/Cargo.toml +1 -0
  41. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-router/src/cost.rs +13 -2
  42. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-router/src/fallback.rs +22 -1
  43. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-router/src/latency.rs +13 -2
  44. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-router/src/round_robin.rs +17 -1
  45. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/pyproject.toml +1 -1
  46. simple_agents_py-0.1.15/simple_agents_py.pyi +240 -0
  47. simple_agents_py-0.1.11/crates/simple-agents-py/simple_agents_py.pyi +0 -45
  48. simple_agents_py-0.1.11/crates/simple-agents-py/src/lib.rs +0 -411
  49. simple_agents_py-0.1.11/simple_agents_py.pyi +0 -45
  50. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/Cargo.toml +0 -0
  51. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/README.md +0 -0
  52. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/TEST_GUIDE.md +0 -0
  53. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/TODO.md +0 -0
  54. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/examples/basic_usage.rs +0 -0
  55. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/examples/mock_provider.rs +0 -0
  56. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/src/cache.rs +0 -0
  57. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/src/coercion.rs +0 -0
  58. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/src/config.rs +0 -0
  59. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/src/error.rs +0 -0
  60. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/src/response.rs +0 -0
  61. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/src/router.rs +0 -0
  62. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/src/validation.rs +0 -0
  63. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agent-type/tests/integration_test.rs +0 -0
  64. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-cache/Cargo.toml +0 -0
  65. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-cache/src/lib.rs +0 -0
  66. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-cache/src/memory.rs +0 -0
  67. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-cache/src/noop.rs +0 -0
  68. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-core/README.md +0 -0
  69. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-core/examples/basic_client.rs +0 -0
  70. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-core/src/healing.rs +0 -0
  71. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-core/src/lib.rs +0 -0
  72. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-core/src/middleware.rs +0 -0
  73. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-core/tests/client_integration.rs +0 -0
  74. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/README.md +0 -0
  75. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/benches/parser_benchmarks.rs +0 -0
  76. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/examples/basic_healing.rs +0 -0
  77. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/examples/coercion_demo.rs +0 -0
  78. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/examples/streaming_annotations.rs +0 -0
  79. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/examples/streaming_partial_types.rs +0 -0
  80. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/src/lib.rs +0 -0
  81. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/src/parser.rs +0 -0
  82. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/src/schema.rs +0 -0
  83. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/src/streaming.rs +0 -0
  84. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/src/string_utils.rs +0 -0
  85. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/tests/parser_tests.rs +0 -0
  86. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/tests/property_tests.rs +0 -0
  87. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/tests/stream_annotations_tests.rs +0 -0
  88. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-healing/tests/streaming_tests.rs +0 -0
  89. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-macros/Cargo.toml +0 -0
  90. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-macros/README.md +0 -0
  91. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-macros/src/lib.rs +0 -0
  92. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-macros/src/partial.rs +0 -0
  93. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-macros/tests/partial_type_tests.rs +0 -0
  94. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/README.md +0 -0
  95. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/anthropic_basic.rs +0 -0
  96. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/anthropic_structured_output.rs +0 -0
  97. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/cache_usage.rs +0 -0
  98. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/custom_api.rs +0 -0
  99. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/healing_fallback.rs +0 -0
  100. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/openai_basic.rs +0 -0
  101. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/openai_structured_output.rs +0 -0
  102. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/openrouter_basic.rs +0 -0
  103. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/retry_demo.rs +0 -0
  104. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/streaming.rs +0 -0
  105. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/streaming_structured.rs +0 -0
  106. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/streaming_with_healing.rs +0 -0
  107. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/test_local_api.rs +0 -0
  108. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/examples/test_reqwest.rs +0 -0
  109. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/run_integration_tests.sh +0 -0
  110. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/anthropic/error.rs +0 -0
  111. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/anthropic/models.rs +0 -0
  112. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/anthropic/streaming.rs +0 -0
  113. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/common/error.rs +0 -0
  114. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/common/http_client.rs +0 -0
  115. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/common/mod.rs +0 -0
  116. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/healing_integration.rs +0 -0
  117. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/lib.rs +0 -0
  118. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/metrics.rs +0 -0
  119. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/openai/error.rs +0 -0
  120. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/openai/streaming.rs +0 -0
  121. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/rate_limit.rs +0 -0
  122. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/retry.rs +0 -0
  123. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/schema_converter.rs +0 -0
  124. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/streaming_structured.rs +0 -0
  125. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/src/utils.rs +0 -0
  126. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/tests/README.md +0 -0
  127. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/tests/healing_integration_tests.rs +0 -0
  128. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-providers/tests/openai_integration.rs +0 -0
  129. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-py/py.typed +0 -0
  130. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-py/tests/test_client.py +0 -0
  131. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-router/examples/round_robin_router.rs +0 -0
  132. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-router/src/circuit_breaker.rs +0 -0
  133. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-router/src/health.rs +0 -0
  134. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-router/src/lib.rs +0 -0
  135. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-router/src/retry.rs +0 -0
  136. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/crates/simple-agents-router/tests/health_tracker_integration.rs +0 -0
  137. {simple_agents_py-0.1.11 → simple_agents_py-0.1.15}/py.typed +0 -0
@@ -2035,7 +2035,7 @@ dependencies = [
2035
2035
 
2036
2036
  [[package]]
2037
2037
  name = "simple-agent-type"
2038
- version = "0.1.11"
2038
+ version = "0.1.15"
2039
2039
  dependencies = [
2040
2040
  "async-trait",
2041
2041
  "blake3",
@@ -2050,7 +2050,7 @@ dependencies = [
2050
2050
 
2051
2051
  [[package]]
2052
2052
  name = "simple-agents-cache"
2053
- version = "0.1.11"
2053
+ version = "0.1.15"
2054
2054
  dependencies = [
2055
2055
  "async-trait",
2056
2056
  "simple-agent-type",
@@ -2059,7 +2059,7 @@ dependencies = [
2059
2059
 
2060
2060
  [[package]]
2061
2061
  name = "simple-agents-cli"
2062
- version = "0.1.11"
2062
+ version = "0.1.15"
2063
2063
  dependencies = [
2064
2064
  "clap",
2065
2065
  "serde",
@@ -2076,9 +2076,10 @@ dependencies = [
2076
2076
 
2077
2077
  [[package]]
2078
2078
  name = "simple-agents-core"
2079
- version = "0.1.11"
2079
+ version = "0.1.15"
2080
2080
  dependencies = [
2081
2081
  "async-trait",
2082
+ "futures-core",
2082
2083
  "serde",
2083
2084
  "serde_json",
2084
2085
  "simple-agent-type",
@@ -2103,7 +2104,7 @@ dependencies = [
2103
2104
 
2104
2105
  [[package]]
2105
2106
  name = "simple-agents-ffi"
2106
- version = "0.1.11"
2107
+ version = "0.1.15"
2107
2108
  dependencies = [
2108
2109
  "async-trait",
2109
2110
  "simple-agent-type",
@@ -2114,7 +2115,7 @@ dependencies = [
2114
2115
 
2115
2116
  [[package]]
2116
2117
  name = "simple-agents-healing"
2117
- version = "0.1.11"
2118
+ version = "0.1.15"
2118
2119
  dependencies = [
2119
2120
  "criterion",
2120
2121
  "proptest",
@@ -2130,7 +2131,7 @@ dependencies = [
2130
2131
 
2131
2132
  [[package]]
2132
2133
  name = "simple-agents-macros"
2133
- version = "0.1.11"
2134
+ version = "0.1.15"
2134
2135
  dependencies = [
2135
2136
  "proc-macro2",
2136
2137
  "quote",
@@ -2142,7 +2143,7 @@ dependencies = [
2142
2143
 
2143
2144
  [[package]]
2144
2145
  name = "simple-agents-napi"
2145
- version = "0.1.11"
2146
+ version = "0.1.15"
2146
2147
  dependencies = [
2147
2148
  "napi",
2148
2149
  "napi-derive",
@@ -2154,7 +2155,7 @@ dependencies = [
2154
2155
 
2155
2156
  [[package]]
2156
2157
  name = "simple-agents-providers"
2157
- version = "0.1.11"
2158
+ version = "0.1.15"
2158
2159
  dependencies = [
2159
2160
  "async-trait",
2160
2161
  "bytes",
@@ -2182,23 +2183,29 @@ dependencies = [
2182
2183
 
2183
2184
  [[package]]
2184
2185
  name = "simple-agents-py"
2185
- version = "0.1.11"
2186
+ version = "0.1.15"
2186
2187
  dependencies = [
2188
+ "async-trait",
2189
+ "futures-util",
2187
2190
  "pyo3",
2188
2191
  "pythonize",
2189
2192
  "reqwest",
2190
2193
  "serde_json",
2191
2194
  "simple-agent-type",
2195
+ "simple-agents-cache",
2192
2196
  "simple-agents-core",
2197
+ "simple-agents-healing",
2193
2198
  "simple-agents-providers",
2199
+ "simple-agents-router",
2194
2200
  "tokio",
2195
2201
  ]
2196
2202
 
2197
2203
  [[package]]
2198
2204
  name = "simple-agents-router"
2199
- version = "0.1.11"
2205
+ version = "0.1.15"
2200
2206
  dependencies = [
2201
2207
  "async-trait",
2208
+ "futures-core",
2202
2209
  "rand 0.8.5",
2203
2210
  "serde_json",
2204
2211
  "simple-agent-type",
@@ -3,7 +3,7 @@ members = ["crates/*"]
3
3
  resolver = "2"
4
4
 
5
5
  [workspace.package]
6
- version = "0.1.11"
6
+ version = "0.1.15"
7
7
  edition = "2021"
8
8
  rust-version = "1.75"
9
9
  authors = ["SimpleAgents Contributors"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simple-agents-py
3
- Version: 0.1.11
3
+ Version: 0.1.15
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -57,7 +57,145 @@ from simple_agents_py import Client
57
57
 
58
58
  client = Client("openai")
59
59
  response = client.complete("gpt-4", "Hello from Python!", max_tokens=128, temperature=0.7)
60
- print(response)
60
+ print(response.content)
61
+ ```
62
+
63
+ ## Feature Guide
64
+
65
+ ### Streaming
66
+
67
+ ```python
68
+ from simple_agents_py import Client
69
+
70
+ client = Client("openai")
71
+ messages = [{"role": "user", "content": "Say hello in one sentence."}]
72
+ for chunk in client.stream("gpt-4o-mini", messages, max_tokens=64):
73
+ if chunk.content:
74
+ print(chunk.content, end="", flush=True)
75
+ print()
76
+ ```
77
+
78
+ ### Structured Output (JSON Mode)
79
+
80
+ ```python
81
+ from simple_agents_py import Client
82
+ import json
83
+
84
+ client = Client("openai")
85
+ schema = {
86
+ "type": "object",
87
+ "properties": {
88
+ "name": {"type": "string"},
89
+ "age": {"type": "number"},
90
+ },
91
+ "required": ["name", "age"],
92
+ }
93
+ messages = [{"role": "user", "content": "Extract name and age: Alice is 28."}]
94
+ json_text = client.complete_json_schema("gpt-4o-mini", messages, schema, "person")
95
+ print(json.loads(json_text))
96
+ ```
97
+
98
+ Pydantic models are accepted too:
99
+
100
+ ```python
101
+ from pydantic import BaseModel
102
+ from simple_agents_py import Client
103
+
104
+ class Person(BaseModel):
105
+ name: str
106
+ age: int
107
+
108
+ client = Client("openai")
109
+ messages = [{"role": "user", "content": "Extract name and age: Alice is 28."}]
110
+ json_text = client.complete_json_schema("gpt-4o-mini", messages, Person, "person")
111
+ print(json_text)
112
+ ```
113
+
114
+ **Healing for Structured Outputs**: Healing is enabled by default for structured outputs, automatically fixing malformed JSON, type mismatches, and missing fields. To disable healing:
115
+
116
+ ```python
117
+ client = Client("openai", healing=False)
118
+ ```
119
+
120
+ ### Structured Streaming
121
+
122
+ ```python
123
+ from simple_agents_py import Client
124
+
125
+ client = Client("openai")
126
+ schema = {
127
+ "type": "object",
128
+ "properties": {"name": {"type": "string"}, "age": {"type": "number"}},
129
+ "required": ["name", "age"],
130
+ }
131
+ messages = [{"role": "user", "content": "Extract name and age: Alice is 28."}]
132
+ for event in client.stream_structured("gpt-4o-mini", messages, schema, max_tokens=64):
133
+ if event.is_partial:
134
+ print("partial:", event.partial_value)
135
+ else:
136
+ print("complete:", event.value)
137
+ ```
138
+
139
+ ### Response Healing
140
+
141
+ ```python
142
+ from simple_agents_py import Client
143
+
144
+ client = Client("openai")
145
+ messages = [{"role": "user", "content": "Return JSON: {\"name\":\"Sam\",\"age\":30}"}]
146
+ healed = client.complete_json_healed("gpt-4o-mini", messages, max_tokens=64)
147
+ print(healed.content)
148
+ print(healed.was_healed, healed.confidence)
149
+ print(healed.usage.get("total_tokens"))
150
+ ```
151
+
152
+ ### Tool Calling
153
+
154
+ ```python
155
+ from simple_agents_py import Client
156
+
157
+ client = Client("openai")
158
+ tools = [
159
+ {
160
+ "type": "function",
161
+ "function": {
162
+ "name": "get_weather",
163
+ "description": "Get the weather for a city",
164
+ "parameters": {
165
+ "type": "object",
166
+ "properties": {
167
+ "city": {"type": "string"},
168
+ "unit": {"type": "string", "enum": ["c", "f"]},
169
+ },
170
+ "required": ["city"],
171
+ },
172
+ },
173
+ }
174
+ ]
175
+ messages = [{"role": "user", "content": "What's the weather in Tokyo?"}]
176
+ response = client.complete_with_tools("gpt-4o-mini", messages, tools)
177
+ print(response.tool_calls)
178
+ ```
179
+
180
+ ### ClientBuilder (Routing, Cache, Healing, Middleware)
181
+
182
+ ```python
183
+ from simple_agents_py import ClientBuilder
184
+
185
+ class TimingMiddleware:
186
+ def before_request(self, request):
187
+ print("sending", request.model)
188
+
189
+ builder = (
190
+ ClientBuilder()
191
+ .add_provider("openai", api_key="sk-...")
192
+ .with_routing("direct")
193
+ .with_cache(ttl_seconds=60)
194
+ .with_healing_config({"enabled": True, "min_confidence": 0.7})
195
+ .add_middleware(TimingMiddleware())
196
+ )
197
+ client = builder.build()
198
+ print(client.complete("gpt-4o-mini", "Give me one idea.").content)
61
199
  ```
62
200
 
63
201
  ## Examples
@@ -68,8 +206,8 @@ OpenAI with a short prompt:
68
206
  from simple_agents_py import Client
69
207
 
70
208
  client = Client("openai")
71
- text = client.complete("gpt-4o-mini", "Summarize this in one sentence.")
72
- print(text)
209
+ response = client.complete("gpt-4o-mini", "Summarize this in one sentence.")
210
+ print(response.content)
73
211
  ```
74
212
 
75
213
  Anthropic with custom tokens and temperature:
@@ -78,13 +216,13 @@ Anthropic with custom tokens and temperature:
78
216
  from simple_agents_py import Client
79
217
 
80
218
  client = Client("anthropic")
81
- text = client.complete(
219
+ response = client.complete(
82
220
  "claude-3-5-sonnet-20240620",
83
221
  "Write a friendly welcome message for a new user.",
84
222
  max_tokens=120,
85
223
  temperature=0.5,
86
224
  )
87
- print(text)
225
+ print(response.content)
88
226
  ```
89
227
 
90
228
  OpenRouter with a specific model:
@@ -93,8 +231,8 @@ OpenRouter with a specific model:
93
231
  from simple_agents_py import Client
94
232
 
95
233
  client = Client("openrouter")
96
- text = client.complete("openai/gpt-4o-mini", "Give me three project ideas.")
97
- print(text)
234
+ response = client.complete("openai/gpt-4o-mini", "Give me three project ideas.")
235
+ print(response.content)
98
236
  ```
99
237
 
100
238
  OpenRouter with explicit API base and key:
@@ -107,8 +245,8 @@ client = Client(
107
245
  api_base="https://openrouter.ai/api/v1",
108
246
  api_key="sk-your-openrouter-key",
109
247
  )
110
- text = client.complete("openai/gpt-4o-mini", "Give me three project ideas.")
111
- print(text)
248
+ response = client.complete("openai/gpt-4o-mini", "Give me three project ideas.")
249
+ print(response.content)
112
250
  ```
113
251
 
114
252
  OpenAI with a custom gateway:
@@ -121,8 +259,8 @@ client = Client(
121
259
  api_base="http://localhost:4000/v1",
122
260
  api_key="sk-your-openai-key",
123
261
  )
124
- text = client.complete("gpt-4o-mini", "Say hello from a local proxy.")
125
- print(text)
262
+ response = client.complete("gpt-4o-mini", "Say hello from a local proxy.")
263
+ print(response.content)
126
264
  ```
127
265
 
128
266
  Basic error handling:
@@ -132,7 +270,7 @@ from simple_agents_py import Client
132
270
 
133
271
  try:
134
272
  client = Client("openai")
135
- print(client.complete("gpt-4o-mini", "Hello!"))
273
+ print(client.complete("gpt-4o-mini", "Hello!").content)
136
274
  except RuntimeError as exc:
137
275
  print(f"Request failed: {exc}")
138
276
  ```
@@ -42,7 +42,145 @@ from simple_agents_py import Client
42
42
 
43
43
  client = Client("openai")
44
44
  response = client.complete("gpt-4", "Hello from Python!", max_tokens=128, temperature=0.7)
45
- print(response)
45
+ print(response.content)
46
+ ```
47
+
48
+ ## Feature Guide
49
+
50
+ ### Streaming
51
+
52
+ ```python
53
+ from simple_agents_py import Client
54
+
55
+ client = Client("openai")
56
+ messages = [{"role": "user", "content": "Say hello in one sentence."}]
57
+ for chunk in client.stream("gpt-4o-mini", messages, max_tokens=64):
58
+ if chunk.content:
59
+ print(chunk.content, end="", flush=True)
60
+ print()
61
+ ```
62
+
63
+ ### Structured Output (JSON Mode)
64
+
65
+ ```python
66
+ from simple_agents_py import Client
67
+ import json
68
+
69
+ client = Client("openai")
70
+ schema = {
71
+ "type": "object",
72
+ "properties": {
73
+ "name": {"type": "string"},
74
+ "age": {"type": "number"},
75
+ },
76
+ "required": ["name", "age"],
77
+ }
78
+ messages = [{"role": "user", "content": "Extract name and age: Alice is 28."}]
79
+ json_text = client.complete_json_schema("gpt-4o-mini", messages, schema, "person")
80
+ print(json.loads(json_text))
81
+ ```
82
+
83
+ Pydantic models are accepted too:
84
+
85
+ ```python
86
+ from pydantic import BaseModel
87
+ from simple_agents_py import Client
88
+
89
+ class Person(BaseModel):
90
+ name: str
91
+ age: int
92
+
93
+ client = Client("openai")
94
+ messages = [{"role": "user", "content": "Extract name and age: Alice is 28."}]
95
+ json_text = client.complete_json_schema("gpt-4o-mini", messages, Person, "person")
96
+ print(json_text)
97
+ ```
98
+
99
+ **Healing for Structured Outputs**: Healing is enabled by default for structured outputs, automatically fixing malformed JSON, type mismatches, and missing fields. To disable healing:
100
+
101
+ ```python
102
+ client = Client("openai", healing=False)
103
+ ```
104
+
105
+ ### Structured Streaming
106
+
107
+ ```python
108
+ from simple_agents_py import Client
109
+
110
+ client = Client("openai")
111
+ schema = {
112
+ "type": "object",
113
+ "properties": {"name": {"type": "string"}, "age": {"type": "number"}},
114
+ "required": ["name", "age"],
115
+ }
116
+ messages = [{"role": "user", "content": "Extract name and age: Alice is 28."}]
117
+ for event in client.stream_structured("gpt-4o-mini", messages, schema, max_tokens=64):
118
+ if event.is_partial:
119
+ print("partial:", event.partial_value)
120
+ else:
121
+ print("complete:", event.value)
122
+ ```
123
+
124
+ ### Response Healing
125
+
126
+ ```python
127
+ from simple_agents_py import Client
128
+
129
+ client = Client("openai")
130
+ messages = [{"role": "user", "content": "Return JSON: {\"name\":\"Sam\",\"age\":30}"}]
131
+ healed = client.complete_json_healed("gpt-4o-mini", messages, max_tokens=64)
132
+ print(healed.content)
133
+ print(healed.was_healed, healed.confidence)
134
+ print(healed.usage.get("total_tokens"))
135
+ ```
136
+
137
+ ### Tool Calling
138
+
139
+ ```python
140
+ from simple_agents_py import Client
141
+
142
+ client = Client("openai")
143
+ tools = [
144
+ {
145
+ "type": "function",
146
+ "function": {
147
+ "name": "get_weather",
148
+ "description": "Get the weather for a city",
149
+ "parameters": {
150
+ "type": "object",
151
+ "properties": {
152
+ "city": {"type": "string"},
153
+ "unit": {"type": "string", "enum": ["c", "f"]},
154
+ },
155
+ "required": ["city"],
156
+ },
157
+ },
158
+ }
159
+ ]
160
+ messages = [{"role": "user", "content": "What's the weather in Tokyo?"}]
161
+ response = client.complete_with_tools("gpt-4o-mini", messages, tools)
162
+ print(response.tool_calls)
163
+ ```
164
+
165
+ ### ClientBuilder (Routing, Cache, Healing, Middleware)
166
+
167
+ ```python
168
+ from simple_agents_py import ClientBuilder
169
+
170
+ class TimingMiddleware:
171
+ def before_request(self, request):
172
+ print("sending", request.model)
173
+
174
+ builder = (
175
+ ClientBuilder()
176
+ .add_provider("openai", api_key="sk-...")
177
+ .with_routing("direct")
178
+ .with_cache(ttl_seconds=60)
179
+ .with_healing_config({"enabled": True, "min_confidence": 0.7})
180
+ .add_middleware(TimingMiddleware())
181
+ )
182
+ client = builder.build()
183
+ print(client.complete("gpt-4o-mini", "Give me one idea.").content)
46
184
  ```
47
185
 
48
186
  ## Examples
@@ -53,8 +191,8 @@ OpenAI with a short prompt:
53
191
  from simple_agents_py import Client
54
192
 
55
193
  client = Client("openai")
56
- text = client.complete("gpt-4o-mini", "Summarize this in one sentence.")
57
- print(text)
194
+ response = client.complete("gpt-4o-mini", "Summarize this in one sentence.")
195
+ print(response.content)
58
196
  ```
59
197
 
60
198
  Anthropic with custom tokens and temperature:
@@ -63,13 +201,13 @@ Anthropic with custom tokens and temperature:
63
201
  from simple_agents_py import Client
64
202
 
65
203
  client = Client("anthropic")
66
- text = client.complete(
204
+ response = client.complete(
67
205
  "claude-3-5-sonnet-20240620",
68
206
  "Write a friendly welcome message for a new user.",
69
207
  max_tokens=120,
70
208
  temperature=0.5,
71
209
  )
72
- print(text)
210
+ print(response.content)
73
211
  ```
74
212
 
75
213
  OpenRouter with a specific model:
@@ -78,8 +216,8 @@ OpenRouter with a specific model:
78
216
  from simple_agents_py import Client
79
217
 
80
218
  client = Client("openrouter")
81
- text = client.complete("openai/gpt-4o-mini", "Give me three project ideas.")
82
- print(text)
219
+ response = client.complete("openai/gpt-4o-mini", "Give me three project ideas.")
220
+ print(response.content)
83
221
  ```
84
222
 
85
223
  OpenRouter with explicit API base and key:
@@ -92,8 +230,8 @@ client = Client(
92
230
  api_base="https://openrouter.ai/api/v1",
93
231
  api_key="sk-your-openrouter-key",
94
232
  )
95
- text = client.complete("openai/gpt-4o-mini", "Give me three project ideas.")
96
- print(text)
233
+ response = client.complete("openai/gpt-4o-mini", "Give me three project ideas.")
234
+ print(response.content)
97
235
  ```
98
236
 
99
237
  OpenAI with a custom gateway:
@@ -106,8 +244,8 @@ client = Client(
106
244
  api_base="http://localhost:4000/v1",
107
245
  api_key="sk-your-openai-key",
108
246
  )
109
- text = client.complete("gpt-4o-mini", "Say hello from a local proxy.")
110
- print(text)
247
+ response = client.complete("gpt-4o-mini", "Say hello from a local proxy.")
248
+ print(response.content)
111
249
  ```
112
250
 
113
251
  Basic error handling:
@@ -117,7 +255,7 @@ from simple_agents_py import Client
117
255
 
118
256
  try:
119
257
  client = Client("openai")
120
- print(client.complete("gpt-4o-mini", "Hello!"))
258
+ print(client.complete("gpt-4o-mini", "Hello!").content)
121
259
  except RuntimeError as exc:
122
260
  print(f"Request failed: {exc}")
123
261
  ```
@@ -58,6 +58,7 @@ pub mod provider;
58
58
  pub mod request;
59
59
  pub mod response;
60
60
  pub mod router;
61
+ pub mod tool;
61
62
  pub mod validation;
62
63
 
63
64
  // Re-export commonly used types at crate root
@@ -101,6 +102,12 @@ pub mod prelude {
101
102
  // Coercion
102
103
  pub use crate::coercion::{CoercionFlag, CoercionResult};
103
104
 
105
+ // Tool calling
106
+ pub use crate::tool::{
107
+ ToolCall, ToolCallFunction, ToolChoice, ToolChoiceFunction, ToolChoiceMode, ToolChoiceTool,
108
+ ToolDefinition, ToolFunction, ToolType,
109
+ };
110
+
104
111
  // Traits
105
112
  pub use crate::cache::Cache;
106
113
  pub use crate::provider::Provider;
@@ -4,6 +4,8 @@
4
4
 
5
5
  use serde::{Deserialize, Serialize};
6
6
 
7
+ use crate::tool::ToolCall;
8
+
7
9
  /// Role of a message in a conversation.
8
10
  #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9
11
  #[serde(rename_all = "lowercase")]
@@ -32,6 +34,9 @@ pub struct Message {
32
34
  /// Tool call ID (for tool role messages)
33
35
  #[serde(skip_serializing_if = "Option::is_none")]
34
36
  pub tool_call_id: Option<String>,
37
+ /// Tool calls emitted by the assistant.
38
+ #[serde(skip_serializing_if = "Option::is_none")]
39
+ pub tool_calls: Option<Vec<ToolCall>>,
35
40
  }
36
41
 
37
42
  impl Message {
@@ -51,6 +56,7 @@ impl Message {
51
56
  content: content.into(),
52
57
  name: None,
53
58
  tool_call_id: None,
59
+ tool_calls: None,
54
60
  }
55
61
  }
56
62
 
@@ -69,6 +75,7 @@ impl Message {
69
75
  content: content.into(),
70
76
  name: None,
71
77
  tool_call_id: None,
78
+ tool_calls: None,
72
79
  }
73
80
  }
74
81
 
@@ -87,6 +94,7 @@ impl Message {
87
94
  content: content.into(),
88
95
  name: None,
89
96
  tool_call_id: None,
97
+ tool_calls: None,
90
98
  }
91
99
  }
92
100
 
@@ -106,6 +114,7 @@ impl Message {
106
114
  content: content.into(),
107
115
  name: None,
108
116
  tool_call_id: Some(tool_call_id.into()),
117
+ tool_calls: None,
109
118
  }
110
119
  }
111
120
 
@@ -122,6 +131,12 @@ impl Message {
122
131
  self.name = Some(name.into());
123
132
  self
124
133
  }
134
+
135
+ /// Set tool calls for assistant messages.
136
+ pub fn with_tool_calls(mut self, tool_calls: Vec<ToolCall>) -> Self {
137
+ self.tool_calls = Some(tool_calls);
138
+ self
139
+ }
125
140
  }
126
141
 
127
142
  #[cfg(test)]
@@ -135,6 +150,7 @@ mod tests {
135
150
  assert_eq!(msg.content, "test");
136
151
  assert_eq!(msg.name, None);
137
152
  assert_eq!(msg.tool_call_id, None);
153
+ assert_eq!(msg.tool_calls, None);
138
154
  }
139
155
 
140
156
  #[test]
@@ -142,6 +158,7 @@ mod tests {
142
158
  let msg = Message::assistant("response");
143
159
  assert_eq!(msg.role, Role::Assistant);
144
160
  assert_eq!(msg.content, "response");
161
+ assert_eq!(msg.tool_calls, None);
145
162
  }
146
163
 
147
164
  #[test]
@@ -149,6 +166,7 @@ mod tests {
149
166
  let msg = Message::system("instruction");
150
167
  assert_eq!(msg.role, Role::System);
151
168
  assert_eq!(msg.content, "instruction");
169
+ assert_eq!(msg.tool_calls, None);
152
170
  }
153
171
 
154
172
  #[test]
@@ -157,6 +175,7 @@ mod tests {
157
175
  assert_eq!(msg.role, Role::Tool);
158
176
  assert_eq!(msg.content, "result");
159
177
  assert_eq!(msg.tool_call_id, Some("call_123".to_string()));
178
+ assert_eq!(msg.tool_calls, None);
160
179
  }
161
180
 
162
181
  #[test]
@@ -194,6 +213,7 @@ mod tests {
194
213
  let json = serde_json::to_value(&msg).unwrap();
195
214
  assert!(json.get("name").is_none());
196
215
  assert!(json.get("tool_call_id").is_none());
216
+ assert!(json.get("tool_calls").is_none());
197
217
  }
198
218
 
199
219
  #[test]