selectools 0.19.0__tar.gz → 0.19.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.
Files changed (233) hide show
  1. {selectools-0.19.0/src/selectools.egg-info → selectools-0.19.2}/PKG-INFO +105 -11
  2. {selectools-0.19.0 → selectools-0.19.2}/README.md +103 -10
  3. {selectools-0.19.0 → selectools-0.19.2}/pyproject.toml +4 -1
  4. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/__init__.py +35 -3
  5. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/agent/_memory_manager.py +2 -1
  6. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/agent/_provider_caller.py +55 -15
  7. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/agent/_tool_executor.py +85 -25
  8. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/agent/core.py +28 -15
  9. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/audit.py +5 -3
  10. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/coherence.py +30 -4
  11. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/entity_memory.py +8 -3
  12. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/__init__.py +26 -2
  13. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/badge.py +8 -2
  14. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/evaluators.py +397 -1
  15. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/history.py +25 -20
  16. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/html.py +4 -1
  17. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/junit.py +4 -1
  18. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/llm_evaluators.py +323 -41
  19. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/regression.py +7 -3
  20. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/report.py +10 -6
  21. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/snapshot.py +13 -7
  22. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/suite.py +23 -0
  23. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/types.py +27 -0
  24. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/guardrails/format.py +6 -0
  25. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/guardrails/length.py +12 -0
  26. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/guardrails/pii.py +5 -2
  27. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/guardrails/toxicity.py +4 -2
  28. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/knowledge.py +43 -12
  29. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/knowledge_graph.py +11 -1
  30. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/knowledge_store_redis.py +14 -3
  31. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/knowledge_store_supabase.py +11 -3
  32. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/memory.py +21 -6
  33. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/orchestration/checkpoint.py +3 -1
  34. selectools-0.19.2/src/selectools/patterns/__init__.py +44 -0
  35. selectools-0.19.2/src/selectools/patterns/debate.py +131 -0
  36. selectools-0.19.2/src/selectools/patterns/plan_and_execute.py +221 -0
  37. selectools-0.19.2/src/selectools/patterns/reflective.py +133 -0
  38. selectools-0.19.2/src/selectools/patterns/team_lead.py +303 -0
  39. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/policy.py +58 -5
  40. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/providers/_openai_compat.py +69 -7
  41. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/providers/anthropic_provider.py +2 -2
  42. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/providers/fallback.py +57 -22
  43. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/providers/gemini_provider.py +28 -4
  44. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/providers/stubs.py +1 -1
  45. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/bm25.py +70 -27
  46. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/chunking.py +77 -30
  47. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/hybrid.py +7 -3
  48. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/loaders.py +33 -4
  49. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/stores/chroma.py +12 -4
  50. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/stores/memory.py +62 -44
  51. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/stores/pinecone.py +19 -5
  52. selectools-0.19.2/src/selectools/rag/stores/sqlite.py +265 -0
  53. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/tools.py +3 -2
  54. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/security.py +13 -0
  55. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/sessions.py +14 -4
  56. selectools-0.19.2/src/selectools/stability.py +111 -0
  57. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/toolbox/datetime_tools.py +3 -1
  58. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/toolbox/text_tools.py +10 -2
  59. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/tools/base.py +77 -18
  60. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/tools/decorators.py +43 -4
  61. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/tools/loader.py +23 -7
  62. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/tools/registry.py +14 -3
  63. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/trace.py +176 -1
  64. {selectools-0.19.0 → selectools-0.19.2/src/selectools.egg-info}/PKG-INFO +105 -11
  65. {selectools-0.19.0 → selectools-0.19.2}/src/selectools.egg-info/SOURCES.txt +12 -0
  66. {selectools-0.19.0 → selectools-0.19.2}/src/selectools.egg-info/requires.txt +1 -0
  67. {selectools-0.19.0 → selectools-0.19.2}/tests/test_audit.py +46 -0
  68. selectools-0.19.2/tests/test_coherence.py +272 -0
  69. selectools-0.19.2/tests/test_concurrency_smoke.py +617 -0
  70. {selectools-0.19.0 → selectools-0.19.2}/tests/test_entity_memory.py +70 -0
  71. {selectools-0.19.0 → selectools-0.19.2}/tests/test_evals_advanced.py +26 -4
  72. {selectools-0.19.0 → selectools-0.19.2}/tests/test_evals_e2e.py +2 -2
  73. {selectools-0.19.0 → selectools-0.19.2}/tests/test_evals_final.py +40 -0
  74. selectools-0.19.2/tests/test_evals_hardening.py +1016 -0
  75. selectools-0.19.2/tests/test_evals_v0191.py +602 -0
  76. {selectools-0.19.0 → selectools-0.19.2}/tests/test_guardrails.py +137 -0
  77. {selectools-0.19.0 → selectools-0.19.2}/tests/test_knowledge_graph.py +127 -0
  78. {selectools-0.19.0 → selectools-0.19.2}/tests/test_knowledge_store_redis.py +41 -0
  79. {selectools-0.19.0 → selectools-0.19.2}/tests/test_knowledge_store_supabase.py +46 -0
  80. selectools-0.19.2/tests/test_knowledge_stores.py +631 -0
  81. {selectools-0.19.0 → selectools-0.19.2}/tests/test_memory.py +71 -0
  82. selectools-0.19.2/tests/test_patterns.py +520 -0
  83. selectools-0.19.2/tests/test_policy.py +403 -0
  84. selectools-0.19.2/tests/test_property_based.py +298 -0
  85. {selectools-0.19.0 → selectools-0.19.2}/tests/test_security.py +58 -0
  86. {selectools-0.19.0 → selectools-0.19.2}/tests/test_sessions_edge_cases.py +28 -0
  87. {selectools-0.19.0 → selectools-0.19.2}/tests/test_sessions_redis.py +52 -0
  88. selectools-0.19.2/tests/test_stability.py +195 -0
  89. selectools-0.19.2/tests/test_trace_html.py +159 -0
  90. selectools-0.19.0/src/selectools/rag/stores/sqlite.py +0 -247
  91. selectools-0.19.0/tests/test_coherence.py +0 -146
  92. selectools-0.19.0/tests/test_evals_hardening.py +0 -527
  93. selectools-0.19.0/tests/test_knowledge_stores.py +0 -299
  94. selectools-0.19.0/tests/test_policy.py +0 -215
  95. {selectools-0.19.0 → selectools-0.19.2}/LICENSE +0 -0
  96. {selectools-0.19.0 → selectools-0.19.2}/setup.cfg +0 -0
  97. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/agent/__init__.py +0 -0
  98. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/agent/_lifecycle.py +0 -0
  99. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/agent/config.py +0 -0
  100. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/agent/config_groups.py +0 -0
  101. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/analytics.py +0 -0
  102. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/cache.py +0 -0
  103. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/cache_redis.py +0 -0
  104. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/cache_semantic.py +0 -0
  105. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/cancellation.py +0 -0
  106. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/checkpoint_postgres.py +0 -0
  107. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/compose.py +0 -0
  108. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/embeddings/__init__.py +0 -0
  109. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/embeddings/anthropic.py +0 -0
  110. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/embeddings/cohere.py +0 -0
  111. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/embeddings/gemini.py +0 -0
  112. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/embeddings/openai.py +0 -0
  113. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/embeddings/provider.py +0 -0
  114. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/env.py +0 -0
  115. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/__main__.py +0 -0
  116. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/dataset.py +0 -0
  117. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/generator.py +0 -0
  118. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/pairwise.py +0 -0
  119. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/serve.py +0 -0
  120. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/evals/templates.py +0 -0
  121. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/exceptions.py +0 -0
  122. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/guardrails/__init__.py +0 -0
  123. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/guardrails/base.py +0 -0
  124. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/guardrails/pipeline.py +0 -0
  125. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/guardrails/topic.py +0 -0
  126. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/mcp/__init__.py +0 -0
  127. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/mcp/_loop.py +0 -0
  128. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/mcp/bridge.py +0 -0
  129. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/mcp/client.py +0 -0
  130. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/mcp/config.py +0 -0
  131. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/mcp/multi.py +0 -0
  132. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/mcp/server.py +0 -0
  133. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/models.py +0 -0
  134. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/observe/__init__.py +0 -0
  135. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/observe/trace_store.py +0 -0
  136. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/observer.py +0 -0
  137. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/orchestration/__init__.py +0 -0
  138. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/orchestration/graph.py +0 -0
  139. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/orchestration/node.py +0 -0
  140. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/orchestration/state.py +0 -0
  141. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/orchestration/supervisor.py +0 -0
  142. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/parser.py +0 -0
  143. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/pipeline.py +0 -0
  144. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/pricing.py +0 -0
  145. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/prompt.py +0 -0
  146. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/providers/__init__.py +0 -0
  147. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/providers/base.py +0 -0
  148. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/providers/ollama_provider.py +0 -0
  149. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/providers/openai_provider.py +0 -0
  150. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/__init__.py +0 -0
  151. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/reranker.py +0 -0
  152. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/stores/__init__.py +0 -0
  153. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/rag/vector_store.py +0 -0
  154. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/serve/__init__.py +0 -0
  155. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/serve/app.py +0 -0
  156. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/serve/cli.py +0 -0
  157. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/serve/models.py +0 -0
  158. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/serve/playground.py +0 -0
  159. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/structured.py +0 -0
  160. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/templates/__init__.py +0 -0
  161. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/templates/code_reviewer.py +0 -0
  162. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/templates/customer_support.py +0 -0
  163. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/templates/data_analyst.py +0 -0
  164. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/templates/rag_chatbot.py +0 -0
  165. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/templates/research_assistant.py +0 -0
  166. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/token_estimation.py +0 -0
  167. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/toolbox/__init__.py +0 -0
  168. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/toolbox/data_tools.py +0 -0
  169. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/toolbox/file_tools.py +0 -0
  170. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/toolbox/memory_tools.py +0 -0
  171. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/toolbox/web_tools.py +0 -0
  172. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/tools/__init__.py +0 -0
  173. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/types.py +0 -0
  174. {selectools-0.19.0 → selectools-0.19.2}/src/selectools/usage.py +0 -0
  175. {selectools-0.19.0 → selectools-0.19.2}/src/selectools.egg-info/dependency_links.txt +0 -0
  176. {selectools-0.19.0 → selectools-0.19.2}/src/selectools.egg-info/entry_points.txt +0 -0
  177. {selectools-0.19.0 → selectools-0.19.2}/src/selectools.egg-info/top_level.txt +0 -0
  178. {selectools-0.19.0 → selectools-0.19.2}/tests/test_approval_gate.py +0 -0
  179. {selectools-0.19.0 → selectools-0.19.2}/tests/test_architecture.py +0 -0
  180. {selectools-0.19.0 → selectools-0.19.2}/tests/test_async_observers.py +0 -0
  181. {selectools-0.19.0 → selectools-0.19.2}/tests/test_budget.py +0 -0
  182. {selectools-0.19.0 → selectools-0.19.2}/tests/test_bug_hunt_batch1_core.py +0 -0
  183. {selectools-0.19.0 → selectools-0.19.2}/tests/test_bug_hunt_batch1_security.py +0 -0
  184. {selectools-0.19.0 → selectools-0.19.2}/tests/test_bug_hunt_batch1_tools.py +0 -0
  185. {selectools-0.19.0 → selectools-0.19.2}/tests/test_bug_hunt_regression.py +0 -0
  186. {selectools-0.19.0 → selectools-0.19.2}/tests/test_cache.py +0 -0
  187. {selectools-0.19.0 → selectools-0.19.2}/tests/test_cache_redis.py +0 -0
  188. {selectools-0.19.0 → selectools-0.19.2}/tests/test_cancellation.py +0 -0
  189. {selectools-0.19.0 → selectools-0.19.2}/tests/test_consolidation_regression.py +0 -0
  190. {selectools-0.19.0 → selectools-0.19.2}/tests/test_conversation_branching.py +0 -0
  191. {selectools-0.19.0 → selectools-0.19.2}/tests/test_env.py +0 -0
  192. {selectools-0.19.0 → selectools-0.19.2}/tests/test_evals.py +0 -0
  193. {selectools-0.19.0 → selectools-0.19.2}/tests/test_evals_new_evaluators.py +0 -0
  194. {selectools-0.19.0 → selectools-0.19.2}/tests/test_evals_release.py +0 -0
  195. {selectools-0.19.0 → selectools-0.19.2}/tests/test_evals_v017_features.py +0 -0
  196. {selectools-0.19.0 → selectools-0.19.2}/tests/test_features_in_graph.py +0 -0
  197. {selectools-0.19.0 → selectools-0.19.2}/tests/test_hardening.py +0 -0
  198. {selectools-0.19.0 → selectools-0.19.2}/tests/test_knowledge.py +0 -0
  199. {selectools-0.19.0 → selectools-0.19.2}/tests/test_mcp.py +0 -0
  200. {selectools-0.19.0 → selectools-0.19.2}/tests/test_memory_async.py +0 -0
  201. {selectools-0.19.0 → selectools-0.19.2}/tests/test_memory_boundary.py +0 -0
  202. {selectools-0.19.0 → selectools-0.19.2}/tests/test_memory_integration.py +0 -0
  203. {selectools-0.19.0 → selectools-0.19.2}/tests/test_model_switching.py +0 -0
  204. {selectools-0.19.0 → selectools-0.19.2}/tests/test_multi_agent_edge_cases.py +0 -0
  205. {selectools-0.19.0 → selectools-0.19.2}/tests/test_orchestration_checkpoint.py +0 -0
  206. {selectools-0.19.0 → selectools-0.19.2}/tests/test_orchestration_e2e.py +0 -0
  207. {selectools-0.19.0 → selectools-0.19.2}/tests/test_orchestration_evals.py +0 -0
  208. {selectools-0.19.0 → selectools-0.19.2}/tests/test_orchestration_graph.py +0 -0
  209. {selectools-0.19.0 → selectools-0.19.2}/tests/test_orchestration_integration.py +0 -0
  210. {selectools-0.19.0 → selectools-0.19.2}/tests/test_orchestration_primitives.py +0 -0
  211. {selectools-0.19.0 → selectools-0.19.2}/tests/test_orchestration_supervisor.py +0 -0
  212. {selectools-0.19.0 → selectools-0.19.2}/tests/test_parser.py +0 -0
  213. {selectools-0.19.0 → selectools-0.19.2}/tests/test_phase1_design_patterns.py +0 -0
  214. {selectools-0.19.0 → selectools-0.19.2}/tests/test_pipeline.py +0 -0
  215. {selectools-0.19.0 → selectools-0.19.2}/tests/test_prompt.py +0 -0
  216. {selectools-0.19.0 → selectools-0.19.2}/tests/test_prompt_compression.py +0 -0
  217. {selectools-0.19.0 → selectools-0.19.2}/tests/test_reasoning_strategy.py +0 -0
  218. {selectools-0.19.0 → selectools-0.19.2}/tests/test_routing_mode.py +0 -0
  219. {selectools-0.19.0 → selectools-0.19.2}/tests/test_semantic_cache.py +0 -0
  220. {selectools-0.19.0 → selectools-0.19.2}/tests/test_sessions.py +0 -0
  221. {selectools-0.19.0 → selectools-0.19.2}/tests/test_simple_observer.py +0 -0
  222. {selectools-0.19.0 → selectools-0.19.2}/tests/test_simulation_evals.py +0 -0
  223. {selectools-0.19.0 → selectools-0.19.2}/tests/test_structured.py +0 -0
  224. {selectools-0.19.0 → selectools-0.19.2}/tests/test_structured_config.py +0 -0
  225. {selectools-0.19.0 → selectools-0.19.2}/tests/test_structured_tool_results.py +0 -0
  226. {selectools-0.19.0 → selectools-0.19.2}/tests/test_summarize_on_trim.py +0 -0
  227. {selectools-0.19.0 → selectools-0.19.2}/tests/test_terminal_actions.py +0 -0
  228. {selectools-0.19.0 → selectools-0.19.2}/tests/test_token_estimation.py +0 -0
  229. {selectools-0.19.0 → selectools-0.19.2}/tests/test_tool_caching.py +0 -0
  230. {selectools-0.19.0 → selectools-0.19.2}/tests/test_trace.py +0 -0
  231. {selectools-0.19.0 → selectools-0.19.2}/tests/test_v016_regression.py +0 -0
  232. {selectools-0.19.0 → selectools-0.19.2}/tests/test_v019_features.py +0 -0
  233. {selectools-0.19.0 → selectools-0.19.2}/tests/test_yaml_config.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: selectools
3
- Version: 0.19.0
3
+ Version: 0.19.2
4
4
  Summary: Production-ready AI agents with tool calling, structured output, execution traces, and RAG. Provider-agnostic (OpenAI, Anthropic, Gemini, Ollama) with fallback chains, batch processing, tool policies, streaming, caching, and cost tracking.
5
5
  Author-email: John Nichev <johnnichev@gmail.com>
6
6
  Maintainer-email: NichevLabs <support@nichevlabs.com>
@@ -40,6 +40,7 @@ Requires-Dist: isort>=5.13.0; extra == "dev"
40
40
  Requires-Dist: flake8>=7.0.0; extra == "dev"
41
41
  Requires-Dist: mypy>=1.8.0; extra == "dev"
42
42
  Requires-Dist: bandit>=1.7.0; extra == "dev"
43
+ Requires-Dist: hypothesis>=6.100.0; extra == "dev"
43
44
  Requires-Dist: mkdocs-material>=9.5.0; extra == "dev"
44
45
  Provides-Extra: rag
45
46
  Requires-Dist: chromadb>=0.4.0; extra == "rag"
@@ -63,7 +64,7 @@ Dynamic: license-file
63
64
  [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://johnnichev.github.io/selectools)
64
65
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
65
66
  [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
66
- [![Evaluators](https://img.shields.io/badge/evaluators-39-06b6d4.svg)](https://johnnichev.github.io/selectools/modules/EVALS/)
67
+ [![Evaluators](https://img.shields.io/badge/evaluators-50-06b6d4.svg)](https://johnnichev.github.io/selectools/modules/EVALS/)
67
68
 
68
69
  An open-source project from **[NichevLabs](https://nichevlabs.com)**.
69
70
 
@@ -83,7 +84,83 @@ result = AgentGraph.chain(planner, writer, reviewer).run("Write a blog post")
83
84
  # selectools serve agent.yaml
84
85
  ```
85
86
 
86
- ## What's New in v0.18
87
+ ## What's New in v0.19
88
+
89
+ ### v0.19.2 — Enterprise Hardening
90
+
91
+ ```python
92
+ from selectools.stability import stable, beta, deprecated
93
+ from selectools import trace_to_html
94
+
95
+ # Mark your own extensions with stability levels
96
+ @stable
97
+ class MyProductionAgent: ...
98
+
99
+ @beta
100
+ class MyExperimentalFeature: ...
101
+
102
+ @deprecated(since="0.19", replacement="MyProductionAgent")
103
+ class MyOldAgent: ...
104
+
105
+ # Visualise any trace as a waterfall HTML timeline
106
+ Path("trace.html").write_text(trace_to_html(result.trace))
107
+ ```
108
+
109
+ - **Stability markers** — `@stable`, `@beta`, `@deprecated(since, replacement)` for public API signalling
110
+ - **Trace HTML viewer** — `trace_to_html(trace)` renders a standalone waterfall timeline
111
+ - **Deprecation policy** — 2-minor-version window, programmatic introspection via `.__stability__`
112
+ - **Security audit** — all 41 `# nosec` annotations reviewed and published in `docs/SECURITY.md`
113
+ - **Quality infrastructure** — property-based tests (Hypothesis), thread-safety smoke suite, 5 new production simulations (3135 tests total)
114
+
115
+ ### v0.19.1 — Advanced Agent Patterns
116
+
117
+ ```python
118
+ from selectools.patterns import PlanAndExecuteAgent, ReflectiveAgent, DebateAgent, TeamLeadAgent
119
+
120
+ # PlanAndExecute — planner generates typed steps, executor runs them sequentially
121
+ agent = PlanAndExecuteAgent(planner=planner, executor=executor, provider=provider)
122
+ result = agent.run("Research and write a blog post about LLM safety")
123
+
124
+ # ReflectiveAgent — actor drafts, critic reviews, actor revises until approved
125
+ agent = ReflectiveAgent(actor=actor, critic=critic, provider=provider, max_reflections=3)
126
+ result = agent.run("Draft a product announcement email")
127
+
128
+ # DebateAgent — multiple agents argue, judge synthesizes conclusion
129
+ agent = DebateAgent(agents={"optimist": opt, "skeptic": skep}, judge=judge, provider=provider)
130
+ result = agent.run("Should we migrate our infrastructure to microservices?")
131
+
132
+ # TeamLeadAgent — lead delegates subtasks, team executes in parallel or sequentially
133
+ agent = TeamLeadAgent(lead=lead, team={"researcher": r, "writer": w}, provider=provider)
134
+ result = agent.run("Produce a competitive analysis report")
135
+ ```
136
+
137
+ - **PlanAndExecuteAgent** — Typed `PlanStep` list; optional replanning on step failure
138
+ - **ReflectiveAgent** — Actor–critic loop with `ReflectionRound` records per revision
139
+ - **DebateAgent** — N-agent debate with transcript, judge synthesis, `DebateResult`
140
+ - **TeamLeadAgent** — `sequential`, `parallel`, or `dynamic` delegation strategies
141
+
142
+ ### v0.19.0 — Serve, Deploy & Complete Composition
143
+
144
+ ```python
145
+ # One command deploys your agent over HTTP with SSE streaming
146
+ # selectools serve agent.yaml
147
+
148
+ # Compose tools into a single callable
149
+ from selectools import compose
150
+ search_and_summarize = compose(search_web, summarize)
151
+
152
+ # Streaming composition
153
+ async for chunk in pipeline.astream("input"):
154
+ print(chunk)
155
+ ```
156
+
157
+ - **`selectools serve`** — HTTP deployment with SSE streaming, Playground UI, `/health`, `/schema`
158
+ - **YAML config** — `AgentConfig.from_yaml("agent.yaml")`, 5 built-in templates
159
+ - **`compose()`** — Chain tools into composite tool; `retry()` and `cache_step()` wrappers
160
+ - **PostgresCheckpointStore** — Durable graph checkpointing backed by PostgreSQL
161
+
162
+ <details>
163
+ <summary><strong>v0.18.x highlights</strong></summary>
87
164
 
88
165
  ### v0.18.0 — Multi-Agent Orchestration
89
166
 
@@ -154,6 +231,8 @@ route = branch(
154
231
  - **parallel()** — Fan-out to multiple steps and merge results
155
232
  - **branch()** — Conditional routing based on input data
156
233
 
234
+ </details>
235
+
157
236
  <details>
158
237
  <summary><strong>v0.17.x highlights</strong></summary>
159
238
 
@@ -276,7 +355,7 @@ report = suite.run()
276
355
  report.to_html("report.html")
277
356
  ```
278
357
 
279
- - **39 Evaluators** — 22 deterministic + 17 LLM-as-judge
358
+ - **50 Evaluators** — 30 deterministic + 21 LLM-as-judge
280
359
  - **A/B Testing**, regression detection, snapshot testing
281
360
  - **HTML reports**, JUnit XML, CLI, GitHub Action integration
282
361
 
@@ -316,10 +395,12 @@ report.to_html("report.html")
316
395
  | `StateGraph` + `add_node` + `add_edge` + `compile()` | `AgentGraph.chain(a, b, c).run(prompt)` |
317
396
  | LCEL `prompt \| llm \| parser` with Runnable protocol | `@step` + `\|` on plain functions |
318
397
  | `interrupt()` restarts the whole node on resume | `yield InterruptRequest()` resumes at yield point |
319
- | LangSmith (paid) for tracing and evals | Built-in: 39 evaluators + traces, zero cost |
398
+ | LangSmith (paid) for tracing and evals | Built-in: 50 evaluators + traces, zero cost |
320
399
  | 5+ packages (`langchain-core`, `langgraph`, `langsmith`...) | 1 package: `pip install selectools` |
321
400
  | `langserve` for deployment | `selectools serve agent.yaml` |
322
401
 
402
+ > Full migration guide with code examples: **[Coming from LangChain](docs/MIGRATION.md)**
403
+
323
404
  ## Why Selectools
324
405
 
325
406
  | Capability | What You Get |
@@ -346,7 +427,7 @@ report.to_html("report.html")
346
427
  | **Knowledge Graph** | Relationship triple extraction with in-memory and SQLite storage and keyword-based querying. |
347
428
  | **Cross-Session Knowledge** | Daily logs + persistent facts with auto-registered `remember` tool. |
348
429
  | **MCP Integration** | Connect to any MCP tool server (stdio + HTTP). MCPClient, MultiMCPClient, MCPServer. Circuit breaker, retry, graceful degradation. |
349
- | **Eval Framework** | 39 built-in evaluators (22 deterministic + 17 LLM-as-judge). A/B testing, regression detection, snapshot testing, HTML reports, JUnit XML, CI integration. |
430
+ | **Eval Framework** | 50 built-in evaluators (30 deterministic + 21 LLM-as-judge). A/B testing, regression detection, snapshot testing, HTML reports, JUnit XML, CI integration. |
350
431
  | **Multi-Agent Orchestration** | `AgentGraph` for directed agent graphs, `SupervisorAgent` with 4 strategies, HITL via generator nodes, parallel execution, checkpointing, subgraph composition. |
351
432
  | **Composable Pipelines** | `Pipeline` + `@step` + `|` operator + `parallel()` + `branch()` — chain agents, tools, and transforms with plain Python. |
352
433
  | **AgentObserver Protocol** | 45-event lifecycle observer with `run_id`/`call_id` correlation. Built-in `LoggingObserver` + `SimpleStepObserver`. |
@@ -382,10 +463,10 @@ report.to_html("report.html")
382
463
  - **Conversation Branching**: `ConversationMemory.branch()` and `SessionStore.branch()` for A/B exploration and checkpointing
383
464
  - **Multi-Agent Orchestration**: `AgentGraph` with routing, parallel execution, HITL, checkpointing; `SupervisorAgent` with 4 strategies (plan_and_execute, round_robin, dynamic, magentic)
384
465
  - **Composable Pipelines**: `Pipeline` + `@step` + `|` operator + `parallel()` + `branch()` — chain agents, tools, and transforms
385
- - **61 Examples**: Multi-agent graphs, RAG, hybrid search, streaming, structured output, traces, batch, policy, observer, guardrails, audit, sessions, entity memory, knowledge graph, eval framework, and more
386
- - **Built-in Eval Framework**: 39 evaluators (22 deterministic + 17 LLM-as-judge), A/B testing, regression detection, HTML reports, JUnit XML, snapshot testing
466
+ - **75 Examples**: Multi-agent graphs, RAG, hybrid search, streaming, structured output, traces, batch, policy, observer, guardrails, audit, sessions, entity memory, knowledge graph, eval framework, advanced agent patterns, stability markers, HTML trace viewer, and more
467
+ - **Built-in Eval Framework**: 50 evaluators (30 deterministic + 21 LLM-as-judge), A/B testing, regression detection, HTML reports, JUnit XML, snapshot testing
387
468
  - **AgentObserver Protocol**: 45 lifecycle events with `run_id` correlation, `LoggingObserver`, `SimpleStepObserver`, OTel export
388
- - **2529 Tests**: Unit, integration, regression, and E2E with real API calls
469
+ - **3135 Tests**: Unit, integration, regression, and E2E with real API calls
389
470
 
390
471
  ## Install
391
472
 
@@ -934,6 +1015,18 @@ Examples are numbered by difficulty. Start from 01 and work your way up.
934
1015
  | 59 | `59_agent_graph_checkpointing.py` | Checkpoint, interrupt, resume | No |
935
1016
  | 60 | `60_supervisor_agent.py` | SupervisorAgent with 4 strategies | No |
936
1017
  | 61 | `61_agent_graph_subgraph.py` | Nested subgraph composition | No |
1018
+ | 62 | `62_yaml_config.py` | Load AgentConfig from YAML | No |
1019
+ | 63 | `63_agent_templates.py` | Built-in agent templates | No |
1020
+ | 64 | `64_selectools_serve.py` | Serve agent over HTTP with `selectools serve` | No |
1021
+ | 65 | `65_tool_composition.py` | `compose()` tool chaining | No |
1022
+ | 66 | `66_streaming_pipeline.py` | `pipeline.astream()` streaming composition | No |
1023
+ | 67 | `67_type_safe_pipeline.py` | Type-safe step contracts | No |
1024
+ | 68 | `68_postgres_checkpoints.py` | PostgresCheckpointStore for AgentGraph | Yes + `[postgres]` |
1025
+ | 69 | `69_trace_store.py` | Trace storage and querying | No |
1026
+ | 70 | `70_plan_and_execute.py` | PlanAndExecuteAgent with typed steps | No |
1027
+ | 71 | `71_reflective_agent.py` | ReflectiveAgent actor–critic loop | No |
1028
+ | 72 | `72_debate_agent.py` | DebateAgent with optimist/skeptic/judge | No |
1029
+ | 73 | `73_team_lead_agent.py` | TeamLeadAgent with all 3 delegation strategies | No |
937
1030
 
938
1031
  Run any example:
939
1032
 
@@ -970,12 +1063,13 @@ Also available in [`docs/`](docs/README.md):
970
1063
  | [GUARDRAILS](docs/modules/GUARDRAILS.md) | Input/output validation pipeline |
971
1064
  | [AUDIT](docs/modules/AUDIT.md) | JSONL audit logging |
972
1065
  | [SECURITY](docs/modules/SECURITY.md) | Screening & coherence checking |
973
- | [EVALS](docs/modules/EVALS.md) | 39 evaluators, A/B testing, regression |
1066
+ | [EVALS](docs/modules/EVALS.md) | 50 evaluators, A/B testing, regression |
974
1067
  | [MCP](docs/modules/MCP.md) | MCP client/server integration |
975
1068
  | [BUDGET](docs/modules/BUDGET.md) | Token/cost budget limits |
976
1069
  | [CANCELLATION](docs/modules/CANCELLATION.md) | Cooperative cancellation |
977
1070
  | [ORCHESTRATION](docs/modules/ORCHESTRATION.md) | AgentGraph, routing, parallel, HITL |
978
1071
  | [SUPERVISOR](docs/modules/SUPERVISOR.md) | SupervisorAgent, 4 strategies |
1072
+ | [PATTERNS](docs/modules/PATTERNS.md) | PlanAndExecute, Reflective, Debate, TeamLead |
979
1073
  | [PARSER](docs/modules/PARSER.md) | Tool call parsing |
980
1074
  | [PROMPT](docs/modules/PROMPT.md) | System prompt generation |
981
1075
 
@@ -986,7 +1080,7 @@ pytest tests/ -x -q # All tests
986
1080
  pytest tests/ -k "not e2e" # Skip E2E (no API keys needed)
987
1081
  ```
988
1082
 
989
- 2529 tests covering parsing, agent loop, providers, RAG pipeline, hybrid search, advanced chunking, dynamic tools, caching, streaming, guardrails, sessions, memory, eval framework, budget/cancellation, knowledge stores, orchestration, pipelines, and E2E integration with real API calls.
1083
+ 3135 tests covering parsing, agent loop, providers, RAG pipeline, hybrid search, advanced chunking, dynamic tools, caching, streaming, guardrails, sessions, memory, eval framework, budget/cancellation, knowledge stores, orchestration, pipelines, agent patterns, stability markers, trace viewer, and E2E integration with real API calls.
990
1084
 
991
1085
  ## License
992
1086
 
@@ -4,7 +4,7 @@
4
4
  [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://johnnichev.github.io/selectools)
5
5
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
6
6
  [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
7
- [![Evaluators](https://img.shields.io/badge/evaluators-39-06b6d4.svg)](https://johnnichev.github.io/selectools/modules/EVALS/)
7
+ [![Evaluators](https://img.shields.io/badge/evaluators-50-06b6d4.svg)](https://johnnichev.github.io/selectools/modules/EVALS/)
8
8
 
9
9
  An open-source project from **[NichevLabs](https://nichevlabs.com)**.
10
10
 
@@ -24,7 +24,83 @@ result = AgentGraph.chain(planner, writer, reviewer).run("Write a blog post")
24
24
  # selectools serve agent.yaml
25
25
  ```
26
26
 
27
- ## What's New in v0.18
27
+ ## What's New in v0.19
28
+
29
+ ### v0.19.2 — Enterprise Hardening
30
+
31
+ ```python
32
+ from selectools.stability import stable, beta, deprecated
33
+ from selectools import trace_to_html
34
+
35
+ # Mark your own extensions with stability levels
36
+ @stable
37
+ class MyProductionAgent: ...
38
+
39
+ @beta
40
+ class MyExperimentalFeature: ...
41
+
42
+ @deprecated(since="0.19", replacement="MyProductionAgent")
43
+ class MyOldAgent: ...
44
+
45
+ # Visualise any trace as a waterfall HTML timeline
46
+ Path("trace.html").write_text(trace_to_html(result.trace))
47
+ ```
48
+
49
+ - **Stability markers** — `@stable`, `@beta`, `@deprecated(since, replacement)` for public API signalling
50
+ - **Trace HTML viewer** — `trace_to_html(trace)` renders a standalone waterfall timeline
51
+ - **Deprecation policy** — 2-minor-version window, programmatic introspection via `.__stability__`
52
+ - **Security audit** — all 41 `# nosec` annotations reviewed and published in `docs/SECURITY.md`
53
+ - **Quality infrastructure** — property-based tests (Hypothesis), thread-safety smoke suite, 5 new production simulations (3135 tests total)
54
+
55
+ ### v0.19.1 — Advanced Agent Patterns
56
+
57
+ ```python
58
+ from selectools.patterns import PlanAndExecuteAgent, ReflectiveAgent, DebateAgent, TeamLeadAgent
59
+
60
+ # PlanAndExecute — planner generates typed steps, executor runs them sequentially
61
+ agent = PlanAndExecuteAgent(planner=planner, executor=executor, provider=provider)
62
+ result = agent.run("Research and write a blog post about LLM safety")
63
+
64
+ # ReflectiveAgent — actor drafts, critic reviews, actor revises until approved
65
+ agent = ReflectiveAgent(actor=actor, critic=critic, provider=provider, max_reflections=3)
66
+ result = agent.run("Draft a product announcement email")
67
+
68
+ # DebateAgent — multiple agents argue, judge synthesizes conclusion
69
+ agent = DebateAgent(agents={"optimist": opt, "skeptic": skep}, judge=judge, provider=provider)
70
+ result = agent.run("Should we migrate our infrastructure to microservices?")
71
+
72
+ # TeamLeadAgent — lead delegates subtasks, team executes in parallel or sequentially
73
+ agent = TeamLeadAgent(lead=lead, team={"researcher": r, "writer": w}, provider=provider)
74
+ result = agent.run("Produce a competitive analysis report")
75
+ ```
76
+
77
+ - **PlanAndExecuteAgent** — Typed `PlanStep` list; optional replanning on step failure
78
+ - **ReflectiveAgent** — Actor–critic loop with `ReflectionRound` records per revision
79
+ - **DebateAgent** — N-agent debate with transcript, judge synthesis, `DebateResult`
80
+ - **TeamLeadAgent** — `sequential`, `parallel`, or `dynamic` delegation strategies
81
+
82
+ ### v0.19.0 — Serve, Deploy & Complete Composition
83
+
84
+ ```python
85
+ # One command deploys your agent over HTTP with SSE streaming
86
+ # selectools serve agent.yaml
87
+
88
+ # Compose tools into a single callable
89
+ from selectools import compose
90
+ search_and_summarize = compose(search_web, summarize)
91
+
92
+ # Streaming composition
93
+ async for chunk in pipeline.astream("input"):
94
+ print(chunk)
95
+ ```
96
+
97
+ - **`selectools serve`** — HTTP deployment with SSE streaming, Playground UI, `/health`, `/schema`
98
+ - **YAML config** — `AgentConfig.from_yaml("agent.yaml")`, 5 built-in templates
99
+ - **`compose()`** — Chain tools into composite tool; `retry()` and `cache_step()` wrappers
100
+ - **PostgresCheckpointStore** — Durable graph checkpointing backed by PostgreSQL
101
+
102
+ <details>
103
+ <summary><strong>v0.18.x highlights</strong></summary>
28
104
 
29
105
  ### v0.18.0 — Multi-Agent Orchestration
30
106
 
@@ -95,6 +171,8 @@ route = branch(
95
171
  - **parallel()** — Fan-out to multiple steps and merge results
96
172
  - **branch()** — Conditional routing based on input data
97
173
 
174
+ </details>
175
+
98
176
  <details>
99
177
  <summary><strong>v0.17.x highlights</strong></summary>
100
178
 
@@ -217,7 +295,7 @@ report = suite.run()
217
295
  report.to_html("report.html")
218
296
  ```
219
297
 
220
- - **39 Evaluators** — 22 deterministic + 17 LLM-as-judge
298
+ - **50 Evaluators** — 30 deterministic + 21 LLM-as-judge
221
299
  - **A/B Testing**, regression detection, snapshot testing
222
300
  - **HTML reports**, JUnit XML, CLI, GitHub Action integration
223
301
 
@@ -257,10 +335,12 @@ report.to_html("report.html")
257
335
  | `StateGraph` + `add_node` + `add_edge` + `compile()` | `AgentGraph.chain(a, b, c).run(prompt)` |
258
336
  | LCEL `prompt \| llm \| parser` with Runnable protocol | `@step` + `\|` on plain functions |
259
337
  | `interrupt()` restarts the whole node on resume | `yield InterruptRequest()` resumes at yield point |
260
- | LangSmith (paid) for tracing and evals | Built-in: 39 evaluators + traces, zero cost |
338
+ | LangSmith (paid) for tracing and evals | Built-in: 50 evaluators + traces, zero cost |
261
339
  | 5+ packages (`langchain-core`, `langgraph`, `langsmith`...) | 1 package: `pip install selectools` |
262
340
  | `langserve` for deployment | `selectools serve agent.yaml` |
263
341
 
342
+ > Full migration guide with code examples: **[Coming from LangChain](docs/MIGRATION.md)**
343
+
264
344
  ## Why Selectools
265
345
 
266
346
  | Capability | What You Get |
@@ -287,7 +367,7 @@ report.to_html("report.html")
287
367
  | **Knowledge Graph** | Relationship triple extraction with in-memory and SQLite storage and keyword-based querying. |
288
368
  | **Cross-Session Knowledge** | Daily logs + persistent facts with auto-registered `remember` tool. |
289
369
  | **MCP Integration** | Connect to any MCP tool server (stdio + HTTP). MCPClient, MultiMCPClient, MCPServer. Circuit breaker, retry, graceful degradation. |
290
- | **Eval Framework** | 39 built-in evaluators (22 deterministic + 17 LLM-as-judge). A/B testing, regression detection, snapshot testing, HTML reports, JUnit XML, CI integration. |
370
+ | **Eval Framework** | 50 built-in evaluators (30 deterministic + 21 LLM-as-judge). A/B testing, regression detection, snapshot testing, HTML reports, JUnit XML, CI integration. |
291
371
  | **Multi-Agent Orchestration** | `AgentGraph` for directed agent graphs, `SupervisorAgent` with 4 strategies, HITL via generator nodes, parallel execution, checkpointing, subgraph composition. |
292
372
  | **Composable Pipelines** | `Pipeline` + `@step` + `|` operator + `parallel()` + `branch()` — chain agents, tools, and transforms with plain Python. |
293
373
  | **AgentObserver Protocol** | 45-event lifecycle observer with `run_id`/`call_id` correlation. Built-in `LoggingObserver` + `SimpleStepObserver`. |
@@ -323,10 +403,10 @@ report.to_html("report.html")
323
403
  - **Conversation Branching**: `ConversationMemory.branch()` and `SessionStore.branch()` for A/B exploration and checkpointing
324
404
  - **Multi-Agent Orchestration**: `AgentGraph` with routing, parallel execution, HITL, checkpointing; `SupervisorAgent` with 4 strategies (plan_and_execute, round_robin, dynamic, magentic)
325
405
  - **Composable Pipelines**: `Pipeline` + `@step` + `|` operator + `parallel()` + `branch()` — chain agents, tools, and transforms
326
- - **61 Examples**: Multi-agent graphs, RAG, hybrid search, streaming, structured output, traces, batch, policy, observer, guardrails, audit, sessions, entity memory, knowledge graph, eval framework, and more
327
- - **Built-in Eval Framework**: 39 evaluators (22 deterministic + 17 LLM-as-judge), A/B testing, regression detection, HTML reports, JUnit XML, snapshot testing
406
+ - **75 Examples**: Multi-agent graphs, RAG, hybrid search, streaming, structured output, traces, batch, policy, observer, guardrails, audit, sessions, entity memory, knowledge graph, eval framework, advanced agent patterns, stability markers, HTML trace viewer, and more
407
+ - **Built-in Eval Framework**: 50 evaluators (30 deterministic + 21 LLM-as-judge), A/B testing, regression detection, HTML reports, JUnit XML, snapshot testing
328
408
  - **AgentObserver Protocol**: 45 lifecycle events with `run_id` correlation, `LoggingObserver`, `SimpleStepObserver`, OTel export
329
- - **2529 Tests**: Unit, integration, regression, and E2E with real API calls
409
+ - **3135 Tests**: Unit, integration, regression, and E2E with real API calls
330
410
 
331
411
  ## Install
332
412
 
@@ -875,6 +955,18 @@ Examples are numbered by difficulty. Start from 01 and work your way up.
875
955
  | 59 | `59_agent_graph_checkpointing.py` | Checkpoint, interrupt, resume | No |
876
956
  | 60 | `60_supervisor_agent.py` | SupervisorAgent with 4 strategies | No |
877
957
  | 61 | `61_agent_graph_subgraph.py` | Nested subgraph composition | No |
958
+ | 62 | `62_yaml_config.py` | Load AgentConfig from YAML | No |
959
+ | 63 | `63_agent_templates.py` | Built-in agent templates | No |
960
+ | 64 | `64_selectools_serve.py` | Serve agent over HTTP with `selectools serve` | No |
961
+ | 65 | `65_tool_composition.py` | `compose()` tool chaining | No |
962
+ | 66 | `66_streaming_pipeline.py` | `pipeline.astream()` streaming composition | No |
963
+ | 67 | `67_type_safe_pipeline.py` | Type-safe step contracts | No |
964
+ | 68 | `68_postgres_checkpoints.py` | PostgresCheckpointStore for AgentGraph | Yes + `[postgres]` |
965
+ | 69 | `69_trace_store.py` | Trace storage and querying | No |
966
+ | 70 | `70_plan_and_execute.py` | PlanAndExecuteAgent with typed steps | No |
967
+ | 71 | `71_reflective_agent.py` | ReflectiveAgent actor–critic loop | No |
968
+ | 72 | `72_debate_agent.py` | DebateAgent with optimist/skeptic/judge | No |
969
+ | 73 | `73_team_lead_agent.py` | TeamLeadAgent with all 3 delegation strategies | No |
878
970
 
879
971
  Run any example:
880
972
 
@@ -911,12 +1003,13 @@ Also available in [`docs/`](docs/README.md):
911
1003
  | [GUARDRAILS](docs/modules/GUARDRAILS.md) | Input/output validation pipeline |
912
1004
  | [AUDIT](docs/modules/AUDIT.md) | JSONL audit logging |
913
1005
  | [SECURITY](docs/modules/SECURITY.md) | Screening & coherence checking |
914
- | [EVALS](docs/modules/EVALS.md) | 39 evaluators, A/B testing, regression |
1006
+ | [EVALS](docs/modules/EVALS.md) | 50 evaluators, A/B testing, regression |
915
1007
  | [MCP](docs/modules/MCP.md) | MCP client/server integration |
916
1008
  | [BUDGET](docs/modules/BUDGET.md) | Token/cost budget limits |
917
1009
  | [CANCELLATION](docs/modules/CANCELLATION.md) | Cooperative cancellation |
918
1010
  | [ORCHESTRATION](docs/modules/ORCHESTRATION.md) | AgentGraph, routing, parallel, HITL |
919
1011
  | [SUPERVISOR](docs/modules/SUPERVISOR.md) | SupervisorAgent, 4 strategies |
1012
+ | [PATTERNS](docs/modules/PATTERNS.md) | PlanAndExecute, Reflective, Debate, TeamLead |
920
1013
  | [PARSER](docs/modules/PARSER.md) | Tool call parsing |
921
1014
  | [PROMPT](docs/modules/PROMPT.md) | System prompt generation |
922
1015
 
@@ -927,7 +1020,7 @@ pytest tests/ -x -q # All tests
927
1020
  pytest tests/ -k "not e2e" # Skip E2E (no API keys needed)
928
1021
  ```
929
1022
 
930
- 2529 tests covering parsing, agent loop, providers, RAG pipeline, hybrid search, advanced chunking, dynamic tools, caching, streaming, guardrails, sessions, memory, eval framework, budget/cancellation, knowledge stores, orchestration, pipelines, and E2E integration with real API calls.
1023
+ 3135 tests covering parsing, agent loop, providers, RAG pipeline, hybrid search, advanced chunking, dynamic tools, caching, streaming, guardrails, sessions, memory, eval framework, budget/cancellation, knowledge stores, orchestration, pipelines, agent patterns, stability markers, trace viewer, and E2E integration with real API calls.
931
1024
 
932
1025
  ## License
933
1026
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "selectools"
7
- version = "0.19.0"
7
+ version = "0.19.2"
8
8
  description = "Production-ready AI agents with tool calling, structured output, execution traces, and RAG. Provider-agnostic (OpenAI, Anthropic, Gemini, Ollama) with fallback chains, batch processing, tool policies, streaming, caching, and cost tracking."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -51,6 +51,7 @@ dev = [
51
51
  "flake8>=7.0.0",
52
52
  "mypy>=1.8.0",
53
53
  "bandit>=1.7.0",
54
+ "hypothesis>=6.100.0",
54
55
  "mkdocs-material>=9.5.0",
55
56
  ]
56
57
  rag = [
@@ -142,8 +143,10 @@ testpaths = ["tests"]
142
143
  pythonpath = ["src", "."]
143
144
  asyncio_mode = "strict"
144
145
  addopts = "-v"
146
+ python_files = ["test_*.py", "sim_*.py"]
145
147
  markers = [
146
148
  "e2e: mark test as end-to-end (requires real API keys, use --run-e2e to run)",
149
+ "integration: mark test as integration (no API keys, uses real implementations with mocks)",
147
150
  "openai: mark test as requiring OpenAI API key",
148
151
  "anthropic: mark test as requiring Anthropic API key",
149
152
  "gemini: mark test as requiring Gemini API key",
@@ -1,9 +1,9 @@
1
1
  """Public exports for the selectools package."""
2
2
 
3
- __version__ = "0.19.0"
3
+ __version__ = "0.19.2"
4
4
 
5
5
  # Import submodules (lazy loading for optional dependencies)
6
- from . import embeddings, evals, guardrails, models, rag, toolbox
6
+ from . import embeddings, evals, guardrails, models, patterns, rag, toolbox
7
7
  from .agent import Agent, AgentConfig
8
8
  from .agent.config_groups import (
9
9
  BudgetConfig,
@@ -99,6 +99,19 @@ from .orchestration import (
99
99
  SupervisorStrategy,
100
100
  )
101
101
  from .parser import ToolCallParser
102
+ from .patterns import (
103
+ DebateAgent,
104
+ DebateResult,
105
+ DebateRound,
106
+ PlanAndExecuteAgent,
107
+ PlanStep,
108
+ ReflectionRound,
109
+ ReflectiveAgent,
110
+ ReflectiveResult,
111
+ Subtask,
112
+ TeamLeadAgent,
113
+ TeamLeadResult,
114
+ )
102
115
  from .pipeline import Pipeline, Step, StepResult, branch, cache_step, parallel, retry, step
103
116
  from .policy import PolicyDecision, PolicyResult, ToolPolicy
104
117
  from .pricing import PRICING, calculate_cost, calculate_embedding_cost, get_model_pricing
@@ -116,10 +129,11 @@ from .sessions import (
116
129
  SessionStore,
117
130
  SQLiteSessionStore,
118
131
  )
132
+ from .stability import beta, deprecated, stable
119
133
  from .structured import ResponseFormat
120
134
  from .token_estimation import TokenEstimate, estimate_run_tokens, estimate_tokens
121
135
  from .tools import Tool, ToolParameter, ToolRegistry, tool
122
- from .trace import AgentTrace, StepType, TraceStep
136
+ from .trace import AgentTrace, StepType, TraceStep, trace_to_html
123
137
  from .types import AgentResult, Message, Role, ToolCall
124
138
  from .usage import AgentUsage, UsageStats
125
139
 
@@ -188,6 +202,10 @@ __all__ = [
188
202
  "PolicyResult",
189
203
  # Structured output
190
204
  "ResponseFormat",
205
+ # Stability markers
206
+ "stable",
207
+ "beta",
208
+ "deprecated",
191
209
  # Observability
192
210
  "AgentObserver",
193
211
  "AsyncAgentObserver",
@@ -196,6 +214,7 @@ __all__ = [
196
214
  "AgentTrace",
197
215
  "StepType",
198
216
  "TraceStep",
217
+ "trace_to_html",
199
218
  # Guardrails
200
219
  "guardrails",
201
220
  "Guardrail",
@@ -267,4 +286,17 @@ __all__ = [
267
286
  "SupervisorAgent",
268
287
  "SupervisorStrategy",
269
288
  "ModelSplit",
289
+ # Patterns
290
+ "patterns",
291
+ "PlanAndExecuteAgent",
292
+ "PlanStep",
293
+ "ReflectiveAgent",
294
+ "ReflectionRound",
295
+ "ReflectiveResult",
296
+ "DebateAgent",
297
+ "DebateRound",
298
+ "DebateResult",
299
+ "TeamLeadAgent",
300
+ "Subtask",
301
+ "TeamLeadResult",
270
302
  ]
@@ -159,7 +159,8 @@ class _MemoryManagerMixin:
159
159
  return
160
160
 
161
161
  # Each "turn" is one user + one assistant message, so keep_recent * 2 messages.
162
- keep_recent = self.config.compress_keep_recent * 2
162
+ # Always keep at least 1 message so the current user prompt is never compressed away.
163
+ keep_recent = max(self.config.compress_keep_recent * 2, 1)
163
164
  system_msgs: List[Message] = []
164
165
  non_system: List[Message] = []
165
166
  for m in self._history:
@@ -3,10 +3,30 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
+ import threading
6
7
  import time
7
8
  from concurrent.futures import ThreadPoolExecutor
8
9
  from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, cast
9
10
 
11
+ # Module-level singleton for running sync provider calls in an async context.
12
+ # Creating a new ThreadPoolExecutor per call (inside a retry loop) wastes
13
+ # resources and prevents thread reuse (pitfall #20).
14
+ _async_provider_executor: Optional[ThreadPoolExecutor] = None
15
+ _async_provider_executor_lock = threading.Lock()
16
+
17
+
18
+ def _get_async_provider_executor() -> ThreadPoolExecutor:
19
+ """Return the shared ThreadPoolExecutor for sync provider calls in async context."""
20
+ global _async_provider_executor
21
+ if _async_provider_executor is None:
22
+ with _async_provider_executor_lock:
23
+ if _async_provider_executor is None:
24
+ _async_provider_executor = ThreadPoolExecutor(
25
+ max_workers=16, thread_name_prefix="selectools_provider"
26
+ )
27
+ return _async_provider_executor
28
+
29
+
10
30
  from ..cache import CacheKeyBuilder
11
31
  from ..providers.base import ProviderError
12
32
  from ..trace import StepType, TraceStep
@@ -252,19 +272,39 @@ class _ProviderCallerMixin:
252
272
  self._effective_model,
253
273
  self._system_prompt,
254
274
  )
275
+ await self._anotify_observers(
276
+ "on_llm_start",
277
+ run_id,
278
+ self._history,
279
+ self._effective_model,
280
+ self._system_prompt,
281
+ )
255
282
  self._notify_observers(
256
283
  "on_llm_end",
257
284
  run_id,
258
285
  cached_msg.content,
259
286
  cached_usage,
260
287
  )
288
+ await self._anotify_observers(
289
+ "on_llm_end",
290
+ run_id,
291
+ cached_msg.content,
292
+ cached_usage,
293
+ )
261
294
  self._notify_observers(
262
295
  "on_cache_hit",
263
296
  run_id,
264
297
  self._effective_model,
265
298
  cached_msg.content or "",
266
299
  )
300
+ await self._anotify_observers(
301
+ "on_cache_hit",
302
+ run_id,
303
+ self._effective_model,
304
+ cached_msg.content or "",
305
+ )
267
306
  self._notify_observers("on_usage", run_id, cached_usage)
307
+ await self._anotify_observers("on_usage", run_id, cached_usage)
268
308
  if self.config.verbose:
269
309
  print("[agent] cache hit -- skipping provider call")
270
310
  if trace is not None:
@@ -322,21 +362,21 @@ class _ProviderCallerMixin:
322
362
  )
323
363
  response_text = response_msg.content or ""
324
364
  else:
325
- # Fallback to sync in executor
326
- loop = asyncio.get_event_loop()
327
- with ThreadPoolExecutor() as executor:
328
- response_msg, usage_stats = await loop.run_in_executor(
329
- executor,
330
- lambda: self.provider.complete(
331
- model=self._effective_model,
332
- system_prompt=self._system_prompt,
333
- messages=self._history,
334
- tools=self.tools,
335
- temperature=self.config.temperature,
336
- max_tokens=self.config.max_tokens,
337
- timeout=self.config.request_timeout,
338
- ),
339
- )
365
+ # Fallback to sync in executor — reuse the module-level singleton
366
+ # to avoid spawning a new thread pool on every retry attempt.
367
+ loop = asyncio.get_running_loop()
368
+ response_msg, usage_stats = await loop.run_in_executor(
369
+ _get_async_provider_executor(),
370
+ lambda: self.provider.complete(
371
+ model=self._effective_model,
372
+ system_prompt=self._system_prompt,
373
+ messages=self._history,
374
+ tools=self.tools,
375
+ temperature=self.config.temperature,
376
+ max_tokens=self.config.max_tokens,
377
+ timeout=self.config.request_timeout,
378
+ ),
379
+ )
340
380
  response_text = response_msg.content or ""
341
381
 
342
382
  self.usage.add_usage(usage_stats, tool_name=None)